cozy-search
Version:
UI components about search bar and IA assistant
344 lines (276 loc) • 14.8 kB
JavaScript
;
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;