UNPKG

@assistant-ui/react

Version:

React components for AI chat.

278 lines 9.12 kB
// src/api/ThreadRuntime.ts import { MessageRuntimeImpl } from "./MessageRuntime.mjs"; import { NestedSubscriptionSubject } from "./subscribable/NestedSubscriptionSubject.mjs"; import { ShallowMemoizeSubject } from "./subscribable/ShallowMemoizeSubject.mjs"; import { ThreadComposerRuntimeImpl } from "./ComposerRuntime.mjs"; import { LazyMemoizeSubject } from "./subscribable/LazyMemoizeSubject.mjs"; import { SKIP_UPDATE } from "./subscribable/SKIP_UPDATE.mjs"; var toAppendMessage = (messages, message) => { if (typeof message === "string") { return { parentId: messages.at(-1)?.id ?? null, role: "user", content: [{ type: "text", text: message }], attachments: [] }; } if (message.role && message.parentId && message.attachments) { return message; } return { ...message, parentId: message.parentId ?? messages.at(-1)?.id ?? null, role: message.role ?? "user", attachments: message.attachments ?? [] }; }; var getThreadState = (runtime) => { const lastMessage = runtime.messages.at(-1); return Object.freeze({ threadId: runtime.threadId, capabilities: runtime.capabilities, isDisabled: runtime.isDisabled, isRunning: lastMessage?.role !== "assistant" ? false : lastMessage.status.type === "running", messages: runtime.messages, suggestions: runtime.suggestions, extras: runtime.extras, speech: runtime.speech }); }; var ThreadRuntimeImpl = class { get path() { return this._threadBinding.path; } /** * @deprecated Use `getState().threadId` instead. This will be removed in 0.6.0. */ get threadId() { return this.getState().threadId; } /** * @deprecated Use `getState().isDisabled` instead. This will be removed in 0.6.0. */ get isDisabled() { return this.getState().isDisabled; } /** * @deprecated Use `getState().isRunning` instead. This will be removed in 0.6.0. */ get isRunning() { return this.getState().isRunning; } /** * @deprecated Use `getState().capabilities` instead. This will be removed in 0.6.0. */ get capabilities() { return this.getState().capabilities; } /** * @deprecated Use `getState().extras` instead. This will be removed in 0.6.0. */ get extras() { return this._threadBinding.getState().extras; } /** * @deprecated Use `getState().followupSuggestions` instead. This will be removed in 0.6.0. */ get suggestions() { return this._threadBinding.getState().suggestions; } /** * @deprecated Use `getState().messages` instead. This will be removed in 0.6.0. */ get messages() { return this._threadBinding.getState().messages; } /** * @deprecated Use `getState().speechState` instead. This will be removed in 0.6.0. */ get speech() { return this._threadBinding.getState().speech; } unstable_getCore() { return this._threadBinding.getState(); } _threadBinding; constructor(threadBinding) { const stateBinding = new LazyMemoizeSubject({ path: threadBinding.path, getState: () => getThreadState(threadBinding.getState()), subscribe: (callback) => threadBinding.subscribe(callback) }); this._threadBinding = { path: threadBinding.path, getState: () => threadBinding.getState(), getStateState: () => stateBinding.getState(), outerSubscribe: (callback) => threadBinding.outerSubscribe(callback), subscribe: (callback) => threadBinding.subscribe(callback) }; this.composer = new ThreadComposerRuntimeImpl( new NestedSubscriptionSubject({ path: { ...this.path, ref: this.path.ref + `${this.path.ref}.composer`, composerSource: "thread" }, getState: () => this._threadBinding.getState().composer, subscribe: (callback) => this._threadBinding.subscribe(callback) }) ); } composer; getState() { return this._threadBinding.getStateState(); } append(message) { this._threadBinding.getState().append( toAppendMessage(this._threadBinding.getState().messages, message) ); } subscribe(callback) { return this._threadBinding.subscribe(callback); } /** * @derprecated Use `getMesssageById(id).getState().branchNumber` / `getMesssageById(id).getState().branchCount` instead. This will be removed in 0.6.0. */ getBranches(messageId) { return this._threadBinding.getState().getBranches(messageId); } getModelConfig() { return this._threadBinding.getState().getModelConfig(); } // TODO sometimes you want to continue when there is no child message startRun(parentId) { return this._threadBinding.getState().startRun(parentId); } cancelRun() { this._threadBinding.getState().cancelRun(); } /** * @deprecated Use `getMesssageById(id).getContentPartByToolCallId(toolCallId).addToolResult({ result })` instead. This will be removed in 0.6.0. */ addToolResult(options) { this._threadBinding.getState().addToolResult(options); } /** * @deprecated Use `getMesssageById(id).switchToBranch({ options })` instead. This will be removed in 0.6.0. */ switchToBranch(branchId) { return this._threadBinding.getState().switchToBranch(branchId); } /** * @deprecated Use `getMesssageById(id).speak()` instead. This will be removed in 0.6.0. */ speak(messageId) { return this._threadBinding.getState().speak(messageId); } stopSpeaking() { return this._threadBinding.getState().stopSpeaking(); } getSubmittedFeedback(messageId) { return this._threadBinding.getState().getSubmittedFeedback(messageId); } /** * @deprecated Use `getMesssageById(id).submitFeedback({ type })` instead. This will be removed in 0.6.0. */ submitFeedback(options) { return this._threadBinding.getState().submitFeedback(options); } /** * @deprecated Use `getMesssageById(id).getMessageByIndex(idx).composer` instead. This will be removed in 0.6.0. */ getEditComposer(messageId) { return this._threadBinding.getState().getEditComposer(messageId); } /** * @deprecated Use `getMesssageById(id).getMessageByIndex(idx).composer.beginEdit()` instead. This will be removed in 0.6.0. */ beginEdit(messageId) { return this._threadBinding.getState().beginEdit(messageId); } export() { return this._threadBinding.getState().export(); } import(data) { this._threadBinding.getState().import(data); } getMesssageByIndex(idx) { if (idx < 0) throw new Error("Message index must be >= 0"); return this._getMessageRuntime( { ...this.path, ref: this.path.ref + `${this.path.ref}.messages[${idx}]`, messageSelector: { type: "index", index: idx } }, () => { const messages = this._threadBinding.getState().messages; const message = messages[idx]; if (!message) return void 0; return { message, parentId: messages[idx - 1]?.id ?? null }; } ); } getMesssageById(messageId) { return this._getMessageRuntime( { ...this.path, ref: this.path.ref + `${this.path.ref}.messages[messageId=${JSON.stringify(messageId)}]`, messageSelector: { type: "messageId", messageId } }, () => this._threadBinding.getState().getMessageById(messageId) ); } _getMessageRuntime(path, callback) { return new MessageRuntimeImpl( new ShallowMemoizeSubject({ path, getState: () => { const { message, parentId } = callback() ?? {}; const { messages, speech: speechState } = this._threadBinding.getState(); if (!message || parentId === void 0) return SKIP_UPDATE; const thread = this._threadBinding.getState(); const branches = thread.getBranches(message.id); const submittedFeedback = thread.getSubmittedFeedback(message.id); return { ...message, message, isLast: messages.at(-1)?.id === message.id, parentId, branches, branchNumber: branches.indexOf(message.id) + 1, branchCount: branches.length, speech: speechState?.messageId === message.id ? speechState : void 0, submittedFeedback }; }, subscribe: (callback2) => this._threadBinding.subscribe(callback2) }), this._threadBinding ); } _eventListenerNestedSubscriptions = /* @__PURE__ */ new Map(); unstable_on(event, callback) { let subject = this._eventListenerNestedSubscriptions.get(event); if (!subject) { subject = new NestedSubscriptionSubject({ path: this.path, getState: () => ({ subscribe: (callback2) => this._threadBinding.getState().unstable_on(event, callback2) }), subscribe: (callback2) => this._threadBinding.outerSubscribe(callback2) }); this._eventListenerNestedSubscriptions.set(event, subject); } return subject.subscribe(callback); } }; export { ThreadRuntimeImpl, getThreadState }; //# sourceMappingURL=ThreadRuntime.mjs.map