Runtime components, options, and adapters for using assistant-ui with externally owned chat state.
API Reference
ExternalStoreAdapter
- isDisabled?boolean | undefined
Whether the entire thread is disabled. When `true`, the composer's input is also disabled (the user cannot type, attach files, or submit). For a narrower gate that keeps the input usable but blocks only sending, use `isSendDisabled`.
- isSendDisabled?boolean | undefined
Whether sending new messages is currently disabled. When `true`, the thread composer's input remains usable but `send()` becomes a no-op and the thread composer's `canSend` is `false`. Use this to gate sending on external React state (e.g. while tool config is loading) without disabling the input itself the way `isDisabled` does. Edit composers (saving message edits) intentionally ignore this flag.
- isRunning?boolean | undefined
Whether the thread is running. When provided, this value flows directly to `thread.isRunning`, letting the application keep the thread in a running state even after the last assistant message has completed (for example while non-message stream chunks like suggestions or metadata updates are still arriving). When omitted, `thread.isRunning` falls back to the last-message-status heuristic.
- isLoading?boolean | undefined
- messages?readonly T[]
- messageRepository?ExportedMessageRepository
- ExportedMessageRepository
- headId?string | null
- messagesArray<{ message: ThreadMessage; parentId: string | null; runConfig?: RunConfig; }>
- unstable_messageRepositoryInstance?MessageRepository | undefinedunstable
An externally owned message repository instance. When provided, the thread runtime adopts it as its branch store and swaps to it atomically whenever a different instance is passed, so hosts that route multiple conversations through one runtime keep each conversation's history and branches isolated in its own instance. Omit it to keep the runtime's own repository.
ExternalStoreAdapter["unstable_messageRepositoryInstance"]- messagesMap<string, RepositoryMessage>
- Map
- clear() => void
- delete(key: string) => boolean
- forEach(callbackfn: (value: { children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; }, key: string, map: Map<string, { children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; }>) => void, thisArg?: any) => void
- get(key: string) => ({ children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; })
- has(key: string) => boolean
- set(key: string, value: { children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; }) => Map<string, { children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; }>
- sizenumber
- entries() => MapIterator<[string, { children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; }]>
- keys() => MapIterator<string>
- values() => MapIterator<{ children: string[]; next: (RepositoryParent & { prev: (RepositoryParent & any) | null; current: ThreadMessage; level: number; }) | null; } & { prev: ({ children: string[]; next: (RepositoryParent & any) | null; } & any) | null; current: ThreadMessage; level: number; }>
- headRepositoryMessage | null
- ExternalStoreAdapter["unstable_messageRepositoryInstance"]["head"]
- childrenstring[]
- nextRepositoryMessage | null
- ExternalStoreAdapter["unstable_messageRepositoryInstance"]["head"]["next"]
- childrenstring[]
- nextRepositoryMessage | null
- prevRepositoryMessage | null
- currentThreadMessage
- levelnumber
- prevRepositoryMessage | null
- ExternalStoreAdapter["unstable_messageRepositoryInstance"]["head"]["prev"]
- childrenstring[]
- nextRepositoryMessage | null
- prevRepositoryMessage | null
- currentThreadMessage
- levelnumber
- currentThreadMessage
- ThreadMessage
- status?ThreadAssistantMessage["status"]
- metadata{ readonly unstable_state?: ReadonlyJSONValue; readonly unstable_annotations?: readonly ReadonlyJSONValue[]; readonly unstable_data?: readonly ReadonlyJSONValue[]; readonly steps?: readonly ThreadStep[]; readonly submittedFeedback?: { readonly type: "positive" | "negative" }; readonly timing?: MessageTiming; readonly isOptimistic?: boolean; readonly custom: Record<string, unknown>; }
- attachments?ThreadUserMessage["attachments"]
- idstring
- createdAtDate
- role"system"
- contentreadonly [TextMessagePart]
- levelnumber
- rootRepositoryParent
- RepositoryParent
- childrenstring[]
- nextRepositoryMessage | null
- RepositoryParent["next"]
- childrenstring[]
- nextRepositoryMessage | null
- prevRepositoryMessage | null
- currentThreadMessage
- levelnumber
- updateLevels(message: RepositoryMessage, newLevel: number) => void
- selectPathTo(message: RepositoryMessage) => void
- performOp(newParent: RepositoryMessage | null, child: RepositoryMessage, operation: "cut" | "link" | "relink") => void
- _messagesCachedValue<readonly ThreadMessage[]>
- CachedValue
- _valueT | null
- func() => T
- valuereadonly ThreadMessage[]
- dirty() => void
- headIdstring | null
- canonicalHeadIdstring | null
- getMessages(headId?: string) => readonly ThreadMessage[]
- addOrUpdateMessage(parentId: string | null, message: ThreadMessage) => void
- getMessage(messageId: string) => { parentId: string | null; message: ThreadMessage; index: number; }
- deleteMessage(messageId: string, replacementId?: string | null | undefined) => void
- getBranches(messageId: string) => string[]
- evictOffBranchOptimisticMessages(previousHead: RepositoryMessage | null, currentHead: RepositoryMessage | null) => void
Evicts optimistic messages (`metadata.isOptimistic`) the head just moved away from. Since eviction runs on every head move, the only optimistic messages in the repository live on the branch the head previously pointed at — so we walk just that branch rather than the whole repository. Keeps a client→server id swap from leaving a phantom sibling, and drops off-branch placeholders.
- switchToBranch(messageId: string) => void
- resetHead(messageId: string | null) => void
- clear() => void
- export() => ExportedMessageRepository
- import({ headId, messages }: ExportedMessageRepository) => void
- suggestions?readonly ThreadSuggestion[] | undefined
- state?ReadonlyJSONValue | undefined
- extras?unknown
- setMessages?((messages: readonly T[]) => void) | undefined
Applies a message list the runtime rewrote, and is what tells the runtime a removal it makes will survive the next snapshot. Without it, cancelling a run leaves a trailing user message in the thread and the composer untouched; an adapter that removes that message itself owns handing it back, because the runtime cannot see a removal it did not make.
- unstable_onBranchChange?((event: ExternalStoreBranchChange) => void) | undefineddeprecatedunstable
Fires when the user explicitly switches branches via the runtime's `switchToBranch` action (e.g. a BranchPicker click). It does not fire on adapter resync, `append`, edit/regenerate, content-only updates, or while the thread is running. Consecutive switches that resolve to the same canonical head are de-duped. `headId` is the canonical (persisted) head of the now-visible branch — optimistic/transient ids are never surfaced. `visibleMessageIds` lists the visible path in order. This complements `setMessages` rather than replacing it: switching still requires `setMessages`, and this callback does not on its own enable branch switching.
Deprecated: This API is still under active development and might change without notice.
- onImport?((messages: readonly ThreadMessage[]) => void) | undefined
- onExportExternalState?(() => any) | undefined
- onLoadExternalState?((state: any) => void) | undefined
- onNew(message: AppendMessage) => Promise<void>
- queue?ExternalThreadQueueAdapter | undefined
Opt in to message queuing. Typically produced by `createMessageQueue`.
ExternalStoreAdapter["queue"]- itemsreadonly QueueItemState[]
- steerItemsreadonly QueueItemState[]
- enqueue(message: AppendMessage) => void
Send a message into the queue lane, processed in order.
- steer(message: AppendMessage) => void
Send a message into the steer lane, processed next.
- move(queueItemId: string, placement: QueuePlacement) => void
Move a queued message between lanes or within a lane. An unanchored move into the steer lane mid-run interrupts — cancels the live run and dispatches the item — when the runtime supports cancellation; a move with `insertAfter`/`insertBefore` only places the item and never interrupts.
- edit(queueItemId: string, message: AppendMessage) => void
- remove(queueItemId: string) => void
- onEdit?((message: AppendMessage) => Promise<void>) | undefined
- onDelete?((messageId: string) => Promise<void> | void) | undefined
- onReload?((parentId: string | null, config: StartRunConfig) => Promise<void>) | undefined
- onResume?((config: ResumeRunConfig) => Promise<void>) | undefined
- onCancel?(() => Promise<void>) | undefined
- onRefetchThread?(() => Promise<void>) | undefined
Re-fetches the thread's state from the backing store, in place; a rejection reaches the `threads.reloadMainThread()` caller. Unrelated to `onReload`, which re-generates an assistant message. The caller does not stop a run in progress first, so an adapter that can stream owns whatever coordination one needs.
- onAddToolResult?((options: AddToolResultOptions) => Promise<void> | void) | undefined
- onResumeToolCall?((options: { toolCallId: string; payload: unknown }) => void) | undefined
- onRespondToToolApproval?((options: RespondToToolApprovalOptions) => Promise<void> | void) | undefined
- convertMessage?ExternalStoreMessageConverter<T> | undefined
- adapters?ExternalStoreAdapter["adapters"]
- ExternalStoreAdapter["adapters"]
- attachments?AttachmentAdapter | undefined
- ExternalStoreAdapter["adapters"]["attachments"]
- acceptstring
- add(state: { file: File; }) => Promise<PendingAttachment> | AsyncGenerator<PendingAttachment, void>
- remove(attachment: Attachment) => Promise<void>
- send(attachment: PendingAttachment) => Promise<CompleteAttachment>
- speech?SpeechSynthesisAdapter | undefined
- ExternalStoreAdapter["adapters"]["speech"]
- speak(text: string) => SpeechSynthesisAdapter.Utterance
- dictation?DictationAdapter | undefined
- ExternalStoreAdapter["adapters"]["dictation"]
- listen() => DictationAdapter.Session
- disableInputDuringDictation?boolean
- voice?RealtimeVoiceAdapter | undefined
- ExternalStoreAdapter["adapters"]["voice"]
- connect(options: { abortSignal?: AbortSignal; }) => RealtimeVoiceAdapter.Session
- feedback?FeedbackAdapter | undefined
- ExternalStoreAdapter["adapters"]["feedback"]
- submit(feedback: FeedbackAdapterFeedback) => void
- threadList?ExternalStoreThreadListAdapter | undefineddeprecated
Deprecated: This API is still under active development and might change without notice.
ExternalStoreAdapter["adapters"]["threadList"]- threadId?string | undefineddeprecated
Deprecated: This API is still under active development and might change without notice.
- isLoading?boolean | undefined
- threads?readonly ExternalStoreThreadData<"regular">[] | undefined
- archivedThreads?readonly ExternalStoreThreadData<"archived">[] | undefined
- onSwitchToNewThread?(() => Promise<void> | void) | undefineddeprecated
Deprecated: This API is still under active development and might change without notice.
- onSwitchToThread?((threadId: string) => Promise<void> | void) | undefineddeprecated
Deprecated: This API is still under active development and might change without notice.
- onRename?( threadId: string, newTitle: string, ) => (Promise<void> | void) | undefined
- onUpdateCustom?(( threadId: string, custom: Record<string, unknown> | undefined, ) => Promise<void> | void) | undefined
- onArchive?((threadId: string) => Promise<void> | void) | undefined
- onUnarchive?((threadId: string) => Promise<void> | void) | undefined
- onDelete?((threadId: string) => Promise<void> | void) | undefined
- unstable_capabilities?ExternalStoreAdapter["unstable_capabilities"]unstable
- ExternalStoreAdapter["unstable_capabilities"]
- copy?boolean | undefined
- unstable_enableToolInvocations?boolean | undefinedunstable
Opt in to the built-in client-side tool-invocations pipeline (`streamCall` / `execute` / tool-status tracking) for this thread. Defaults to `false` — the runtime does *not* drive client-side tool callbacks on its own. Set to `true` to have the runtime construct a `ToolInvocationTracker` and feed every snapshot through it, so tool callbacks fire automatically for tool-call parts in `messages`. Opt-in by default because most external-store runtimes either run tools entirely server-side, or already wire their own client-side dispatch path. Enabling the embedded tracker on top of an existing dispatch path would cause tool callbacks to run twice. When enabled, client-side tool results (from `execute()` returning, or from `streamCall` resolving) flow back through `adapter.onAddToolResult` like any other tool result, with `modelContent` populated when present.
- unstable_isClientToolCall?((toolCall: ToolCallMessagePart) => boolean) | undefinedunstable
Decides whether a tool call's result is produced on the client. Only consulted when `unstable_enableToolInvocations` is `true`. A provider that runs tools itself answers its own calls, and its result arrives one or more snapshots after the call's arguments complete. In that window the call is complete and result-less, so a registered tool of the same name would otherwise execute locally and produce a result the provider never asked for. An adapter that can tell the two apart supplies this predicate; it is read once per tool call, when the call is first observed live. The predicate is also what licenses running a frontend tool while the provider's run is still open. Without it, ownership is unknown until the run ends, so a registered tool executes only once the run's outcome is known and cannot fire on a call the provider was about to answer or gate.
- setToolStatuses?((statuses: Record<string, ToolExecutionStatus>) => void) | undefined
Receives the current per-tool-call execution status map whenever it changes. Only invoked when `unstable_enableToolInvocations` is `true` — the runtime maintains the map via the embedded tracker. Wire this into local React state and feed it into the converter's `metadata.toolStatuses` so the UI can render `executing` spinners and human-input prompts.
ExternalThread
- 0ExternalThreadProps
- ExternalThreadProps
- messagesreadonly ExternalThreadMessage[]
- isRunning?boolean
- isLoading?boolean | undefined
- state?ReadonlyJSONValue | undefined
- extras?unknown
- isSendDisabled?boolean
Whether sending new messages is currently disabled. When `true`, the thread composer's input remains usable but `send()` is a no-op and `composer.canSend` is `false`. Edit composers (saving message edits) intentionally ignore this flag.
- onNew?(message: AppendMessage) => void
Callback for new messages (non-queue runtimes).
- onEdit?(message: AppendMessage) => void
- onReload?(parentId: string | null) => void
- onStartRun?() => void
- onCancel?() => void
- onResume?(() => void) | undefined
- onRefetchThread?(() => Promise<void>) | undefined
Handler for re-fetching this thread's state in place, driving `threads.reloadMainThread()`. Unrelated to `onReload`, which re-generates an assistant message. Presence enables the `refetchThread` capability; rejections propagate to the caller.
- onAddToolResult?((options: AddToolResultOptions) => void) | undefined
- onResumeToolCall?((options: ResumeToolCallOptions) => void) | undefined
Callback for resuming a tool call that is waiting for human input.
- onLoadExternalState?((state: unknown) => void) | undefined
- attachmentAdapter?AttachmentAdapter | undefined
- ExternalThreadProps["attachmentAdapter"]
- acceptstring
- add(state: { file: File; }) => Promise<PendingAttachment> | AsyncGenerator<PendingAttachment, void>
- remove(attachment: Attachment) => Promise<void>
- send(attachment: PendingAttachment) => Promise<CompleteAttachment>
- feedbackAdapter?FeedbackAdapter | undefined
- ExternalThreadProps["feedbackAdapter"]
- submit(feedback: FeedbackAdapterFeedback) => void
- speechAdapter?SpeechSynthesisAdapter | undefined
- ExternalThreadProps["speechAdapter"]
- speak(text: string) => SpeechSynthesisAdapter.Utterance
- queue?ExternalThreadQueueAdapter
Queue adapter for runtimes that support message queuing and steering.
ExternalThreadQueueAdapter- itemsreadonly QueueItemState[]
- steerItemsreadonly QueueItemState[]
- enqueue(message: AppendMessage) => void
Send a message into the queue lane, processed in order.
- steer(message: AppendMessage) => void
Send a message into the steer lane, processed next.
- move(queueItemId: string, placement: QueuePlacement) => void
Move a queued message between lanes or within a lane. An unanchored move into the steer lane mid-run interrupts — cancels the live run and dispatches the item — when the runtime supports cancellation; a move with `insertAfter`/`insertBefore` only places the item and never interrupts.
- edit(queueItemId: string, message: AppendMessage) => void
- remove(queueItemId: string) => void
- branches?ExternalThreadBranchAdapter
Branch adapter for runtimes that track sibling variants of messages.
ExternalThreadBranchAdapter- getBranches(messageId: string) => readonly string[]
Returns the sibling branch ids for a message in display order, including the message's own id. Return an empty array for messages without alternative branches.
- switchToBranch(branchId: string) => void
Makes the given branch the visible one. The runtime is expected to swap the `messages` array to the selected branch. May be invoked programmatically while a run is in progress; pending queue items are not cleared, and reconciling them with the new branch is the runtime's responsibility.
- onRespondToToolApproval?( options: RespondToToolApprovalOptions, ) => void | Promise<void>
Callback for tool approval decisions. Absent: responding to an approval throws a capability error.
- length1
- toString() => string
- toLocaleString{ (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string; }
- pop() => ExternalThreadProps
- push(...items: ExternalThreadProps[]) => number
- concat{ (...items: ConcatArray<ExternalThreadProps>[]): ExternalThreadProps[]; (...items: (ExternalThreadProps | ConcatArray<ExternalThreadProps>)[]): ExternalThreadProps[]; }
- join(separator?: string) => string
- reverse() => ExternalThreadProps[]
- shift() => ExternalThreadProps
- slice(start?: number, end?: number) => ExternalThreadProps[]
- sort(compareFn?: ((a: ExternalThreadProps, b: ExternalThreadProps) => number) | undefined) => [ExternalThreadProps]
- splice{ (start: number, deleteCount?: number): ExternalThreadProps[]; (start: number, deleteCount: number, ...items: ExternalThreadProps[]): ExternalThreadProps[]; }
- unshift(...items: ExternalThreadProps[]) => number
- indexOf(searchElement: ExternalThreadProps, fromIndex?: number) => number
- lastIndexOf(searchElement: ExternalThreadProps, fromIndex?: number) => number
- every{ <S>(predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => unknown, thisArg?: any): boolean; }
- some(predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => unknown, thisArg?: any) => boolean
- forEach(callbackfn: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => void, thisArg?: any) => void
- map<U>(callbackfn: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => U, thisArg?: any) => U[]
- filter{ <S>(predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => value is S, thisArg?: any): S[]; (predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => unknown, thisArg?: any): ExternalThreadProps[]; }
- reduce{ (callbackfn: (previousValue: ExternalThreadProps, currentValue: ExternalThreadProps, currentIndex: number, array: ExternalThreadProps[]) => ExternalThreadProps): ExternalThreadProps; (callbackfn: (previousValue: ExternalThreadProps, currentValue: ExternalThreadProps, currentIndex: number, array: ExternalThreadProps[]) => ExternalThreadProps, initialValue: ExternalThreadProps): ExternalThreadProps; <U>(callbackfn: (previousValue: U, currentValue: ExternalThreadProps, currentIndex: number, array: ExternalThreadProps[]) => U, initialValue: U): U; }
- reduceRight{ (callbackfn: (previousValue: ExternalThreadProps, currentValue: ExternalThreadProps, currentIndex: number, array: ExternalThreadProps[]) => ExternalThreadProps): ExternalThreadProps; (callbackfn: (previousValue: ExternalThreadProps, currentValue: ExternalThreadProps, currentIndex: number, array: ExternalThreadProps[]) => ExternalThreadProps, initialValue: ExternalThreadProps): ExternalThreadProps; <U>(callbackfn: (previousValue: U, currentValue: ExternalThreadProps, currentIndex: number, array: ExternalThreadProps[]) => U, initialValue: U): U; }
- find{ <S>(predicate: (value: ExternalThreadProps, index: number, obj: ExternalThreadProps[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: ExternalThreadProps, index: number, obj: ExternalThreadProps[]) => unknown, thisArg?: any): ExternalThreadProps | undefined; }
- findIndex(predicate: (value: ExternalThreadProps, index: number, obj: ExternalThreadProps[]) => unknown, thisArg?: any) => number
- fill(value: ExternalThreadProps, start?: number, end?: number) => [ExternalThreadProps]
- copyWithin(target: number, start: number, end?: number) => [ExternalThreadProps]
- entries() => ArrayIterator<[number, ExternalThreadProps]>
- keys() => ArrayIterator<number>
- values() => ArrayIterator<ExternalThreadProps>
- includes(searchElement: ExternalThreadProps, fromIndex?: number) => boolean
- flatMap<U, This>(callback: (this: This, value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => U | readonly U[], thisArg?: This | undefined) => U[]
- flat<A, D>(this: A, depth?: D | undefined) => FlatArray<A, D>[]
- at(index: number) => ExternalThreadProps
- findLast{ <S>(predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => value is S, thisArg?: any): S | undefined; (predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => unknown, thisArg?: any): ExternalThreadProps | undefined; }
- findLastIndex(predicate: (value: ExternalThreadProps, index: number, array: ExternalThreadProps[]) => unknown, thisArg?: any) => number
- toReversed() => ExternalThreadProps[]
- toSorted(compareFn?: ((a: ExternalThreadProps, b: ExternalThreadProps) => number) | undefined) => ExternalThreadProps[]
- toSpliced{ (start: number, deleteCount: number, ...items: ExternalThreadProps[]): ExternalThreadProps[]; (start: number, deleteCount?: number): ExternalThreadProps[]; }
- with(index: number, value: ExternalThreadProps) => ExternalThreadProps[]
ExternalThreadProps
- messagesreadonly ExternalThreadMessage[]
- isRunning?boolean
- isLoading?boolean | undefined
- state?ReadonlyJSONValue | undefined
- extras?unknown
- isSendDisabled?boolean
Whether sending new messages is currently disabled. When `true`, the thread composer's input remains usable but `send()` is a no-op and `composer.canSend` is `false`. Edit composers (saving message edits) intentionally ignore this flag.
- onNew?(message: AppendMessage) => void
Callback for new messages (non-queue runtimes).
- onEdit?(message: AppendMessage) => void
- onReload?(parentId: string | null) => void
- onStartRun?() => void
- onCancel?() => void
- onResume?(() => void) | undefined
- onRefetchThread?(() => Promise<void>) | undefined
Handler for re-fetching this thread's state in place, driving `threads.reloadMainThread()`. Unrelated to `onReload`, which re-generates an assistant message. Presence enables the `refetchThread` capability; rejections propagate to the caller.
- onAddToolResult?((options: AddToolResultOptions) => void) | undefined
- onResumeToolCall?((options: ResumeToolCallOptions) => void) | undefined
Callback for resuming a tool call that is waiting for human input.
- onLoadExternalState?((state: unknown) => void) | undefined
- attachmentAdapter?AttachmentAdapter | undefined
- ExternalThreadProps["attachmentAdapter"]
- acceptstring
- add(state: { file: File; }) => Promise<PendingAttachment> | AsyncGenerator<PendingAttachment, void>
- remove(attachment: Attachment) => Promise<void>
- send(attachment: PendingAttachment) => Promise<CompleteAttachment>
- feedbackAdapter?FeedbackAdapter | undefined
- ExternalThreadProps["feedbackAdapter"]
- submit(feedback: FeedbackAdapterFeedback) => void
- speechAdapter?SpeechSynthesisAdapter | undefined
- ExternalThreadProps["speechAdapter"]
- speak(text: string) => SpeechSynthesisAdapter.Utterance
- queue?ExternalThreadQueueAdapter
Queue adapter for runtimes that support message queuing and steering.
ExternalThreadQueueAdapter- itemsreadonly QueueItemState[]
- steerItemsreadonly QueueItemState[]
- enqueue(message: AppendMessage) => void
Send a message into the queue lane, processed in order.
- steer(message: AppendMessage) => void
Send a message into the steer lane, processed next.
- move(queueItemId: string, placement: QueuePlacement) => void
Move a queued message between lanes or within a lane. An unanchored move into the steer lane mid-run interrupts — cancels the live run and dispatches the item — when the runtime supports cancellation; a move with `insertAfter`/`insertBefore` only places the item and never interrupts.
- edit(queueItemId: string, message: AppendMessage) => void
- remove(queueItemId: string) => void
- branches?ExternalThreadBranchAdapter
Branch adapter for runtimes that track sibling variants of messages.
ExternalThreadBranchAdapter- getBranches(messageId: string) => readonly string[]
Returns the sibling branch ids for a message in display order, including the message's own id. Return an empty array for messages without alternative branches.
- switchToBranch(branchId: string) => void
Makes the given branch the visible one. The runtime is expected to swap the `messages` array to the selected branch. May be invoked programmatically while a run is in progress; pending queue items are not cleared, and reconciling them with the new branch is the runtime's responsibility.
- onRespondToToolApproval?( options: RespondToToolApprovalOptions, ) => void | Promise<void>
Callback for tool approval decisions. Absent: responding to an approval throws a capability error.
ExternalThreadQueueAdapter
The queue surface a runtime exposes so the composer can stay usable during a run and render the pending messages.
- itemsreadonly QueueItemState[]
- steerItemsreadonly QueueItemState[]
- enqueue(message: AppendMessage) => void
Send a message into the queue lane, processed in order.
- steer(message: AppendMessage) => void
Send a message into the steer lane, processed next.
- move(queueItemId: string, placement: QueuePlacement) => void
Move a queued message between lanes or within a lane. An unanchored move into the steer lane mid-run interrupts — cancels the live run and dispatches the item — when the runtime supports cancellation; a move with `insertAfter`/`insertBefore` only places the item and never interrupts.
- edit(queueItemId: string, message: AppendMessage) => void
- remove(queueItemId: string) => void
pickExternalStoreSharedOptions
const pickExternalStoreSharedOptions: (options: ExternalStoreSharedOptions) => ExternalStoreSharedOptions;useExternalStoreRuntime
- storeExternalStoreAdapter<T>
useExternalStoreSharedOptions
- optionsExternalStoreSharedOptions
- ExternalStoreSharedOptions
- suggestions?readonly ThreadSuggestion[] | undefined
- isDisabled?boolean | undefined
Whether the entire thread is disabled. When `true`, the composer's input is also disabled (the user cannot type, attach files, or submit). For a narrower gate that keeps the input usable but blocks only sending, use `isSendDisabled`.
- isSendDisabled?boolean | undefined
Whether sending new messages is currently disabled. When `true`, the thread composer's input remains usable but `send()` becomes a no-op and the thread composer's `canSend` is `false`. Use this to gate sending on external React state (e.g. while tool config is loading) without disabling the input itself the way `isDisabled` does. Edit composers (saving message edits) intentionally ignore this flag.
- unstable_capabilities?ExternalStoreSharedOptions["unstable_capabilities"]unstable
- ExternalStoreSharedOptions["unstable_capabilities"]
- copy?boolean | undefined