@assistant-ui/core 0.3.12 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/react/client/interactable-model-context.d.ts.map +1 -1
- package/dist/react/client/interactable-model-context.js +5 -1
- package/dist/react/client/interactable-model-context.js.map +1 -1
- package/dist/runtime/api/thread-runtime.d.ts.map +1 -1
- package/dist/runtime/api/thread-runtime.js +5 -1
- package/dist/runtime/api/thread-runtime.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +25 -0
- package/dist/runtime/base/base-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.js +64 -11
- package/dist/runtime/base/base-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.d.ts +14 -0
- package/dist/runtime/base/base-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/base-thread-runtime-core.js +31 -0
- package/dist/runtime/base/base-thread-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +1 -6
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-thread-composer-runtime-core.js +1 -4
- package/dist/runtime/base/default-thread-composer-runtime-core.js.map +1 -1
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts +15 -0
- package/dist/runtime/queue/external-thread-queue-adapter.d.ts.map +1 -1
- package/dist/runtime/queue/message-queue.js +23 -10
- package/dist/runtime/queue/message-queue.js.map +1 -1
- package/dist/runtimes/external-store/external-store-adapter.d.ts +7 -0
- package/dist/runtimes/external-store/external-store-adapter.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts +3 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js +49 -13
- package/dist/runtimes/external-store/external-store-thread-runtime-core.js.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.d.ts.map +1 -1
- package/dist/runtimes/local/local-thread-runtime-core.js +2 -1
- package/dist/runtimes/local/local-thread-runtime-core.js.map +1 -1
- package/dist/store/clients/external-thread.d.ts +7 -0
- package/dist/store/clients/external-thread.d.ts.map +1 -1
- package/dist/store/clients/external-thread.js +460 -369
- package/dist/store/clients/external-thread.js.map +1 -1
- package/dist/store/clients/runtime-adapter.d.ts.map +1 -1
- package/dist/store/clients/runtime-adapter.js +5 -2
- package/dist/store/clients/runtime-adapter.js.map +1 -1
- package/dist/store/clients/single-thread-list.d.ts.map +1 -1
- package/dist/store/clients/single-thread-list.js +31 -27
- package/dist/store/clients/single-thread-list.js.map +1 -1
- package/dist/store/clients/suggestions.d.ts +3 -1
- package/dist/store/clients/suggestions.d.ts.map +1 -1
- package/dist/store/clients/suggestions.js +65 -37
- package/dist/store/clients/suggestions.js.map +1 -1
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js +64 -50
- package/dist/store/runtime-clients/thread-list-item-runtime-client.js.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.d.ts.map +1 -1
- package/dist/store/runtime-clients/thread-runtime-client.js +98 -82
- package/dist/store/runtime-clients/thread-runtime-client.js.map +1 -1
- package/dist/store/scope-registration.d.ts +2 -2
- package/dist/store/scopes/suggestions.d.ts +6 -1
- package/dist/store/scopes/suggestions.d.ts.map +1 -1
- package/dist/store/scopes/thread.d.ts +17 -0
- package/dist/store/scopes/thread.d.ts.map +1 -1
- package/dist/types/error.d.ts +15 -1
- package/dist/types/error.d.ts.map +1 -1
- package/dist/types/error.js +18 -1
- package/dist/types/error.js.map +1 -1
- package/dist/types/message.d.ts +2 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +1 -0
- package/src/react/client/interactable-model-context.ts +6 -1
- package/src/react/runtimes/useExternalStoreRuntime.suggestions.test.tsx +114 -0
- package/src/runtime/api/thread-runtime.ts +8 -1
- package/src/runtime/base/base-composer-runtime-core.ts +100 -8
- package/src/runtime/base/base-thread-runtime-core.ts +36 -0
- package/src/runtime/base/default-edit-composer-runtime-core.ts +1 -15
- package/src/runtime/base/default-thread-composer-runtime-core.ts +1 -11
- package/src/runtime/queue/external-thread-queue-adapter.ts +17 -0
- package/src/runtime/queue/message-queue.ts +26 -9
- package/src/runtimes/external-store/external-store-adapter.ts +7 -0
- package/src/runtimes/external-store/external-store-thread-runtime-core.ts +100 -26
- package/src/runtimes/local/local-thread-runtime-core.ts +4 -1
- package/src/store/clients/external-thread.ts +119 -16
- package/src/store/clients/runtime-adapter.ts +5 -2
- package/src/store/clients/single-thread-list.ts +2 -1
- package/src/store/clients/suggestions.ts +39 -13
- package/src/store/runtime-clients/thread-list-item-runtime-client.ts +13 -28
- package/src/store/runtime-clients/thread-runtime-client.ts +5 -0
- package/src/store/scopes/suggestions.ts +6 -0
- package/src/store/scopes/thread.ts +17 -0
- package/src/tests/append-interactable-snapshots.test.ts +350 -0
- package/src/tests/base-composer-runtime-core-send.test.ts +126 -0
- package/src/tests/base-composer-runtime-core.test.ts +108 -1
- package/src/tests/default-edit-composer-runtime-core.test.ts +0 -68
- package/src/tests/external-store-thread-runtime-core-adapter.test.ts +300 -0
- package/src/tests/external-thread-attachments.test.tsx +214 -0
- package/src/tests/external-thread-parity.test.tsx +54 -0
- package/src/tests/external-thread-refetch.test.tsx +117 -0
- package/src/tests/external-thread-suggestions.test.tsx +59 -0
- package/src/tests/message-queue.test.ts +26 -0
- package/src/tests/thread-message-like.test.ts +39 -0
- package/src/tests/thread-switch-events.test.tsx +136 -0
- package/src/types/error.ts +24 -0
- package/src/types/message.ts +2 -0
- package/src/tests/default-thread-composer-runtime-core.test.ts +0 -82
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-composer-runtime-core.js","names":["isCreateAttachment","Attachment","CompleteAttachment","CreateAttachment","PendingAttachment","MessageRole","AppendMessage","QuoteInfo","Unsubscribe","RunConfig","BaseSubscribable","AttachmentAdapter","fileMatchesAccept","AttachmentAddErrorReason","ComposerRuntimeCore","ComposerRuntimeEventCallback","ComposerRuntimeEventPayload","ComposerRuntimeEventType","DictationState","SendOptions","DictationAdapter","QueuePlacement","EMPTY_QUEUE_ITEMS","QueueItemState","generateId","notifyEventListeners","isAttachmentComplete","a","status","type","AttachmentAddOperation","cancelled","attachmentIds","Set","BaseComposerRuntimeCore","isEditing","getAttachmentAdapter","getDictationAdapter","enrichWithComposerMetadata","metadata","custom","Record","message","T","composerMetadata","attachmentAccept","accept","_attachments","attachments","setAttachments","value","_notifySubscribers","canCancel","canSend","isEmpty","text","trim","length","_text","_role","role","_runConfig","runConfig","_quote","undefined","quote","setQuote","setText","_dictation","_dictationBaseText","_currentInterimText","inputDisabled","setRole","setRunConfig","_isSending","_removedDuringSend","_sendGeneration","_attachmentAddOperations","_cancelAttachmentAdd","attachmentId","operation","has","delete","_cancelAllAttachmentAdds","clear","_emptyTextAndAttachments","_onClearAttachments","adapter","pending","filter","Promise","all","map","remove","reset","Object","keys","task","clearAttachments","send","options","_dictationSession","cancel","_cleanupDictation","attachmentTasks","Error","result","originalAttachments","generation","resolvedAttachments","e","allSettled","then","sentIds","id","finalAttachments","Omit","createdAt","Date","content","sendTask","handleSend","catch","_notifyEventSubscribers","handleCancel","queue","moveQueueItem","_queueItemId","_placement","removeQueueItem","addAttachment","fileOrAttachment","File","name","contentType","err","_safeEmitAttachmentAddError","operations","add","upsertAttachment","idx","findIndex","attachment","slice","lastAttachment","promiseOrGenerator","file","Symbol","asyncIterator","r","reason","String","error","subscriberError","console","removeAttachment","index","candidate","Session","_dictationUnsubscribes","_dictationSessionIdCounter","_activeDictationSessionId","_isCleaningDictation","dictation","_isActiveSession","sessionId","session","startDictation","unsub","oldSession","stop","disableInputDuringDictation","listen","unsubSpeech","onSpeech","isFinal","needsSeparator","endsWith","transcript","separator","_","rest","push","unsubStart","onSpeechStart","unsubEnd","onSpeechEnd","statusInterval","setInterval","clearInterval","stopDictation","finally","isStaleSession","_eventSubscribers","Map","payload","event","E","subscribers","get","unstable_on","callback","wrapped","set"],"sources":["../../../src/runtime/base/base-composer-runtime-core.ts"],"sourcesContent":["import {\n isCreateAttachment,\n type Attachment,\n type CompleteAttachment,\n type CreateAttachment,\n type PendingAttachment,\n} from \"../../types/attachment\";\nimport type { MessageRole, AppendMessage } from \"../../types/message\";\nimport type { QuoteInfo } from \"../../types/quote\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { RunConfig } from \"../../types/message\";\nimport { BaseSubscribable } from \"../../subscribable/subscribable\";\nimport {\n type AttachmentAdapter,\n fileMatchesAccept,\n} from \"../../adapters/attachment\";\nimport type {\n AttachmentAddErrorReason,\n ComposerRuntimeCore,\n ComposerRuntimeEventCallback,\n ComposerRuntimeEventPayload,\n ComposerRuntimeEventType,\n DictationState,\n SendOptions,\n} from \"../interfaces/composer-runtime-core\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type { QueuePlacement } from \"../queue/external-thread-queue-adapter\";\nimport {\n EMPTY_QUEUE_ITEMS,\n type QueueItemState,\n} from \"../../store/scopes/queue-item\";\nimport { generateId } from \"../../utils/id\";\nimport { notifyEventListeners } from \"../../utils/notify-event-listeners\";\n\nconst isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>\n a.status.type === \"complete\";\n\ntype AttachmentAddOperation = {\n cancelled: boolean;\n attachmentIds: Set<string>;\n};\n\nexport abstract class BaseComposerRuntimeCore\n extends BaseSubscribable\n implements ComposerRuntimeCore\n{\n public readonly isEditing = true;\n\n protected abstract getAttachmentAdapter(): AttachmentAdapter | undefined;\n protected abstract getDictationAdapter(): DictationAdapter | undefined;\n\n protected enrichWithComposerMetadata<\n T extends { metadata?: { custom?: Record<string, unknown> } },\n >(message: T, composerMetadata: Record<string, unknown> | undefined): T {\n if (!composerMetadata) return message;\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: { ...message.metadata?.custom, ...composerMetadata },\n },\n } as T;\n }\n\n public get attachmentAccept(): string {\n return this.getAttachmentAdapter()?.accept ?? \"*\";\n }\n\n private _attachments: readonly Attachment[] = [];\n public get attachments() {\n return this._attachments;\n }\n\n protected setAttachments(value: readonly Attachment[]) {\n this._attachments = value;\n this._notifySubscribers();\n }\n\n public abstract get canCancel(): boolean;\n public abstract get canSend(): boolean;\n\n public get isEmpty() {\n return !this.text.trim() && !this.attachments.length;\n }\n\n private _text = \"\";\n\n get text() {\n return this._text;\n }\n\n private _role: MessageRole = \"user\";\n\n get role() {\n return this._role;\n }\n\n private _runConfig: RunConfig = {};\n\n get runConfig() {\n return this._runConfig;\n }\n\n private _quote: QuoteInfo | undefined = undefined;\n\n get quote() {\n return this._quote;\n }\n\n public setQuote(quote: QuoteInfo | undefined) {\n if (this._quote === quote) return;\n\n this._quote = quote;\n this._notifySubscribers();\n }\n\n public setText(value: string) {\n if (this._text === value) return;\n\n this._text = value;\n if (this._dictation) {\n this._dictationBaseText = value;\n this._currentInterimText = \"\";\n const { status, inputDisabled } = this._dictation;\n this._dictation = inputDisabled ? { status, inputDisabled } : { status };\n }\n this._notifySubscribers();\n }\n\n public setRole(role: MessageRole) {\n if (this._role === role) return;\n\n this._role = role;\n this._notifySubscribers();\n }\n\n public setRunConfig(runConfig: RunConfig) {\n if (this._runConfig === runConfig) return;\n\n this._runConfig = runConfig;\n this._notifySubscribers();\n }\n\n protected _isSending = false;\n private _removedDuringSend = new Set<string>();\n private _sendGeneration = 0;\n private _attachmentAddOperations = new Set<AttachmentAddOperation>();\n\n private _cancelAttachmentAdd(attachmentId: string) {\n for (const operation of [...this._attachmentAddOperations]) {\n if (!operation.attachmentIds.has(attachmentId)) continue;\n operation.cancelled = true;\n this._attachmentAddOperations.delete(operation);\n }\n }\n\n private _cancelAllAttachmentAdds() {\n for (const operation of this._attachmentAddOperations) {\n operation.cancelled = true;\n }\n this._attachmentAddOperations.clear();\n }\n\n private _emptyTextAndAttachments() {\n this._attachments = [];\n this._text = \"\";\n this._notifySubscribers();\n }\n\n private async _onClearAttachments() {\n const adapter = this.getAttachmentAdapter();\n if (adapter) {\n const pending = this._attachments.filter((a) => !isAttachmentComplete(a));\n await Promise.all(pending.map((a) => adapter.remove(a)));\n }\n }\n\n public async reset() {\n this._cancelAllAttachmentAdds();\n\n // A send whose adapter never settles must not brick the composer; reset is\n // the escape hatch that releases the in-flight lock. Bumping the generation\n // invalidates that send entirely so a late-settling upload can neither\n // append the discarded draft nor touch a newer send's lock.\n this._sendGeneration++;\n this._isSending = false;\n this._removedDuringSend.clear();\n\n if (\n this._attachments.length === 0 &&\n this._text === \"\" &&\n this._role === \"user\" &&\n Object.keys(this._runConfig).length === 0 &&\n this._quote === undefined\n ) {\n return;\n }\n\n this._role = \"user\";\n this._runConfig = {};\n this._quote = undefined;\n\n const task = this._onClearAttachments();\n this._emptyTextAndAttachments();\n await task;\n }\n\n public async clearAttachments() {\n this._cancelAllAttachmentAdds();\n const task = this._onClearAttachments();\n this.setAttachments([]);\n\n await task;\n }\n\n public async send(options?: SendOptions) {\n if (!this.canSend || this._isSending) return;\n\n if (this._dictationSession) {\n this._dictationSession.cancel();\n this._cleanupDictation();\n }\n\n const adapter = this.getAttachmentAdapter();\n const attachmentTasks = this.attachments.map(async (a) => {\n if (isAttachmentComplete(a)) return a;\n if (!adapter) throw new Error(\"Attachments are not supported\");\n const result = await adapter.send(a);\n return result as CompleteAttachment;\n });\n\n const originalAttachments = this.attachments;\n const text = this.text;\n const quote = this._quote;\n this._quote = undefined;\n this._text = \"\";\n this._isSending = true;\n const generation = ++this._sendGeneration;\n this._notifySubscribers();\n\n let resolvedAttachments: CompleteAttachment[];\n try {\n resolvedAttachments = await Promise.all(attachmentTasks);\n } catch (e) {\n if (generation === this._sendGeneration) {\n if (!this.text.trim() && this._quote === undefined) {\n this._text = text;\n this._quote = quote;\n this._notifySubscribers();\n }\n // Promise.all rejects on the first failure, but sibling uploads from\n // this batch keep running; the send rejects immediately while the\n // retry lock is held until they settle, or a retry could re-send\n // attachments that are still in flight.\n void Promise.allSettled(attachmentTasks).then(() => {\n if (generation !== this._sendGeneration) return;\n this._removedDuringSend.clear();\n this._isSending = false;\n this._notifySubscribers();\n });\n }\n throw e;\n }\n\n // A reset during the upload discarded this send's draft; the settled\n // uploads must not append it or touch the lock a newer send may own.\n if (generation !== this._sendGeneration) return;\n\n // Drop by id, not wholesale: the user may have added or removed chips while\n // the upload was in flight.\n const sentIds = new Set(originalAttachments.map((a) => a.id));\n this._attachments = this._attachments.filter((a) => !sentIds.has(a.id));\n this._isSending = false;\n this._notifySubscribers();\n\n // An attachment removed mid-upload can't be cancelled, but it can still be\n // dropped from the outgoing message instead of silently being sent anyway.\n const finalAttachments = resolvedAttachments.filter(\n (a) => !this._removedDuringSend.has(a.id),\n );\n this._removedDuringSend.clear();\n\n const message: Omit<AppendMessage, \"parentId\" | \"sourceId\"> = {\n createdAt: new Date(),\n role: this.role,\n content: text ? [{ type: \"text\", text }] : [],\n attachments: finalAttachments,\n runConfig: this.runConfig,\n metadata: { custom: { ...(quote ? { quote } : {}) } },\n };\n\n const sendTask = this.handleSend(message, options);\n if (sendTask) void sendTask.catch(() => {});\n this._notifyEventSubscribers(\"send\", {});\n }\n\n public cancel() {\n this.handleCancel();\n }\n\n public get queue(): readonly QueueItemState[] {\n return EMPTY_QUEUE_ITEMS;\n }\n\n public moveQueueItem(\n _queueItemId: string,\n _placement: QueuePlacement,\n ): void {}\n public removeQueueItem(_queueItemId: string): void {}\n\n protected abstract handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ): void | Promise<void>;\n protected abstract handleCancel(): void;\n\n async addAttachment(fileOrAttachment: File | CreateAttachment) {\n if (isCreateAttachment(fileOrAttachment)) {\n const adapter = this.getAttachmentAdapter();\n if (\n adapter &&\n !fileMatchesAccept(\n {\n name: fileOrAttachment.name,\n type: fileOrAttachment.contentType ?? \"\",\n },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.contentType || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\n \"not-accepted\",\n message,\n undefined,\n err,\n );\n throw err;\n }\n\n const a: CompleteAttachment = {\n id: fileOrAttachment.id ?? generateId(),\n type: fileOrAttachment.type ?? \"document\",\n name: fileOrAttachment.name,\n contentType: fileOrAttachment.contentType,\n content: fileOrAttachment.content,\n status: { type: \"complete\" },\n };\n this._attachments = [...this._attachments, a];\n this._notifySubscribers();\n this._notifyEventSubscribers(\"attachmentAdd\", {});\n return;\n }\n\n const adapter = this.getAttachmentAdapter();\n if (!adapter) {\n const message = \"Attachments are not supported\";\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\"no-adapter\", message, undefined, err);\n throw err;\n }\n\n if (\n !fileMatchesAccept(\n { name: fileOrAttachment.name, type: fileOrAttachment.type },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.type || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\"not-accepted\", message, undefined, err);\n throw err;\n }\n\n const operation: AttachmentAddOperation = {\n cancelled: false,\n attachmentIds: new Set(),\n };\n const operations = this._attachmentAddOperations;\n operations.add(operation);\n const upsertAttachment = (a: PendingAttachment) => {\n if (operation.cancelled) return false;\n\n operation.attachmentIds.add(a.id);\n const idx = this._attachments.findIndex(\n (attachment) => attachment.id === a.id,\n );\n if (idx !== -1)\n this._attachments = [\n ...this._attachments.slice(0, idx),\n a,\n ...this._attachments.slice(idx + 1),\n ];\n else {\n this._attachments = [...this._attachments, a];\n }\n\n this._notifySubscribers();\n return true;\n };\n let lastAttachment: PendingAttachment | undefined;\n try {\n const promiseOrGenerator = adapter.add({ file: fileOrAttachment });\n if (Symbol.asyncIterator in promiseOrGenerator) {\n for await (const r of promiseOrGenerator) {\n lastAttachment = r;\n if (!upsertAttachment(r)) break;\n }\n } else {\n lastAttachment = await promiseOrGenerator;\n upsertAttachment(lastAttachment);\n }\n } catch (e) {\n if (operation.cancelled) return;\n if (lastAttachment) {\n upsertAttachment({\n ...lastAttachment,\n status: {\n type: \"incomplete\",\n reason: \"error\",\n message: e instanceof Error ? e.message : String(e),\n },\n });\n }\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n e instanceof Error ? e.message : String(e),\n lastAttachment?.id,\n e instanceof Error ? e : undefined,\n );\n throw e;\n } finally {\n operations.delete(operation);\n }\n\n if (operation.cancelled) return;\n if (\n lastAttachment?.status.type === \"incomplete\" &&\n lastAttachment.status.reason === \"error\"\n ) {\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n lastAttachment.status.message ??\n \"Attachment upload did not complete successfully.\",\n lastAttachment.id,\n );\n } else {\n this._notifyEventSubscribers(\"attachmentAdd\", {});\n }\n }\n\n private _safeEmitAttachmentAddError(\n reason: AttachmentAddErrorReason,\n message: string,\n attachmentId?: string,\n error?: Error,\n ) {\n try {\n this._notifyEventSubscribers(\"attachmentAddError\", {\n reason,\n message,\n ...(attachmentId !== undefined && { attachmentId }),\n ...(error !== undefined && { error }),\n });\n } catch (subscriberError) {\n console.error(\n \"[assistant-ui] attachmentAddError subscriber threw:\",\n subscriberError,\n );\n }\n }\n\n async removeAttachment(attachmentId: string) {\n const index = this._attachments.findIndex((a) => a.id === attachmentId);\n if (index === -1) throw new Error(\"Attachment not found\");\n const attachment = this._attachments[index]!;\n\n this._cancelAttachmentAdd(attachmentId);\n\n // A send in flight may already be uploading this attachment; the upload\n // can't be cancelled, so mark it to be dropped from the outgoing message\n // before any await gives the upload a chance to settle first.\n if (this._isSending) this._removedDuringSend.add(attachmentId);\n\n if (!isAttachmentComplete(attachment)) {\n const adapter = this.getAttachmentAdapter();\n if (!adapter) throw new Error(\"Attachments are not supported\");\n try {\n await adapter.remove(attachment);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this._attachments = this._attachments.map((candidate) =>\n candidate.id === attachmentId && !isAttachmentComplete(candidate)\n ? {\n ...candidate,\n status: { type: \"incomplete\", reason: \"error\", message },\n }\n : candidate,\n );\n this._notifySubscribers();\n throw error;\n }\n }\n this._attachments = this._attachments.filter((a) => a.id !== attachmentId);\n this._notifySubscribers();\n }\n\n private _dictation: DictationState | undefined;\n private _dictationSession: DictationAdapter.Session | undefined;\n private _dictationUnsubscribes: Unsubscribe[] = [];\n private _dictationBaseText = \"\";\n private _currentInterimText = \"\";\n private _dictationSessionIdCounter = 0;\n private _activeDictationSessionId: number | undefined;\n private _isCleaningDictation = false;\n\n public get dictation(): DictationState | undefined {\n return this._dictation;\n }\n\n private _isActiveSession(\n sessionId: number,\n session: DictationAdapter.Session,\n ): boolean {\n return (\n this._activeDictationSessionId === sessionId &&\n this._dictationSession === session\n );\n }\n\n public startDictation(): void {\n const adapter = this.getDictationAdapter();\n if (!adapter) {\n throw new Error(\"Dictation adapter not configured\");\n }\n\n if (this._dictationSession) {\n for (const unsub of this._dictationUnsubscribes) {\n unsub();\n }\n this._dictationUnsubscribes = [];\n const oldSession = this._dictationSession;\n oldSession.stop().catch(() => {});\n this._dictationSession = undefined;\n }\n\n const inputDisabled = adapter.disableInputDuringDictation ?? false;\n\n this._dictationBaseText = this._text;\n this._currentInterimText = \"\";\n\n const session = adapter.listen();\n this._dictationSession = session;\n const sessionId = ++this._dictationSessionIdCounter;\n this._activeDictationSessionId = sessionId;\n this._dictation = { status: session.status, inputDisabled };\n this._notifySubscribers();\n\n const unsubSpeech = session.onSpeech((result) => {\n if (!this._isActiveSession(sessionId, session)) return;\n const isFinal = result.isFinal !== false;\n\n const needsSeparator =\n this._dictationBaseText &&\n !this._dictationBaseText.endsWith(\" \") &&\n result.transcript;\n const separator = needsSeparator ? \" \" : \"\";\n\n if (isFinal) {\n this._dictationBaseText =\n this._dictationBaseText + separator + result.transcript;\n this._currentInterimText = \"\";\n this._text = this._dictationBaseText;\n\n if (this._dictation) {\n const { transcript: _, ...rest } = this._dictation;\n this._dictation = rest;\n }\n this._notifySubscribers();\n } else {\n this._currentInterimText = separator + result.transcript;\n this._text = this._dictationBaseText + this._currentInterimText;\n\n if (this._dictation) {\n this._dictation = {\n ...this._dictation,\n transcript: result.transcript,\n };\n }\n this._notifySubscribers();\n }\n });\n this._dictationUnsubscribes.push(unsubSpeech);\n\n const unsubStart = session.onSpeechStart(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n this._dictation = {\n status: { type: \"running\" },\n inputDisabled,\n ...(this._dictation?.transcript && {\n transcript: this._dictation.transcript,\n }),\n };\n this._notifySubscribers();\n });\n this._dictationUnsubscribes.push(unsubStart);\n\n const unsubEnd = session.onSpeechEnd(() => {\n this._cleanupDictation({ sessionId });\n });\n this._dictationUnsubscribes.push(unsubEnd);\n\n const statusInterval = setInterval(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n if (session.status.type === \"ended\") {\n this._cleanupDictation({ sessionId });\n }\n }, 100);\n this._dictationUnsubscribes.push(() => clearInterval(statusInterval));\n }\n\n public stopDictation(): void {\n if (!this._dictationSession) return;\n\n const session = this._dictationSession;\n const sessionId = this._activeDictationSessionId;\n session.stop().finally(() => {\n this._cleanupDictation({ sessionId });\n });\n }\n\n private _cleanupDictation(options?: { sessionId: number | undefined }): void {\n const isStaleSession =\n options?.sessionId !== undefined &&\n options.sessionId !== this._activeDictationSessionId;\n if (isStaleSession || this._isCleaningDictation) return;\n\n this._isCleaningDictation = true;\n try {\n for (const unsub of this._dictationUnsubscribes) {\n unsub();\n }\n this._dictationUnsubscribes = [];\n this._dictationSession = undefined;\n this._activeDictationSessionId = undefined;\n this._dictation = undefined;\n this._dictationBaseText = \"\";\n this._currentInterimText = \"\";\n this._notifySubscribers();\n } finally {\n this._isCleaningDictation = false;\n }\n }\n\n private _eventSubscribers = new Map<\n ComposerRuntimeEventType,\n Set<(payload?: unknown) => void>\n >();\n\n protected _notifyEventSubscribers<E extends ComposerRuntimeEventType>(\n event: E,\n payload: ComposerRuntimeEventPayload[E],\n ) {\n const subscribers = this._eventSubscribers.get(event);\n if (!subscribers) return;\n\n notifyEventListeners(subscribers, payload, `Composer runtime \"${event}\"`);\n }\n\n public unstable_on<E extends ComposerRuntimeEventType>(\n event: E,\n callback: ComposerRuntimeEventCallback<E>,\n ) {\n const wrapped = callback as (payload?: unknown) => void;\n let subscribers = this._eventSubscribers.get(event);\n if (!subscribers) {\n subscribers = new Set();\n this._eventSubscribers.set(event, subscribers);\n }\n subscribers.add(wrapped);\n\n return () => {\n this._eventSubscribers.get(event)?.delete(wrapped);\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-composer-runtime-core.js","names":["isCreateAttachment","Attachment","CompleteAttachment","CreateAttachment","PendingAttachment","MessageRole","AppendMessage","isMessageNotSentError","QuoteInfo","Unsubscribe","RunConfig","BaseSubscribable","AttachmentAdapter","fileMatchesAccept","AttachmentAddErrorReason","ComposerRuntimeCore","ComposerRuntimeEventCallback","ComposerRuntimeEventPayload","ComposerRuntimeEventType","DictationState","SendOptions","DictationAdapter","QueuePlacement","EMPTY_QUEUE_ITEMS","QueueItemState","generateId","notifyEventListeners","isAttachmentComplete","a","status","type","AttachmentAddOperation","cancelled","attachmentIds","Set","BaseComposerRuntimeCore","isEditing","getAttachmentAdapter","getDictationAdapter","enrichWithComposerMetadata","metadata","custom","Record","message","T","composerMetadata","attachmentAccept","accept","_attachments","attachments","setAttachments","value","_notifySubscribers","canCancel","canSend","isEmpty","text","trim","length","_text","_role","role","_runConfig","runConfig","_quote","undefined","quote","setQuote","setText","_rebaseDictation","_dictation","_dictationBaseText","_currentInterimText","inputDisabled","setRole","setRunConfig","_isSending","_removedDuringSend","_sendGeneration","_attachmentAddOperations","_cancelAttachmentAdd","attachmentId","operation","has","delete","_cancelAllAttachmentAdds","clear","_emptyTextAndAttachments","_onClearAttachments","adapter","pending","filter","Promise","all","map","remove","reset","Object","keys","task","clearAttachments","send","options","_dictationSession","cancel","_cleanupDictation","attachmentTasks","Error","result","originalAttachments","generation","resolvedAttachments","e","allSettled","then","sentIds","id","finalAttachments","Omit","createdAt","Date","content","draft","sendTask","handleSend","error","_restoreUnsentDraft","catch","_notifyEventSubscribers","restoreDraft","retractDraft","attachmentsUntouched","handleCancel","queue","moveQueueItem","_queueItemId","_placement","removeQueueItem","addAttachment","fileOrAttachment","File","name","contentType","err","_safeEmitAttachmentAddError","operations","add","upsertAttachment","idx","findIndex","attachment","slice","lastAttachment","promiseOrGenerator","file","Symbol","asyncIterator","r","reason","String","subscriberError","console","removeAttachment","index","candidate","Session","_dictationUnsubscribes","_dictationSessionIdCounter","_activeDictationSessionId","_isCleaningDictation","dictation","_isActiveSession","sessionId","session","startDictation","unsub","oldSession","stop","disableInputDuringDictation","listen","unsubSpeech","onSpeech","isFinal","needsSeparator","endsWith","transcript","separator","_","rest","push","unsubStart","onSpeechStart","unsubEnd","onSpeechEnd","statusInterval","setInterval","clearInterval","stopDictation","finally","isStaleSession","_eventSubscribers","Map","payload","event","E","subscribers","get","unstable_on","callback","wrapped","set"],"sources":["../../../src/runtime/base/base-composer-runtime-core.ts"],"sourcesContent":["import {\n isCreateAttachment,\n type Attachment,\n type CompleteAttachment,\n type CreateAttachment,\n type PendingAttachment,\n} from \"../../types/attachment\";\nimport type { MessageRole, AppendMessage } from \"../../types/message\";\nimport { isMessageNotSentError } from \"../../types/error\";\nimport type { QuoteInfo } from \"../../types/quote\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { RunConfig } from \"../../types/message\";\nimport { BaseSubscribable } from \"../../subscribable/subscribable\";\nimport {\n type AttachmentAdapter,\n fileMatchesAccept,\n} from \"../../adapters/attachment\";\nimport type {\n AttachmentAddErrorReason,\n ComposerRuntimeCore,\n ComposerRuntimeEventCallback,\n ComposerRuntimeEventPayload,\n ComposerRuntimeEventType,\n DictationState,\n SendOptions,\n} from \"../interfaces/composer-runtime-core\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type { QueuePlacement } from \"../queue/external-thread-queue-adapter\";\nimport {\n EMPTY_QUEUE_ITEMS,\n type QueueItemState,\n} from \"../../store/scopes/queue-item\";\nimport { generateId } from \"../../utils/id\";\nimport { notifyEventListeners } from \"../../utils/notify-event-listeners\";\n\nconst isAttachmentComplete = (a: Attachment): a is CompleteAttachment =>\n a.status.type === \"complete\";\n\ntype AttachmentAddOperation = {\n cancelled: boolean;\n attachmentIds: Set<string>;\n};\n\nexport abstract class BaseComposerRuntimeCore\n extends BaseSubscribable\n implements ComposerRuntimeCore\n{\n public readonly isEditing = true;\n\n protected abstract getAttachmentAdapter(): AttachmentAdapter | undefined;\n protected abstract getDictationAdapter(): DictationAdapter | undefined;\n\n protected enrichWithComposerMetadata<\n T extends { metadata?: { custom?: Record<string, unknown> } },\n >(message: T, composerMetadata: Record<string, unknown> | undefined): T {\n if (!composerMetadata) return message;\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: { ...message.metadata?.custom, ...composerMetadata },\n },\n } as T;\n }\n\n public get attachmentAccept(): string {\n return this.getAttachmentAdapter()?.accept ?? \"*\";\n }\n\n private _attachments: readonly Attachment[] = [];\n public get attachments() {\n return this._attachments;\n }\n\n protected setAttachments(value: readonly Attachment[]) {\n this._attachments = value;\n this._notifySubscribers();\n }\n\n public abstract get canCancel(): boolean;\n public abstract get canSend(): boolean;\n\n public get isEmpty() {\n return !this.text.trim() && !this.attachments.length;\n }\n\n private _text = \"\";\n\n get text() {\n return this._text;\n }\n\n private _role: MessageRole = \"user\";\n\n get role() {\n return this._role;\n }\n\n private _runConfig: RunConfig = {};\n\n get runConfig() {\n return this._runConfig;\n }\n\n private _quote: QuoteInfo | undefined = undefined;\n\n get quote() {\n return this._quote;\n }\n\n public setQuote(quote: QuoteInfo | undefined) {\n if (this._quote === quote) return;\n\n this._quote = quote;\n this._notifySubscribers();\n }\n\n public setText(value: string) {\n if (this._text === value) return;\n\n this._text = value;\n this._rebaseDictation(value);\n this._notifySubscribers();\n }\n\n // A live dictation session appends to the text it last saw, so any write\n // that bypasses `setText` has to move that baseline or the next transcript\n // overwrites what was just written.\n private _rebaseDictation(value: string) {\n if (!this._dictation) return;\n\n this._dictationBaseText = value;\n this._currentInterimText = \"\";\n const { status, inputDisabled } = this._dictation;\n this._dictation = inputDisabled ? { status, inputDisabled } : { status };\n }\n\n public setRole(role: MessageRole) {\n if (this._role === role) return;\n\n this._role = role;\n this._notifySubscribers();\n }\n\n public setRunConfig(runConfig: RunConfig) {\n if (this._runConfig === runConfig) return;\n\n this._runConfig = runConfig;\n this._notifySubscribers();\n }\n\n protected _isSending = false;\n private _removedDuringSend = new Set<string>();\n private _sendGeneration = 0;\n private _attachmentAddOperations = new Set<AttachmentAddOperation>();\n\n private _cancelAttachmentAdd(attachmentId: string) {\n for (const operation of [...this._attachmentAddOperations]) {\n if (!operation.attachmentIds.has(attachmentId)) continue;\n operation.cancelled = true;\n this._attachmentAddOperations.delete(operation);\n }\n }\n\n private _cancelAllAttachmentAdds() {\n for (const operation of this._attachmentAddOperations) {\n operation.cancelled = true;\n }\n this._attachmentAddOperations.clear();\n }\n\n private _emptyTextAndAttachments() {\n this._attachments = [];\n this._text = \"\";\n this._notifySubscribers();\n }\n\n private async _onClearAttachments() {\n const adapter = this.getAttachmentAdapter();\n if (adapter) {\n const pending = this._attachments.filter((a) => !isAttachmentComplete(a));\n await Promise.all(pending.map((a) => adapter.remove(a)));\n }\n }\n\n public async reset() {\n this._cancelAllAttachmentAdds();\n\n // A send whose adapter never settles must not brick the composer; reset is\n // the escape hatch that releases the in-flight lock. Bumping the generation\n // invalidates that send entirely so a late-settling upload can neither\n // append the discarded draft nor touch a newer send's lock.\n this._sendGeneration++;\n this._isSending = false;\n this._removedDuringSend.clear();\n\n if (\n this._attachments.length === 0 &&\n this._text === \"\" &&\n this._role === \"user\" &&\n Object.keys(this._runConfig).length === 0 &&\n this._quote === undefined\n ) {\n return;\n }\n\n this._role = \"user\";\n this._runConfig = {};\n this._quote = undefined;\n\n const task = this._onClearAttachments();\n this._emptyTextAndAttachments();\n await task;\n }\n\n public async clearAttachments() {\n this._cancelAllAttachmentAdds();\n const task = this._onClearAttachments();\n this.setAttachments([]);\n\n await task;\n }\n\n public async send(options?: SendOptions) {\n if (!this.canSend || this._isSending) return;\n\n if (this._dictationSession) {\n this._dictationSession.cancel();\n this._cleanupDictation();\n }\n\n const adapter = this.getAttachmentAdapter();\n const attachmentTasks = this.attachments.map(async (a) => {\n if (isAttachmentComplete(a)) return a;\n if (!adapter) throw new Error(\"Attachments are not supported\");\n const result = await adapter.send(a);\n return result as CompleteAttachment;\n });\n\n const originalAttachments = this.attachments;\n const text = this.text;\n const quote = this._quote;\n this._quote = undefined;\n this._text = \"\";\n this._isSending = true;\n const generation = ++this._sendGeneration;\n this._notifySubscribers();\n\n let resolvedAttachments: CompleteAttachment[];\n try {\n resolvedAttachments = await Promise.all(attachmentTasks);\n } catch (e) {\n if (generation === this._sendGeneration) {\n if (!this.text.trim() && this._quote === undefined) {\n this._text = text;\n this._rebaseDictation(text);\n this._quote = quote;\n this._notifySubscribers();\n }\n // Promise.all rejects on the first failure, but sibling uploads from\n // this batch keep running; the send rejects immediately while the\n // retry lock is held until they settle, or a retry could re-send\n // attachments that are still in flight.\n void Promise.allSettled(attachmentTasks).then(() => {\n if (generation !== this._sendGeneration) return;\n this._removedDuringSend.clear();\n this._isSending = false;\n this._notifySubscribers();\n });\n }\n throw e;\n }\n\n // A reset during the upload discarded this send's draft; the settled\n // uploads must not append it or touch the lock a newer send may own.\n if (generation !== this._sendGeneration) return;\n\n // Drop by id, not wholesale: the user may have added or removed chips while\n // the upload was in flight.\n const sentIds = new Set(originalAttachments.map((a) => a.id));\n this._attachments = this._attachments.filter((a) => !sentIds.has(a.id));\n this._isSending = false;\n this._notifySubscribers();\n\n // An attachment removed mid-upload can't be cancelled, but it can still be\n // dropped from the outgoing message instead of silently being sent anyway.\n const finalAttachments = resolvedAttachments.filter(\n (a) => !this._removedDuringSend.has(a.id),\n );\n this._removedDuringSend.clear();\n\n const message: Omit<AppendMessage, \"parentId\" | \"sourceId\"> = {\n createdAt: new Date(),\n role: this.role,\n content: text ? [{ type: \"text\", text }] : [],\n attachments: finalAttachments,\n runConfig: this.runConfig,\n metadata: { custom: { ...(quote ? { quote } : {}) } },\n };\n\n const draft = { text, quote, attachments: finalAttachments };\n let sendTask: void | Promise<void>;\n try {\n sendTask = this.handleSend(message, options);\n } catch (error) {\n this._restoreUnsentDraft(error, generation, draft);\n throw error;\n }\n if (sendTask)\n void sendTask.catch((error) => {\n this._restoreUnsentDraft(error, generation, draft);\n });\n this._notifyEventSubscribers(\"send\", {});\n }\n\n /**\n * Take a message back into the composer when it has nowhere else to live:\n * a send the runtime never dispatched, or a message a cancelled run is\n * removing from the thread. Reports whether the composer accepted it, so a\n * caller that is also removing the message can keep it instead of dropping\n * it. Refused, and left untouched, while the composer holds anything of its\n * own.\n */\n public restoreDraft(draft: {\n text: string;\n quote?: QuoteInfo | undefined;\n attachments?: readonly Attachment[] | undefined;\n }): boolean {\n if (\n this._text.trim() ||\n this._quote !== undefined ||\n this._attachments.length > 0\n )\n return false;\n\n this._text = draft.text;\n this._rebaseDictation(draft.text);\n this._quote = draft.quote;\n this._attachments = draft.attachments ?? [];\n this._notifySubscribers();\n return true;\n }\n\n /**\n * Inverse of `restoreDraft`: clears the composer while it still holds\n * exactly the given draft. A draft the user has edited since is left\n * untouched.\n */\n public retractDraft(draft: {\n text: string;\n quote?: QuoteInfo | undefined;\n attachments?: readonly Attachment[] | undefined;\n }): void {\n const attachmentsUntouched =\n draft.attachments !== undefined\n ? this._attachments === draft.attachments\n : this._attachments.length === 0;\n if (\n this._text !== draft.text ||\n this._quote !== draft.quote ||\n !attachmentsUntouched\n )\n return;\n\n this._text = \"\";\n this._rebaseDictation(\"\");\n this._quote = undefined;\n this._attachments = [];\n this._notifySubscribers();\n }\n\n // The generation check is what a reset and a later send use to invalidate a\n // draft, so of several queued drafts only the most recent one is still\n // restorable.\n private _restoreUnsentDraft(\n error: unknown,\n generation: number,\n draft: {\n text: string;\n quote: QuoteInfo | undefined;\n attachments: readonly CompleteAttachment[];\n },\n ) {\n if (!isMessageNotSentError(error)) return;\n if (generation !== this._sendGeneration) return;\n this.restoreDraft(draft);\n }\n\n public cancel() {\n this.handleCancel();\n }\n\n public get queue(): readonly QueueItemState[] {\n return EMPTY_QUEUE_ITEMS;\n }\n\n public moveQueueItem(\n _queueItemId: string,\n _placement: QueuePlacement,\n ): void {}\n public removeQueueItem(_queueItemId: string): void {}\n\n protected abstract handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ): void | Promise<void>;\n protected abstract handleCancel(): void;\n\n async addAttachment(fileOrAttachment: File | CreateAttachment) {\n if (isCreateAttachment(fileOrAttachment)) {\n const adapter = this.getAttachmentAdapter();\n if (\n adapter &&\n !fileMatchesAccept(\n {\n name: fileOrAttachment.name,\n type: fileOrAttachment.contentType ?? \"\",\n },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.contentType || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\n \"not-accepted\",\n message,\n undefined,\n err,\n );\n throw err;\n }\n\n const a: CompleteAttachment = {\n id: fileOrAttachment.id ?? generateId(),\n type: fileOrAttachment.type ?? \"document\",\n name: fileOrAttachment.name,\n contentType: fileOrAttachment.contentType,\n content: fileOrAttachment.content,\n status: { type: \"complete\" },\n };\n this._attachments = [...this._attachments, a];\n this._notifySubscribers();\n this._notifyEventSubscribers(\"attachmentAdd\", {});\n return;\n }\n\n const adapter = this.getAttachmentAdapter();\n if (!adapter) {\n const message = \"Attachments are not supported\";\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\"no-adapter\", message, undefined, err);\n throw err;\n }\n\n if (\n !fileMatchesAccept(\n { name: fileOrAttachment.name, type: fileOrAttachment.type },\n adapter.accept,\n )\n ) {\n const message = `File type ${fileOrAttachment.type || \"unknown\"} is not accepted. Accepted types: ${adapter.accept}`;\n const err = new Error(message);\n this._safeEmitAttachmentAddError(\"not-accepted\", message, undefined, err);\n throw err;\n }\n\n const operation: AttachmentAddOperation = {\n cancelled: false,\n attachmentIds: new Set(),\n };\n const operations = this._attachmentAddOperations;\n operations.add(operation);\n const upsertAttachment = (a: PendingAttachment) => {\n if (operation.cancelled) return false;\n\n operation.attachmentIds.add(a.id);\n const idx = this._attachments.findIndex(\n (attachment) => attachment.id === a.id,\n );\n if (idx !== -1)\n this._attachments = [\n ...this._attachments.slice(0, idx),\n a,\n ...this._attachments.slice(idx + 1),\n ];\n else {\n this._attachments = [...this._attachments, a];\n }\n\n this._notifySubscribers();\n return true;\n };\n let lastAttachment: PendingAttachment | undefined;\n try {\n const promiseOrGenerator = adapter.add({ file: fileOrAttachment });\n if (Symbol.asyncIterator in promiseOrGenerator) {\n for await (const r of promiseOrGenerator) {\n lastAttachment = r;\n if (!upsertAttachment(r)) break;\n }\n } else {\n lastAttachment = await promiseOrGenerator;\n upsertAttachment(lastAttachment);\n }\n } catch (e) {\n if (operation.cancelled) return;\n if (lastAttachment) {\n upsertAttachment({\n ...lastAttachment,\n status: {\n type: \"incomplete\",\n reason: \"error\",\n message: e instanceof Error ? e.message : String(e),\n },\n });\n }\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n e instanceof Error ? e.message : String(e),\n lastAttachment?.id,\n e instanceof Error ? e : undefined,\n );\n throw e;\n } finally {\n operations.delete(operation);\n }\n\n if (operation.cancelled) return;\n if (\n lastAttachment?.status.type === \"incomplete\" &&\n lastAttachment.status.reason === \"error\"\n ) {\n this._safeEmitAttachmentAddError(\n \"adapter-error\",\n lastAttachment.status.message ??\n \"Attachment upload did not complete successfully.\",\n lastAttachment.id,\n );\n } else {\n this._notifyEventSubscribers(\"attachmentAdd\", {});\n }\n }\n\n private _safeEmitAttachmentAddError(\n reason: AttachmentAddErrorReason,\n message: string,\n attachmentId?: string,\n error?: Error,\n ) {\n try {\n this._notifyEventSubscribers(\"attachmentAddError\", {\n reason,\n message,\n ...(attachmentId !== undefined && { attachmentId }),\n ...(error !== undefined && { error }),\n });\n } catch (subscriberError) {\n console.error(\n \"[assistant-ui] attachmentAddError subscriber threw:\",\n subscriberError,\n );\n }\n }\n\n async removeAttachment(attachmentId: string) {\n const index = this._attachments.findIndex((a) => a.id === attachmentId);\n if (index === -1) throw new Error(\"Attachment not found\");\n const attachment = this._attachments[index]!;\n\n this._cancelAttachmentAdd(attachmentId);\n\n // A send in flight may already be uploading this attachment; the upload\n // can't be cancelled, so mark it to be dropped from the outgoing message\n // before any await gives the upload a chance to settle first.\n if (this._isSending) this._removedDuringSend.add(attachmentId);\n\n if (!isAttachmentComplete(attachment)) {\n const adapter = this.getAttachmentAdapter();\n if (!adapter) throw new Error(\"Attachments are not supported\");\n try {\n await adapter.remove(attachment);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this._attachments = this._attachments.map((candidate) =>\n candidate.id === attachmentId && !isAttachmentComplete(candidate)\n ? {\n ...candidate,\n status: { type: \"incomplete\", reason: \"error\", message },\n }\n : candidate,\n );\n this._notifySubscribers();\n throw error;\n }\n }\n this._attachments = this._attachments.filter((a) => a.id !== attachmentId);\n this._notifySubscribers();\n }\n\n private _dictation: DictationState | undefined;\n private _dictationSession: DictationAdapter.Session | undefined;\n private _dictationUnsubscribes: Unsubscribe[] = [];\n private _dictationBaseText = \"\";\n private _currentInterimText = \"\";\n private _dictationSessionIdCounter = 0;\n private _activeDictationSessionId: number | undefined;\n private _isCleaningDictation = false;\n\n public get dictation(): DictationState | undefined {\n return this._dictation;\n }\n\n private _isActiveSession(\n sessionId: number,\n session: DictationAdapter.Session,\n ): boolean {\n return (\n this._activeDictationSessionId === sessionId &&\n this._dictationSession === session\n );\n }\n\n public startDictation(): void {\n const adapter = this.getDictationAdapter();\n if (!adapter) {\n throw new Error(\"Dictation adapter not configured\");\n }\n\n if (this._dictationSession) {\n for (const unsub of this._dictationUnsubscribes) {\n unsub();\n }\n this._dictationUnsubscribes = [];\n const oldSession = this._dictationSession;\n oldSession.stop().catch(() => {});\n this._dictationSession = undefined;\n }\n\n const inputDisabled = adapter.disableInputDuringDictation ?? false;\n\n this._dictationBaseText = this._text;\n this._currentInterimText = \"\";\n\n const session = adapter.listen();\n this._dictationSession = session;\n const sessionId = ++this._dictationSessionIdCounter;\n this._activeDictationSessionId = sessionId;\n this._dictation = { status: session.status, inputDisabled };\n this._notifySubscribers();\n\n const unsubSpeech = session.onSpeech((result) => {\n if (!this._isActiveSession(sessionId, session)) return;\n const isFinal = result.isFinal !== false;\n\n const needsSeparator =\n this._dictationBaseText &&\n !this._dictationBaseText.endsWith(\" \") &&\n result.transcript;\n const separator = needsSeparator ? \" \" : \"\";\n\n if (isFinal) {\n this._dictationBaseText =\n this._dictationBaseText + separator + result.transcript;\n this._currentInterimText = \"\";\n this._text = this._dictationBaseText;\n\n if (this._dictation) {\n const { transcript: _, ...rest } = this._dictation;\n this._dictation = rest;\n }\n this._notifySubscribers();\n } else {\n this._currentInterimText = separator + result.transcript;\n this._text = this._dictationBaseText + this._currentInterimText;\n\n if (this._dictation) {\n this._dictation = {\n ...this._dictation,\n transcript: result.transcript,\n };\n }\n this._notifySubscribers();\n }\n });\n this._dictationUnsubscribes.push(unsubSpeech);\n\n const unsubStart = session.onSpeechStart(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n this._dictation = {\n status: { type: \"running\" },\n inputDisabled,\n ...(this._dictation?.transcript && {\n transcript: this._dictation.transcript,\n }),\n };\n this._notifySubscribers();\n });\n this._dictationUnsubscribes.push(unsubStart);\n\n const unsubEnd = session.onSpeechEnd(() => {\n this._cleanupDictation({ sessionId });\n });\n this._dictationUnsubscribes.push(unsubEnd);\n\n const statusInterval = setInterval(() => {\n if (!this._isActiveSession(sessionId, session)) return;\n\n if (session.status.type === \"ended\") {\n this._cleanupDictation({ sessionId });\n }\n }, 100);\n this._dictationUnsubscribes.push(() => clearInterval(statusInterval));\n }\n\n public stopDictation(): void {\n if (!this._dictationSession) return;\n\n const session = this._dictationSession;\n const sessionId = this._activeDictationSessionId;\n session.stop().finally(() => {\n this._cleanupDictation({ sessionId });\n });\n }\n\n private _cleanupDictation(options?: { sessionId: number | undefined }): void {\n const isStaleSession =\n options?.sessionId !== undefined &&\n options.sessionId !== this._activeDictationSessionId;\n if (isStaleSession || this._isCleaningDictation) return;\n\n this._isCleaningDictation = true;\n try {\n for (const unsub of this._dictationUnsubscribes) {\n unsub();\n }\n this._dictationUnsubscribes = [];\n this._dictationSession = undefined;\n this._activeDictationSessionId = undefined;\n this._dictation = undefined;\n this._dictationBaseText = \"\";\n this._currentInterimText = \"\";\n this._notifySubscribers();\n } finally {\n this._isCleaningDictation = false;\n }\n }\n\n private _eventSubscribers = new Map<\n ComposerRuntimeEventType,\n Set<(payload?: unknown) => void>\n >();\n\n protected _notifyEventSubscribers<E extends ComposerRuntimeEventType>(\n event: E,\n payload: ComposerRuntimeEventPayload[E],\n ) {\n const subscribers = this._eventSubscribers.get(event);\n if (!subscribers) return;\n\n notifyEventListeners(subscribers, payload, `Composer runtime \"${event}\"`);\n }\n\n public unstable_on<E extends ComposerRuntimeEventType>(\n event: E,\n callback: ComposerRuntimeEventCallback<E>,\n ) {\n const wrapped = callback as (payload?: unknown) => void;\n let subscribers = this._eventSubscribers.get(event);\n if (!subscribers) {\n subscribers = new Set();\n this._eventSubscribers.set(event, subscribers);\n }\n subscribers.add(wrapped);\n\n return () => {\n this._eventSubscribers.get(event)?.delete(wrapped);\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -52,6 +52,20 @@ declare abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
|
|
|
52
52
|
private readonly _contextProvider;
|
|
53
53
|
constructor(_contextProvider: ModelContextProvider);
|
|
54
54
|
getModelContext(): ModelContext;
|
|
55
|
+
/**
|
|
56
|
+
* Stamps provider-contributed composer metadata onto an outgoing message.
|
|
57
|
+
* Called at dispatch rather than in the composer, so programmatic sends are
|
|
58
|
+
* covered too, and exactly once per message: a queued send is stamped when
|
|
59
|
+
* it leaves the lane, never when it enters.
|
|
60
|
+
*
|
|
61
|
+
* Only user messages are stamped, matching the readers: both the version
|
|
62
|
+
* fold and the model injection skip every other role.
|
|
63
|
+
*
|
|
64
|
+
* @param anchorId Message the gated branch prefix ends at. A queued send
|
|
65
|
+
* passes the current tail, having waited through a run that grew the prefix
|
|
66
|
+
* past the parent it was created with.
|
|
67
|
+
*/
|
|
68
|
+
protected enrichAppendMetadata(message: AppendMessage, anchorId?: string | null): AppendMessage;
|
|
55
69
|
private _editComposers;
|
|
56
70
|
getEditComposer(messageId: string): DefaultEditComposerRuntimeCore | undefined;
|
|
57
71
|
beginEdit(messageId: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-thread-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/base-thread-runtime-core.ts"],"mappings":";;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"base-thread-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/base-thread-runtime-core.ts"],"mappings":";;;;;;;;;;;;;;KAuCK;EACH,SAAS;EACT,WAAW;EACX,cAAc;EACd,QAAQ;;uBAGY,iCAAiC;UAC7C;UACA;qBAEW,YAAU;eACT,YAAY;eACZ;eACA;eACA;eACA,wBAAwB;eACxB;eAEA,gBAAgB;WACpB,OAAO,SAAS;WAChB,cAAc,2BAA2B;WACzC,SAAS,QAAQ;WACjB,UAAU,QAAQ;WAClB,cAAc,SAAS;WACvB,eAAe,SAAS;WACxB,sBACd,SAAS;WAEK;WACA;WACA,oBAAoB;YAE1B,gBAAgB;YAChB;UACF;UACA;UACA;YAEE;YAKA,6BAA6B;MAI5B,qBAAqB;MAgBrB,sEAAK,sDAAA;WAWA,UAAQ;mBAEP;EAEL,YAAA,kBAAkB;EAIvB,mBAJuB;;;;;;;;;;;;;;YAqBpB,qBACR,SAAS,eACT,2BACC;UAmBK;EACD,gBAAgB,oBAAiB;EAGjC,UAAU;EAeV,eAAe;;;;;EAsBf,YAAY;EAOZ,eAAe;YAKZ;EAIH,wBAAwB,UAAU,wBACvC,OAAO,GACP,SAAS,0BAA0B;EAQ9B,UAAU,uBAAuB;EAKjC,iBAAiB,WAAW,QAAQ;UAqBnC;EACD,QAAQ;EAER,MAAM;EA8BN;UAMC;UACA;EACD,OAAO;UAEN;UACA;EAED;EAEA,uBAAwB,yBAAuB;EAK/C;UA+DC;UAEA;UA8DA;EAaD;EAeA;EAUA;YAUG;EAOH,UAAM;EAIN,OAAO,MAAM;EAOb,MAAM,2BAA2B;UAIhC;EAKD,YAAY,UAAU,wBAC3B,OAAO,GACP,UAAU,2BAA2B,KAAE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { gateInteractableComposerMetadata } from "../../model-context/interactable-composer-metadata.js";
|
|
1
2
|
import { generateId } from "../../utils/id.js";
|
|
2
3
|
import { getThreadMessageText } from "../../utils/text.js";
|
|
3
4
|
import { ExportedMessageRepository, MessageRepository } from "../utils/message-repository.js";
|
|
@@ -44,6 +45,36 @@ var BaseThreadRuntimeCore = class {
|
|
|
44
45
|
getModelContext() {
|
|
45
46
|
return this._contextProvider.getModelContext();
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Stamps provider-contributed composer metadata onto an outgoing message.
|
|
50
|
+
* Called at dispatch rather than in the composer, so programmatic sends are
|
|
51
|
+
* covered too, and exactly once per message: a queued send is stamped when
|
|
52
|
+
* it leaves the lane, never when it enters.
|
|
53
|
+
*
|
|
54
|
+
* Only user messages are stamped, matching the readers: both the version
|
|
55
|
+
* fold and the model injection skip every other role.
|
|
56
|
+
*
|
|
57
|
+
* @param anchorId Message the gated branch prefix ends at. A queued send
|
|
58
|
+
* passes the current tail, having waited through a run that grew the prefix
|
|
59
|
+
* past the parent it was created with.
|
|
60
|
+
*/
|
|
61
|
+
enrichAppendMetadata(message, anchorId = message.parentId) {
|
|
62
|
+
if (message.role !== "user") return message;
|
|
63
|
+
const messages = this.messages;
|
|
64
|
+
const parentIndex = anchorId === null ? -1 : messages.findIndex((m) => m.id === anchorId);
|
|
65
|
+
const composerMetadata = gateInteractableComposerMetadata(this.getModelContext().unstable_composerMetadata, messages.slice(0, parentIndex + 1));
|
|
66
|
+
if (!composerMetadata) return message;
|
|
67
|
+
return {
|
|
68
|
+
...message,
|
|
69
|
+
metadata: {
|
|
70
|
+
...message.metadata,
|
|
71
|
+
custom: {
|
|
72
|
+
...message.metadata?.custom,
|
|
73
|
+
...composerMetadata
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
47
78
|
_editComposers = /* @__PURE__ */ new Map();
|
|
48
79
|
getEditComposer(messageId) {
|
|
49
80
|
return this._editComposers.get(messageId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-thread-runtime-core.js","names":["AppendMessage","ThreadAssistantMessage","ThreadMessage","Unsubscribe","ModelContextProvider","getThreadMessageText","generateId","ExportedMessageRepository","MessageRepository","DefaultThreadComposerRuntimeCore","AddToolResultOptions","ResumeToolCallOptions","RespondToToolApprovalOptions","ThreadSuggestion","SubmitFeedbackOptions","ThreadRuntimeCore","SpeechState","VoiceSessionState","RuntimeCapabilities","ThreadRuntimeEventCallback","ThreadRuntimeEventPayload","ThreadRuntimeEventType","StartRunConfig","ResumeRunConfig","DefaultEditComposerRuntimeCore","SpeechSynthesisAdapter","FeedbackAdapter","AttachmentAdapter","RealtimeVoiceAdapter","ThreadMessageLike","notifyEventListeners","BaseThreadAdapters","speech","feedback","attachments","voice","BaseThreadRuntimeCore","_subscriptions","Set","_isInitialized","repository","adapters","isDisabled","isSendDisabled","isLoading","suggestions","extras","capabilities","append","message","deleteMessage","messageId","Promise","startRun","config","resumeRun","addToolResult","options","resumeToolCall","respondToToolApproval","cancelRun","exportExternalState","importExternalState","state","_voiceMessages","_voiceGeneration","_cachedMergedMessages","_cachedVoiceGeneration","_cachedMergedBase","_markVoiceMessagesDirty","_getBaseMessages","getMessages","messages","length","base","mostRecentAssistantMessage","this","role","metadata","unstable_state","composer","_contextProvider","constructor","getModelContext","_editComposers","Map","getEditComposer","get","beginEdit","has","Error","set","delete","getMessage","_notifySubscribers","getMessageById","baseMessages","voiceIdx","findIndex","m","id","parentId","at","index","undefined","getBranches","some","switchToBranch","branchId","callback","_notifyEventSubscribers","event","E","payload","subscribers","_eventSubscribers","subscribe","add","submitFeedback","type","adapter","submit","updatedMessage","submittedFeedback","addOrUpdateMessage","_stopSpeaking","speak","utterance","unsub","status","cancel","stopSpeaking","_voiceSession","Session","_voiceUnsubs","Array","_voiceVolume","_voiceVolumeSubscribers","getVoiceVolume","subscribeVoiceVolume","connectVoice","disconnectVoice","session","connect","unsubs","currentMode","Mode","isMuted","mode","push","onStatusChange","_finishVoiceAssistantMessage","onModeChange","onVolumeChange","volume","cb","onTranscript","transcript","_handleVoiceTranscript","_currentAssistantMsg","TranscriptItem","ensureInitialized","isFinal","content","text","custom","createdAt","Date","reason","unstable_annotations","unstable_data","steps","idx","indexOf","updated","last","disconnect","muteVoice","mute","unmuteVoice","unmute","export","import","data","clear","reset","initialMessages","fromArray","unstable_on","wrapped","queueMicrotask"],"sources":["../../../src/runtime/base/base-thread-runtime-core.ts"],"sourcesContent":["import type {\n AppendMessage,\n ThreadAssistantMessage,\n ThreadMessage,\n} from \"../../types/message\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { ModelContextProvider } from \"../../model-context/types\";\nimport { getThreadMessageText } from \"../../utils/text\";\nimport { generateId } from \"../../utils/id\";\nimport {\n ExportedMessageRepository,\n MessageRepository,\n} from \"../utils/message-repository\";\nimport { DefaultThreadComposerRuntimeCore } from \"./default-thread-composer-runtime-core\";\nimport type {\n AddToolResultOptions,\n ResumeToolCallOptions,\n RespondToToolApprovalOptions,\n ThreadSuggestion,\n SubmitFeedbackOptions,\n ThreadRuntimeCore,\n SpeechState,\n VoiceSessionState,\n RuntimeCapabilities,\n ThreadRuntimeEventCallback,\n ThreadRuntimeEventPayload,\n ThreadRuntimeEventType,\n StartRunConfig,\n ResumeRunConfig,\n} from \"../interfaces/thread-runtime-core\";\nimport { DefaultEditComposerRuntimeCore } from \"./default-edit-composer-runtime-core\";\nimport type { SpeechSynthesisAdapter } from \"../../adapters/speech\";\nimport type { FeedbackAdapter } from \"../../adapters/feedback\";\nimport type { AttachmentAdapter } from \"../../adapters/attachment\";\nimport type { RealtimeVoiceAdapter } from \"../../adapters/voice\";\nimport type { ThreadMessageLike } from \"../utils/thread-message-like\";\nimport { notifyEventListeners } from \"../../utils/notify-event-listeners\";\n\ntype BaseThreadAdapters = {\n speech?: SpeechSynthesisAdapter | undefined;\n feedback?: FeedbackAdapter | undefined;\n attachments?: AttachmentAdapter | undefined;\n voice?: RealtimeVoiceAdapter | undefined;\n};\n\nexport abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {\n private _subscriptions = new Set<() => void>();\n private _isInitialized = false;\n\n protected readonly repository = new MessageRepository();\n public abstract get adapters(): BaseThreadAdapters | undefined;\n public abstract get isDisabled(): boolean;\n public abstract get isSendDisabled(): boolean;\n public abstract get isLoading(): boolean;\n public abstract get suggestions(): readonly ThreadSuggestion[];\n public abstract get extras(): unknown;\n\n public abstract get capabilities(): RuntimeCapabilities;\n public abstract append(message: AppendMessage): void;\n public abstract deleteMessage(messageId: string): void | Promise<void>;\n public abstract startRun(config: StartRunConfig): void;\n public abstract resumeRun(config: ResumeRunConfig): void;\n public abstract addToolResult(options: AddToolResultOptions): void;\n public abstract resumeToolCall(options: ResumeToolCallOptions): void;\n public abstract respondToToolApproval(\n options: RespondToToolApprovalOptions,\n ): void;\n public abstract cancelRun(): void;\n public abstract exportExternalState(): any;\n public abstract importExternalState(state: any): void;\n\n protected _voiceMessages: ThreadMessage[] = [];\n protected _voiceGeneration = 0;\n private _cachedMergedMessages: readonly ThreadMessage[] | null = null;\n private _cachedVoiceGeneration = -1;\n private _cachedMergedBase: readonly ThreadMessage[] | null = null;\n\n protected _markVoiceMessagesDirty() {\n this._voiceGeneration++;\n this._cachedMergedMessages = null;\n }\n\n protected _getBaseMessages(): readonly ThreadMessage[] {\n return this.repository.getMessages();\n }\n\n public get messages(): readonly ThreadMessage[] {\n if (this._voiceMessages.length === 0) {\n return this._getBaseMessages();\n }\n const base = this._getBaseMessages();\n if (\n this._cachedVoiceGeneration !== this._voiceGeneration ||\n this._cachedMergedBase !== base\n ) {\n this._cachedMergedMessages = [...base, ...this._voiceMessages];\n this._cachedVoiceGeneration = this._voiceGeneration;\n this._cachedMergedBase = base;\n }\n return this._cachedMergedMessages!;\n }\n\n public get state() {\n let mostRecentAssistantMessage: (typeof this.messages)[number] | undefined;\n for (const message of this.messages) {\n if (message.role === \"assistant\") {\n mostRecentAssistantMessage = message;\n }\n }\n\n return mostRecentAssistantMessage?.metadata.unstable_state ?? null;\n }\n\n public readonly composer = new DefaultThreadComposerRuntimeCore(this);\n\n private readonly _contextProvider: ModelContextProvider;\n\n constructor(_contextProvider: ModelContextProvider) {\n this._contextProvider = _contextProvider;\n }\n\n public getModelContext() {\n return this._contextProvider.getModelContext();\n }\n\n private _editComposers = new Map<string, DefaultEditComposerRuntimeCore>();\n public getEditComposer(messageId: string) {\n return this._editComposers.get(messageId);\n }\n public beginEdit(messageId: string) {\n if (this._editComposers.has(messageId))\n throw new Error(\"Edit already in progress\");\n\n this._editComposers.set(\n messageId,\n new DefaultEditComposerRuntimeCore(\n this,\n () => this._editComposers.delete(messageId),\n this.repository.getMessage(messageId),\n ),\n );\n this._notifySubscribers();\n }\n\n public getMessageById(messageId: string) {\n try {\n return this.repository.getMessage(messageId);\n } catch {\n // Check voice messages\n const baseMessages = this.repository.getMessages();\n const voiceIdx = this._voiceMessages.findIndex((m) => m.id === messageId);\n if (voiceIdx !== -1) {\n const parentId =\n voiceIdx > 0\n ? this._voiceMessages[voiceIdx - 1]!.id\n : (baseMessages.at(-1)?.id ?? null);\n return {\n parentId,\n message: this._voiceMessages[voiceIdx]!,\n index: baseMessages.length + voiceIdx,\n };\n }\n return undefined;\n }\n }\n\n public getBranches(messageId: string): string[] {\n if (this._voiceMessages.some((m) => m.id === messageId)) {\n return [];\n }\n return this.repository.getBranches(messageId);\n }\n\n public switchToBranch(branchId: string): void {\n this.repository.switchToBranch(branchId);\n this._notifySubscribers();\n }\n\n protected _notifySubscribers() {\n for (const callback of this._subscriptions) callback();\n }\n\n public _notifyEventSubscribers<E extends ThreadRuntimeEventType>(\n event: E,\n payload: ThreadRuntimeEventPayload[E],\n ) {\n const subscribers = this._eventSubscribers.get(event);\n if (!subscribers) return;\n\n notifyEventListeners(subscribers, payload, `Thread runtime \"${event}\"`);\n }\n\n public subscribe(callback: () => void): Unsubscribe {\n this._subscriptions.add(callback);\n return () => this._subscriptions.delete(callback);\n }\n\n public submitFeedback({ messageId, type }: SubmitFeedbackOptions) {\n const adapter = this.adapters?.feedback;\n if (!adapter) throw new Error(\"Feedback adapter not configured\");\n\n const { message, parentId } = this.repository.getMessage(messageId);\n adapter.submit({ message, type });\n\n if (message.role === \"assistant\") {\n const updatedMessage: ThreadMessage = {\n ...message,\n metadata: {\n ...message.metadata,\n submittedFeedback: { type },\n },\n };\n this.repository.addOrUpdateMessage(parentId, updatedMessage);\n }\n\n this._notifySubscribers();\n }\n\n private _stopSpeaking: Unsubscribe | undefined;\n public speech: SpeechState | undefined;\n\n public speak(messageId: string) {\n const adapter = this.adapters?.speech;\n if (!adapter) throw new Error(\"Speech adapter not configured\");\n\n const { message } = this.repository.getMessage(messageId);\n\n this._stopSpeaking?.();\n\n const utterance = adapter.speak(getThreadMessageText(message));\n const unsub = utterance.subscribe(() => {\n if (utterance.status.type === \"ended\") {\n this._stopSpeaking = undefined;\n this.speech = undefined;\n } else {\n this.speech = { messageId, status: utterance.status };\n }\n this._notifySubscribers();\n });\n\n this.speech = { messageId, status: utterance.status };\n this._notifySubscribers();\n\n this._stopSpeaking = () => {\n utterance.cancel();\n unsub();\n this.speech = undefined;\n this._stopSpeaking = undefined;\n };\n }\n\n public stopSpeaking() {\n if (!this._stopSpeaking) throw new Error(\"No message is being spoken\");\n this._stopSpeaking();\n this._notifySubscribers();\n }\n\n private _voiceSession: RealtimeVoiceAdapter.Session | undefined;\n private _voiceUnsubs: Array<() => void> = [];\n public voice: VoiceSessionState | undefined;\n\n private _voiceVolume = 0;\n private _voiceVolumeSubscribers = new Set<() => void>();\n\n public getVoiceVolume = () => this._voiceVolume;\n\n public subscribeVoiceVolume = (callback: () => void): Unsubscribe => {\n this._voiceVolumeSubscribers.add(callback);\n return () => this._voiceVolumeSubscribers.delete(callback);\n };\n\n public connectVoice() {\n const adapter = this.adapters?.voice;\n if (!adapter) throw new Error(\"Voice adapter not configured\");\n\n this.disconnectVoice();\n\n const session = adapter.connect({});\n this._voiceSession = session;\n const unsubs: Array<() => void> = [];\n\n let currentMode: RealtimeVoiceAdapter.Mode = \"listening\";\n\n this.voice = {\n status: session.status,\n isMuted: session.isMuted,\n mode: currentMode,\n };\n this._voiceVolume = 0;\n this._notifySubscribers();\n\n unsubs.push(\n session.onStatusChange((status) => {\n if (status.type === \"ended\") {\n this._finishVoiceAssistantMessage();\n this._voiceSession = undefined;\n this.voice = undefined;\n } else {\n this.voice = {\n status,\n isMuted: session.isMuted,\n mode: currentMode,\n };\n }\n this._notifySubscribers();\n }),\n );\n\n unsubs.push(\n session.onModeChange((mode) => {\n currentMode = mode;\n if (this.voice) {\n this.voice = { ...this.voice, mode };\n this._notifySubscribers();\n }\n }),\n );\n\n unsubs.push(\n session.onVolumeChange((volume) => {\n this._voiceVolume = volume;\n for (const cb of this._voiceVolumeSubscribers) cb();\n }),\n );\n\n unsubs.push(\n session.onTranscript((transcript) => {\n this._handleVoiceTranscript(transcript);\n }),\n );\n\n this._voiceUnsubs = unsubs;\n }\n\n private _currentAssistantMsg: ThreadAssistantMessage | null = null;\n\n private _handleVoiceTranscript(\n transcript: RealtimeVoiceAdapter.TranscriptItem,\n ) {\n this.ensureInitialized();\n\n if (transcript.role === \"user\") {\n this._finishVoiceAssistantMessage();\n this._currentAssistantMsg = null;\n\n if (transcript.isFinal) {\n this._voiceMessages.push({\n id: generateId(),\n role: \"user\",\n content: [{ type: \"text\", text: transcript.text }],\n metadata: { custom: {} },\n createdAt: new Date(),\n status: { type: \"complete\", reason: \"unknown\" },\n attachments: [],\n });\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n } else {\n if (!this._currentAssistantMsg) {\n this._currentAssistantMsg = {\n id: generateId(),\n role: \"assistant\",\n content: [{ type: \"text\", text: transcript.text }],\n metadata: {\n unstable_state: this.state,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n custom: {},\n },\n status: { type: \"running\" },\n createdAt: new Date(),\n };\n this._voiceMessages.push(this._currentAssistantMsg);\n } else {\n const idx = this._voiceMessages.indexOf(this._currentAssistantMsg);\n if (idx === -1) return;\n const updated: ThreadAssistantMessage = {\n ...this._currentAssistantMsg,\n content: [{ type: \"text\", text: transcript.text }],\n ...(transcript.isFinal\n ? { status: { type: \"complete\", reason: \"stop\" } }\n : {}),\n };\n this._voiceMessages[idx] = updated;\n this._currentAssistantMsg = updated;\n }\n\n if (transcript.isFinal) {\n this._currentAssistantMsg = null;\n }\n\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n }\n\n private _finishVoiceAssistantMessage() {\n const last = this._voiceMessages.at(-1);\n if (last?.role === \"assistant\" && last.status.type === \"running\") {\n const idx = this._voiceMessages.length - 1;\n this._voiceMessages[idx] = {\n ...(last as ThreadAssistantMessage),\n status: { type: \"complete\", reason: \"stop\" },\n };\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n }\n\n public disconnectVoice() {\n this._finishVoiceAssistantMessage();\n this._currentAssistantMsg = null;\n for (const unsub of this._voiceUnsubs) unsub();\n this._voiceUnsubs = [];\n this._voiceSession?.disconnect();\n this._voiceSession = undefined;\n this.voice = undefined;\n this._voiceVolume = 0;\n for (const cb of this._voiceVolumeSubscribers) cb();\n this._voiceMessages = [];\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n\n public muteVoice() {\n if (!this._voiceSession) throw new Error(\"No active voice session\");\n this._voiceSession.mute();\n this.voice = {\n ...this.voice!,\n isMuted: true,\n };\n this._notifySubscribers();\n }\n\n public unmuteVoice() {\n if (!this._voiceSession) throw new Error(\"No active voice session\");\n this._voiceSession.unmute();\n this.voice = {\n ...this.voice!,\n isMuted: false,\n };\n this._notifySubscribers();\n }\n\n protected ensureInitialized() {\n if (!this._isInitialized) {\n this._isInitialized = true;\n this._notifyEventSubscribers(\"initialize\", {});\n }\n }\n\n public export() {\n return this.repository.export();\n }\n\n public import(data: ExportedMessageRepository) {\n this.ensureInitialized();\n this.repository.clear();\n this.repository.import(data);\n this._notifySubscribers();\n }\n\n public reset(initialMessages?: readonly ThreadMessageLike[]) {\n this.import(ExportedMessageRepository.fromArray(initialMessages ?? []));\n }\n\n private _eventSubscribers = new Map<\n ThreadRuntimeEventType,\n Set<(payload?: unknown) => void>\n >();\n\n public unstable_on<E extends ThreadRuntimeEventType>(\n event: E,\n callback: ThreadRuntimeEventCallback<E>,\n ) {\n const wrapped = callback as (payload?: unknown) => void;\n if (event === \"modelContextUpdate\") {\n // provider.subscribe is `() => void`; pump the typed empty payload to the user callback.\n return this._contextProvider.subscribe?.(() => wrapped({})) ?? (() => {});\n }\n\n let subscribers = this._eventSubscribers.get(event);\n if (!subscribers) {\n subscribers = new Set();\n this._eventSubscribers.set(event, subscribers);\n }\n subscribers.add(wrapped);\n\n // `initialize` latches: replay it (deferred) to subscribers that attach\n // after the thread already initialized, mirroring a BehaviorSubject.\n if (event === \"initialize\" && this._isInitialized) {\n queueMicrotask(() => {\n if (subscribers.has(wrapped)) wrapped({});\n });\n }\n\n return () => {\n this._eventSubscribers.get(event)?.delete(wrapped);\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-thread-runtime-core.js","names":["AppendMessage","ThreadAssistantMessage","ThreadMessage","Unsubscribe","ModelContextProvider","getThreadMessageText","generateId","ExportedMessageRepository","MessageRepository","DefaultThreadComposerRuntimeCore","AddToolResultOptions","ResumeToolCallOptions","RespondToToolApprovalOptions","ThreadSuggestion","SubmitFeedbackOptions","ThreadRuntimeCore","SpeechState","VoiceSessionState","RuntimeCapabilities","ThreadRuntimeEventCallback","ThreadRuntimeEventPayload","ThreadRuntimeEventType","StartRunConfig","ResumeRunConfig","DefaultEditComposerRuntimeCore","SpeechSynthesisAdapter","FeedbackAdapter","AttachmentAdapter","RealtimeVoiceAdapter","ThreadMessageLike","notifyEventListeners","gateInteractableComposerMetadata","BaseThreadAdapters","speech","feedback","attachments","voice","BaseThreadRuntimeCore","_subscriptions","Set","_isInitialized","repository","adapters","isDisabled","isSendDisabled","isLoading","suggestions","extras","capabilities","append","message","deleteMessage","messageId","Promise","startRun","config","resumeRun","addToolResult","options","resumeToolCall","respondToToolApproval","cancelRun","exportExternalState","importExternalState","state","_voiceMessages","_voiceGeneration","_cachedMergedMessages","_cachedVoiceGeneration","_cachedMergedBase","_markVoiceMessagesDirty","_getBaseMessages","getMessages","messages","length","base","mostRecentAssistantMessage","this","role","metadata","unstable_state","composer","_contextProvider","constructor","getModelContext","enrichAppendMetadata","anchorId","parentId","parentIndex","findIndex","m","id","composerMetadata","unstable_composerMetadata","slice","custom","_editComposers","Map","getEditComposer","get","beginEdit","has","Error","set","delete","getMessage","_notifySubscribers","getMessageById","baseMessages","voiceIdx","at","index","undefined","getBranches","some","switchToBranch","branchId","callback","_notifyEventSubscribers","event","E","payload","subscribers","_eventSubscribers","subscribe","add","submitFeedback","type","adapter","submit","updatedMessage","submittedFeedback","addOrUpdateMessage","_stopSpeaking","speak","utterance","unsub","status","cancel","stopSpeaking","_voiceSession","Session","_voiceUnsubs","Array","_voiceVolume","_voiceVolumeSubscribers","getVoiceVolume","subscribeVoiceVolume","connectVoice","disconnectVoice","session","connect","unsubs","currentMode","Mode","isMuted","mode","push","onStatusChange","_finishVoiceAssistantMessage","onModeChange","onVolumeChange","volume","cb","onTranscript","transcript","_handleVoiceTranscript","_currentAssistantMsg","TranscriptItem","ensureInitialized","isFinal","content","text","createdAt","Date","reason","unstable_annotations","unstable_data","steps","idx","indexOf","updated","last","disconnect","muteVoice","mute","unmuteVoice","unmute","export","import","data","clear","reset","initialMessages","fromArray","unstable_on","wrapped","queueMicrotask"],"sources":["../../../src/runtime/base/base-thread-runtime-core.ts"],"sourcesContent":["import type {\n AppendMessage,\n ThreadAssistantMessage,\n ThreadMessage,\n} from \"../../types/message\";\nimport type { Unsubscribe } from \"../../types/unsubscribe\";\nimport type { ModelContextProvider } from \"../../model-context/types\";\nimport { getThreadMessageText } from \"../../utils/text\";\nimport { generateId } from \"../../utils/id\";\nimport {\n ExportedMessageRepository,\n MessageRepository,\n} from \"../utils/message-repository\";\nimport { DefaultThreadComposerRuntimeCore } from \"./default-thread-composer-runtime-core\";\nimport type {\n AddToolResultOptions,\n ResumeToolCallOptions,\n RespondToToolApprovalOptions,\n ThreadSuggestion,\n SubmitFeedbackOptions,\n ThreadRuntimeCore,\n SpeechState,\n VoiceSessionState,\n RuntimeCapabilities,\n ThreadRuntimeEventCallback,\n ThreadRuntimeEventPayload,\n ThreadRuntimeEventType,\n StartRunConfig,\n ResumeRunConfig,\n} from \"../interfaces/thread-runtime-core\";\nimport { DefaultEditComposerRuntimeCore } from \"./default-edit-composer-runtime-core\";\nimport type { SpeechSynthesisAdapter } from \"../../adapters/speech\";\nimport type { FeedbackAdapter } from \"../../adapters/feedback\";\nimport type { AttachmentAdapter } from \"../../adapters/attachment\";\nimport type { RealtimeVoiceAdapter } from \"../../adapters/voice\";\nimport type { ThreadMessageLike } from \"../utils/thread-message-like\";\nimport { notifyEventListeners } from \"../../utils/notify-event-listeners\";\nimport { gateInteractableComposerMetadata } from \"../../model-context/interactable-composer-metadata\";\n\ntype BaseThreadAdapters = {\n speech?: SpeechSynthesisAdapter | undefined;\n feedback?: FeedbackAdapter | undefined;\n attachments?: AttachmentAdapter | undefined;\n voice?: RealtimeVoiceAdapter | undefined;\n};\n\nexport abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {\n private _subscriptions = new Set<() => void>();\n private _isInitialized = false;\n\n protected readonly repository = new MessageRepository();\n public abstract get adapters(): BaseThreadAdapters | undefined;\n public abstract get isDisabled(): boolean;\n public abstract get isSendDisabled(): boolean;\n public abstract get isLoading(): boolean;\n public abstract get suggestions(): readonly ThreadSuggestion[];\n public abstract get extras(): unknown;\n\n public abstract get capabilities(): RuntimeCapabilities;\n public abstract append(message: AppendMessage): void;\n public abstract deleteMessage(messageId: string): void | Promise<void>;\n public abstract startRun(config: StartRunConfig): void;\n public abstract resumeRun(config: ResumeRunConfig): void;\n public abstract addToolResult(options: AddToolResultOptions): void;\n public abstract resumeToolCall(options: ResumeToolCallOptions): void;\n public abstract respondToToolApproval(\n options: RespondToToolApprovalOptions,\n ): void;\n public abstract cancelRun(): void;\n public abstract exportExternalState(): any;\n public abstract importExternalState(state: any): void;\n\n protected _voiceMessages: ThreadMessage[] = [];\n protected _voiceGeneration = 0;\n private _cachedMergedMessages: readonly ThreadMessage[] | null = null;\n private _cachedVoiceGeneration = -1;\n private _cachedMergedBase: readonly ThreadMessage[] | null = null;\n\n protected _markVoiceMessagesDirty() {\n this._voiceGeneration++;\n this._cachedMergedMessages = null;\n }\n\n protected _getBaseMessages(): readonly ThreadMessage[] {\n return this.repository.getMessages();\n }\n\n public get messages(): readonly ThreadMessage[] {\n if (this._voiceMessages.length === 0) {\n return this._getBaseMessages();\n }\n const base = this._getBaseMessages();\n if (\n this._cachedVoiceGeneration !== this._voiceGeneration ||\n this._cachedMergedBase !== base\n ) {\n this._cachedMergedMessages = [...base, ...this._voiceMessages];\n this._cachedVoiceGeneration = this._voiceGeneration;\n this._cachedMergedBase = base;\n }\n return this._cachedMergedMessages!;\n }\n\n public get state() {\n let mostRecentAssistantMessage: (typeof this.messages)[number] | undefined;\n for (const message of this.messages) {\n if (message.role === \"assistant\") {\n mostRecentAssistantMessage = message;\n }\n }\n\n return mostRecentAssistantMessage?.metadata.unstable_state ?? null;\n }\n\n public readonly composer = new DefaultThreadComposerRuntimeCore(this);\n\n private readonly _contextProvider: ModelContextProvider;\n\n constructor(_contextProvider: ModelContextProvider) {\n this._contextProvider = _contextProvider;\n }\n\n public getModelContext() {\n return this._contextProvider.getModelContext();\n }\n\n /**\n * Stamps provider-contributed composer metadata onto an outgoing message.\n * Called at dispatch rather than in the composer, so programmatic sends are\n * covered too, and exactly once per message: a queued send is stamped when\n * it leaves the lane, never when it enters.\n *\n * Only user messages are stamped, matching the readers: both the version\n * fold and the model injection skip every other role.\n *\n * @param anchorId Message the gated branch prefix ends at. A queued send\n * passes the current tail, having waited through a run that grew the prefix\n * past the parent it was created with.\n */\n protected enrichAppendMetadata(\n message: AppendMessage,\n anchorId: string | null = message.parentId,\n ): AppendMessage {\n if (message.role !== \"user\") return message;\n const messages = this.messages;\n const parentIndex =\n anchorId === null ? -1 : messages.findIndex((m) => m.id === anchorId);\n const composerMetadata = gateInteractableComposerMetadata(\n this.getModelContext().unstable_composerMetadata,\n messages.slice(0, parentIndex + 1),\n );\n if (!composerMetadata) return message;\n return {\n ...message,\n metadata: {\n ...message.metadata,\n custom: { ...message.metadata?.custom, ...composerMetadata },\n },\n };\n }\n\n private _editComposers = new Map<string, DefaultEditComposerRuntimeCore>();\n public getEditComposer(messageId: string) {\n return this._editComposers.get(messageId);\n }\n public beginEdit(messageId: string) {\n if (this._editComposers.has(messageId))\n throw new Error(\"Edit already in progress\");\n\n this._editComposers.set(\n messageId,\n new DefaultEditComposerRuntimeCore(\n this,\n () => this._editComposers.delete(messageId),\n this.repository.getMessage(messageId),\n ),\n );\n this._notifySubscribers();\n }\n\n public getMessageById(messageId: string) {\n try {\n return this.repository.getMessage(messageId);\n } catch {\n // Check voice messages\n const baseMessages = this.repository.getMessages();\n const voiceIdx = this._voiceMessages.findIndex((m) => m.id === messageId);\n if (voiceIdx !== -1) {\n const parentId =\n voiceIdx > 0\n ? this._voiceMessages[voiceIdx - 1]!.id\n : (baseMessages.at(-1)?.id ?? null);\n return {\n parentId,\n message: this._voiceMessages[voiceIdx]!,\n index: baseMessages.length + voiceIdx,\n };\n }\n return undefined;\n }\n }\n\n public getBranches(messageId: string): string[] {\n if (this._voiceMessages.some((m) => m.id === messageId)) {\n return [];\n }\n return this.repository.getBranches(messageId);\n }\n\n public switchToBranch(branchId: string): void {\n this.repository.switchToBranch(branchId);\n this._notifySubscribers();\n }\n\n protected _notifySubscribers() {\n for (const callback of this._subscriptions) callback();\n }\n\n public _notifyEventSubscribers<E extends ThreadRuntimeEventType>(\n event: E,\n payload: ThreadRuntimeEventPayload[E],\n ) {\n const subscribers = this._eventSubscribers.get(event);\n if (!subscribers) return;\n\n notifyEventListeners(subscribers, payload, `Thread runtime \"${event}\"`);\n }\n\n public subscribe(callback: () => void): Unsubscribe {\n this._subscriptions.add(callback);\n return () => this._subscriptions.delete(callback);\n }\n\n public submitFeedback({ messageId, type }: SubmitFeedbackOptions) {\n const adapter = this.adapters?.feedback;\n if (!adapter) throw new Error(\"Feedback adapter not configured\");\n\n const { message, parentId } = this.repository.getMessage(messageId);\n adapter.submit({ message, type });\n\n if (message.role === \"assistant\") {\n const updatedMessage: ThreadMessage = {\n ...message,\n metadata: {\n ...message.metadata,\n submittedFeedback: { type },\n },\n };\n this.repository.addOrUpdateMessage(parentId, updatedMessage);\n }\n\n this._notifySubscribers();\n }\n\n private _stopSpeaking: Unsubscribe | undefined;\n public speech: SpeechState | undefined;\n\n public speak(messageId: string) {\n const adapter = this.adapters?.speech;\n if (!adapter) throw new Error(\"Speech adapter not configured\");\n\n const { message } = this.repository.getMessage(messageId);\n\n this._stopSpeaking?.();\n\n const utterance = adapter.speak(getThreadMessageText(message));\n const unsub = utterance.subscribe(() => {\n if (utterance.status.type === \"ended\") {\n this._stopSpeaking = undefined;\n this.speech = undefined;\n } else {\n this.speech = { messageId, status: utterance.status };\n }\n this._notifySubscribers();\n });\n\n this.speech = { messageId, status: utterance.status };\n this._notifySubscribers();\n\n this._stopSpeaking = () => {\n utterance.cancel();\n unsub();\n this.speech = undefined;\n this._stopSpeaking = undefined;\n };\n }\n\n public stopSpeaking() {\n if (!this._stopSpeaking) throw new Error(\"No message is being spoken\");\n this._stopSpeaking();\n this._notifySubscribers();\n }\n\n private _voiceSession: RealtimeVoiceAdapter.Session | undefined;\n private _voiceUnsubs: Array<() => void> = [];\n public voice: VoiceSessionState | undefined;\n\n private _voiceVolume = 0;\n private _voiceVolumeSubscribers = new Set<() => void>();\n\n public getVoiceVolume = () => this._voiceVolume;\n\n public subscribeVoiceVolume = (callback: () => void): Unsubscribe => {\n this._voiceVolumeSubscribers.add(callback);\n return () => this._voiceVolumeSubscribers.delete(callback);\n };\n\n public connectVoice() {\n const adapter = this.adapters?.voice;\n if (!adapter) throw new Error(\"Voice adapter not configured\");\n\n this.disconnectVoice();\n\n const session = adapter.connect({});\n this._voiceSession = session;\n const unsubs: Array<() => void> = [];\n\n let currentMode: RealtimeVoiceAdapter.Mode = \"listening\";\n\n this.voice = {\n status: session.status,\n isMuted: session.isMuted,\n mode: currentMode,\n };\n this._voiceVolume = 0;\n this._notifySubscribers();\n\n unsubs.push(\n session.onStatusChange((status) => {\n if (status.type === \"ended\") {\n this._finishVoiceAssistantMessage();\n this._voiceSession = undefined;\n this.voice = undefined;\n } else {\n this.voice = {\n status,\n isMuted: session.isMuted,\n mode: currentMode,\n };\n }\n this._notifySubscribers();\n }),\n );\n\n unsubs.push(\n session.onModeChange((mode) => {\n currentMode = mode;\n if (this.voice) {\n this.voice = { ...this.voice, mode };\n this._notifySubscribers();\n }\n }),\n );\n\n unsubs.push(\n session.onVolumeChange((volume) => {\n this._voiceVolume = volume;\n for (const cb of this._voiceVolumeSubscribers) cb();\n }),\n );\n\n unsubs.push(\n session.onTranscript((transcript) => {\n this._handleVoiceTranscript(transcript);\n }),\n );\n\n this._voiceUnsubs = unsubs;\n }\n\n private _currentAssistantMsg: ThreadAssistantMessage | null = null;\n\n private _handleVoiceTranscript(\n transcript: RealtimeVoiceAdapter.TranscriptItem,\n ) {\n this.ensureInitialized();\n\n if (transcript.role === \"user\") {\n this._finishVoiceAssistantMessage();\n this._currentAssistantMsg = null;\n\n if (transcript.isFinal) {\n this._voiceMessages.push({\n id: generateId(),\n role: \"user\",\n content: [{ type: \"text\", text: transcript.text }],\n metadata: { custom: {} },\n createdAt: new Date(),\n status: { type: \"complete\", reason: \"unknown\" },\n attachments: [],\n });\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n } else {\n if (!this._currentAssistantMsg) {\n this._currentAssistantMsg = {\n id: generateId(),\n role: \"assistant\",\n content: [{ type: \"text\", text: transcript.text }],\n metadata: {\n unstable_state: this.state,\n unstable_annotations: [],\n unstable_data: [],\n steps: [],\n custom: {},\n },\n status: { type: \"running\" },\n createdAt: new Date(),\n };\n this._voiceMessages.push(this._currentAssistantMsg);\n } else {\n const idx = this._voiceMessages.indexOf(this._currentAssistantMsg);\n if (idx === -1) return;\n const updated: ThreadAssistantMessage = {\n ...this._currentAssistantMsg,\n content: [{ type: \"text\", text: transcript.text }],\n ...(transcript.isFinal\n ? { status: { type: \"complete\", reason: \"stop\" } }\n : {}),\n };\n this._voiceMessages[idx] = updated;\n this._currentAssistantMsg = updated;\n }\n\n if (transcript.isFinal) {\n this._currentAssistantMsg = null;\n }\n\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n }\n\n private _finishVoiceAssistantMessage() {\n const last = this._voiceMessages.at(-1);\n if (last?.role === \"assistant\" && last.status.type === \"running\") {\n const idx = this._voiceMessages.length - 1;\n this._voiceMessages[idx] = {\n ...(last as ThreadAssistantMessage),\n status: { type: \"complete\", reason: \"stop\" },\n };\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n }\n\n public disconnectVoice() {\n this._finishVoiceAssistantMessage();\n this._currentAssistantMsg = null;\n for (const unsub of this._voiceUnsubs) unsub();\n this._voiceUnsubs = [];\n this._voiceSession?.disconnect();\n this._voiceSession = undefined;\n this.voice = undefined;\n this._voiceVolume = 0;\n for (const cb of this._voiceVolumeSubscribers) cb();\n this._voiceMessages = [];\n this._markVoiceMessagesDirty();\n this._notifySubscribers();\n }\n\n public muteVoice() {\n if (!this._voiceSession) throw new Error(\"No active voice session\");\n this._voiceSession.mute();\n this.voice = {\n ...this.voice!,\n isMuted: true,\n };\n this._notifySubscribers();\n }\n\n public unmuteVoice() {\n if (!this._voiceSession) throw new Error(\"No active voice session\");\n this._voiceSession.unmute();\n this.voice = {\n ...this.voice!,\n isMuted: false,\n };\n this._notifySubscribers();\n }\n\n protected ensureInitialized() {\n if (!this._isInitialized) {\n this._isInitialized = true;\n this._notifyEventSubscribers(\"initialize\", {});\n }\n }\n\n public export() {\n return this.repository.export();\n }\n\n public import(data: ExportedMessageRepository) {\n this.ensureInitialized();\n this.repository.clear();\n this.repository.import(data);\n this._notifySubscribers();\n }\n\n public reset(initialMessages?: readonly ThreadMessageLike[]) {\n this.import(ExportedMessageRepository.fromArray(initialMessages ?? []));\n }\n\n private _eventSubscribers = new Map<\n ThreadRuntimeEventType,\n Set<(payload?: unknown) => void>\n >();\n\n public unstable_on<E extends ThreadRuntimeEventType>(\n event: E,\n callback: ThreadRuntimeEventCallback<E>,\n ) {\n const wrapped = callback as (payload?: unknown) => void;\n if (event === \"modelContextUpdate\") {\n // provider.subscribe is `() => void`; pump the typed empty payload to the user callback.\n return this._contextProvider.subscribe?.(() => wrapped({})) ?? (() => {});\n }\n\n let subscribers = this._eventSubscribers.get(event);\n if (!subscribers) {\n subscribers = new Set();\n this._eventSubscribers.set(event, subscribers);\n }\n subscribers.add(wrapped);\n\n // `initialize` latches: replay it (deferred) to subscribers that attach\n // after the thread already initialized, mirroring a BehaviorSubject.\n if (event === \"initialize\" && this._isInitialized) {\n queueMicrotask(() => {\n if (subscribers.has(wrapped)) wrapped({});\n });\n }\n\n return () => {\n this._eventSubscribers.get(event)?.delete(wrapped);\n };\n }\n}\n"],"mappings":";;;;;;;;AA8CA,IAAsBqC,wBAAtB,MAAyE;CACvE,iCAAyB,IAAIE,IAAgB;CAC7C,iBAAyB;CAEzB,aAAgC,IAAI/B,kBAAkB;CAsBtD,iBAA4C,CAAA;CAC5C,mBAA6B;CAC7B,wBAAiE;CACjE,yBAAiC;CACjC,oBAA6D;CAE7D,0BAAoC;EAClC,KAAK0D;EACL,KAAKC,wBAAwB;CAC/B;CAEA,mBAAuD;EACrD,OAAO,KAAK1B,WAAW+B,YAAY;CACrC;CAEA,IAAWC,WAAqC;EAC9C,IAAI,KAAKR,eAAeS,WAAW,GACjC,OAAO,KAAKH,iBAAiB;EAE/B,MAAMI,OAAO,KAAKJ,iBAAiB;EACnC,IACE,KAAKH,2BAA2B,KAAKF,oBACrC,KAAKG,sBAAsBM,MAC3B;GACA,KAAKR,wBAAwB,CAAC,GAAGQ,MAAM,GAAG,KAAKV,cAAc;GAC7D,KAAKG,yBAAyB,KAAKF;GACnC,KAAKG,oBAAoBM;EAC3B;EACA,OAAO,KAAKR;CACd;CAEA,IAAWH,QAAQ;EACjB,IAAIY;EACJ,KAAK,MAAM1B,WAAW,KAAKuB,UACzB,IAAIvB,QAAQ4B,SAAS,aACnBF,6BAA6B1B;EAIjC,OAAO0B,4BAA4BG,SAASC,kBAAkB;CAChE;CAEA,WAA2B,IAAIvE,iCAAiC,IAAI;CAEpE;CAEA0E,YAAYD,kBAAwC;EAClD,KAAKA,mBAAmBA;CAC1B;CAEA,kBAAyB;EACvB,OAAO,KAAKA,iBAAiBE,gBAAgB;CAC/C;;;;;;;;;;;;;;CAeA,qBACElC,SACAoC,WAA0BpC,QAAQqC,UACnB;EACf,IAAIrC,QAAQ4B,SAAS,QAAQ,OAAO5B;EACpC,MAAMuB,WAAW,KAAKA;EACtB,MAAMe,cACJF,aAAa,OAAO,KAAKb,SAASgB,WAAWC,MAAMA,EAAEC,OAAOL,QAAQ;EACtE,MAAMM,mBAAmB7D,iCACvB,KAAKqD,gBAAgB,CAAC,CAACS,2BACvBpB,SAASqB,MAAM,GAAGN,cAAc,CAAC,CACnC;EACA,IAAI,CAACI,kBAAkB,OAAO1C;EAC9B,OAAO;GACL,GAAGA;GACH6B,UAAU;IACR,GAAG7B,QAAQ6B;IACXgB,QAAQ;KAAE,GAAG7C,QAAQ6B,UAAUgB;KAAQ,GAAGH;IAAiB;GAC7D;EACF;CACF;CAEA,iCAAyB,IAAIK,IAA4C;CACzE,gBAAuB7C,WAAmB;EACxC,OAAO,KAAK4C,eAAeG,IAAI/C,SAAS;CAC1C;CACA,UAAiBA,WAAmB;EAClC,IAAI,KAAK4C,eAAeK,IAAIjD,SAAS,GACnC,MAAM,IAAIkD,MAAM,0BAA0B;EAE5C,KAAKN,eAAeO,IAClBnD,WACA,IAAI5B,+BACF,YACM,KAAKwE,eAAeQ,OAAOpD,SAAS,GAC1C,KAAKX,WAAWgE,WAAWrD,SAAS,CACtC,CACF;EACA,KAAKsD,mBAAmB;CAC1B;CAEA,eAAsBtD,WAAmB;EACvC,IAAI;GACF,OAAO,KAAKX,WAAWgE,WAAWrD,SAAS;EAC7C,QAAQ;GAEN,MAAMwD,eAAe,KAAKnE,WAAW+B,YAAY;GACjD,MAAMqC,WAAW,KAAK5C,eAAewB,WAAWC,MAAMA,EAAEC,OAAOvC,SAAS;GACxE,IAAIyD,aAAa,IAKf,OAAO;IACLtB,UAJAsB,WAAW,IACP,KAAK5C,eAAe4C,WAAW,EAAE,CAAElB,KAClCiB,aAAaE,GAAG,EAAE,CAAC,EAAEnB,MAAM;IAGhCzC,SAAS,KAAKe,eAAe4C;IAC7BE,OAAOH,aAAalC,SAASmC;GAC/B;GAEF;EACF;CACF;CAEA,YAAmBzD,WAA6B;EAC9C,IAAI,KAAKa,eAAeiD,MAAMxB,MAAMA,EAAEC,OAAOvC,SAAS,GACpD,OAAO,CAAA;EAET,OAAO,KAAKX,WAAWwE,YAAY7D,SAAS;CAC9C;CAEA,eAAsBgE,UAAwB;EAC5C,KAAK3E,WAAW0E,eAAeC,QAAQ;EACvC,KAAKV,mBAAmB;CAC1B;CAEA,qBAA+B;EAC7B,KAAK,MAAMW,YAAY,KAAK/E,gBAAgB+E,SAAS;CACvD;CAEA,wBACEE,OACAE,SACA;EACA,MAAMC,cAAc,KAAKC,kBAAkBxB,IAAIoB,KAAK;EACpD,IAAI,CAACG,aAAa;EAElB5F,qBAAqB4F,aAAaD,SAAS,mBAAmBF,MAAK,EAAG;CACxE;CAEA,UAAiBF,UAAmC;EAClD,KAAK/E,eAAeuF,IAAIR,QAAQ;EAChC,aAAa,KAAK/E,eAAekE,OAAOa,QAAQ;CAClD;CAEA,eAAsB,EAAEjE,WAAW2E,QAA+B;EAChE,MAAMC,UAAU,KAAKtF,UAAUR;EAC/B,IAAI,CAAC8F,SAAS,MAAM,IAAI1B,MAAM,iCAAiC;EAE/D,MAAM,EAAEpD,SAASqC,aAAa,KAAK9C,WAAWgE,WAAWrD,SAAS;EAClE4E,QAAQC,OAAO;GAAE/E;GAAS6E;EAAK,CAAC;EAEhC,IAAI7E,QAAQ4B,SAAS,aAAa;GAChC,MAAMoD,iBAAgC;IACpC,GAAGhF;IACH6B,UAAU;KACR,GAAG7B,QAAQ6B;KACXoD,mBAAmB,EAAEJ,KAAK;IAC5B;GACF;GACA,KAAKtF,WAAW2F,mBAAmB7C,UAAU2C,cAAc;EAC7D;EAEA,KAAKxB,mBAAmB;CAC1B;CAEA;CACA;CAEA,MAAatD,WAAmB;EAC9B,MAAM4E,UAAU,KAAKtF,UAAUT;EAC/B,IAAI,CAAC+F,SAAS,MAAM,IAAI1B,MAAM,+BAA+B;EAE7D,MAAM,EAAEpD,YAAY,KAAKT,WAAWgE,WAAWrD,SAAS;EAExD,KAAKiF,gBAAgB;EAErB,MAAME,YAAYP,QAAQM,MAAMjI,qBAAqB6C,OAAO,CAAC;EAC7D,MAAMsF,QAAQD,UAAUX,gBAAgB;GACtC,IAAIW,UAAUE,OAAOV,SAAS,SAAS;IACrC,KAAKM,gBAAgBrB,KAAAA;IACrB,KAAK/E,SAAS+E,KAAAA;GAChB,OACE,KAAK/E,SAAS;IAAEmB;IAAWqF,QAAQF,UAAUE;GAAO;GAEtD,KAAK/B,mBAAmB;EAC1B,CAAC;EAED,KAAKzE,SAAS;GAAEmB;GAAWqF,QAAQF,UAAUE;EAAO;EACpD,KAAK/B,mBAAmB;EAExB,KAAK2B,sBAAsB;GACzBE,UAAUG,OAAO;GACjBF,MAAM;GACN,KAAKvG,SAAS+E,KAAAA;GACd,KAAKqB,gBAAgBrB,KAAAA;EACvB;CACF;CAEA,eAAsB;EACpB,IAAI,CAAC,KAAKqB,eAAe,MAAM,IAAI/B,MAAM,4BAA4B;EACrE,KAAK+B,cAAc;EACnB,KAAK3B,mBAAmB;CAC1B;CAEA;CACA,eAA0C,CAAA;CAC1C;CAEA,eAAuB;CACvB,0CAAkC,IAAInE,IAAgB;CAEtD,uBAA8B,KAAKyG;CAEnC,wBAA+B3B,aAAsC;EACnE,KAAK4B,wBAAwBpB,IAAIR,QAAQ;EACzC,aAAa,KAAK4B,wBAAwBzC,OAAOa,QAAQ;CAC3D;CAEA,eAAsB;EACpB,MAAMW,UAAU,KAAKtF,UAAUN;EAC/B,IAAI,CAAC4F,SAAS,MAAM,IAAI1B,MAAM,8BAA8B;EAE5D,KAAK+C,gBAAgB;EAErB,MAAMC,UAAUtB,QAAQuB,QAAQ,CAAC,CAAC;EAClC,KAAKX,gBAAgBU;EACrB,MAAME,SAA4B,CAAA;EAElC,IAAIC,cAAyC;EAE7C,KAAKrH,QAAQ;GACXqG,QAAQa,QAAQb;GAChBkB,SAASL,QAAQK;GACjBC,MAAMH;EACR;EACA,KAAKT,eAAe;EACpB,KAAKtC,mBAAmB;EAExB8C,OAAOK,KACLP,QAAQQ,gBAAgBrB,WAAW;GACjC,IAAIA,OAAOV,SAAS,SAAS;IAC3B,KAAKgC,6BAA6B;IAClC,KAAKnB,gBAAgB5B,KAAAA;IACrB,KAAK5E,QAAQ4E,KAAAA;GACf,OACE,KAAK5E,QAAQ;IACXqG;IACAkB,SAASL,QAAQK;IACjBC,MAAMH;GACR;GAEF,KAAK/C,mBAAmB;EAC1B,CAAC,CACH;EAEA8C,OAAOK,KACLP,QAAQU,cAAcJ,SAAS;GAC7BH,cAAcG;GACd,IAAI,KAAKxH,OAAO;IACd,KAAKA,QAAQ;KAAE,GAAG,KAAKA;KAAOwH;IAAK;IACnC,KAAKlD,mBAAmB;GAC1B;EACF,CAAC,CACH;EAEA8C,OAAOK,KACLP,QAAQW,gBAAgBC,WAAW;GACjC,KAAKlB,eAAekB;GACpB,KAAK,MAAMC,MAAM,KAAKlB,yBAAyBkB,GAAG;EACpD,CAAC,CACH;EAEAX,OAAOK,KACLP,QAAQc,cAAcC,eAAe;GACnC,KAAKC,uBAAuBD,UAAU;EACxC,CAAC,CACH;EAEA,KAAKvB,eAAeU;CACtB;CAEA,uBAA8D;CAE9D,uBACEa,YACA;EACA,KAAKI,kBAAkB;EAEvB,IAAIJ,WAAWvF,SAAS,QAAQ;GAC9B,KAAKiF,6BAA6B;GAClC,KAAKQ,uBAAuB;GAE5B,IAAIF,WAAWK,SAAS;IACtB,KAAKzG,eAAe4F,KAAK;KACvBlE,IAAIrF,WAAW;KACfwE,MAAM;KACN6F,SAAS,CAAC;MAAE5C,MAAM;MAAQ6C,MAAMP,WAAWO;KAAK,CAAC;KACjD7F,UAAU,EAAEgB,QAAQ,CAAC,EAAE;KACvB8E,2BAAW,IAAIC,KAAK;KACpBrC,QAAQ;MAAEV,MAAM;MAAYgD,QAAQ;KAAU;KAC9C5I,aAAa,CAAA;IACf,CAAC;IACD,KAAKmC,wBAAwB;IAC7B,KAAKoC,mBAAmB;GAC1B;EACF,OAAO;GACL,IAAI,CAAC,KAAK6D,sBAAsB;IAC9B,KAAKA,uBAAuB;KAC1B5E,IAAIrF,WAAW;KACfwE,MAAM;KACN6F,SAAS,CAAC;MAAE5C,MAAM;MAAQ6C,MAAMP,WAAWO;KAAK,CAAC;KACjD7F,UAAU;MACRC,gBAAgB,KAAKhB;MACrBgH,sBAAsB,CAAA;MACtBC,eAAe,CAAA;MACfC,OAAO,CAAA;MACPnF,QAAQ,CAAC;KACX;KACA0C,QAAQ,EAAEV,MAAM,UAAU;KAC1B8C,2BAAW,IAAIC,KAAK;IACtB;IACA,KAAK7G,eAAe4F,KAAK,KAAKU,oBAAoB;GACpD,OAAO;IACL,MAAMY,MAAM,KAAKlH,eAAemH,QAAQ,KAAKb,oBAAoB;IACjE,IAAIY,QAAQ,IAAI;IAChB,MAAME,UAAkC;KACtC,GAAG,KAAKd;KACRI,SAAS,CAAC;MAAE5C,MAAM;MAAQ6C,MAAMP,WAAWO;KAAK,CAAC;KACjD,GAAIP,WAAWK,UACX,EAAEjC,QAAQ;MAAEV,MAAM;MAAYgD,QAAQ;KAAO,EAAE,IAC/C,CAAC;IACP;IACA,KAAK9G,eAAekH,OAAOE;IAC3B,KAAKd,uBAAuBc;GAC9B;GAEA,IAAIhB,WAAWK,SACb,KAAKH,uBAAuB;GAG9B,KAAKjG,wBAAwB;GAC7B,KAAKoC,mBAAmB;EAC1B;CACF;CAEA,+BAAuC;EACrC,MAAM4E,OAAO,KAAKrH,eAAe6C,GAAG,EAAE;EACtC,IAAIwE,MAAMxG,SAAS,eAAewG,KAAK7C,OAAOV,SAAS,WAAW;GAChE,MAAMoD,MAAM,KAAKlH,eAAeS,SAAS;GACzC,KAAKT,eAAekH,OAAO;IACzB,GAAIG;IACJ7C,QAAQ;KAAEV,MAAM;KAAYgD,QAAQ;IAAO;GAC7C;GACA,KAAKzG,wBAAwB;GAC7B,KAAKoC,mBAAmB;EAC1B;CACF;CAEA,kBAAyB;EACvB,KAAKqD,6BAA6B;EAClC,KAAKQ,uBAAuB;EAC5B,KAAK,MAAM/B,SAAS,KAAKM,cAAcN,MAAM;EAC7C,KAAKM,eAAe,CAAA;EACpB,KAAKF,eAAe2C,WAAW;EAC/B,KAAK3C,gBAAgB5B,KAAAA;EACrB,KAAK5E,QAAQ4E,KAAAA;EACb,KAAKgC,eAAe;EACpB,KAAK,MAAMmB,MAAM,KAAKlB,yBAAyBkB,GAAG;EAClD,KAAKlG,iBAAiB,CAAA;EACtB,KAAKK,wBAAwB;EAC7B,KAAKoC,mBAAmB;CAC1B;CAEA,YAAmB;EACjB,IAAI,CAAC,KAAKkC,eAAe,MAAM,IAAItC,MAAM,yBAAyB;EAClE,KAAKsC,cAAc6C,KAAK;EACxB,KAAKrJ,QAAQ;GACX,GAAG,KAAKA;GACRuH,SAAS;EACX;EACA,KAAKjD,mBAAmB;CAC1B;CAEA,cAAqB;EACnB,IAAI,CAAC,KAAKkC,eAAe,MAAM,IAAItC,MAAM,yBAAyB;EAClE,KAAKsC,cAAc+C,OAAO;EAC1B,KAAKvJ,QAAQ;GACX,GAAG,KAAKA;GACRuH,SAAS;EACX;EACA,KAAKjD,mBAAmB;CAC1B;CAEA,oBAA8B;EAC5B,IAAI,CAAC,KAAKlE,gBAAgB;GACxB,KAAKA,iBAAiB;GACtB,KAAK8E,wBAAwB,cAAc,CAAC,CAAC;EAC/C;CACF;CAEA,SAAgB;EACd,OAAO,KAAK7E,WAAWmJ,OAAO;CAChC;CAEA,OAAcE,MAAiC;EAC7C,KAAKrB,kBAAkB;EACvB,KAAKhI,WAAWsJ,MAAM;EACtB,KAAKtJ,WAAWoJ,OAAOC,IAAI;EAC3B,KAAKpF,mBAAmB;CAC1B;CAEA,MAAauF,iBAAgD;EAC3D,KAAKJ,OAAOtL,0BAA0B2L,UAAUD,mBAAmB,CAAA,CAAE,CAAC;CACxE;CAEA,oCAA4B,IAAIhG,IAG9B;CAEF,YACEsB,OACAF,UACA;EACA,MAAM+E,UAAU/E;EAChB,IAAIE,UAAU,sBAEZ,OAAO,KAAKrC,iBAAiB0C,kBAAkBwE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;EAGzE,IAAI1E,cAAc,KAAKC,kBAAkBxB,IAAIoB,KAAK;EAClD,IAAI,CAACG,aAAa;GAChBA,8BAAc,IAAInF,IAAI;GACtB,KAAKoF,kBAAkBpB,IAAIgB,OAAOG,WAAW;EAC/C;EACAA,YAAYG,IAAIuE,OAAO;EAIvB,IAAI7E,UAAU,gBAAgB,KAAK/E,gBACjC6J,qBAAqB;GACnB,IAAI3E,YAAYrB,IAAI+F,OAAO,GAAGA,QAAQ,CAAC,CAAC;EAC1C,CAAC;EAGH,aAAa;GACX,KAAKzE,kBAAkBxB,IAAIoB,KAAK,CAAC,EAAEf,OAAO4F,OAAO;EACnD;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-edit-composer-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/default-edit-composer-runtime-core.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"default-edit-composer-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/default-edit-composer-runtime-core.ts"],"mappings":";;;;;;;cAUa,uCAAuC;MACvC;MAIA;YAID,wBAAoB;YAIpB,uBAAmB;UAIrB;UACA;UACA;UACA;UAQA;EAGN,YAAA,SAAS;IACP;MAEM,cAAc;MACd,YAAY;;KAIpB,+BACE,UAAU;IAAa;IAAyB,SAAS;;MA6BlD;MAIA;EAIE,WACX,SAAS,KAAK,yCACd,UAAU,cAAW;EAqBhB"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { gateInteractableComposerMetadata } from "../../model-context/interactable-composer-metadata.js";
|
|
2
1
|
import { liftNonTextParts } from "../../adapters/attachment.js";
|
|
3
2
|
import { getThreadMessageText } from "../../utils/text.js";
|
|
4
3
|
import { BaseComposerRuntimeCore } from "./base-composer-runtime-core.js";
|
|
@@ -48,12 +47,8 @@ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
|
|
|
48
47
|
}
|
|
49
48
|
async handleSend(message, options) {
|
|
50
49
|
const content = this._nonTextPassthrough.length > 0 ? [...message.content, ...this._nonTextPassthrough] : message.content;
|
|
51
|
-
const messages = this.runtime.messages;
|
|
52
|
-
const parentIndex = this._parentId === null ? -1 : messages.findIndex((m) => m.id === this._parentId);
|
|
53
|
-
const composerMetadata = gateInteractableComposerMetadata(this.runtime.getModelContext().unstable_composerMetadata, messages.slice(0, parentIndex + 1));
|
|
54
|
-
const enriched = this.enrichWithComposerMetadata(message, composerMetadata);
|
|
55
50
|
const appendTask = this.runtime.append({
|
|
56
|
-
...
|
|
51
|
+
...message,
|
|
57
52
|
content,
|
|
58
53
|
parentId: this._parentId,
|
|
59
54
|
sourceId: this._sourceId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-edit-composer-runtime-core.js","names":["AppendMessage","ThreadMessage","CompleteAttachment","getThreadMessageText","liftNonTextParts","AttachmentAdapter","DictationAdapter","SendOptions","ThreadRuntimeCore","BaseComposerRuntimeCore","
|
|
1
|
+
{"version":3,"file":"default-edit-composer-runtime-core.js","names":["AppendMessage","ThreadMessage","CompleteAttachment","getThreadMessageText","liftNonTextParts","AttachmentAdapter","DictationAdapter","SendOptions","ThreadRuntimeCore","BaseComposerRuntimeCore","DefaultEditComposerRuntimeCore","canCancel","canSend","isEmpty","_isSending","getAttachmentAdapter","runtime","adapters","attachments","getDictationAdapter","dictation","_nonTextPassthrough","_parentId","_sourceId","endEditCallback","constructor","parentId","message","id","setText","setRole","role","content","filter","p","type","setAttachments","setRunConfig","composer","runConfig","sourceId","handleSend","Omit","options","length","appendTask","append","startRun","handleCancel","_notifySubscribers"],"sources":["../../../src/runtime/base/default-edit-composer-runtime-core.ts"],"sourcesContent":["import type { AppendMessage, ThreadMessage } from \"../../types/message\";\nimport type { CompleteAttachment } from \"../../types/attachment\";\nimport { getThreadMessageText } from \"../../utils/text\";\nimport { liftNonTextParts } from \"../../adapters/attachment\";\nimport type { AttachmentAdapter } from \"../../adapters/attachment\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type { SendOptions } from \"../interfaces/composer-runtime-core\";\nimport type { ThreadRuntimeCore } from \"../interfaces/thread-runtime-core\";\nimport { BaseComposerRuntimeCore } from \"./base-composer-runtime-core\";\n\nexport class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {\n public get canCancel() {\n return true;\n }\n\n public get canSend() {\n return !this.isEmpty && !this._isSending;\n }\n\n protected getAttachmentAdapter() {\n return this.runtime.adapters?.attachments;\n }\n\n protected getDictationAdapter() {\n return this.runtime.adapters?.dictation;\n }\n\n private _nonTextPassthrough: readonly ThreadMessage[\"content\"][number][];\n private _parentId: string | null;\n private _sourceId: string | null;\n private runtime: ThreadRuntimeCore & {\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n }\n | undefined;\n };\n private endEditCallback: () => void;\n\n constructor(\n runtime: ThreadRuntimeCore & {\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n }\n | undefined;\n },\n endEditCallback: () => void,\n { parentId, message }: { parentId: string | null; message: ThreadMessage },\n ) {\n super();\n this.runtime = runtime;\n this.endEditCallback = endEditCallback;\n this._parentId = parentId;\n this._sourceId = message.id;\n this.setText(getThreadMessageText(message));\n\n this.setRole(message.role);\n\n let attachments: readonly CompleteAttachment[];\n if (message.role === \"user\") {\n attachments = [\n ...(message.attachments ?? []),\n ...liftNonTextParts(message.content),\n ];\n this._nonTextPassthrough = [];\n } else {\n attachments = message.attachments ?? [];\n this._nonTextPassthrough = message.content.filter(\n (p) => p.type !== \"text\",\n );\n }\n this.setAttachments(attachments);\n\n this.setRunConfig({ ...runtime.composer.runConfig });\n }\n\n public get parentId() {\n return this._parentId;\n }\n\n public get sourceId() {\n return this._sourceId;\n }\n\n public async handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ) {\n const content =\n this._nonTextPassthrough.length > 0\n ? ([\n ...message.content,\n ...this._nonTextPassthrough,\n ] as AppendMessage[\"content\"])\n : message.content;\n const appendTask = this.runtime.append({\n ...message,\n content,\n parentId: this._parentId,\n sourceId: this._sourceId,\n startRun: options?.startRun,\n });\n\n this.handleCancel();\n return appendTask;\n }\n\n public handleCancel() {\n this.endEditCallback();\n this._notifySubscribers();\n }\n}\n"],"mappings":";;;;AAUA,IAAaU,iCAAb,cAAoDD,wBAAwB;CAC1E,IAAWE,YAAY;EACrB,OAAO;CACT;CAEA,IAAWC,UAAU;EACnB,OAAO,CAAC,KAAKC,WAAW,CAAC,KAAKC;CAChC;CAEA,uBAAiC;EAC/B,OAAO,KAAKE,QAAQC,UAAUC;CAChC;CAEA,sBAAgC;EAC9B,OAAO,KAAKF,QAAQC,UAAUG;CAChC;CAEA;CACA;CACA;CACA;CAQA;CAEAK,YACET,SAQAQ,iBACA,EAAEE,UAAUC,WACZ;EACA,MAAM;EACN,KAAKX,UAAUA;EACf,KAAKQ,kBAAkBA;EACvB,KAAKF,YAAYI;EACjB,KAAKH,YAAYI,QAAQC;EACzB,KAAKC,QAAQ1B,qBAAqBwB,OAAO,CAAC;EAE1C,KAAKG,QAAQH,QAAQI,IAAI;EAEzB,IAAIb;EACJ,IAAIS,QAAQI,SAAS,QAAQ;GAC3Bb,cAAc,CACZ,GAAIS,QAAQT,eAAe,CAAA,GAC3B,GAAGd,iBAAiBuB,QAAQK,OAAO,CAAC;GAEtC,KAAKX,sBAAsB,CAAA;EAC7B,OAAO;GACLH,cAAcS,QAAQT,eAAe,CAAA;GACrC,KAAKG,sBAAsBM,QAAQK,QAAQC,QACxCC,MAAMA,EAAEC,SAAS,MACpB;EACF;EACA,KAAKC,eAAelB,WAAW;EAE/B,KAAKmB,aAAa,EAAE,GAAGrB,QAAQsB,SAASC,UAAU,CAAC;CACrD;CAEA,IAAWb,WAAW;EACpB,OAAO,KAAKJ;CACd;CAEA,IAAWkB,WAAW;EACpB,OAAO,KAAKjB;CACd;CAEA,MAAakB,WACXd,SACAgB,SACA;EACA,MAAMX,UACJ,KAAKX,oBAAoBuB,SAAS,IAC7B,CACC,GAAGjB,QAAQK,SACX,GAAG,KAAKX,mBAAmB,IAE7BM,QAAQK;EACd,MAAMa,aAAa,KAAK7B,QAAQ8B,OAAO;GACrC,GAAGnB;GACHK;GACAN,UAAU,KAAKJ;GACfkB,UAAU,KAAKjB;GACfwB,UAAUJ,SAASI;EACrB,CAAC;EAED,KAAKC,aAAa;EAClB,OAAOH;CACT;CAEA,eAAsB;EACpB,KAAKrB,gBAAgB;EACrB,KAAKyB,mBAAmB;CAC1B;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-thread-composer-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/default-thread-composer-runtime-core.ts"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"default-thread-composer-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/default-thread-composer-runtime-core.ts"],"mappings":";;;;;;;;;;;cAea,yCACH,mCACG;UAEH;MACG;MAIA;UAIH;MAQY,kBAAkB;EAgBtB,cACd,qBACA,WAAW;EAKG,gBAAgB;YAItB,wBAAoB;YAIpB,uBAAmB;UAIrB;EAUN,YAAA,SAAS,KAAK;IACZ;MAEM,cAAc;MACd,YAAY;;;EAUf,WAVe;EA+BT,WACX,SAAS,KAAK,yCACd,UAAU,cAAW;EAWV,gBAAY"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { gateInteractableComposerMetadata } from "../../model-context/interactable-composer-metadata.js";
|
|
2
1
|
import { EMPTY_QUEUE_ITEMS } from "../../store/scopes/queue-item.js";
|
|
3
2
|
import { BaseComposerRuntimeCore } from "./base-composer-runtime-core.js";
|
|
4
3
|
//#region src/runtime/base/default-thread-composer-runtime-core.ts
|
|
@@ -63,10 +62,8 @@ var DefaultThreadComposerRuntimeCore = class extends BaseComposerRuntimeCore {
|
|
|
63
62
|
});
|
|
64
63
|
}
|
|
65
64
|
async handleSend(message, options) {
|
|
66
|
-
const composerMetadata = gateInteractableComposerMetadata(this.runtime.getModelContext().unstable_composerMetadata, this.runtime.messages);
|
|
67
|
-
const enriched = this.enrichWithComposerMetadata(message, composerMetadata);
|
|
68
65
|
return this.runtime.append({
|
|
69
|
-
...
|
|
66
|
+
...message,
|
|
70
67
|
parentId: this.runtime.messages.at(-1)?.id ?? null,
|
|
71
68
|
sourceId: null,
|
|
72
69
|
startRun: options?.startRun,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-thread-composer-runtime-core.js","names":["AppendMessage","AttachmentAdapter","DictationAdapter","SendOptions","ThreadComposerRuntimeCore","ThreadRuntimeCore","QueuePlacement","EMPTY_QUEUE_ITEMS","QueueItemState","BaseComposerRuntimeCore","
|
|
1
|
+
{"version":3,"file":"default-thread-composer-runtime-core.js","names":["AppendMessage","AttachmentAdapter","DictationAdapter","SendOptions","ThreadComposerRuntimeCore","ThreadRuntimeCore","QueuePlacement","EMPTY_QUEUE_ITEMS","QueueItemState","BaseComposerRuntimeCore","DefaultThreadComposerRuntimeCore","_canCancel","canCancel","canSend","isEmpty","runtime","isSendDisabled","_isSending","_queueCache","steer","queue","flat","getSteerQueueItems","getQueueItems","cache","length","moveQueueItem","queueItemId","placement","removeQueueItem","getAttachmentAdapter","adapters","attachments","getDictationAdapter","dictation","Omit","constructor","connect","lastIsSendDisabled","lastQueue","subscribe","changed","capabilities","cancel","_notifySubscribers","handleSend","message","options","append","parentId","messages","at","id","sourceId","startRun","handleCancel","cancelRun"],"sources":["../../../src/runtime/base/default-thread-composer-runtime-core.ts"],"sourcesContent":["import type { AppendMessage } from \"../../types/message\";\nimport type { AttachmentAdapter } from \"../../adapters/attachment\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type {\n SendOptions,\n ThreadComposerRuntimeCore,\n} from \"../interfaces/composer-runtime-core\";\nimport type { ThreadRuntimeCore } from \"../interfaces/thread-runtime-core\";\nimport type { QueuePlacement } from \"../queue/external-thread-queue-adapter\";\nimport {\n EMPTY_QUEUE_ITEMS,\n type QueueItemState,\n} from \"../../store/scopes/queue-item\";\nimport { BaseComposerRuntimeCore } from \"./base-composer-runtime-core\";\n\nexport class DefaultThreadComposerRuntimeCore\n extends BaseComposerRuntimeCore\n implements ThreadComposerRuntimeCore\n{\n private _canCancel = false;\n public get canCancel() {\n return this._canCancel;\n }\n\n public get canSend() {\n return !this.isEmpty && !this.runtime.isSendDisabled && !this._isSending;\n }\n\n private _queueCache:\n | {\n steer: readonly QueueItemState[];\n queue: readonly QueueItemState[];\n flat: readonly QueueItemState[];\n }\n | undefined;\n\n public override get queue(): readonly QueueItemState[] {\n const steer = this.runtime.getSteerQueueItems?.() ?? EMPTY_QUEUE_ITEMS;\n const queue = this.runtime.getQueueItems?.() ?? EMPTY_QUEUE_ITEMS;\n const cache = this._queueCache;\n if (cache && cache.steer === steer && cache.queue === queue)\n return cache.flat;\n const flat =\n steer.length === 0\n ? queue\n : queue.length === 0\n ? steer\n : [...steer, ...queue];\n this._queueCache = { steer, queue, flat };\n return flat;\n }\n\n public override moveQueueItem(\n queueItemId: string,\n placement: QueuePlacement,\n ): void {\n this.runtime.moveQueueItem?.(queueItemId, placement);\n }\n\n public override removeQueueItem(queueItemId: string): void {\n this.runtime.removeQueueItem?.(queueItemId);\n }\n\n protected getAttachmentAdapter() {\n return this.runtime.adapters?.attachments;\n }\n\n protected getDictationAdapter() {\n return this.runtime.adapters?.dictation;\n }\n\n private runtime: Omit<ThreadRuntimeCore, \"composer\"> & {\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n }\n | undefined;\n };\n\n constructor(\n runtime: Omit<ThreadRuntimeCore, \"composer\"> & {\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n }\n | undefined;\n },\n ) {\n super();\n this.runtime = runtime;\n this.connect();\n }\n\n public connect() {\n let lastIsSendDisabled = this.runtime.isSendDisabled;\n let lastQueue = this.queue;\n return this.runtime.subscribe(() => {\n let changed = false;\n if (this.canCancel !== this.runtime.capabilities.cancel) {\n this._canCancel = this.runtime.capabilities.cancel;\n changed = true;\n }\n if (lastIsSendDisabled !== this.runtime.isSendDisabled) {\n lastIsSendDisabled = this.runtime.isSendDisabled;\n changed = true;\n }\n if (lastQueue !== this.queue) {\n lastQueue = this.queue;\n changed = true;\n }\n if (changed) this._notifySubscribers();\n });\n }\n\n public async handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ) {\n return this.runtime.append({\n ...(message as AppendMessage),\n parentId: this.runtime.messages.at(-1)?.id ?? null,\n sourceId: null,\n startRun: options?.startRun,\n steer: options?.steer,\n });\n }\n\n public async handleCancel() {\n this.runtime.cancelRun();\n }\n}\n"],"mappings":";;;AAeA,IAAaU,mCAAb,cACUD,wBAEV;CACE,aAAqB;CACrB,IAAWG,YAAY;EACrB,OAAO,KAAKD;CACd;CAEA,IAAWE,UAAU;EACnB,OAAO,CAAC,KAAKC,WAAW,CAAC,KAAKC,QAAQC,kBAAkB,CAAC,KAAKC;CAChE;CAEA;CAQA,IAAoBG,QAAmC;EACrD,MAAMD,QAAQ,KAAKJ,QAAQO,qBAAqB,KAAKf;EACrD,MAAMa,QAAQ,KAAKL,QAAQQ,gBAAgB,KAAKhB;EAChD,MAAMiB,QAAQ,KAAKN;EACnB,IAAIM,SAASA,MAAML,UAAUA,SAASK,MAAMJ,UAAUA,OACpD,OAAOI,MAAMH;EACf,MAAMA,OACJF,MAAMM,WAAW,IACbL,QACAA,MAAMK,WAAW,IACfN,QACA,CAAC,GAAGA,OAAO,GAAGC,KAAK;EAC3B,KAAKF,cAAc;GAAEC;GAAOC;GAAOC;EAAK;EACxC,OAAOA;CACT;CAEA,cACEM,aACAC,WACM;EACN,KAAKb,QAAQW,gBAAgBC,aAAaC,SAAS;CACrD;CAEA,gBAAgCD,aAA2B;EACzD,KAAKZ,QAAQc,kBAAkBF,WAAW;CAC5C;CAEA,uBAAiC;EAC/B,OAAO,KAAKZ,QAAQgB,UAAUC;CAChC;CAEA,sBAAgC;EAC9B,OAAO,KAAKjB,QAAQgB,UAAUG;CAChC;CAEA;CASAE,YACErB,SAQA;EACA,MAAM;EACN,KAAKA,UAAUA;EACf,KAAKsB,QAAQ;CACf;CAEA,UAAiB;EACf,IAAIC,qBAAqB,KAAKvB,QAAQC;EACtC,IAAIuB,YAAY,KAAKnB;EACrB,OAAO,KAAKL,QAAQyB,gBAAgB;GAClC,IAAIC,UAAU;GACd,IAAI,KAAK7B,cAAc,KAAKG,QAAQ2B,aAAaC,QAAQ;IACvD,KAAKhC,aAAa,KAAKI,QAAQ2B,aAAaC;IAC5CF,UAAU;GACZ;GACA,IAAIH,uBAAuB,KAAKvB,QAAQC,gBAAgB;IACtDsB,qBAAqB,KAAKvB,QAAQC;IAClCyB,UAAU;GACZ;GACA,IAAIF,cAAc,KAAKnB,OAAO;IAC5BmB,YAAY,KAAKnB;IACjBqB,UAAU;GACZ;GACA,IAAIA,SAAS,KAAKG,mBAAmB;EACvC,CAAC;CACH;CAEA,MAAaC,WACXC,SACAC,SACA;EACA,OAAO,KAAKhC,QAAQiC,OAAO;GACzB,GAAIF;GACJG,UAAU,KAAKlC,QAAQmC,SAASC,GAAG,EAAE,CAAC,EAAEC,MAAM;GAC9CC,UAAU;GACVC,UAAUP,SAASO;GACnBnC,OAAO4B,SAAS5B;EAClB,CAAC;CACH;CAEA,MAAaoC,eAAe;EAC1B,KAAKxC,QAAQyC,UAAU;CACzB;AACF"}
|
|
@@ -26,6 +26,21 @@ type ExternalThreadQueueAdapter = {
|
|
|
26
26
|
move: (queueItemId: string, placement: QueuePlacement) => void;
|
|
27
27
|
edit: (queueItemId: string, message: AppendMessage) => void;
|
|
28
28
|
remove: (queueItemId: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Installed by the owning runtime, applied to a message as it leaves a lane.
|
|
31
|
+
* A message can wait through an entire run, so state the runtime attaches at
|
|
32
|
+
* send time is recomputed against the thread it actually lands on. Adapters
|
|
33
|
+
* from `createMessageQueue` provide this; a hand-rolled adapter that omits
|
|
34
|
+
* it dispatches whatever was enqueued.
|
|
35
|
+
*/
|
|
36
|
+
__internal_setDispatchTransform?: ((transform: (message: AppendMessage) => AppendMessage) => void) | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Called by the owning runtime when the user cancels the run, before the run
|
|
39
|
+
* is aborted. Pauses the queue so the cancelled run's settle keeps the
|
|
40
|
+
* pending items instead of dispatching the next one; the next send re-arms
|
|
41
|
+
* draining. A hand-rolled adapter that omits it drains on cancel.
|
|
42
|
+
*/
|
|
43
|
+
__internal_notifyCancelled?: (() => void) | undefined;
|
|
29
44
|
};
|
|
30
45
|
//#endregion
|
|
31
46
|
export { ExternalThreadQueueAdapter, QueuePlacement };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-thread-queue-adapter.d.ts","names":[],"sources":["../../../src/runtime/queue/external-thread-queue-adapter.ts"],"mappings":";;;KAGY;WACD;WACA;WACA;;;;;;KAOC;EACV,gBAAgB;EAChB,qBAAqB;;EAErB,UAAU,SAAS;;EAEnB,QAAQ,SAAS;;;;;;;EAOjB,OAAO,qBAAqB,WAAW;EACvC,OAAO,qBAAqB,SAAS;EACrC,SAAS"}
|
|
1
|
+
{"version":3,"file":"external-thread-queue-adapter.d.ts","names":[],"sources":["../../../src/runtime/queue/external-thread-queue-adapter.ts"],"mappings":";;;KAGY;WACD;WACA;WACA;;;;;;KAOC;EACV,gBAAgB;EAChB,qBAAqB;;EAErB,UAAU,SAAS;;EAEnB,QAAQ,SAAS;;;;;;;EAOjB,OAAO,qBAAqB,WAAW;EACvC,OAAO,qBAAqB,SAAS;EACrC,SAAS;;;;;;;;EAQT,oCACM,YAAY,SAAS,kBAAkB;;;;;;;EAQ7C"}
|