UNPKG

cozy-search

Version:

UI components about search bar and IA assistant

344 lines (276 loc) 14.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = require("@assistant-ui/react"); var _react2 = _interopRequireWildcard(require("react")); var _reactRouterDom = require("react-router-dom"); var _cozyClient = require("cozy-client"); var _cozyMinilog = _interopRequireDefault(require("cozy-minilog")); var _useRealtime3 = _interopRequireDefault(require("cozy-realtime/dist/useRealtime")); var _Buttons = _interopRequireDefault(require("cozy-ui/transpiled/react/Buttons")); var _Spinner = _interopRequireDefault(require("cozy-ui/transpiled/react/Spinner")); var _Typography = _interopRequireDefault(require("cozy-ui/transpiled/react/Typography")); var _twakeI18n = require("twake-i18n"); var _AssistantProvider = require("./AssistantProvider"); var _CozyRealtimeChatAdapter = require("./adapters/CozyRealtimeChatAdapter"); var _StreamBridge = require("./adapters/StreamBridge"); var _constants = require("./constants"); var _helpers = require("./helpers"); var _queries = require("./queries"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } var log = (0, _cozyMinilog.default)('🔍 [CozyAssistantRuntimeProvider]'); var convertMessagesToThreadMessages = function convertMessagesToThreadMessages(messages) { if (!messages) return []; return messages.map(function (msg, idx) { return { id: msg.id || "msg-".concat(idx), role: msg.role, content: (0, _helpers.sanitizeChatContent)(msg.content), metadata: msg.role === 'assistant' && msg.sources ? { custom: { sources: msg.sources } } : undefined }; }); }; var ConversationLoader = function ConversationLoader(_ref) { var _conversation$relatio4, _conversation$relatio5, _conversation$relatio6; var children = _ref.children, conversationId = _ref.conversationId; var _useAssistant = (0, _AssistantProvider.useAssistant)(), setSelectedAssistantId = _useAssistant.setSelectedAssistantId; var conversationQuery = (0, _queries.buildChatConversationQueryById)(conversationId); var queryResult = (0, _cozyClient.useQuery)(conversationQuery.definition, conversationQuery.options); var conversation = queryResult.data; var isLoading = (0, _cozyClient.isQueryLoading)(queryResult); var initialMessages = (0, _react2.useMemo)(function () { return convertMessagesToThreadMessages(conversation === null || conversation === void 0 ? void 0 : conversation.messages); }, [conversation === null || conversation === void 0 ? void 0 : conversation.messages]); (0, _react2.useEffect)(function () { var _conversation$relatio, _conversation$relatio2, _conversation$relatio3; setSelectedAssistantId((conversation === null || conversation === void 0 ? void 0 : (_conversation$relatio = conversation.relationships) === null || _conversation$relatio === void 0 ? void 0 : (_conversation$relatio2 = _conversation$relatio.assistant) === null || _conversation$relatio2 === void 0 ? void 0 : (_conversation$relatio3 = _conversation$relatio2.data) === null || _conversation$relatio3 === void 0 ? void 0 : _conversation$relatio3._id) || _constants.DEFAULT_ASSISTANT._id); }, [conversation === null || conversation === void 0 ? void 0 : (_conversation$relatio4 = conversation.relationships) === null || _conversation$relatio4 === void 0 ? void 0 : (_conversation$relatio5 = _conversation$relatio4.assistant) === null || _conversation$relatio5 === void 0 ? void 0 : (_conversation$relatio6 = _conversation$relatio5.data) === null || _conversation$relatio6 === void 0 ? void 0 : _conversation$relatio6._id, setSelectedAssistantId]); if (isLoading) { return /*#__PURE__*/_react2.default.createElement("div", { className: "u-flex u-flex-items-center u-flex-justify-center u-h-100 u-w-100" }, /*#__PURE__*/_react2.default.createElement(_Spinner.default, { size: "xxlarge" })); } return /*#__PURE__*/_react2.default.createElement(CozyAssistantRuntimeProviderInner, { key: conversationId, conversationId: conversationId, initialMessages: initialMessages }, children); }; var CozyAssistantRuntimeProviderInner = function CozyAssistantRuntimeProviderInner(_ref2) { var children = _ref2.children, conversationId = _ref2.conversationId, initialMessages = _ref2.initialMessages; var _useI18n = (0, _twakeI18n.useI18n)(), t = _useI18n.t; var client = (0, _cozyClient.useClient)(); var streamBridgeRef = (0, _react2.useRef)(new _StreamBridge.StreamBridge()); var messagesIdRef = (0, _react2.useRef)([]); var cancelledMessageIdsRef = (0, _react2.useRef)(new Set()); var currentStreamingMessageIdRef = (0, _react2.useRef)(null); var _useAssistant2 = (0, _AssistantProvider.useAssistant)(), selectedAssistantId = _useAssistant2.selectedAssistantId, websearchEnabled = _useAssistant2.websearchEnabled; (0, _react2.useEffect)(function () { messagesIdRef.current = initialMessages.map(function (m) { return m.id; }).filter(function (id) { return !!id; }); }, [initialMessages]); (0, _react2.useEffect)(function () { streamBridgeRef.current.setCleanupCallback(function () { try { if (currentStreamingMessageIdRef.current) { cancelledMessageIdsRef.current.add(currentStreamingMessageIdRef.current); currentStreamingMessageIdRef.current = null; } } catch (error) { log.error('Error during StreamBridge cleanup callback:', error); } }); }, []); var handleConversationChange = (0, _react2.useCallback)(function (res) { try { if (res._id === conversationId && res.messages) { var newIds = res.messages.map(function (m) { return m.id; }); var lastAssistantMsg = res.messages.filter(function (m) { return m.role === 'assistant'; }).pop(); if (lastAssistantMsg && !messagesIdRef.current.includes(lastAssistantMsg.id)) { if (currentStreamingMessageIdRef.current && currentStreamingMessageIdRef.current !== lastAssistantMsg.id) { cancelledMessageIdsRef.current.add(currentStreamingMessageIdRef.current); } currentStreamingMessageIdRef.current = lastAssistantMsg.id; } messagesIdRef.current = newIds; } } catch (error) { log.error('Error handling conversation change:', error); } }, [conversationId]); (0, _useRealtime3.default)(client, (0, _defineProperty2.default)({}, _queries.CHAT_CONVERSATIONS_DOCTYPE, { created: handleConversationChange, updated: handleConversationChange }), [conversationId]); (0, _useRealtime3.default)(client, (0, _defineProperty2.default)({}, _queries.CHAT_EVENTS_DOCTYPE, { created: function created(res) { if (cancelledMessageIdsRef.current.has(res._id)) { if (res.object === 'done' || res.object === 'error') { cancelledMessageIdsRef.current.delete(res._id); } return; } // Track which message is currently streaming // When a different message starts, mark the old one as cancelled if (res.object === 'delta') { if (currentStreamingMessageIdRef.current && currentStreamingMessageIdRef.current !== res._id) { cancelledMessageIdsRef.current.add(currentStreamingMessageIdRef.current); } currentStreamingMessageIdRef.current = res._id; } try { if (res.object === 'delta' && res.content !== undefined) { streamBridgeRef.current.onDelta(conversationId, res.content, res.position); } if (res.object === 'sources') { streamBridgeRef.current.onSources(conversationId, res.content); } if (res.object === 'done') { streamBridgeRef.current.onDone(conversationId); currentStreamingMessageIdRef.current = null; } if (res.object === 'error') { log.error('LLM error:', res.message); streamBridgeRef.current.onError(conversationId, new Error('LLM error')); currentStreamingMessageIdRef.current = null; } } catch (error) { log.error('Error handling chat real-time event:', error); } } }), [conversationId]); var adapter = (0, _react2.useMemo)(function () { return (0, _CozyRealtimeChatAdapter.createCozyRealtimeChatAdapter)({ client: client, conversationId: conversationId, assistantId: selectedAssistantId, websearchEnabled: websearchEnabled }, t, // eslint-disable-next-line react-hooks/refs -- streamBridgeRef is stable and only read inside adapter.run(), not during render streamBridgeRef); }, [client, conversationId, selectedAssistantId, websearchEnabled, t]); var runtime = (0, _react.useLocalRuntime)(adapter, { initialMessages: initialMessages }); (0, _react2.useEffect)(function () { var streamBridge = streamBridgeRef.current; return function () { try { streamBridge.cleanup(conversationId); } catch (error) { log.error('Error cleaning up StreamBridge on unmount:', error); } }; }, [conversationId]); return /*#__PURE__*/_react2.default.createElement(_react.AssistantRuntimeProvider, { runtime: runtime }, children); }; /** * Provider that sets up assistant-ui runtime with Cozy's backend. * Must be used within a route that provides conversationId param. */ var CozyAssistantRuntimeProvider = function CozyAssistantRuntimeProvider(_ref3) { var children = _ref3.children; var _useParams = (0, _reactRouterDom.useParams)(), conversationId = _useParams.conversationId; if (!conversationId) { return null; } return /*#__PURE__*/_react2.default.createElement(ConversationLoader, { conversationId: conversationId }, children); }; var CozyAssistantErrorBoundary = /*#__PURE__*/function (_React$Component) { (0, _inherits2.default)(CozyAssistantErrorBoundary, _React$Component); var _super = _createSuper(CozyAssistantErrorBoundary); function CozyAssistantErrorBoundary(props) { var _this; (0, _classCallCheck2.default)(this, CozyAssistantErrorBoundary); _this = _super.call(this, props); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "handleRetry", function () { _this.setState({ hasError: false, error: null }); }); _this.state = { hasError: false, error: null }; return _this; } (0, _createClass2.default)(CozyAssistantErrorBoundary, [{ key: "componentDidCatch", value: function componentDidCatch(error, errorInfo) { log.error('Assistant Runtime UI crashed:', error, errorInfo); } }, { key: "render", value: function render() { if (this.state.hasError) { return /*#__PURE__*/_react2.default.createElement("div", { className: "u-flex u-flex-column u-flex-items-center u-flex-justify-center u-h-100 u-w-100 u-ta-center" }, /*#__PURE__*/_react2.default.createElement(_Typography.default, { variant: "h4", className: "u-mb-1", color: "error" }, this.props.t('assistant.default_error')), /*#__PURE__*/_react2.default.createElement(_Buttons.default, { label: this.props.t('assistant.actions.reload'), onClick: this.handleRetry, variant: "secondary" })); } return this.props.children; } }], [{ key: "getDerivedStateFromError", value: function getDerivedStateFromError(error) { return { hasError: true, error: error }; } }]); return CozyAssistantErrorBoundary; }(_react2.default.Component); var CozyAssistantRuntimeProviderWithErrorBoundary = function CozyAssistantRuntimeProviderWithErrorBoundary(props) { var _useI18n2 = (0, _twakeI18n.useI18n)(), t = _useI18n2.t; return /*#__PURE__*/_react2.default.createElement(CozyAssistantErrorBoundary, { t: t }, /*#__PURE__*/_react2.default.createElement(CozyAssistantRuntimeProvider, props)); }; var _default = CozyAssistantRuntimeProviderWithErrorBoundary; exports.default = _default;