@assistant-ui/core#
0.3.30#
Patch Changes#
-
#9811
69bf91a- fix: preserve AI SDK history messages listed before their parents by sharing core's parent-first ordering helper. Keep the selected head and sibling branches while continuing to skip malformed messages and orphaned descendants. (@Kinfe123) -
#9108
ed0d969- Track selectors that read through a forwarding client when its target changes. (@rupic-app) -
#9862
1a3359e- Add a Resume control for interrupted runs.useComposerResumefrom@assistant-ui/core/reactandComposerPrimitive.Resumeresume a run whose adapter reportscanResume; the control is disabled while the draft is not empty or the thread is busy. (@okisdev) -
#9861
2dc72a8- Add an opt-incanResumeflag for interrupted runs. An adapter that keeps an exact checkpoint setscanResume, andresumeRunresumes it; concurrent resumes share one attempt.canResumeis optional on thread state, so existing custom thread clients remain compatible. The AI SDK runtime offers it only while resumable storage holds a pending stream, and the server must replay the interrupted message with its original ID. (@okisdev) -
#9815
32869e0- fix: preserve mention labels and IDs containing directive delimiters without changing existing bracket-form directives. (@Kinfe123) -
#9851
118dedb- fix: isolate adapter hooks so swapping thread list adapters preserves the hosted runtime's hook order (@okisdev) -
#9538
79e10db- fix: restore unsent drafts using the latest attachment cleanup state. (@okisdev) -
#9776
32a1b79-useAuiStateandaui.composer.getState()now see composer text as soon assetTextreturns, so an input that keeps its own state, such as react-mentions, no longer moves the caret to the end. (@okisdev) -
#9804
d7fb0ee- refactor:createLocalStorageAdapter(and socreateFileStorageAdapterin@assistant-ui/react-ink) no longer setsunstable_Provider, which only wrapped the adapters itsunstable_useAdaptersalready returns, souseRemoteThreadListRuntimeruns it on theRemoteThreadListstore client like the cloud adapter. auseRemoteThreadListRuntimethat mounts with it now ignoresunstable_Provideron any later adapter, so give that adapterunstable_useAdaptersto keep its per-thread history (@okisdev) -
#9891
545836d- feat:ModelContext()takesmaxSystemLengthto cap the merged system prompt, trimming the lowest-priority parts first, ormergeSystemto combine the prioritizedSystemParts yourself (@Yonom) -
#9449
e21ce83- adapters may omit unarchive; archived threads then open without unarchiving and explicit unarchive rejects. the OpenCode adapter omits it because OpenCode cannot unarchive a session. (@okisdev) -
#9652
ca0a1be- feat: add the internal thread list runtime core that runs on aRemoteThreadListclient, and letRemoteThreadListHookInstanceManagerpublish hosted thread runtimes during commit (@okisdev) -
#9649
d420f42- feat: add the internalRemoteThreadListseams thatuseRemoteThreadListRuntimeneeds to run on the store client. a plainRemoteThreadListnow aborts a thread's pending send when that thread is deleted, detached or dropped by an adapter-replacing reload, asInMemoryThreadListanduseRemoteThreadListRuntimealready do, and logs a failed automatic title the wayuseRemoteThreadListRuntimedoes (@okisdev) -
#9650
9f673a3- feat: runuseRemoteThreadListRuntimeon theRemoteThreadListstore client unless the adapter it mounts with setsunstable_Provider, so both thread list paths share one implementation. a runtime that mounts withoutunstable_Providerserves later adapters throughunstable_useAdaptersand warns in development when one only hasunstable_Provider. The thread list still lives as long as the returned runtime. After a failed first load, a controlledthreadIdchange no longer reloads the list; callreload()to retry.RemoteThreadListThreadListRuntimeCoreis deprecated for direct use. (@okisdev) -
#9653
ab3454d- refactor: add the internal per-thread hosts that run auseRemoteThreadListRuntimeruntime hook inside aRemoteThreadListclient (@okisdev) -
#9766
506aba9- Pass draft thread custom metadata to remote thread initialization. (@okisdev) -
#9764
2d17e77- fix: keep a controlled new-thread request selected when the previous draft initializes during the switch (@okisdev) -
#9767
45e3d22- fix: send mutations for each remote thread to its adapter in call order (@okisdev) -
#9765
a587b28- Wait for a replacement thread runtime to attach before a thread switch settles. A switch still pending when the thread list is destroyed now rejects with a silentThreadListDestroyedError, and a switch whose replacement runtime fails to mount rejects with the mount error. (@okisdev) -
#9864
50fb79b- retry automatic title generation after a thread's first run ends if it still has no title, including threads created outside the runtime. (@okisdev) -
#9552
e6cace0- fix(core): re-read the server title after a failed title write-back instead of leaving the list on a title the server never received (@okisdev) -
Updated dependencies [
6966821,e99250f,54e2e9b,be30245]:- assistant-stream@0.3.53
0.3.29#
Patch Changes#
-
#9670
b78a043- fix: keep copy feedback when unrelated assistant scopes change (@okisdev) -
#9750
fe13206-assistant-cloudis a dependency of@assistant-ui/coreinstead of an optional peer, so@assistant-ui/core/reactloads in Node and Vitest without installing it separately. (@okisdev) -
#9738
8289dd1- Project legacy audio parts as file parts with anaudio/<format>media type when building a queued message's item, instead of dropping them. (@tunglambk) -
#9615
5588bfb- fix: prevent dictation from starting on a disabled thread (@Kinfe123) -
#9754
d6e8a0c- A message an external-store host drops from the middle of itsmessagesarray is removed from the thread, with its feedback, instead of staying behind as a sibling branch. (@okisdev) -
#9763
fe7179d- Discard late client tool calls from cancelled external-store runs using host-provided run ids. (@okisdev) -
#9768
c71326f- Clear frame tools and pending calls when the iframe document changes or reloads. (@okisdev) -
#9702
55d065c- Keep external-store history copies up to date when an existing user message's attachments are added, removed, or changed. (@Kinfe123) -
#9537
61aaccf- fix: settle pending deletes after reloads, branch switches, and edits (@okisdev) -
#9555
43c9c7c- Percent-decode base64 data URL payloads before forwarding them to model adapters, so escaped padding and alphabet characters are sent as bare base64. (@Jun516) -
#9745
75abfbe- Selecting the thread that is already displayed no longer cancels an in-flight controlled switch in theRemoteThreadListclient. (@okisdev) -
#9744
12dfc85- Selecting the thread that is already displayed no longer cancels a pending thread switch inuseRemoteThreadListRuntime. (@okisdev) -
#9639
1091bbc- fix: report a still-initializing thread throughonThreadIdChangeonce its remote id settles, instead of asundefined(@okisdev) -
#9642
6537c5f- feat: report a failed thread switch, such as a URL-controlledthreadIdwhosefetch()rejects, asswitchErroron the threads state, and retry a controlled switch when the browser comes back online or the tab becomes visible (@okisdev) -
#9551
2217804- fix(core): make an automatic title wait for an explicit title generation in flight and run only if that produced no title, so the thread list and the server end on the same title (@okisdev) -
#9556
7ba7c54- fix(core): show the automatic title the server already saved when an explicit title generation fails or returns no title, and settle overlapping automatic titles on the newest one (@okisdev) -
#9769
cd5fd6c- A tool-call part carriesresponseDeliveryStatus: "queued"while the runtime holds its reply and has not sent it. The ADK runtime sets it on interrupt replies and tool answers held for the next turn, and LangGraph sets it on buffered tool replies, so the tool UI no longer shows them as sent. (@okisdev) -
#9575
5197671- fix: keep text sending available when voice setup ends synchronously (@Kinfe123) -
#9751
04c5d36- A base64 data URL whose payload is percent-encoded is sent to providers with the decoded payload, even when its media type already matches. (@okisdev) -
Updated dependencies [
e09563a,b88d62d,01225b9]:- assistant-stream@0.3.52
0.3.28#
Patch Changes#
-
#9503
1f77925- fix(core): leave an interactable that is still on itsinitialStateout of persistence saves andexportState(), so a changedinitialStatereaches users who never edited it (@okisdev) -
#9338
a12da09- fix: run layout effects throughuseIsomorphicLayoutEffectso React 18 server renders stop warning, while Ink keeps its layout phase (@okisdev) -
#9532
dbfdd0a- Preserve imported descendants through messages-array synchronization. (@rupic-app) -
#9508
140988a- fix(core): skip a client tool whose call first appears after its turn was cancelled (@okisdev) -
#9518
f2963d3- fix(core): preserve runtime routing when a queued item is edited (@rupic-app) -
#9509
7745f91- fix: cancelling an idle external-store thread no longer takes its last user message back into the composer, and a message sent right after a stop that took the unanswered message back is no longer lost; if a host re-adds the stopped message from a captured snapshot, its draft is removed from the composer (@okisdev) -
#9440
2bf54c5- fix(core): hand running tool executions to a runtime remounted over the same message repository (@okisdev) -
#9506
1fb6eb0- fix(core): keep the messages below an imported head instead of deleting them (@okisdev) -
#9504
8cb0b97- fix(core): a message deleted through an external store'sonDeletewhile an earlier reply regenerates stays deleted when the old reply's branch is restored (@okisdev) -
#9438
6c7c7b2- fix(core): keep a thread created in the page when a replacement adapter lists it (@okisdev) -
#9516
de2f5a9- Keep a local runtime thread running, with Stop available, while its run streams on a branch you switched away from. (@okisdev) -
#9400
c31385e- fix(core): keep a rating on an off-branch message after switching branches in an external-store runtime (@rupic-app) -
#9502
d02fac2- fix(core): a queued external store message is dispatched under the thread tail and metadata of the runtime that queued it when several runtimes share one message queue (@okisdev) -
#9396
2627294- Keep retained tool actions bound to their original message and tool call. (@rupic-app) -
#9510
fdbf0a2- fix(core): retry the cleanup of a file removed from a sending message when its removal fails and the message still goes out (@okisdev) -
#9340
7139acd- Keep tool interaction recorders bound to the thread, message, and tool call that created them. (@rupic-app) -
#9536
2091bcf- fix: keep a stopped user message in the host when its run restarts (@okisdev) -
#9370
7f3d804- fix(core): keep a submitted rating visible when the host refreshes its messages (@rupic-app) -
Updated dependencies [
05462a5,7bff761]:- assistant-stream@0.3.51
0.3.27#
Patch Changes#
-
#9284
c157aee- A thread created while a replacement thread list loads now gets its automatic title once the list lands. (@rupic-app) -
#9312
2c1963a- fix(core): clear the adapter-change gate before a failed replacement thread list load reportsisLoading: false, so a thread action started from that notification is not rejected (@okisdev) -
#9306
efbf028- fix(core): keepunstable_useInteractableStatereaders updating once the React Compiler optimizes the interactables resource (@okisdev) -
#9337
4e86339- fix(core): drop the previous adapter's threads when a replacement thread list response cannot be applied, keeping threads created under the replacement (@okisdev) -
Updated dependencies [
8b49f28]:- assistant-stream@0.3.50
0.3.26#
Patch Changes#
-
#9209
16afd50- fix(core): preserve initial messages after an empty history load and persist them before the first new message (@okisdev) -
#9166
b86d6cd- Block typing, attachments, sends, and message editing while a thread is disabled. (@rupic-app) -
#9224
2b3e0d3- fix(core): treat each attachment add as a single attachment (@okisdev)
0.3.25#
Patch Changes#
-
#9026
fc73a27- fix(core): retry a failed interactable save on the next requested save orflush()and clear its error once any later snapshot saves it (@kr1shna-exe) -
#9021
5a67c85- fix(core): wait for in-flight saves to an interactables persistence adapter before loading it again (@kr1shna-exe) -
#8262
e45b97b- fix(core): retry the current controlled thread after a failed delete restores it (@rupic-app) -
#8264
c2b93b1- fix(core): retire thread runtimes when the runtime hook changes (@rupic-app) -
#9046
9201447- fix(core): stop applying an assistant transport run's snapshots once it is cancelled, even when its response body had fully arrived (@kr1shna-exe) -
#9014
7e78ca4- ignore the deferred cancel resync once the thread is reset (@rupic-app) -
#9031
2e5432f- fix(core): retain interactable edits when persistence saves fail or time out (@rupic-app) -
#9036
840ac3a-thread.import()on an external store without anonImporthandler now throws instead of changing the runtime repository without updating the store. To load a branch tree, pass it asmessageRepositoryor implementonImportto write imported messages back to your store. (@rupic-app) -
#8955
20f0e5b- Reload Cloud threads when AISDKThreads changes Cloud client or workspace scope. Preserve a new controlled thread selection requested with the replacement adapter without overriding a later manual switch. Unchanged selections from the previous scope still reset. (@jz-krono) -
#8879
14ceafa- assistant transport hooks used outsideuseAssistantTransportRuntimenow throw the shared wrong-runtime error ("The current thread is not backed by the useAssistantTransportRuntime runtime.") instead of their own message, as the adapter runtimes do (@okisdev) -
#9053
3baba6f- fix: restore and pause queued messages when an asynchronous dispatch fails before its run starts. (@Kinfe123) -
#8926
7855706- fix: retain a new thread's first title source through runtime restarts and retry automatic title generation after a detach (@kr1shna-exe) -
#8988
d40092c- keep completed thread-list updates, such as a deletion, applied when a reload starts from their final state notification (@rupic-app) -
#8930
1002313- fix: ignore attempts to switch an in-memory thread list to an unknown thread id (@Kinfe123) -
#7275
d19b547- fix: isolate Cloud attachment URLs and message mappings by account or workspace scope. (@Kinfe123) -
#9143
3926f8f- refactor(core): move cloud run telemetry decoding out of the thread history adapter (@okisdev) -
#8115
4fbf441- fix(core): keep uploading the attachments of a message being sent when the composer's draft attachments are cleared (@samdickson22) -
#8330
dc72a0e- fix(core): keep an attachment removed while its message was being sent out of the composer when the send fails, and keep one whose removal failed in the composer with the reason (@samdickson22) -
#8152
be19872- fix: keep external-store messages with missing fields from crashing the thread or showing "undefined" reasoning text (@samdickson22) -
#9173
40da737- refactor: fence late run work with one RunLeases primitive instead of per-adapter counters (@okisdev) -
#8928
987ffe1- fix: avoid starting suggestion requests after a local runtime detaches while preserving cancelled answer persistence. (@Kinfe123) -
#9147
3ffa474- refactor(core): move the dictation session out of BaseComposerRuntimeCore into its own controller (@okisdev) -
#8125
5bb65a3- fix(core): stop dictation and speech when a thread runtime is disposed or superseded, as a realtime voice session already is (@samdickson22) -
#8944
836432d- fix: editing a message that carries a quote keeps the quote, so the edited message still shows it and still sends it to the model (@Tunaycel) -
#7273
93d04cb- fix: fetch and encode URL-based image attachments before sending them to Pi; inaccessible or invalid URLs now fail the send (@Kinfe123) -
#9082
ae487aa- feat: mark every experimental API@deprecated Experimental since <date>, so editors strike it through as experimental rather than scheduled for removal;@typescript-eslint/no-deprecatedreports these APIs too (@okisdev) -
#8116
59d42c1- fix(core): when a stop does not move the last user message back into the composer, the external store runtime's cancel resync no longer overwrites a host update it has not received yet (a message sent right after stopping); it also no longer writes back a stopped message the composer already holds, and it keeps the running placeholder of a run that started before the resync (@samdickson22) -
#8327
ca4ec1f- fix: stop a message deleted throughonDeletefrom coming back as a branch when a frontend tool finishes before the host's next render (@samdickson22) -
#9111
184b083- fix(core): stop an external store reload from dispatching when Stop lands while client tool executions abort (@okisdev) -
#8095
8a21038- fix(core): an external store runtime recomputes its messages when client tools stop running, so no reply stays marked running afterunstable_notifySessionResetor a conversation swap during a tool call (@samdickson22) -
#8107
7321036- fix(core): an external store send that waited for thread initialization is delivered when the host drops or replaces its message queue in the meantime, instead of being lost (@samdickson22) -
#8113
bf65f81- fix(core): a queued external store send is dispatched after its own thread's last message when another runtime shares the queue, as React StrictMode's second runtime instance does in development (@samdickson22) -
#9038
4d5070d- fix(core): drop the phantom default thread item from the external-store thread list (@cpruijsen) -
#8949
3ef6e7c- fix: editing a message inExternalThreadkeeps its image, file and other non-text parts, as the default edit composer already does, instead of sending only the text (@Tunaycel) -
#8869
9125e30- ForwardExternalThreadmodel-context changes throughthread.modelContextUpdate. (@rupic-app) -
#8865
4ac25b9- return the registered model context fromExternalThread'sgetModelContextinstead of an empty one (@okisdev) -
#8924
23a4677- fix:AssistantFrameProvider.dispose()now tells the parent it is gone, soAssistantFrameHostrejects tool calls still waiting on the frame right away instead of after the 30 s timeout (@kr1shna-exe) -
#8922
7aa5bdd- fix: send the update that withdraws a frame's last cross-origin provider to the parent's origin, so the parent drops its tools instead of waiting out the 30 s call timeout (@kr1shna-exe) -
#8380
afe32c6- fix: isolate LocalRuntime thread state across history scope changes (@Kinfe123) -
#9005
30c2480- Preserve the no-argument mutation methods on InMemoryThreadListAdapter while retaining thread metadata updates when arguments are provided. (@Kinfe123) -
#8261
ef5a1e2- fix: show a pending save, and its failure, on an interactable that unmounts and mounts again while the save is in flight (@samdickson22) -
#8121
5a09ea3- fix(core): let a persistence load replace the detached state of an interactable that unmounted before the load resolved without a local edit (@samdickson22) -
#8119
b578c02- fix(core): keep a tool-created interactable's unsent edit with the thread it was made in when switching threads (@samdickson22) -
#9157
4709edf- fix(core): let a mounted thread keep initializing after a reload unlists it in useRemoteThreadListRuntime (@okisdev) -
#8100
820ab5f- fix(core): keep the local message queue to one send at a time when a regenerate, a cancel or a follow-up run overlaps a queued send, or the queue is turned on during a run or while a message waits to be sent, and keep it sending after a cancel while a queued send waits to start. Once a regenerate replaces a cancelled run whose model adapter ignores the abort, the queue now moves on when the regenerate ends instead of waiting for the cancelled run as well. (@samdickson22) -
#8604
63df0e4- fix: supportwithFormatin the local storage history adapter souseChatRuntimepersists AI SDK messages withcreateLocalStorageAdapter(@bnb) -
#8938
2307752- fix: retry local storage thread deletion across adapter reloads (@rupic-app) -
#8142
5bd5de3- fix(core): keep every saved branch when a thread is exported while a placeholder message is its head (@samdickson22) -
#8351
b03f90e- fix: a send with no text no longer adds an empty user message when its only attachment is removed while the attachment is being prepared (@samdickson22) -
#7673
f6d1489- fix: let cancellation interrupt asynchronous request preparation, keep later resolver failures out ofonError, and reuse the shared abort-race behavior in the A2A and Google ADK adapters (@Kinfe123) -
#8981
b4b56fe- chore: maintenance update with no changes to runtime behavior. (@Kinfe123) -
#7221
a6ca3f9- fix: parse base64 data URLs without a media type across core converters, Google ADK, A2A, and AG-UI, defaulting them toapplication/octet-streamand keepingtext/plainfor media-less percent-encoded data URLs. Outgoing base64 URL envelopes without a type are stamped with the same default so downstream adapters do not receive an empty media type. Media-less image URLs continue to use image sniffing before reaching AG-UI. (@Kinfe123) -
#8990
7f7d512- Keep deleted local drafts hidden during remote thread-list adapter replacement. (@rupic-app) -
#9001
0d74a05- keep a stale draft initialization from promoting after a replacement adapter list lands (@rupic-app) -
#8941
1cabbbd- Respect the runtime send policy for send-enabled suggestion triggers. (@rupic-app) -
#8640
9121416- fix: preserve behavior on the advertised React 18 peer range (@rupic-app) -
#8878
429a26d- share the remote thread list's page merge between the store client and the legacy runtime core (@okisdev) -
#8361
2356e80- fix(core): calladapter.removeonce for a composer attachment whose removal is still pending. Removing it again does nothing, andreset()andclearAttachments()skip it. If that removal then fails, only theremoveAttachment()caller sees the rejection (@samdickson22) -
#8971
194c0e2- chore: maintenance update with no changes to runtime behavior. (@Kinfe123) -
#8972
fae89b1- chore: maintenance update with no changes to runtime behavior. (@Kinfe123) -
#8962
708bf2c- preserve later thread switches when a replacement list load settles (@rupic-app) -
#7910
4b44723- Clear tool invocation state when restarting a failed stream pipeline. (@rupic-app) -
#9153
92e7ab1- fix(core): keep a thread seeded withinitialMessageslocal until its first send or run, so a remote thread list no longer creates an empty remote thread and requests its title on mount (@okisdev) -
#8904
a1caaa8- keep the stored order of sibling branches when a thread session loads a message stored before its parent (@okisdev) -
#8305
7842639- fix: follow generated suggestion adapter replacements without restarting inline adapters (@Kinfe123) -
#9110
399621e- fix(core): keep a new thread's automatic title in the store client's thread list when its body remounts during the first initialize (@okisdev) -
#9109
79867bd- fix(core): reject item actions on a thread the store client's thread list no longer shows, matching useRemoteThreadListRuntime (@okisdev) -
#8737
081a239- fix: bound retained input in shared line and SSE decoders, with configurable line and event limits across streaming clients (@Kinfe123) -
#8328
0967886- fix: stop a delete, archive, unarchive, rename or custom metadata update still running on the previous thread list adapter from changing the new adapter's thread with the same id (@samdickson22) -
#8076
e7534a2- fix: keep a thread created and deleted in this session deleted when a thread list response served before the deletion arrives afterwards (@samdickson22) -
#8101
361d590- fix: keep a thread off the main slot whendetach,archiveordeleteis called in the tick a switch to it lands, instead of stopping, archiving or deleting the thread the user is now in (@samdickson22) -
#8075
c04f09d- fix: merge a deep-linked thread's fetched metadata as an optimistic update, so an archive or delete that fails afterwards rolls back, a thread that initialized or was archived or deleted while the fetch was in flight keeps its current state as long as its slot id still resolves, and one remote thread never gets two slots (@samdickson22) -
#8145
efb83eb- fix(core): stopuseRemoteThreadListRuntimelisting threads a reload no longer returns: they leavethreadItemsand list item actions reject them, as in theRemoteThreadListclient, while a hidden thread whose runtime is still mounted stays readable throughgetItemById(@samdickson22) -
#8077
1cd8911- fix: switch away from the main thread when an archive or delete aimed at its listed duplicate lands on it onceinitialize()merges the two, instead of leaving the runtime on a deleted or archived thread (@samdickson22) -
#8103
79e9a5a- fix: start the main thread's runtime when a switch orinitialize()selects a thread that was detached while it was in flight, instead of leaving the main thread with no runtime (@samdickson22) -
#8105
9aff121- fix: open the controlledthreadIdonce the thread list loads it when its first switch failed, instead of staying on a new thread while the prop names another (@samdickson22) -
#8263
01b5e06- Keep in-memory thread list entries available across reloads. (@rupic-app) -
#8934
06c3fef- Keep local-storage thread deletion successful once metadata is removed even if history cleanup fails, preventing the client from restoring a thread whose later messages cannot be saved. Log cleanup failures and retry stale-history cleanup before reinitializing the same thread ID. (@kr1shna-exe) -
#8950
41344cb- ExposeargsStatusfromuseToolArgsStatusto distinguish incomplete argument objects from completed arguments while a tool is still running. (@okisdev)Mark settled AI SDK tool input as complete while execution continues. This also lets
propStatusreport received fields as complete, rather than streaming, once the input is final.Settled AI SDK
argsare shallow copies ofpart.inputwith enumerable completion metadata: the top-level object identity changes, while nested values retain their identity. Prototype-named JSON fields remain intact without changing safe parser policy. -
#8256
cebaed5- fix: stop thread title generation from calling the adapter for a thread whose deletion already completed (@samdickson22) -
#8255
2a1a788- fix: keep a successful rename as the thread title when an overlapping later rename fails during title generation (@samdickson22) -
#8123
b9a5d38- fix(core): do not run a frontend tool whose turn is cancelled, reloaded or replaced in the same tick its run settles (@samdickson22) -
#7901
cb20f13- fix: render MCP Apps through ToolUIDisplay on Parts, grouped, native, and ink (@Kinfe123) -
#8129
1d550c0- fix(core): a message appended right before asendCommandcall reaches the assistant transport server ahead of that command when no client tool is executing (@samdickson22) -
#8132
9dfd037- fix(core):cancelRun()ends an assistant transport run that failed while itsonErrorcallback is still pending, instead of leaving the run active until that callback settles, and reports the commands queued meanwhile toonCancel(@samdickson22) -
#8147
ef87d70- fix(core):cancelRun()ends a resumed assistant transport run whose replay is waiting for a render that has not committed (for example while the UI around the runtime is suspended), instead of leaving the run active until that render commits (@samdickson22) -
#8127
4f2ad45- fix(core): an assistant transport command sent right aftercancelRun()is sent in a follow-up run instead of being reported toonCancel;onCancelreports only the work pending when the cancel happened, including for a run cancelled before it started or while itsonErrorcallback was running (@samdickson22) -
#8330
dc72a0e- fix(core): keep a file whose removal failed while it was still uploading in the composer when the send fails. A still-uploading file removed from the message being sent now stays incomposer.submission.attachments, with its last status, untiladapter.removeanswers, instead of disappearing once the uploads settle. A file in the message being sent is removed at most once while its removal is pending: removing it again does nothing, andreset()skips it. If that removal then fails, only theremoveAttachment()caller sees the rejection. A removal that has already failed is still retried (@samdickson22) -
#8124
2d37f82- fix(core): keep one live voice session when a thread subscriber or an external store'sonVoiceTranscriptreconnects voice mid-transition, and leave a user transcript or typed message from the replaced session out of the new one (@samdickson22) -
#9148
2bc6e49- refactor(core): move the voice session lifecycle out of BaseThreadRuntimeCore into its own controller (@okisdev) -
#8931
b257f49- fix: reset voice volume when a realtime session ends on its own (@Kinfe123) -
Updated dependencies [
606bc2d,c5a635a,2252059,2abd1e0,2ed2043,ae487aa,01ac83d,8c32dea,0a3ca24,ee517fb,081a239,542d871,e79cdd4,41344cb,e8620c1,3b7b337]:- assistant-stream@0.3.49
0.3.24#
Patch Changes#
-
#8260
c883dc0- fix(core): release realtime voice listeners when a session ends on its own (@rupic-app) -
#8796
fd444e4- a tool approval can ask several questions at once, or let one question take several answers:display: "questions"withapproval.questions, answered throughrespondToApproval({ answers })keyed by question id, validated before it reachesonRespondToToolApprovaland recorded onapproval.answers; the AI SDK converter readsquestionsandanswersfrom the approval descriptor when a response handler is set, and the cloud format keeps them (@okisdev) -
#8749
791d240- name local runtime initial messages from React's useId during a server render, so a Next.js cacheComponents prerender no longer reads Math.random; the browser keeps random ids (@okisdev) -
#8840
ed84b12- getSuggestionKeys moved to @assistant-ui/core/internal so React and Vue key suggestions the same way. (@okisdev) -
#7099
2bc1edb- fix: traverse deeply nested tool-call messages without overflowing the stack (@Kinfe123) -
#7155
5484ca4- feat: support message-scoped converter metadata invalidation (@Kinfe123) -
#8798
ec48da2- a thread can open on its latest page and load older messages on demand: the external store adapter takeshasEarlierandonLoadEarlier, the runtime surfaces them asthread.hasEarlier,thread.isLoadingEarlierandaui.thread.loadEarlier()with one load in flight at a time,ThreadPrimitive.LoadEarlierloads the next page,ThreadPrimitive.Viewportkeeps the visible messages in place when it lands above them, and the React NativeThreadPrimitive.MessagesFlatListpages through the runtime when it gets nohistoryprop (@okisdev) -
#8110
46133cd- fix(core): keep the selected branch when a local run continues an existing answer (@samdickson22) -
#7622
3effee5- fix: disable message speech actions when no speech adapter is configured (@Kinfe123) -
#8794
451a76c- reasoning parts carry an optionaltimingwith their start and end times, typed as the newMessagePartTimingthatToolCallTimingnow aliases, so a host can show how long its agent thought; the assistant-stream accumulator stamps it while reasoning streams, joined reasoning parts and the cloud format keep it, and aMessagePrimitive.GroupedPartsgroup reports the span of its timed parts astiming(@okisdev) -
#7801
16439da- fix: preserve OpenCode interactions with prototype-named identifiers (@Kinfe123) -
#8795
1f77d04- the composer trigger popover primitives and their adapter, item, category and directive formatter types get stable names; theUnstable_names stay as deprecated aliases, and the trigger popover hooks stay unstable (@okisdev) -
#8799
aecb5eb- a long thread can be virtualized per part instead of per message:createThreadRowsSelectorflattens the thread foruseAuiStateinto stable rows (a user message, each top-level part group of an assistant message, a turn end) that keep their identity while tokens stream, andThreadPrimitive.Rowrenders one row with only the scopes it needs; a turn-end row carries the turn's start time and, once the turn completes, the latest end its messages record, so a turn footer can show how long the agent worked (@okisdev) -
#8755
77a98c1- a server rendered local runtime now names id-less initial messages and tool calls the same way while the browser hydrates, so data-message-id and selection quotes match the client's messages (@rupic-app) -
Updated dependencies [
64277e2,0284a07,451a76c]:- assistant-stream@0.3.48
0.3.23#
Patch Changes#
-
#8680
f7eae39- keep pending history writes from restoring deleted messages without delaying deletion (@okisdev) -
#8723
63233dc- report a history write that fails in the background through a thread historyWriteError event instead of dropping it silently (@okisdev) -
#8724
241b5f1- name a remote thread list's first new thread from React's useId during a server render, so a Next.js cacheComponents prerender no longer reads Math.random; the browser keeps a random id (@okisdev) -
#8684
5b65868- preserve message part state by host-supplied identity across renderers and store lookups, and carry part identity through cloud persistence; a part whose type changes at the same position now mounts fresh state. (@okisdev) -
#8702
351b8cd- fix: the remaining runtime hooks keep their thread loads, runs, queued messages, subagent transcripts and event streams across a fast refresh or a StrictMode replay instead of tearing them down (@okisdev) -
#8707
d33ad09- fix(core): resolveaui.threads.getLoadThreadsPromise(),reload()andloadMore()oncegetState()reports the result: the loaded list, orloadErrorwhen the initial load orreload()fails. A failedloadMore()request is logged and its promise still resolves. If the client can't commit within 100ms, as inside theact()that completes the load in a test or under a Suspense boundary that hides the client, the promises resolve anyway. In tests, await them outside thatact()to read the loaded list. (@bnb) -
#8323
4290eac- fix(core): end the voice session on hang up even when committing the unfinished reply throws; a synchronous voice commit failure is reported like a rejected one (@samdickson22) -
Updated dependencies [
6b7df95,098c140]:- assistant-stream@0.3.47
0.3.22#
Patch Changes#
-
#8416
f77dbea- feat:RuntimeCapabilities.answerToolCallreports whether a thread can answer a waiting tool call by adding its result, resuming it, or responding to its approval. a readonly thread reportsfalse, a local threadtrue, and an external storetrueonce it setsonAddToolResult,onResumeToolCall, oronRespondToToolApproval, or runs tools itself throughunstable_enableToolInvocations; the react-inkToolFallbackshows a pending approval's prompt without its Allow and Deny controls where it isfalse(@okisdev) -
#8431
98f3dbd- fix: a history adapter withoutupdatenow stores a paused run once a later turn cancels it, and importing a thread accepts a message listed before its parent, so a turn sent after a pause reloads instead of failing withParent message not found(@okisdev) -
#7933
7a41e54- fix(core): log a failedThreadRuntime.appendorMessageRuntime.reloadwithconsole.errorinstead of letting it surface as an unhandled rejection. Neither call returns its task, so the rejection never reached a caller; a host that sends these failures to an error tracker should catch them inside its own runtime callbacks. (@metaslim) -
#8378
f054d07- fix: cancel pending suggestions when their adapter is removed (@Kinfe123) -
#8415
b1a3211- fix: a message sent while a local run is paused ends the pause instead of stranding it: open approvals recordresolution: "cancelled", the paused message settles as cancelled, and a result added to it later no longer resumes the run and drops the turns after it;toGenericMessagescloses out the calls of an earlier or settled message as not completed (@okisdev) -
#8506
d7d3d2e- fix: register the SDK that changes along with the cloud on the new cloud inuseCloudThreadListAdapter. (@okisdev) -
#8418
bb6122a- feat: the cloud thread list'screatereceives the id of the thread being saved, so a runtime whose backend assigns its id on the first turn can wait for that turn, andupsert: truemakes a retried create reuse the thread that already has the returned external id (@okisdev) -
#8503
ac91c4c- fix: the anonymous cloud client picks upNEXT_PUBLIC_ASSISTANT_BASE_URLin Next.js production builds made with Turbopack, where the browser fell back to an in-memory thread list (@okisdev) -
#8153
c66cc10- fix: keep an empty file part filename through cloud history, as image parts and attachments already do (@samdickson22) -
#8448
c978a22- fix: refresh original source messages when a converter reuses its output for new inputs. (@Kinfe123) -
#8453
038cd9f- fix: extract base64 data from URLs that omit the media type, preserving explicit file-type hints and defaulting standalone parsing to text/plain. (@Kinfe123) -
#8663
fa460c6- fix: never resume a pause that a follow-up ended, even after the follow-up is deleted (@okisdev) -
#8451
5df393f- fix: derive joined assistant message status from its latest assistant segment. (@Kinfe123) -
#8450
9eba158- fix: read a tool part's original messages when it contains a nested conversation. (@Kinfe123) -
#8449
e72ac92- fix: preserve a tool call's nested conversation when its result omits a replacement transcript. (@Kinfe123) -
#8452
1e9493f- fix: reserve a queued run before notifying subscribers so reentrant enqueues preserve FIFO order. (@Kinfe123) -
#8674
f6374de- fix: keep a turn a subscriber appends while a run or an append is still moving the head (@okisdev) -
#8504
cf19d4b- fix: stop reloading a running thread from notifying store subscribers during render. (@okisdev) -
#8506
d7d3d2e- fix: keep a runtime host's threads, their in-flight runs, and its runtime object across a fast refresh. (@okisdev) -
#8557
e79b815- fix: store a message before a turn that follows it while its run is still open, store a completed message a tool result replaced, and load a history that holds a child without its parent (@okisdev) -
#8387
1b49876- fix: keep copy feedback scoped to the message that was copied (@Kinfe123) -
#8120
e971918- fix(core): ignore an interactable setState for an id that is not registered, so a later load still restores its stored value (@samdickson22) -
#8302
73c7de7- fix: give each in-memory thread its own composer, and abandon a deleted thread's pending attachment send instead of dispatching it through that thread; an external-store core adopting a shared repository mid-run now reuses its live optimistic placeholder (@Kinfe123) -
#8515
fda7946- fix: a thread its thread list discards for good now abandons an attachment send it was still preparing, instead of dispatching it after the thread is gone. (@okisdev) -
#8481
a5208c1- fix(core): keep the message queue draining when a subscriber cancels while a queued message is being dispatched (@samdickson22) -
#8379
2b6597a- fix: disconnect active voice sessions when their adapter is removed (@Kinfe123) -
#8518
e73db99- fix: runtime hooks keep their clients, runs, streams, queued sends and pending history copies across a fast refresh or a StrictMode replay instead of rebuilding or tearing them down (@okisdev) -
#8522
a4f6ce9- fix: a voice session ends and a pending attachment send is abandoned when the component calling auseExternalStoreRuntimethat no thread list hosts unmounts, or when a remountedAssistantRuntimeProviderreplaces a thread list's runtime (@okisdev) -
#8589
fd28612- fix: emit threadListItem.switchedTo and switchedAway from the tap thread lists (@okisdev) -
#8491
9946dc1- fix: preserve higher-priority model context settings when providers overlap (@Kinfe123) -
#8536
3e33ac2- fix: give assistant transport user messages a client id, so the settled message replaces the optimistic one and reaches the cloud copy (@okisdev) -
Updated dependencies [
b1a3211,ce5b7ed]:- assistant-stream@0.3.46
0.3.21#
Patch Changes#
-
#7637
b4f5153- fix: useCloudRuntime sends the active Cloud thread id, including on the first run of a new thread, and pins the ui message stream protocol (@rupic-app) -
#7826
aa83d87- fix(core): the assistant transport runtime sends a new thread's remote id with its first request and keeps its default thread when the host re-renders; a resume never creates a thread, and a new thread whose first run is not an append still gets its title (@rupic-app) -
#8032
d096801- fix: type the assistant transport request body thatprepareSendCommandsRequestreceives; its fields are no longerunknownin@assistant-ui/react, andthreadIdis an optionalstring, absent when a resume has no remote id, instead ofstring | null(@rupic-app) -
#7893
9b902fa- fix(core): keep a message appended during a local history load on the loaded branch (@Kinfe123) -
#8342
aa0f338- feat:useAssistantTransportRuntimeacceptscloud: Assistant Cloud backs the thread list and every request carries the cloud thread id; withoutcloud,NEXT_PUBLIC_ASSISTANT_BASE_URLselects Assistant Cloud, as it does foruseLocalRuntime.adapters.history, which this runtime never read, is deprecated (@okisdev) -
#8048
d8394bc- fix: stop an attachment send when the thread it belongs to is destroyed (@okisdev)an
ExternalThreadcomposer now aborts the send it is preparing when the client that owns the thread is destroyed, and never hands it toonNeworonEditafterwards, whether or not the adapter honors the abort. hiding the thread, for example inside<Activity>, still lets the send finish and deliver the message.SimpleImageAttachmentAdapter,SimpleTextAttachmentAdapter, the AI SDK attachment adapter andOpenCodeAttachmentAdapterstop reading the file once the send's signal aborts. -
#7903
63f3236- fix(core): keep image filename and text/image provider metadata through the aui/v0 encoder (@Kinfe123) -
#8041
6b93933- fix: feedback submitted mid-run no longer strands the message, drops its history write, or keeps invoking the adapter. (@rupic-app) -
#7735
eb034f6- fix: roll back subscriptions when connecting to their source fails (@Kinfe123) -
#7738
5a8ff94- fix: validate persisted assistant statuses and steps before loading history (@Kinfe123) -
#7719
2e3fd9e- fix: keep app-scoped interactables isolated and persist edits made before adapter attachment (@Kinfe123)
fix: preserve loaded and unmounted app entries in persistence adapter snapshots -
#7822
9f286dc- fix: report cloud engagement events once per thread list instead of once per mounted thread, keep counting a run that ends while its thread is in the background, and let an engagement id resolver decline an event for a thread it does not know (@okisdev) -
#8073
02043de- fix: preserve file and attachment provider metadata in Cloud history (@Kinfe123) -
#8056
9cb7aa4- fix: keep a tool call's artifact and provider metadata in cloud history (@okisdev)the aui/v0 cloud encoder dropped both fields, so a thread reloaded from assistant-cloud lost them and a tool UI rendering its artifact came back empty.
-
#8339
967de5d- feat:CloudRendererHostdraws a stored conversation in the Assistant Cloud dashboard's As shown view with the app's own components; a read only thread now reports itself disabled, so its composer renders disabled, and ignores composer input instead of throwing (@okisdev) -
#8088
a88fa97- fix: warn about lossy tool results before Cloud persistence can discard their data (@Kinfe123) -
#8074
96e11d9- fix: use a binary MIME type for Cloud uploads with unknown file types (@Kinfe123) -
#7675
3af3b61- fix: attempt every runtime cleanup when an unsubscribe throws (@Kinfe123) -
#8030
e8fac8d- feat: show a message with uploading attachments in the thread while it is being sent (@okisdev)MessagePrimitive.Attachmentsnow hands its render functionAttachmentrather thanCompleteAttachment, because the row of a message that is still being sent shows attachments that are still uploading. a render function that readsattachment.contentshould checkattachment.status.type === "complete"first. -
#8338
d403574- feat: LangGraph, LangChain, Google ADK and custom external store runtimes under a cloud thread list now store a copy of their settled messages in Assistant Cloud by default, keyed by their backend's message ids, so the dashboard shows the transcript and feedback can rate it; tool interactions recorded in their tool UIs are kept on the copy instead of throwing. a message the cloud refuses, such as one over the size limit, is skipped with a console warning and the later messages are still copied, while a thread it refuses as a whole (deleted, its end user past the plan cap, or refused twice before any message was accepted) stops being copied with one warning.telemetry: { messages: false }on theAssistantCloudclient keeps the copy out, and tool interactions then throw as before. a stored user message counts its end user toward the project's monthly active users. (@okisdev) -
#7934
f71c285- fix(core): report isLast on the message client, not only on the thread list (@Kinfe123) -
#7769
0ad784f- fix: keep a tool call's pending approval or interrupt actionable when the call already carries a result, so a question raised by a tool that streamed output first (react-pi partial results) still renders its controls instead of reading as complete (@okisdev) -
#7947
bbd01b5- fix(core): spoken user turns no longer carry astatus, which only assistant messages accept, so a host that stores a voice transcript and converts it back throughconvertMessageno longer throws (@okisdev) -
#7760
84e0cf4- fix: emit declarations from one TypeScript program so two builds of the same commit produce the same.d.ts(@okisdev)aui-buildnow emits the unbundled.d.tsoutput in one TypeScript pass over the whole package, so two builds of the same commit produce identical declarations; the per-module emit it replaced followed the bundler's load order and let union member order, alias visibility and import specifiers move between builds. Declarations import barrels as the source does and keepimport type; the exported types are unchanged. A/// <reference>directive that must reach the published declarations now carriespreserve="true"in the source. -
#8122
fc3aa3e- fix(core): keep a dictation session that a composer subscriber starts while send cancels the previous one (@samdickson22) -
#8024
9eafe31- fix: bound Web Speech dictation shutdown when the browser never ends (@Kinfe123) -
#8337
d97af06- fix(core): a message part type that the part renderer orfromThreadMessageLikedoes not handle is now a type error, andThreadMessageLikecontent accepts every part ofThreadAssistantMessagePartandThreadUserMessagePart(@okisdev) -
#8098
e0b7805- fix(core): a message deleted through an external store'sonDeletestays deleted when the host re-renders or the thread reloads beforeonDeleteresolves, instead of coming back as a branch (@samdickson22) -
#8092
1c58865- fix(core): an external store runtime that switches threads throughadapters.threadList.threadIdbuilds the new thread from the current store, so the previous thread's messages no longer show up as a branch of the new one and a tool call in the new thread's history no longer executes on switch (@samdickson22) -
#8007
5496fce- fix: prevent a cancelled edit from sending after an attachment upload finishes. (@Kinfe123) -
#8008
f04c7f0- fix: disconnect a thread's voice session when a thread switch or its thread list discards the runtime (@Kinfe123) -
#7649
a4a2739- fix(core): keep nested required fields in interactable update tool schemas, so the model sends a nested object whole instead of a partial one that the shallow merge would store as is (@rupic-app) -
#7682
fdf5706- refactor: make the replay boundary stream clear its own replay state on read failures and cancellation, so the transition out of replay mode is balanced with the transition in (@Kinfe123) -
#8006
443b0a5- fix: keep streaming and persist the final message when a tool result arrives mid-run. (@Kinfe123) -
#8136
178e340- fix(core):AssistantFrameProvider.dispose()withdraws the frame's tools from the parent host (@samdickson22) -
#7992
1afdc46- fix: render registered tool and data UIs when GroupedParts children return null (@Kinfe123) -
#7674
dea2462- fix: prevent late local-storage history writes from restoring deleted threads (@Kinfe123) -
#7866
c45ae5a- fix: keep a nested object's unwritten fields while an interactable update streams it (@okisdev) -
#7757
7face86- fix: keep messages stable across values events when UI lives in graph state (@okisdev)useStreamRuntimereconverted every root message and every nested subagent transcript on eachvaluesevent whenstream.values.ui(or the configureduiStateKey) held generative UI, even when its contents had not changed. The SDK rebuilds thevaluesobject from every snapshot and reconciles only the messages slot by id, so an unchanged UI list arrives as a new array of new entries on every superstep and every cached conversion missed. The runtime now recovers entry identity where the snapshot enters the merge: an entry structurally equal to the previous entry with its id keeps the previous object, and an unchanged list keeps the previous list, so the merged UI map, the converter and the subagent transcripts only change when the UI state does.@assistant-ui/core/internalexportsisJSONValueEqual. -
#7959
0a9ed7b- fix(core): persist a tool result added after its message settled through the history adapter'supdate, and report a cloud run only from the write that first settles its message; Assistant Cloud still rejects rewriting a message that later turns follow (@rupic-app) -
#7329
6407760- fix: tear down late voice controls at most once while preserving cleanup after early cancellation and the original session end reason. (@Kinfe123) -
#7868
4bed51f- fix(core): refresh model context subscribers when the main thread runtime attaches (@okisdev) -
#8130
819c065- fix(core): leave the message repository unchanged when it rejects an update or a delete (@samdickson22) -
#8146
e9c1ccd- docs(core): describe which optimistic messages eviction removes and when completed optimistic updates stop being replayed (@samdickson22) -
#7762
4928364- fix: resolve component registries by own keys only, so a component, tool or data part name that onlyObject.prototypehas (toString,constructor,__proto__) takes theFallbackorGenerativeUIRenderErrorpath instead of rendering the inherited built-in (@okisdev) -
#8300
5c5eb45- fix: persist settled feedback in histories that support message updates, including the bundled local storage adapter (@Kinfe123) -
#7775
11f9648- feat: mark interim tool output asisPreliminaryso a tool that streams its result stays running until the final result lands, instead of reading as complete on the first chunk; react-pi flags livepartialResultoutput and ai-sdk flagspreliminaryoutputs, and the default tool fallback keeps the output a cancelled tool streamed before it was cut off (@okisdev) -
#7852
c5b5d3a- fix(core): settle a tool call only on its final result in the tool tracker, aui/v0 persistence andaddToolResult(@rupic-app)the external store tool tracker settled a call on its first interim result, so a
streamCallreader resolved with that value and never saw the final one. the aui/v0 encoder droppedisPreliminary, so a thread saved while a tool was streaming reloaded with the interim value as its final result. the local runtime'saddToolResulttreated a call holding an interim result as already answered, so the final result neither resumed the run nor persisted the paused message. -
#7390
7725cbd- fix: preserve falsy error payloads such as0,""andfalsein external runtimes, while continuing to treatnullas no error (@Kinfe123) -
#7734
777df32- fix: clean up dictation sessions when listener setup fails (@Kinfe123) -
#8057
a486a13- fix: a readonly thread ignores mutations instead of throwing, so a stored conversation rendered through ReadonlyThreadProvider no longer breaks when a tool UI adds a result, answers an approval or submits feedback; reading external state still throws (@okisdev) -
#7367
0ee58d8- fix: reuse successful attachment uploads after a sibling fails in both runtime and ExternalThread composers, while preserving cleanup when the unsent draft is discarded. (@Kinfe123) -
#7981
0252c69- feat: name the runtime state typesThreadRuntimeState,MessageRuntimeState,ComposerRuntimeState,AttachmentRuntimeStateandThreadListItemRuntimeState(@okisdev)these are the states
ThreadRuntime,MessageRuntime,ComposerRuntime,AttachmentRuntimeandThreadListItemRuntimereturn fromgetState(), now exported by all three distributions;@assistant-ui/react-nativeand@assistant-ui/react-inkhad no name for them. in@assistant-ui/react,ThreadState,MessageState,ComposerState,AttachmentStateandThreadListItemStatestill name these runtime states but are deprecated: from 0.16 they name the store statesuseAuiStatereads, as they already do in@assistant-ui/react-nativeand@assistant-ui/react-ink. code that annotates a runtime'sgetState()result should move to the new names. -
#7707
75bd488- fix: correct settled and failed tool-call arg conversion (@balazsrozsenich-dakai)Stop re-reporting a settled tool call's unchanged arguments each time it is reconverted (which could OOM the renderer on large args), skip re-serializing them while the call keeps the same input object, and preserve a schema-failed tool call's arguments from
rawInputinstead of converting the error snapshot to{}. -
#8022
7260270- fix: handle synchronous Web Speech synthesis terminal events (@Kinfe123) -
#8126
0cfd31e- fix(core): clear a tool call's status when a human-input request made from streamCall is resumed or aborted, so the runtime stops reporting it as running or waiting; an execute that keeps running after its request is aborted now shows as executing instead of waiting (@samdickson22) -
#7860
c2e125e- fix: suggestion chips withsendfollow the voice session'scanSendTextinstead of the run state, so a chip clicked during a spoken reply sends its prompt into a connected session that takes typed text, and stays disabled while the session cannot (@okisdev) -
#8134
662b607- fix(core): log a failed controlledthreadIdswitch inuseRemoteThreadListRuntimeinstead of dropping it, as theRemoteThreadListclient already does (@samdickson22) -
#8102
f270950- fix: reject archiving, deleting or detaching the thread the user is in when its firstinitialize()fails, instead of looping forever and freezing the tab (@samdickson22) -
#7887
84cdbb0- fix: key each rendered suggestion by its content instead of its array index, so removing or reordering a suggestion no longer displays a removed suggestion's component state against a surviving one (@Kinfe123) -
#7618
92e991a- fix: render numeric and nested-array generative UI children (@Kinfe123)GenerativeUINodenow also acceptsnumberandreadonly GenerativeUINode[]. Code that narrows the union exhaustively needs cases for the new members; componentchildrenremains areadonly GenerativeUINode[]. -
#7729
534e11f- fix: ignore malformed AssistantFrame messages (@Kinfe123) -
#7835
9da3697- feat: let a tool approval question declare that it accepts a dismissal (@okisdev)ToolCallMessagePart.approvalgains an optional request field,dismissible. a question (display: "select"or"text") offers no refusal by default, because the kit never fabricates one the host did not ask for; a host that records a dismissal setsdismissible: trueand the default tool fallback renders a Dismiss control that sends{ approved: false }with no answer attached. the fallback also submits a text answer as typed, an empty one included, instead of gating Send on visible text; a host that cannot record an empty answer rejects the response and the controls come back with its error.@assistant-ui/react-piprojects Piselect,inputandeditorrequests as dismissible, since Pi resolves a cancelled request withundefinedand the runtime already mapsapproved: falseto that dismissal.@assistant-ui/ai-sdkreadsdismissiblefrom theapprovalDescriptorlike the other request fields. -
#8065
2caacad- feat: a tool UI can record what the user did on its tool call withunstable_recordInteraction, kept on the part asunstable_interactionsand stored in cloud history; the answer to a human input request is recorded once the runtime accepts it, the local runtime persists records and keeps them out of model input, external stores receive them throughunstable_onRecordToolInteraction, and readonly threads ignore them (@okisdev) -
#7908
e525f14- fix: carry a tool result'smodelContentacross the data-stream wire and aui/v0 persistence (@Kinfe123)The data-stream encoder dropped
modelContentfrom the tool result frame and the aui/v0 cloud encoder dropped it from the stored tool-call part, so a tool that returned a large UI blob plus a short model summary sent the blob to the model, and a reloaded cloud thread disagreed with the localStorage boundary, which kept the field. -
#8118
c171588- fix(core): cancelling an assistant transport run after its response body was fully received callsonCanceland clears the queued commands, instead of leaving them pending and sending them with the next run (@samdickson22) -
#8128
a5c9c5a- fix(core): an assistant transport request no longer carries theparentIdof a message that a cancel or a failed run discarded (@samdickson22) -
#7942
d9e4086- fix: drop a voice transcript or typed turn whose thread runtime is replaced or unmounted before it commits. one held for a pending history load no longer waits forever, so a typed turn'sappendresolves, and a typed turn still sending is no longer written to the replaced runtime's history or handed to itsonVoiceTranscript(@okisdev) -
#7790
89c0f55- fix: hold a voice transcript or typed turn until a pending thread history load settles, so it is committed onto the loaded thread instead of a branch the import leaves behind. A thread switched before the load ends drops the waiting message rather than committing it under the wrong thread (@spark-328) -
#7777
c51ba8f- feat(core): let typed text enter a connected voice session throughsendText(@okisdev)a
RealtimeVoiceAdapter.Session(and theVoiceSessionControlsreturned tocreateVoiceSession) can implementsendText(text). while a running session takes typed text,VoiceSessionState.canSendTextis true, the thread composer can send, andthread.appendwith a plain text user message hands the text to the session and commits it once as a typed turn (nometadata.modality) through the same path as a finalized transcript: the local runtime writes it to the repository and history, an external store receives it throughonVoiceTranscript. the session must not echo the typed text throughonTranscript. a session withoutsendTextkeeps rejecting typed sends as before. while a session is connected the send button and the Enter key followcanSendalone, so a reply being spoken no longer blocks them. the ai-sdk runtime keeps the message's own modality when it persists a voice session message, so a typed turn is no longer marked as spoken. -
#8027
e6aa5df- fix: wait for an attachment that is still uploading before sending it (@okisdev) -
Updated dependencies [
9619b42,dcd43fd,e046327,e525f14,4b069f9]:- assistant-stream@0.3.45
0.3.20#
Patch Changes#
-
#7530
43b587d- feat: voice transcripts persist into the useChat messages through onVoiceTranscript. the external message converter keeps a voice transcript as its own message instead of joining it into the neighbouring assistant message, and the history adapter stores a transcript as it lands instead of waiting for the next text run (@okisdev) -
#7089
5428610- fix: publishcancelRun's message rollback as it happens, so rendering right after a cancel no longer throws "Entry not available in the store" (@Kinfe123) -
#7700
ddb7201- fix: keep a cloud aui/v0 thread loadable when one stored row is malformed. an unreadable part, attachment or nested tool call message is dropped on its own, a row that does not hold a message at all is dropped together with the thread below it, and nesting is bounded so a deeply nested row cannot overflow the stack (@okisdev) -
#7493
c046153- fix(core): preserve tool result modelContent and stored artifact in addToolResult (@Kinfe123)MessagePartRuntime.addToolResultdropped aToolResponse'smodelContent, so the model-facing content a client-side tool returned never reached the runtime β every runtime read through the public API lost it, while the external-store and assistant-transport paths already forwarded it. It now forwardsmodelContent.LocalThreadRuntimeCore.addToolResultalso never storedmodelContentand spreadartifactunconditionally, so a later result that omitted the artifact overwrote a stored one withundefined. It now storesmodelContentand only overridesartifact/modelContentwhen they are supplied. -
#7544
4788b61- fix: accept explicitly undefined optional metadata on user and system thread messages, so aThreadUserMessageorThreadSystemMessagevalue is assignable toThreadMessageunderexactOptionalPropertyTypes(@okisdev) -
#7709
2caa1ce- feat: message feedback accepts an optional comment and Assistant Cloud stores it (@okisdev) -
#7684
bd77c46- fix: quote and escape filenames in text attachment wrappers (@Kinfe123) -
#7458
4e08ba6- fix: Generative UI rendering no longer throws when a node'schildrenis not an array; a string or node renders as the only child, and any other value is skipped with the malformed-node warning. (@rupic-app) -
#7634
50d65c0- fix: commit remote thread runtimes before the layout effects ofAssistantRuntimeProvider's children, so a layout effect there can update a thread on its first render. effects inside auseRemoteThreadListRuntimeruntime hook now run before paint instead of after it. (@okisdev) -
#7452
bc84250- fix: preserve voice modality when loading local storage history (@rupic-app) -
#7521
f513bc7- fix(core): keep the steer lane for implicit sends made during back-to-back queued runs (@Kinfe123) -
#7635
b712ee8- fix: publish runtime hook changes fromuseRemoteThreadListRuntimein the layout phase, so a run that settles mid-commit reads the current callbacks. the hosted thread runtime now re-renders synchronously before paint when the hook changes, instead of in a later render. (@okisdev) -
#7623
e02bf06- fix: preserve local message feedback when no feedback adapter is configured (@Kinfe123) -
#7474
44248e0- feat: voice transcripts persist as ordinary messages on the local runtime and reach external store hosts through onVoiceTranscript; a text send while a voice session is connected is rejected (@okisdev) -
Updated dependencies [
562e495,99c9988,37a5a95,b7f9a96,408d5f4,70b633f]:- assistant-stream@0.3.44
0.3.19#
Patch Changes#
-
#7414
00cff0b- feat: add an opt-in cache toconvertExternalMessagesso a source message that has not changed keeps itsThreadMessageobject across calls (createExternalMessageConversionCache, exported asunstable_createExternalMessageConversionCachefrom react and react-native); react-langchain uses it for subagent transcripts, so a streamed token no longer rebuilds every message of the nested transcript (@rupic-app) -
#7222
b821506- fix: isolate thread ID change callback errors from completed switches (@Kinfe123) -
#7227
c41d93a- fix: reconnect subjects after an upstream cleanup error (@Kinfe123) -
#7067
4cc817d- fix: exclude cleared attachments from a message when its upload finishes (@ephraimduncan) -
#7239
4e5fde6- fix: report the error, error code and first token time of a run persisted in theai-sdk/v6format; the runtime hands the cloud history adapter the thread message it persisted, whose status and timing complete a report the stored message cannot carry. the failed message's status error is now theAssistantErrorshape ({ code, message }, the code being the AI SDK error'scodeor its name) instead of the message string, andfirst_token_msreadsfirstTokenTimeas the duration the runtime records instead of subtracting the stream start, which also repairs theaui/v0path (@okisdev) -
#7234
e54bf9a- refactor: the cloud history adapter reports runs and engagement events throughassistant-cloud's reporters and reads AI SDK runs throughassistant-cloud/ai-sdk; steps are now reported for a run with a single step as well, an error is reported once per run, a storedai-sdk/v6run that produced tool calls without text reads completed instead of incomplete, and a run whose message carries a cancelled, length or content filter finish reports incomplete instead of completed (@okisdev) -
#7310
3cd7700- fix: preserve cloud message parts and track tool approvals (@okisdev) -
#7330
5fb3235- fix: attempt every pending attachment removal during reset and clearAttachments even when an adapter throws synchronously. (@Kinfe123) -
#7305
83ede73- fix: preserve the complete interim dictation transcript and clear retracted browser results without duplicating finalized words. (@Kinfe123) -
#7312
49ee689- fix: disable the reload, edit and branch switching primitives when the runtime does not expose the capability, instead of throwing when they are pressed (@okisdev) -
#7312
49ee689- fix: keep restored resolved tool calls historical when snapshots change (@okisdev) -
#7326
a8e0ff7- fix: prevent ended speech handles from cancelling newer playback (@Kinfe123) -
#7195
050d915- fix: preserve prototype-named fields in interactable updates and snapshots (@Kinfe123) -
#7232
d49ff90- fix: refresh interactable schemas after configuration changes (@Kinfe123) -
#7219
e7bdef5- fix: cancel cloud attachment uploads when the attachment is removed (@Kinfe123) -
#7354
69cbf47- feat: expose per-status counts on grouped parts and route tool calls by name in groupPartByType (@okisdev) -
#7444
be818db- fix: keep local storage threads loadable when a stored message holds a malformed part, attachment, or nested tool call message; the unreadable entry is dropped and the rest of the message and its descendants still load. (@okisdev) -
#7356
ff1c692- feat: keep a message running while a tool call's nested conversation is still streaming, and report it on the nested thread (@okisdev) -
#7154
b4b0081- fix: avoid repeated scans while joining external message parts (@Kinfe123) -
#7233
6b29e7d- fix: preserve data renderers whose names match object prototype properties (@Kinfe123) -
#7188
ab97a41- fix: restore and pause queued messages after synchronous dispatch failures (@Kinfe123)Failed work is retried before later sends. The next explicit send resumes draining; editing or removing an item does not resume a paused queue. Work already accepted by a driver is not restored, and a failed move returns its item to the original position.
-
#7184
8530b17- fix: avoid leaking a frame host message listener when initialization fails (@Kinfe123) -
#7236
063b9ec- feat: register the package as an integration on theassistant-cloudclient so the cloud can tell which packages talk to a project (@okisdev) -
#7185
2c22f5d- fix: settle pending frame tool calls when cancellation fails (@Kinfe123) -
#7345
d7aa090- fix: finalize cancelled iterators once, skip finalizing naturally exhausted sources, and release abort listeners when stream opening or reads settle. (@Kinfe123) -
#7339
7af9101- fix: send data URL image attachments as inline ADK data and resolve wildcard image types (@Kinfe123) -
#7324
63ae5b8- fix: release completed local speech subscriptions and ignore callbacks from replaced utterances (@Kinfe123) -
#7163
97bd4b3- fix: preserve component state when stable message IDs move (@Kinfe123) -
#7228
e63d2e4- fix: finish realtime voice cleanup after adapter errors (@Kinfe123) -
#7359
75b3bd3- feat: derive thread.tasks from tool calls that carry nested conversations, with a task scope (@okisdev) -
#7229
06bdf1f- fix: finish dictation cleanup after adapter errors (@Kinfe123) -
#7393
3cfddfd- fix: speak and feedback work on voice transcript messages, and edit fails with a clear error (@okisdev) -
#7351
f6b7ba9- feat: mark voice transcript messages with metadata.modality (@okisdev) -
Updated dependencies [
628df88,ed77e95,f6f52cd,790217b,dacfcec,c0d6150,275eeb9,e57c33f,e533f6b,28691a5]:- assistant-stream@0.3.43
0.3.18#
Patch Changes#
-
#6979
a360dda- fix: keep an explicit null parent when a thread appends a message (@ephraimduncan)An explicit
parentId: nullselects a root branch instead of the current tail. This also applies to AG-UI steering and the tapExternalThreadclient.For AG-UI, this includes a normalized
AppendMessagewithparentId: nullpassed tosteerAwayoruseAgUiSteerAway. Such a message starts a root branch. To continue the current branch, omitparentIdor passundefined.On a nonempty
useExternalStoreRuntimethread, an explicit null parent callsonEditinstead ofonNew. WithoutonEdit, the runtime reports that it cannot edit messages. To append at the current tail, omitparentIdor passundefined.The tap
ExternalThreadclient instead passes the null parent straight toonNew. Itsthread.appendhas noonEditroute, so the host owns what a root append means there. -
#6933
931b808- fix: abort superseded Google ADK streams even when interactive cancellation is disabled. (@Kinfe123) -
#6974
57ce984- fix: preserve selected remote thread runtimes when raced slots collapse (@Kinfe123) -
#7090
0ab9b12- fix: notify every remote thread lifecycle subscriber (@Kinfe123) -
#7183
93d1526- fix: complete context provider cleanup when unsubscribe throws (@Kinfe123) -
#7165
0b1c5a1- fix: release frame tool request resources when sending the request fails (@Kinfe123) -
#6981
7f6e012- fix: keep discarded composer text out of dictation results after reset (@ephraimduncan) -
#7115
4767a92- feat: align the cloud SDK with Assistant Cloud 0.2 (@okisdev)- run reports now carry
provider,outcome_type(aborted,disconnected,length,content_filter),error_codeanderror,message_id,first_token_ms,duration_ms, afinish_reasonper step fromuseCloudChatandtrace_id, plusenvironment,releaseandtagsfrom thetelemetryconfig; onecreateRunReportbuilder inassistant-cloudassembles the body for the assistant-ui runtime and for@assistant-ui/cloud-ai-sdk, andprovider_typeandmetadatastay on the wire for older self hosted clouds assistant-cloud/telemetry(server side):createAssistantCloudTraceExporter,createAssistantCloudSpanProcessor,assistantCloudTraceMetadataandwithAssistantCloudTraceMetadatasend AI SDK GenAI spans toPOST /v1/tracesand hand the trace id to the browser, so a client report and its server spans merge into one run; the OpenTelemetry packages are optional peers of the subpath only- engagement events: sends, edits, stops, regenerates, copies, branch switches, suggestions, attachments, thread switches, speech, voice and shown errors are batched to
POST /v1/eventswithout any message content;telemetry.events: falseopts out cloud.scores.createfor custom scores, and message feedback throughuseCloudChat().feedbacknext to the assistant-uiFeedbackAdaptercloud.files.generatePresignedDownloadUrland the objectkeyon upload responsesCloudAPIError.codeanddetails, includingplan_limit_reachedon a 402@assistant-ui/corerequiresassistant-cloud@^0.2.0, and its store emits the composer, message and thread events the engagement reporter reads
- run reports now carry
-
#6815
c9e03ef- feat: submit feedback for cloud-persisted thread messages (@okisdev) -
#6987
b8c5e68- fix: compare arrays with indexed loops so sparse-array holes cannot read as equal; a sparse suggestions list now compacts to a dense one before it reaches the per-suggestion lookup (@Kinfe123) -
#7062
571cd7c- fix: complete assistant voice messages when the first transcript is final (@ephraimduncan) -
#7010
a19db37- fix: keep the selected head aligned when relinking a message (@rupic-app) -
#6895
18c12e6- fix: use the original file to select the adapter for attachment removal when contentType is absent (@ephraimduncan) -
#6911
0d09f05- Handle prototype-named tool and remote thread keys safely. (@rupic-app) -
#7145
ddb7503- fix: speed up large interactable array updates with indexed ID matching (@Kinfe123) -
#6875
73b24d5- fix: keep separate tool calls when their IDs are absent (@ephraimduncan) -
#6880
2c1e65e- fix: match attachment extensions against the complete filename suffix, so.tar.gzacceptsbackup.tar.gzand.pngrejects extensionlesspng. (@ephraimduncan) -
#6980
d4fbb2a- fix: export parent messages before their children (@ephraimduncan)a thread whose message was reparented (
addOrUpdateMessagewith a new parent) exported in map insertion order, so a parent could be emitted after its own child. importing that export threwParent message not found, and consumers that resolve each item's parent as they walk the exported array (exportExternalState, the external-storemessageRepositoryprop) attached messages to the wrong parent. the export now walks the tree in pre-order, which also emits siblings in branch order, so branch positions survive a round-trip. -
#6978
a9efcfa- fix: keep the selected nested branch when an ancestor is selected again (@ephraimduncan) -
#7027
6c85699- fix(core): cancel a thread's in-flight request when its runtime is torn down (@okisdev)each thread the remote thread list hosts now owns a destroy signal that aborts when its runtime is stopped or restarted, and
useChatRuntimestops the chat on it. deleting or detaching a thread, replacing the thread list with one that drops it, or restarting its runtime now cancels the request that thread had in flight instead of leaving it streaming into a runtime nothing reads. hiding a thread under<Activity mode="hidden">is a soft unmount and keeps streaming. -
#6930
4802e15- fix: keep the initialization task on a new thread promoted to regular (@rupic-app) -
#6920
071a879- fix: preserve attachment removal errors in the tap composer (@rupic-app) -
#7122
0529e2d- fix: report AssistantFrame tool results that cannot cross the frame boundary (@Kinfe123) -
#7029
d777777- fix: keep the existing thread title when title generation produces no text, and stop a streaming generation from briefly blanking it (@rupic-app) -
#6824
5630967- fix: preserve a manual thread rename that lands while automatic title generation is in flight. the rename is reasserted through the adapter once the generated run has persisted its own title, so the typed title survives on the server as well as in the list. (@rupic-app) -
#7033
40f0978- fix(store): cancel in-flight work when the React host that owns it unmounts (@okisdev)a React-hosted client now carries a permanent teardown signal, so unmounting an
AuiProvider, auseAui(config)host, or auseRemoteThreadListRuntimehost cancels the requests it owned instead of leaving them streaming into a deleted tree. a hidden<Activity>, a Strict Mode replay, and a re-suspended boundary are soft and keep streaming. -
#7002
ce22d18- fix: keep ancestor branch pointers current after relinking a message (@rupic-app) -
#6982
9a882be- fix: return the requested thread's metadata from getById when another thread is selected (@ephraimduncan) -
#6928
73a1e76- fix: isolate external-store thread records from prototype-named ids (@rupic-app) -
#6931
5febc06- refactor: adjust state during render where an effect only mirrored a prop (@okisdev)The composer trigger's keyboard and navigation resources, and the devtools panel and thread tab, reset their state during render instead of scheduling a second pass from an effect, so a prop change settles in one render. Effects that genuinely synchronize with an external system (a clock, a subscription catch-up, an async load, a registry write undone on unmount) keep their
setState. -
#7187
7ea4669- fix: stop frame provider broadcasts after disposal (@Kinfe123) -
#6964
a05828f- fix: resolve run telemetry model IDs from per-step response metadata (@okisdev) -
#6842
ef584ea- fix(core): keep the thread list and report the error when a load fails. failed loads previously looked like an empty thread list; thread list state now exposesloadError, clears it when a later load starts, and in browsers retries a failed load once when the window comes back online or the document becomes visible again. React Native has neither event, so it keeps recovering throughreload(). (@okisdev) -
#6958
84b6ae2- fix: Notify thread-list subscribers when only the loading state changes. (@ephraimduncan) -
#6864
6f0d7af- fix: defer remote thread deletion cleanup until persistence succeeds (@Kinfe123) -
#7084
441168d- fix: keep explicit title generations ordered after in-flight renames (@Kinfe123) -
#7024
f756047- fix: keep the server on the title that wins the ordering race (@okisdev)an automatic title generation persists its title server-side through its own run, so an explicit generation that superseded it locally could still be overwritten once the older run finished. the losing run now waits for the winner to persist its title and writes that title back, and a rename that outranks the winning generation is reasserted the same way.
-
#7157
306bed1- fix: preserve prototype-named tool UI registrations and argument statuses (@Kinfe123) -
#6915
1f80dd0- fix: skip adapter cleanup for complete edit attachments (@rupic-app) -
Updated dependencies [
3bcd6db,a16b990,253c80d,e6158c8,623d5ff,07eeb54,12c5447,9b9d5e9,afac9e0,4cdcabb,23d2865,b505555,01fdd4b,59a8251]:- assistant-stream@0.3.42
0.3.17#
Patch Changes#
-
#6723
8cc962e- feat: let a tool approval request describe itself and report its outcome (@okisdev)an approval carries
prompt,display, andallowFreeform, so a renderer can tell a question from a permission gate without reading provider metadata, andToolApprovalResponsegains atextanswer that resolves the request as answered rather than approved.respondToToolApprovalnow returns a promise that rejects when the runtime could not record the response, instead of the external-store runtime logging the rejection away, so a refused response leaves the request retryable. -
#6539
2a31285- fix: avoid duplicate external-store runtime publications (@rupic-app) -
#6685
205acf5- refactor: walk the nested tool-call tree through one shared traversal (@okisdev) -
#6678
740a573- fix: never execute a frontend tool on a tool call ADK resolves itself; a client-executed tool must be registered as aLongRunningFunctionToolon the agent (@okisdev) -
#6498
65d449b- feat: background thread bodies and a plain cloud adapter factory (@okisdev)RemoteThreadList gains a backgroundThreads mode that keeps every visited thread mounted: runs continue across switches, per-item isRunning is live, per-thread history and adapters mount once per body, and a freshly initialized thread generates its title. createCloudThreadListAdapter builds the assistant-cloud adapter without a hook call site so non-React hosts can construct it in plain code.
-
#6671
79283c5- fix: report lifecycle events from background thread runtimes (@rupic-app) -
#6645
9ec29e1- fix: report run start and end for threads a remote thread list keeps alive in the background (@Kinfe123) -
#6702
14fc938- fix: cancel AssistantFrame tool calls when their provider is removed (@Kinfe123) -
#6562
3f7af8b- fix: preserve composer queue item component identity after removals (@Kinfe123) -
#6597
5511057- fix: preserve thread list item state when preceding threads are removed (@Kinfe123) -
#6580
dc2cab3- chore: stop hand-rolling the cloud adapter provider that the hosts synthesize (@okisdev) -
#6587
d75944b- fix: keep Cloud thread adapter options scoped to committed renders (@Kinfe123) -
#6547
6bd1570- fix: drop zustand from core (@okisdev)core declared zustand as an optional peer while importing
createanduseShallowunconditionally. pnpm keys a package instance on its resolved peers, so two dependency branches landing on different zustand patches (5.0.14 under one, 5.0.15 under the other) produced two physical copies of core. React context is per copy, so aRuntimeAdapterProviderrendered by one copy was invisible to a runtime hook imported from the other:unstable_Providersupplied ahistoryadapter,useAISDKRuntimereadundefined,withFormat()never fired, and every thread loaded with no messages and no error.core no longer uses zustand at all, so the peer is gone rather than reclassified. the four internal stores now use
WritableSubscribable, a mutable cell built on the existingBaseSubscribableand read throughuseSubscribable. the twouseShallowcall sites wrapped selectors passed touseAuiState, aui's own store, so they now useuseShallowSelectorfrom@assistant-ui/store/internal, which memoizes a selector against theshallowEqualthat already lived there.WritableSubscribablereports a server snapshot anduseSubscribableforwards one when the subscribable offers it, so the components reading these stores render under SSR the way the zustand hook did. Subscribables without one, including every existing runtime client, keep their current behaviour.@assistant-ui/react-nativeand@assistant-ui/react-inkdeclared zustand only to satisfy core's optional peer and never imported it, so they no longer declare it.@assistant-ui/reactand@assistant-ui/uikeep theirs because they import it directly, and@assistant-ui/reactadditionally exposesStoreApithroughReadonlyStorein its published types. -
#6758
60ae973- fix: keep model context callbacks scoped to committed React renders (@Kinfe123) -
#6719
0fb5390- fix: never run a frontend tool on a call the provider is about to answer or gate (@okisdev)a tool call whose name matched a registered tool closed its args stream, and therefore executed, as soon as
argsTextparsed. providers that answer or gate a call do so one or more snapshots later, so in that window a frontendexecutefired on a call the provider was about to take: the AG-UI interrupt protocol carries the outcome only onRUN_FINISHED, so the gate landed on a call the client had already run.closing the args stream now waits until the provider can no longer speak about the call.
unstable_isClientToolCalldecides that per call: a call the adapter reports as client-owned closes as soon as its arguments parse, and a call whose ownership is unknown closes when the run ends.@assistant-ui/react-google-adksupplies the predicate and keeps its previous timing; every other runtime defers a frontend tool to the end of the run.streamCallstill fires once and still streams partial arguments as they arrive, so rendering is unchanged, but a tool that pairsstreamCallwithexecute(interactables) now commits its authoritative merge when the run settles. -
#6580
dc2cab3- chore: remove an internal re-export shim and a duplicated type guard (@okisdev) -
#6761
1fa3e09- fix: report a stopped AI SDK run as cancelled instead of complete (@Kinfe123) -
#6606
0f17ba5- refactor: generate composer attachment IDs with the shared ID utility (@Kinfe123) -
#6764
0c5c574- fix: keep a frontend tool's pendinghuman()interrupt when execution starts (@samdickson22)a tool whose
executeawaitshuman()before any other await had itsinterruptstatus overwritten by theexecutingstatus the execution-start callback writes, so the approval prompt never rendered and the run never settled. -
#6728
ddaac94- fix: isolate errors from initialize listeners replayed after thread startup (@Kinfe123) -
#6781
0c68179- fix: isolate model context update listener errors (@rupic-app) -
#6601
250f69c- fix: preserve attachment component state when message attachments are removed or reordered (@Kinfe123) -
#6567
c22a3dc- feat: resolve toolkit renderText through a framework-neutral seam (@okisdev) -
#6561
aca6e30- fix: preserve composer attachment component identity after removals (@Kinfe123) -
#6711
6fdfc23- fix: keep remote thread runtime hooks scoped to committed renders (@Kinfe123) -
#6380
136bbf5- fix: clear the thread list loading state when a reload or adapter change supersedes the request (@Kinfe123) -
#6518
69d8e1b- fix: keep remote thread actions scoped to the committed adapter (@Kinfe123) -
#6494
dabe8f2- feat: adopt an externally owned message repository instance per adapter swap (@okisdev) -
#6657
8d128af- fix: prevent deleted threads from becoming the active thread (@Kinfe123) -
#6586
9f08bdc- chore: share one shallow-equal across the runtime internals (@okisdev) -
#6760
47a46db- fix: keep the remote main thread facade scoped to committed selections (@Kinfe123) -
#6688
8135d16- fix: peer ranges on the packages this workspace releases now track the release train (@okisdev)changesets rewrites a peer range only when the new version falls outside it, so the hand-written floors had drifted below the code they describe. core declared
@assistant-ui/store: ^0.3.0while importing@assistant-ui/store/internal, a subpath store did not export until 0.3.10, and react-lexical declared*. these peers are nowworkspace:^, which publishes as the version released alongside them. -
#6669
07fed43- fix: keep one thread slot per remote id and clear every alias on delete (@okisdev) -
#6495
fa9c0dc- fix: keep the optimistic assistant placeholder id stable within a run (@okisdev) -
#6450
4ca7de9- fix: publish assistant transport callbacks before descendant layout effects (@Kinfe123) -
#6348
49e727b- fix: keep suggestion state stable across equal configurations (@rupic-app) -
#6701
d56a66a- fix: report cached and reasoning tokens from the AI SDK v7 token details (@okisdev) -
#6489
96a2df8- refactor: share the message error and thread-list load-more predicates across bindings (@okisdev) -
Updated dependencies [
46fad14,f0d0aa2,5bdd416,e53299b]:- assistant-stream@0.3.41
0.3.16#
Patch Changes#
-
#6224
c70c911- docs: name@assistant-ui/ai-sdkin JSDoc examples (@okisdev)the import examples on
injectQuoteContext,unstable_injectInteractableContext, and the interactable and message JSDoc pointed at@assistant-ui/react-ai-sdk. they now name the framework-neutral package, which is where these live; the old package re-exports it, so both imports resolve. -
#6360
e0fa1e6- fix: roll back AssistantFrame providers on registration, release, and disposal failures (@Kinfe123) -
#6346
b2f148e- refactor: share the attachment add cancellation machinery between the composer core and the store client. (@okisdev) -
#6365
9dabbce- refactor: notify every thread runtime subscriber before rethrowing a subscriber error. (@okisdev) -
#6262
5a3e9f7- refactor: move the run report tool call shape and its serialization into assistant-cloud (@okisdev) -
#6297
43d52ad- fix: keep prepended id-less messages in the external message converter (@Kinfe123) -
#6268
cdfc34d- fix: tag static ai-sdk/v6 tool calls as frontend in cloud run telemetry (@okisdev) -
#6222
4000eed- fix: cancelling an edit session cancels its in-flight attachment adds and removes its non-complete attachments through the attachment adapter (@Kinfe123) -
#6329
8217a6e- refactor: derive executing-tool running state inside the external-store runtime; adapters now pass raw provider isRunning. (@okisdev)
the assistant transport runtime enables tool invocations too, so it now keeps the thread running while a client tool executes instead of reporting idle. -
#6369
3fcf338- refactor: collapse the external message converter's duplicate derivation chains into one pure module. (@okisdev) -
#6324
4802d23- fix: derive requires-action for pending and interrupted tool calls in the external-store convertMessage path; messages with unresolved tool calls now report requires-action instead of complete (@ShobhitPatra) -
#6174
c3fd2b3- fix: evict deleted external-store messages so no phantom branch survives. the setMessages path evicts immediately; the onDelete path evicts at the confirming host snapshot (@Kinfe123) -
#6271
231d148- fix: keep prepended history when convertMessage returns no id (@okisdev) -
#6439
7e03b66- refactor: share the file part source resolution branch (@okisdev) -
#6236
1263c1f- fix: report frame tool failures whose error message is empty (@Kinfe123) -
#6458
465a7a6- fix: default assistant frame messaging to the current origin (@Kinfe123) -
#6197
5355528- fix: preserve incomplete tool-call part statuses (@Gujiassh) -
#6199
e97f7c6- fix: resolve InMemoryThreadList index selectors within the archived/regular subset (@Kinfe123) -
#6345
a6d2da5- refactor: share the interactable persistence scheduler between the tap client and the legacy surface. (@okisdev)
a save that settles after its interactable unregistered no longer recreates the removed persistence-status entry. -
#6328
6b797ca- refactor: share the runtime lifecycle callback invoker from core internal. (@okisdev)
callback errors continue to be reported and swallowed through the shared invoker. -
#6257
bea47ed- fix: type MCP app metadata in ThreadMessageLike tool calls (@rupic-app) -
#6325
546dae8- fix: derive requires-action for pending and interrupted tool calls when importing messages into the repository, and resume local runs after approving an imported pending approval (@ShobhitPatra) -
#6430
a06be56- refactor: share the message repository session layer between a2a and ag-ui (@okisdev) -
#6237
96d4ddf- fix: preserve generated thread titles across overlapping optimistic updates (@dawNotPoi) -
#6333
c8db434- refactor: move queue item state ownership into the runtime layer. (@okisdev) -
#6293
bc55058- docs:ToolApprovalOption.kindno longer says the default kit skips custom_-prefixed kinds; the kit renders them and answers with an explicitapprovedvalue alongside theoptionId(@samdickson22) -
#6344
0221348- refactor: back ModelContextRegistry's provider handling with CompositeContextProvider. (@okisdev) -
#6203
c415384- fix: keep threads initialized during a list() flight in the thread list when the stale response lands (@Kinfe123) -
#6347
5bba723- refactor: share the remote thread list empty state and local thread seeding. (@okisdev) -
#6246
0188899- fix: preserve streamed RemoteThreadList titles across optimistic replays (@rupic-app) -
#6409
027f5e2- refactor: share the pending tool-call scan, abortable thread load, and cloud create fallback via core. (@okisdev) -
#6227
ebabca4- fix: reject archived index selectors on SingleThreadList instead of resolving the regular thread (@Kinfe123) -
#6332
fc7f72f- fix: refresh static suggestions when their configuration changes (@Kinfe123) -
#6282
0064d1e- fix: never execute a frontend tool on a tool call that carries a provider approval (@ShobhitPatra) -
Updated dependencies [
8626c1f,531f61a,dfaa94f,a4bc54a,fd471e9,ac7ec15,e96d3de,f96e22f,bfc8bef,2cd5cbc,105af3e,4c3194a]:- assistant-stream@0.3.40
0.3.15#
Patch Changes#
-
#6100
fa30915- fix: propagate AssistantFrame tool cancellation across the frame boundary (@Kinfe123) -
#5823
b355aef- fix: prevent AssistantFrameProvider from ignoring a later explicit targetOrigin (@Kinfe123) -
#6136
f7bd2d9- fix: keep DevTools updates flowing when a subscriber throws (@Kinfe123) -
#6107
4947ef4- fix: preserve falsy assistant transport artifacts (@Kinfe123) -
#5809
332f736- fix: load archived threads in the cloud thread list adapter (@SnowingFox) -
#6112
ef9254d- fix: contain a synchronously throwing clipboard writer in useActionBarCopy (@samdickson22) -
#6156
9c65b51- deprecate leftover Primitive.If and Empty wrappers on react-native and react-ink, and point them at AuiIf (@okisdev)ThreadIf now reads
thread.isEmptyinstead ofmessages.length === 0, matching the loading-aware field already used by ThreadEmpty and AuiIf. First-party examples and docs samples that still called the leftover wrappers now useAuiIfdirectly. -
#6106
5845ba7- fix:ExternalThreadno longer reports an empty thread while it is loading (@samdickson22)ExternalThreadcomputedthread.isEmptyasmessages.length === 0, omitting
theisLoadingterm thatthread-runtime-client.tsalready applies. A thread
withisLoading: trueand no messages yet reportedisEmpty: true, so
<ThreadPrimitive.Empty>,useThreadIsEmpty(), andAuiIfon
s.thread.isEmptyrendered their empty state underneath the loading indicator.
TheThreadStatetype already documents the intended contract: a thread is
empty when it has no messages and is not loading.Both producers now define
isEmptyidentically. Consumers that pass
isLoadingtoExternalThreadand render empty-state UI will see that UI stay
hidden until loading finishes.useExternalStoreRuntimeis unaffected β it
already carried theisLoadingterm. -
#6125
1b30bfd- refactor: collapse the two inert thread cores onto a shared base (@okisdev) -
#6159
365e763- fix: avoid ancestor scans when importing new messages (@rupic-app) -
#6135
d19921d- fix: prevent cancelled external-store runs from resyncing after teardown (@Kinfe123) -
#6080
996aa57- fix: reset remote thread selection and cached records when the thread-list adapter is replaced (@okisdev) -
#6177
21d6e87- fix: notify thread subscribers when a remote thread core is republished (@Yonom) -
#6092
cd247e5- fix: traverse long message branches without recursive stack growth (@Kinfe123) -
#6142
1bf263b- fix: settle aborted and superseded local runs without continuing them, while keeping approval pauses answerable after cancel (@Kinfe123) -
#6081
a614b5e- Disconnect immediately when createVoiceSession receives an already-aborted signal. (@Gujiassh) -
#6087
07b51db- Mark voice sessions cancelled when aborted or explicitly disconnected. (@rupic-app) -
#6168
92e52bd- fix: align tool-call status reasons with message status (@rupic-app) -
Updated dependencies [
19e52c4]:- assistant-stream@0.3.39
0.3.14#
Patch Changes#
-
#6068
ac0c836- fix: stabilizeunstable_useAdaptersresults on both adapter faces and warn on an unkeyed history factory. the React host's synthesized provider now absorbs a fresh but shallow-equal adapters bag the same way theRemoteThreadListstore entry does, reusing the store'suseShallowStableprimitive through its internal entry, and the store entry warns in development when a history adapter arrives while the thread factory is unkeyed, since switching threads would silently keep the first thread's history. (@okisdev) -
#6071
c3fd447- feat: host assistant-cloud thread lists on AISDKThreads via RemoteThreadList (@okisdev)AISDKThreads({ cloud }) uses RemoteThreadList and remounts each thread like useChatRuntime. Cloud history withFormat resolves persistence per call so one adapter can serve many threads. useExternalHistory waits for threadListItem.remoteId instead of latching on the first empty paint.
-
#5872
f9529bf- feat: move useAssistantTransportRuntime into core/react (@okisdev) -
#5872
f9529bf- fix: persist data message parts in aui/v0 cloud history (@okisdev) -
#5983
05b94bd- fix: handle failed LocalRuntime user-message history writes without abandoning the run (@Kinfe123) -
#6030
cef671d- fix: report automatic thread title generation failures (@Kinfe123) -
#6053
ef7f70d- fix: report attachment removal failures without leaking unhandled rejections (@Kinfe123) -
#5376
39db2ff- fix: isolate WebSpeech dictation listener errors and report async listener rejections from speech synthesis and voice sessions (@Kinfe123) -
#5619
a2a753b- fix: handle rejected external-store callbacks (@Kinfe123) -
#6076
bec0753- fix: persist cloud history against the departing thread after a switch (@rupic-app) -
#6005
4326079- feat: move useCloudThreadListRuntime into core/react and drop the unused react copy of the aui/v0 codec (@okisdev) -
#6023
3d68b16- fix: derive thread composer canCancel from an in-flight run (@okisdev) -
#5890
98795aa- fix: snapshot composer role and run configuration before uploading attachments (@Kinfe123) -
#5959
9d920cc- feat: expose InMemoryThreadList and its transform scopes from the store entry, with an onDelete callback and a fresh thread after deleting the last one (@okisdev) -
#5913
1b9c33d- feat: shared disabled predicates for the primitive layer on @assistant-ui/core/store/internal. the composer, action bar, branch picker, and suggestion disabled selectors previously lived as verbatim copies in each binding's hooks; they are now named exports (composerSendDisabled and friends) consumed by the react hooks and the vue and svelte bridges alike, so disabled semantics cannot drift between frameworks. (@okisdev) -
#5932
d68918e- feat: exportruntimeAdapterTransformScopesfrom the store entry, so adapter packages can attachRuntimeAdapter's scope defaults to their own config entries. (@okisdev) -
#5897
74dca03- fix: route ThreadRuntime/ThreadListRuntime subscribe through the memoizing state binding, and give LazyMemoizeSubject the same identity guard ShallowMemoizeSubject has, so getState serves a stable identity between notifications. Note: ThreadRuntime.subscribe now only notifies when the shallow-compared ThreadState changed β composer edits no longer wake thread subscribers; observe them viaruntime.composer.subscribe, matching every other runtime class. (@Yonom) -
#6040
87bf950- fix: generate the thread title as soon as the thread exists. the automatic title generation for a new thread fires when initialization resolves, concurrent with the first run, instead of at the first runEnd, so the sidebar stops showing "New Chat" for the whole first response and a thread abandoned mid-run no longer stays untitled forever. the title request carries the messages present at that moment, typically just the user message. (@okisdev) -
#5937
5a01343- fix: avoid trailing spaces when appending empty suggestions (@rupic-app) -
#5929
0f6e9e9- chore: replace stale example model ids with gpt-5.6-luna (@okisdev) -
#6034
b80a6be- fix: paint the first message of a new thread before initialization resolves. the local core inserts and notifies before awaiting the initialization barrier, rolling the optimistic message back and rejecting withMessageNotSentErrorwhen the barrier fails, and the external-store core no longer holdsonNewon it. behavior change for custom external-store adapters under a remote thread list:onNewandonEditcan now run before the thread record exists, so a dispatch that needs the remote identity mustawait threadListItem.initialize()itself (the ai-sdk transport and langgraph already do,useStreamRuntimenow does). appends that used to be silently dropped when the thread was stopped, unmounted, or switched away during the initialization wait now dispatch immediately instead; the invalidation guard still covers the tool-abort window. the queue path keeps the pre-enqueue barrier. (@okisdev) -
#5892
01580e3- fix: retain the message part children props in published declarations (@charlesverge) -
#6035
e8c53e9- fix: switch away when remote thread unarchive fails (@rupic-app) -
#6044
53ae80f- fix: preserve archived thread state when unarchive fallback reseeds (@rupic-app) -
#5298
5f4dee5- fix: refresh Cloud attachment uploads when the Cloud client changes (@Kinfe123) -
#5405
2da61a3- fix: handle rejected dictation shutdowns (@Kinfe123) -
#5837
0131fc7- fix: migrate interactables update-tool UIs across tools scope replacements and install pending ones once the scope appears (@okisdev) -
#5593
a934d03- fix: preserve metadata from every joined assistant message (@serhiizghama)When consecutive assistant/tool outputs are joined into one message, only the first output's metadata was kept β annotations, data, steps, custom, timing, and feedback on any later assistant message (e.g. the final answer after a tool call) were silently dropped.
unstable_annotations,unstable_data, andstepsnow accumulate across every joined output, andcustommerges with later keys overwriting earlier ones for the same key.unstable_state,timing, andsubmittedFeedbackare scalar and take the last joined output's value (last-wins) β the joined message'sid/createdAt/statusare unaffected and still come from the first output. -
#5864
b6d7b2b- fix: wait for remote thread initialization before external-store appends (@rupic-app) -
#6026
bc337af- fix: resynchronize lazy memoized state when connecting (@rupic-app) -
#5910
dc6eb2f- style: apply oxfmt 0.63 formatting (@okisdev) -
#5874
ce57458- fix: discard pending appends when their thread runtime is replaced (@rupic-app) -
#5880
ab7ead9- fix: gate queued external-store appends on thread initialization (@okisdev) -
#5859
067ef52- fix: ignore suggestions generated by superseded local runtime runs (@Kinfe123) -
#5971
e5bf0ef- fix: keep duplicate model context registrations independent (@rupic-app) -
#5927
a2ab997- fix: isolate overlapping tool executions that reuse a toolCallId (@rupic-app) -
#6050
fc9dd90- fix: notify every external thread-list subscriber when one listener throws (@Kinfe123) -
#5572
0e2a230- fix: flush queued interactable writes through the outgoing persistence adapter, one full-state save at a time (@Kinfe123) -
#5464
d800f8b- fix: notify every model context subscriber before rethrowing, and roll back a provider registration when its subscribe throws (@Kinfe123) -
#6037
f5b39d4- feat: addRemoteThreadListAdapter.unstable_useAdaptersso theRemoteThreadListstore entry can load per-thread history without renderingunstable_Provider(@okisdev) -
#6020
26f40c1- feat: add aRemoteThreadListstore entry so anyAssistantClienthost can run a remote thread list from aRemoteThreadListAdapterand athreadfactory (@okisdev) -
#5871
f618ab6- fix: retry remote thread initialization after a rejected append (@rupic-app) -
#5834
d80e988- fix: model-context registrations follow the committed scope across structural replacements. The newuseAssistantScopeEffect(scope, effect, deps)re-runs a registration when the scope's bound client is replaced (cleaning up against the old one first) while ignoring value updates, and the toolkit, runtime-adapter, interactables, and MCP registration sites now use it instead of registering once against a stable client ref. (@okisdev) -
#5922
7f944be- feat: addunstable_notifySessionResetso adapters with a resettable backing session can clear session-scoped tool-invocation state without run-cancel side effects; the eve reset now uses it instead of composingcancelRunwith a hand-rolled session filter (@okisdev) -
#5435
f37f595- fix: isolate message queue subscriber errors (@Kinfe123) -
#6058
837ef1b- fix: render system messages safely when editing components are omitted (@rupic-app) -
#6014
7748e15- feat: host remote thread runtimeHooks as keyed tap resources on the list hook.useRemoteThreadListRuntimemounts oneuseResourceshost after each thread'sunstable_Provider, so the firstruntimeHookcall already sees Provider adapters. AdapterSink only publishes those adapters.@assistant-ui/store/clientexportsuseConfiguredAuianduseAssistantContextProviderso that host can extend and provide a client the same wayAuiProviderdoes in React. (@okisdev) -
#6013
72705c3- fix: resync a memoized thread snapshot when a subscriber connects, and load local history if the adapter arrives after the first load (@okisdev) -
#5914
0d2e23f- feat: newthreads.selectionChangedevent carryingthreadIdandpreviousThreadId; deprecatethreadListItem.switchedTo/switchedAwayin its favor. Un-deprecate the semantically meaningful events (thread.runStart,thread.runEnd,thread.initialize,composer.send,composer.attachmentAdd). (@Yonom)The new event fires in situations where the deprecated pair did not, so the selection-driven defaults (
scrollToBottomOnThreadSwitch,unstable_focusOnThreadSwitched) now engage there too:InMemoryThreadListemits on selection changes (it previously emitted no switch events at all),switchToNewThread()emits for the newly created thread, and runtimes that resolve a deep-linkedthreadId/initialThreadIdafter mount (useRemoteThreadListRuntime) emit when the deep link resolves, with the initial placeholder thread aspreviousThreadId. -
#6052
4446d45- fix: notify every interactable model-context subscriber when one throws (@Kinfe123) -
#6059
bfe47b6- fix: notify every memoized subject subscriber when one throws (@Kinfe123) -
#5860
ceb8c16- fix: handle thread list action failures without unhandled rejections (@Kinfe123) -
#5631
7ea9de1- feat: runtime suggestions can carry a display title and label (@samdickson22)ThreadSuggestiongains optionaltitleandlabel, so an adapter can show a
short pill while still sending the fullprompt.useThreadSuggestionsnow
passes them through instead of hardcodingtitle: prompt, falling back to
title ?? promptandlabel ?? ""so prompt-only suggestions render exactly as
before.SuggestionConfigis unchanged; the change is additive. -
#5519
51886b2- fix: clean up disconnected voice sessions (@Kinfe123) -
#5968
3053195- fix: isolate voice volume subscriber failures (@rupic-app) -
Updated dependencies [
0e91e27,c5bc8ed,f0d1d48,ab7f49f,61d29f4,a2ab997,e8997d9,44e574f,14c3b5a]:- assistant-stream@0.3.38
0.3.13#
Patch Changes#
-
#5766
a90db30- fix: prevent pending ExternalThread attachment additions from restoring cleared drafts (@Kinfe123) -
#5799
cfb5fab- fix: make a cancelled run move its trailing user message instead of dropping it. the message now leaves the thread only when the composer actually accepts it, so cancelling while a draft is already being written keeps the message in the thread rather than deleting it and handing it back nowhere, and what comes back carries the attachments and quote instead of the text alone. a message carrying content the composer has no home for, such as an image or file part, is left in the thread untouched. adapters keep the existingsetMessagesguard: without it the runtime cannot see its own removal survive, so an adapter that removes the cancelled message itself owns handing it back. (@okisdev) -
#5826
65e03a6- fix: reconcile cancelRun's deferred resync with store updates that land before it flushes, instead of stamping a pre-cancel snapshot over them (@okisdev) -
#5789
d3fece3- feat: give the composer its draft back when a send never reached the backend. a runtime that rejectsonNewwith the newMessageNotSentErrorrestores the text, quote, and attachments the composer cleared at dispatch time, as long as nothing has claimed the composer since. that guard and that outcome are the onescancelRunalready applies to a trailing user message, so whichever fires first keeps the composer, and of several drafts queued behind one turn only the most recent is still restorable. an edit composer closes at dispatch, so a rejected edit is not restored. (@okisdev) -
#5780
1e98bcf- fix: gate interactable state snapshots at dispatch instead of at enqueue. a message sent while a run is in flight waits in a queue lane but carried the snapshot taken when the user sent it, so a run that landed its ownupdate_{name}in the meantime was folded over by a staleuser-editversion: a full snapshot replaced the model's edit outright, and a partial one merged the older diff on top of it, producing a state that never existed. every send path now stamps exactly once, when the message is dispatched rather than when it is queued.LocalThreadRuntimeCorestamps in_runAppend, the point both the direct send and the queue flush pass through, andExternalThreadQueueAdaptergained an optional__internal_setDispatchTransformthatcreateMessageQueueimplements andExternalStoreThreadRuntimeCoreinstalls, so a queued message is re-gated against the thread tail it actually lands on. an adapter that does not implement the transform is stamped at enqueue as before. (@okisdev) -
#5800
82cbc15- fix: pause an external store's message queue when the user cancels. cancelling left the queue running, so the aborted run's settle dispatched the next pending message at the moment the user pressed Stop; the pending items now survive and the next send drains them, matching what the local runtime does underunstable_queueClearOnCancel: falseand the behaviour that flag becomes once it is removed. (@okisdev) -
#5808
e28a62d- fix: hide external thread cancellation when no handler is configured (@Kinfe123) -
#5805
48af3c5- feat: acceptproviderMetadataon image and file message parts, the channel text, reasoning and source parts already carry. A runtime adapter reads its own namespace off it, so a part can carry provider-specific data (an upload id, a document handle) without a field per provider. (@okisdev) -
#5767
22fa20f- fix: preserve ExternalThread composer state while attachments are prepared for send (@Kinfe123) -
#5777
417efee- fix: stamp interactable state snapshots on every send, not just composer sends. the gate ran in the thread and edit composer cores, so a send that skipped the composer carriedmetadata.custom = {}: aSuggestionsentry withsendgoes throughthread.append(), as does user code callingassistant.thread.append(...). the model then saw anupdate_{name}tool whose requiredidis documented as coming from a state snapshot, found no snapshot in the conversation, and could not call the tool at all. gating now runs inBaseThreadRuntimeCore.enrichAppendMetadata, applied by both thread runtime cores on append, deriving the branch prefix from the message'sparentIdso the previous composer behavior is reproduced exactly (the thread tail for an ordinary send, the edited message's parent for an edit). theremoveoperation's item id description in generated array-update schemas no longer reuses the instance-addressing wording that told the model each removable list item was an interactable instance. (@okisdev) -
#5798
1e1d52b- fix: keep trailing user messages out of the composer when an external store cannot persist deletions (@SR0725) -
#5828
685a069- feat: wirethreads.reloadMainThread()through the tapExternalThreadpath via a newonRefetchThreadcallback, with therefetchThreadcapability derived from its presence (@okisdev) -
#5769
f59d24b- fix: deliverthreadListItem.switchedToto default-scope listeners (#5699). the thread list item client now emits the switch from its own observed selection transition, after the flush that rebinds the derived scopes, instead of relaying the runtime's synchronous notification. scoped listeners now resolve their scope against the host's current client at delivery time, so a listener subscribed before a structural swap follows the scope's present binding; the notification manager re-reads the listener set at flush time per the documented live-set semantics. listeners that need a pinned instance subscribe on an id-scoped client instead. (@okisdev) -
#5757
092585b- fix: derive the suggestions scope from the thread so runtime-provided suggestions render throughThreadPrimitive.Suggestions(#5529) (@okisdev)
0.3.12#
Patch Changes#
- #5745
1df4327- refactor: move ExternalThread, SingleThreadList, and the Assistant augmentation namespace into @assistant-ui/core (@Yonom)
0.3.11#
Patch Changes#
-
#5742
f551562- fix: name the offending input when an external message converter returns an invalid message (@Yonom) -
#5733
dc7b77d- Republish: 0.3.10 was left staged on npm by a failed publish and cannot be re-pushed. (@Yonom) -
#5718
d1b7097- fix: expose additional Cloud thread pages through the thread list runtime (@Kinfe123) -
Updated dependencies [
0ae51a8,e319574]:- assistant-stream@0.3.37
0.3.10#
Patch Changes#
0.3.9#
Patch Changes#
- #5720
ab9e765- fix: route sourceId-carrying edit sends to onEdit instead of the queue adapter, and fail fast on beginEdit without an edit handler (@Yonom)
0.3.8#
Patch Changes#
-
#5717
99d09c8- Edit composer send always emits: an unchanged edit re-sends the message on a new branch instead of silently closing the composer. (@Yonom) -
#5639
79253f2- feat: preserve app-authored reasoning summaries on message parts (@rupic-app) -
Updated dependencies [
456b056,a88751d,79253f2]:- assistant-stream@0.3.35
0.3.7#
Patch Changes#
-
#5668
bd4c0ad- feat: expose RuntimeAdapter from the framework-neutral store entry so runtimes mount into createAssistantClient without React (@okisdev) -
#5675
4aa1b1d- feat: expose framework-neutral seams on the ./store entry (useExternalMessageConverter, convertExternalMessages, useStreamingTiming, createRuntimeExtrasBrand, defineToolkit, defineMcpToolkit) and add unstable_createRuntimeExtrasFromBrand so bindings can share one runtime extras brand across packages (@okisdev)
0.3.6#
Patch Changes#
-
#5430
dcacd9b- feat: AuiProvider extends/config grammar.config={AuiConfig({...})}alone creates a top-level root client; nested providers must passextendsβ a client to extend, ornullto isolate (dev-enforced). An empty config creates a client extending theextendsclient;refexposes the resulting client. Theconfigprop only accepts configs built withAuiConfig(...)(branded type). AssistantRuntimeProvider gains an optionalconfigprop whose scopes are provided alongside the runtime scope. TheuseAui({...})extension overload and the AuiProvidervalueprop are deprecated;value={client}now exposes a client extending the given one (same scopes, new identity) rather than the exact instance.useAui({})with an empty scope object now mounts a rooted host (so the scope set can grow across renders) instead of a passthrough derived-only client.useAuiStatestate enumeration (Object.keys/spread) now includes scopes inherited from parent clients, matchingin-operator behavior. Clients derived from a hand-built parent (a plain object withsubscribe/on) forward scopedon(...)listeners to the parent'soninstead of throwing for scopes the parent does not expose. (@Yonom) -
#5569
d8a59ad- fix: preserve falsy tool results (@Kinfe123) -
#5653
e70da91- fix: drop the react type dependency from the core default entry and pin the framework neutral boundary with a contract test (@okisdev) -
#5484
aac3a8c- fix: accept all valid image data URLs in sanitizeImageContent instead of a hardcoded format list (@ShobhitPatra) -
#5650
34cec64- feat: two-lane, placement-aware message queue with steer-by-default mid-run sends (@Yonom)ExternalThreadQueueAdapteris reshaped:enqueue(message, { steer })splits into
enqueue(message)/steer(message),steer(queueItemId)becomes
move(queueItemId, { lane: "steer", insertAfter: null }),clear(reason)is dropped
(queue clear policy is now host-owned), andsteerItems/move/editand
QueueItemState.partsare required. -
Updated dependencies [
d52928d]:- assistant-stream@0.3.34
0.3.5#
Patch Changes#
-
#5552
7f7f8a2- fix: handle stopped initial thread runtime starts (@Kinfe123) -
Updated dependencies [
78943a3]:- assistant-stream@0.3.33
0.3.4#
Patch Changes#
-
#5233
b19c2f5- fix: prevent canceled attachment uploads from reappearing and settle failed removals as attachment errors (@Kinfe123) -
#5447
8c99934- docs: deprecate Unstable_AudioMessagePart in favour of file parts (@okisdev)Audio belongs on a
filepart with anaudio/*mime type.fileis a member of both the user and assistant unions and carries a filename, neither of which the audio part can express. The payload form afilepart needs is still adapter specific; the message primitive docs enumerate it. The audio part and theUnstable_Audioslot stay honored everywhere they are accepted and will not gain fields. -
#5439
ece5a54- feat: sourceType opt-in on file message parts so attachment adapters can send url/id file references (@ShobhitPatra) -
#5445
2fdff87- feat: honor sourceType "url" in a2a, ag-ui, and adk file converters (@ShobhitPatra) -
#5542
55b2824- feat: exposethreadListItem.isRunningso a thread list row can show its own run (@okisdev)a thread list row had no supported way to tell whether its thread was running:
thread.isRunningdescribes the open thread, and the item state carried no run state at all, so a run continuing on a thread the user had switched away from was invisible.threadListItem.isRunningnow reports it, and stays true for a background run. runtimes that keep background threads alive answer it through the new optionalThreadListRuntimeCore.unstable_isThreadRunning; the rest report the open thread's run state, which they already track.InMemoryThreadListalso renames threads for real instead of dropping the new title. -
#5459
22b05a4- fix: wrap a file part payload that is not a parsable url (@okisdev)getPromptPartsputFileMessagePart.datastraight into the OpenCode file part'surl. OpenCode forwards that into an AI SDK file part (sst/opencode,session/message-v2.ts), whoseurlreaches an unguardednew URL(), so a payload that is raw base64 rather than a data URL or an http source failed there. A non-parsable payload is now wrapped in adata:<mime>;base64,envelope; data URLs and http sources are forwarded untouched, and asourceType: "id"reference is left alone so it fails loudly instead of shipping a corrupt payload.The predicate behind that decision moves to
isParsableUrlin@assistant-ui/core/internal, next to thehttpUrlPatternandparseDataUrlit belongs with, and react-ai-sdk now imports it instead of keeping its own copy. No behavior change there. -
#5522
f913c21- feat: add the in-place refetch contract behindthreads.reloadMainThread(). A runtime opts in withunstable_refetchThreadonThreadRuntimeCore, which an external store supplies through the newExternalStoreAdapter.onRefetchThread(unrelated toonReload, which re-generates an assistant message) and which surfaces asRuntimeCapabilities.refetchThread, reporting which mechanism a call would take rather than whether it does anything. Runtimes that opt in keep their runtime identity, so composer drafts survive and messages stay rendered while the refetch runs; the rest fall back to remounting the runtime hook. Core does not stop a run in progress before calling the capability: doing that meanscancelRun, whose contract is that the user abandoned a send, so it returns the trailing user message to the composer. An implementation owns whatever coordination a concurrent run needs. (@taoche)The remount fallback needs the binder's React key to carry a generation, which changes it from
threadIdto${threadId}:${generation}for everyuseRemoteThreadListRuntimeconsumer rather than only for callers of the new method. One existing behaviour changes with it: astopThreadRuntimefollowed bystartThreadRuntimefor the same id inside a single React commit used to reuse the mounted binder and now remounts it, so that binder no longer carries state from before the stop.No adapter registers the capability yet, so every runtime takes the remount fallback for now.
react-langgraphadoption is #5531 andreact-google-adkis #5528. -
#5537
c868710- fix: keep a settled tool call distinguishable from an unfinished one, so a tool returning false, 0, "" or null no longer loses its result on the cloud round trip and no longer reads as never completed (@okisdev) -
#5479
011e275- fix: read an image's media type from its leading bytes in both adapters (@okisdev)detectImageMediaTypeanddataUrlMediaTypejoinparseDataUrlandisParsableUrlin@assistant-ui/core/internal. AnImageMessagePartcarries no media type, so an adapter that must declare one on the wire now reads it from the payload rather than assuming a format. It never throws, whatever a caller put on the part.react-ai-sdk and react-opencode run the same ladder rung for rung: the attachment's
contentType, then a data URL's declared type when that is itself an image type (read whether or not the payload is base64, so an SVG data URL keeps its type), then the leading bytes, thenimage/png. Previously react-opencode had no byte rung at all, and react-ai-sdk's was skipped for anydata:payload, so a JPEG inside a genericapplication/octet-streamenvelope resolved to png on both.Resolving the label alone was not enough, because a data URL's own media type wins over the declared one downstream. Both adapters now rebuild the envelope when it disagrees with the resolved type and forward it untouched when it agrees. That applies to file parts too, where a
mimeType: "application/pdf"part carrying anapplication/octet-streamenvelope was announced as pdf and delivered as octet-stream. File parts also gain the same three rungs, so an emptymimeTypefalls to the envelope and then toapplication/octet-streamrather than producing a malformeddata:;base64,url;vercelAttachmentAdapteremits exactly that shape for a file the OS cannot type. -
#5485
da32fe0- refactor: share the media type ladder and wire url between adapters (@okisdev)resolveImageMediaType,resolveFileMediaTypeandtoMediaWireUrljoin the data URL helpers in@assistant-ui/core/internal. react-ai-sdk and react-opencode had arrived at identical ladders and an identical wire url builder by construction rather than by sharing code, and they had already drifted apart twice while getting there. Both now call the shared functions and keep only their own part-shape plumbing.No behavior change: both adapters' existing suites pass untouched.
-
#5522
f913c21- feat: addthreads.reloadMainThread()to refetch the open thread's remote state in place (@taoche) -
#5417
5bb2573- fix: suggestion trigger withsendno longer overwrites the composer draft while a run is in progress; on runtimes without queue support it now renders disabled mid-run, matchingComposerPrimitive.Send(@ephraimduncan) -
Updated dependencies [
01140bd,4c313cf,c868710,5ececc1]:- assistant-stream@0.3.32
0.3.3#
Patch Changes#
-
#5419
aa74b0d- fix: enumerate the attachment content fields the aui/v0 encoder persists so per-part status stays out of the stored shape (@okisdev) -
#5403
6e5c450- feat: honour a supplied per-part status while the message is running (@okisdev) -
#5404
59ec21b- fix: keep copied feedback visible for the full duration after repeated copies (@Kinfe123) -
#5410
4fd698b- fix: keep grouped and detached part statuses in sync (@okisdev)
0.3.2#
Patch Changes#
-
#5367
ecd7c87- feat: AuiProvider accepts value={null} as an isolation boundary; useAui runs a fixed hook count per overload and deprecates the explicit-parent config (@Yonom) -
#5230
3ae058c- fix: suppressonThreadIdChangecallbacks for prop-driven thread switches (@Kinfe123) -
#5329
f30b54c- refactor: move createRuntimeExtras to the @assistant-ui/core/react entry and drop the internal re-export (@okisdev) -
#5318
ee87dd9- fix: accept case-insensitivedata:URL schemes and normalize parsed mime types to lowercase (@ShobhitPatra) -
#5220
e41734c- fix: parse zero-byte base64 payloads in parseDataUrl (@ShobhitPatra) -
#5369
8643393- refactor: make Thread client importExternalState required (@Yonom) -
#5312
2eca438- refactor: importuseEffectEventfrom React directly for latest-client reads and drop theuse-effect-eventponyfill dependency (@Yonom) -
Updated dependencies [
936c52c,ee87dd9]:- assistant-stream@0.3.31
0.3.1#
Patch Changes#
-
#5304
1bbaa46- refactor: internal selectors read optional scopes vias.optional.partinstead of guarding onaui.part.source(@Yonom) -
#5295
9aac054- fix: keep replacement runs cancellable after superseded runs settle (@Kinfe123) -
Updated dependencies [
a8cd1c9]:- assistant-stream@0.3.30
0.3.0#
Minor Changes#
-
#5275
9a7e776- feat: property API for aui β nullary scope accessors are now properties (aui.thread.getState()instead ofaui.thread().getState()); calling them still works but is deprecated. Accessors keepsource/query/nameselection metadata as properties; these are reserved names for scope methods. An unavailable scope's accessor no longer throws at selection time:aui.threadalways succeeds and is always truthy,.sourceis null, and any other property read (or a call) throws β check availability viaaui.thread.source != null. Accessor identity is binding-keyed: stable across renders without structural change, new on structural change β memoization keyed on an accessor now invalidates exactly when its binding changes. (@Yonom) -
#5281
2f5d0d4- feat: drop APIs deprecated in v0.12/v0.14 β the legacy context hooks (useAssistantRuntime,useThreadRuntime,useThread,useMessageRuntime,useMessage,useComposerRuntime,useComposer,useMessagePartRuntime,useMessagePart,useAttachmentRuntime,useAttachment,useThreadListItemRuntime,useThreadListItem,useThreadList,useEditComposerand their attachment variants; useuseAui/useAuiState), the component-onlyToolsState.toolsmap (usetoolUIs), and the"mcp-app"group key ingroupPartByType(use"standalone-tool-call"). See the v0.15 migration guide. (@Yonom)
Patch Changes#
-
#5282
ae5f831- feat:getClientId(client)returns an opaque, WeakMap-legal identity for a bound client β the same object regardless of accessor wrapping depth. The cloud message persistence cache is now keyed on it instead of the per-mount accessor proxy. RemovesunwrapClientAccessorandgetBoundClient(introduced and replaced pre-release, never published). (@Yonom) -
#5279
a196711- fix: cloud history adapter resolves the aui client at call time instead of capturing the client from the first render (@Yonom) -
#5270
dcc41bb- feat: render-bound immutable aui instances β derived scopes resolve to client instances during render and are frozen into the returned client; structural swaps produce a new client through React while value updates never change client identity. Removes the PartByIndexProvider lastPartRef guards and the useClientLookup stale-index clamp. (@Yonom) -
Updated dependencies [
9a7e776,ae5f831,f78e579,dcc41bb]:- @assistant-ui/store@0.3.0
- assistant-stream@0.3.29
0.2.23#
Patch Changes#
-
#5202
6225d6a- fix: abort pending AssistantFrame tool calls when their run is cancelled (@Kinfe123) -
#5262
801781c- Restore the MessageRepository duplicate-id throw (it detects internal corruption); duplicate ids in an external-store messages array are now deduped at ingestion with a warning, keeping the last occurrence. (@Yonom) -
#5250
d4bdf2c- Warn instead of throw on recoverable inconsistencies: duplicate same-priority tool registrations merge with the latest registration taking precedence, duplicate message ids skip linking, stale client lookup indices are clamped, and null tool names in tool result messages are tolerated. (@Yonom) -
#5208
a0ddc86- AdopterasableSyntaxOnly; public enums are nowas constobjects. (@Yonom) -
#5256
cee74f1- fix: ExternalThread validates the adapter accept string on every addAttachment entry point (@Yonom) -
#5237
cf839ff- feat: ExternalThread props for assistant-transport (isLoading, state, extras, onResume, onAddToolResult, onLoadExternalState, onResumeToolCall, attachmentAdapter; importExternalState); export ToolInvocationTracker from core internal; composer parentId, draft-restore, and part-status fixes (@Yonom) -
#5116
396ea1f- fix(core): persist LocalRuntime runs paused for tool approval (@serhiizghama) -
#5231
e1f27d8- fix(core): preserve thread-list position when switchToThread's on-demand fetch settles after a concurrent list() (@rupic-app) -
#5224
3e8f59e- fix: avoid reloading Cloud thread lists on unchanged runtime rerenders (@Kinfe123) -
#5263
06f5266- Same-priority duplicate tool registrations throw again. TheTooltype gains an optionaloverwriteflag (discouraged escape hatch) that lets a later registration silently replace a same-priority tool of the same name; the flag is stripped from the merged output. (@Yonom) -
Updated dependencies [
f9c1b0f,235c17e,a0ddc86,06f5266,d319637]:- assistant-stream@0.3.28
0.2.22#
Patch Changes#
-
#5089
908ec91- fix: avoid reporting copy success without a clipboard handler (@Kinfe123) -
#5126
0d0834d- fix: refresh Cloud history persistence when the Cloud client changes (@Kinfe123) -
#5163
3355098- fix: restrict AssistantFrame provider messages to the parent window (@Kinfe123) -
#5066
79034bb- fix: settle thread runtime starts when stopped before mounting (@Kinfe123) -
#5137
7207b19- fix: isolate speech synthesis listener failures (@Kinfe123) -
#5090
b17d392- fix: mark a cancelled local runtime run incomplete when the adapter returns without throwing (@VihaanAgarwal) -
#5091
20643e2- fix nested message runtime path references (@Kinfe123) -
#5028
afacb10- test: verify compiler-sensitive hooks against the built package (@Kinfe123) -
#5088
af6c945- fix: preserve falsy runtime state values (@Kinfe123) -
#5132
33924df- fix: stop auto-submitting a parse-error tool result when divergent argsText closes without a backend result (@rupic-app) -
#5067
19cfdcd- fix: detect removed keys in shallow memoized state (@Kinfe123) -
#5057
044def8- fix: preserve the latest thread selection when switches finish out of order (@Kinfe123) -
#5097
039b75f- fix: support attachments without relying on a global File constructor (@Kinfe123) -
#5112
fc6b4ad- fix: keep composer attachments visible while their upload is in flight (@serhiizghama) -
#4847
121ee83- fix: preserve concurrent local thread metadata and history writes (@Kinfe123) -
#4958
2b2587a- fix: preserve optimistic updates in invocation order (@Kinfe123) -
#4981
ca80153- fix: handle failed composer append tasks (@Kinfe123) -
#5081
e4ce1a2- fix: reject pending AssistantFrame tool calls when the host is disposed (@Kinfe123) -
#5117
f2f5e83- fix: handle failed local history loads (@Kinfe123) -
#5177
ec8ee6a- fix: isolate public runtime event subscribers (@Gujiassh) -
#5107
666aaab- fix: prioritize backend tool results over stale argument parse errors (@Solaris-star) -
#5078
c1b1750- fix: isolate realtime voice session listener errors (@Kinfe123) -
#5113
f263c9e- fix: apply pending mute state after voice session setup (@Kinfe123) -
#5034
475fca3- fix: allow omitting externalId in RemoteThreadInitializeResponse (@darreleng) -
#5039
8faad07- refactor: share parseDataUrl and httpUrlPattern from core internal (@ShobhitPatra) -
#5127
61518b9- fix: keep derived part scopes stable while removed parts unmount (@Kinfe123) -
#5120
1eb7275- fix: generate Cloud attachment IDs without requiring Web Crypto (@Kinfe123) -
#5171
c47bdf4- fix: isolate composer runtime event listener errors (@rupic-app) -
#5144
de54334- fix: isolate thread runtime event listener errors (@Kinfe123) -
#5122
2f69f68- fix: preserve metadata.isOptimistic on user messages in fromThreadMessageLike (@ShobhitPatra) -
Updated dependencies [
8630186,446a118,a081656,25a5be0,47562fd,5e4dd9f,5da0d93,85d4976,5135400,9a343db,666aaab,ba948d8,44aac58,9402648,4651ea5,2bc6798]:- assistant-stream@0.3.27
0.2.21#
Patch Changes#
-
#4728
2aca5e0- feat: surface the upload failure reason on failed attachment status (@ShobhitPatra) -
#4961
908af6d- fix(core): accept application/json text attachments and parameterized MIME types (@Kinfe123) -
#4722
1b46551- fix(core): log the swallowed CloudFileAttachmentAdapter upload error instead of discarding it (@ShobhitPatra) -
#4714
7865f67- fix(core): CloudFileAttachmentAdapter now fails uploads that return an HTTP error status instead of attaching a dead link (@ShobhitPatra) -
#4754
438ecd3- fix: preserve user attachments in Cloud history (@Kinfe123) -
#4715
5a34e8c- fix: restore composer text and attachments when an attachment upload fails during send (@ShobhitPatra) -
#4971
5dbbac4- refactor: host the shared JSON type guards in @assistant-ui/core/internal (@okisdev) -
#4704
d3bd0ed- fix: re-convert cached messages when the converter callback or metadata changes, and re-parent children of skipped optimistic messages in repository export (@samdickson22) -
#4842
84e8ddf- feat: AssistantError taxonomy with severity and display metadata propagated through run error status. behavior note: local runtime run failures now store a structured AssistantError object in message status.error instead of a plain string; useMessageError keeps returning a human-readable string for both shapes, and code reading status.error directly should use isAssistantError or toAssistantError (@okisdev) -
#4833
8282269- feat: createSuggestionAdapter factory and AbortSignal forwarding for suggestion generation (@okisdev) -
#4662
03ffe44- feat: infer tool argument types from Standard Schema parameters (@Kinfe123) -
#4954
77c7b26- fix: stop isJSONArray from consuming the array index as recursion depth (@ShobhitPatra) -
#4969
026a7ae- fix: resume the local runtime when a human tool returns a falsy result (@serhiizghama) -
#4741
160b0af- fix: ignore malformed local thread storage (@Kinfe123) -
#4675
c814c9c- feat: support prefixed MCP toolkit tool names (@Kinfe123) -
#4665
6be3b67- feat: support disabled MCP toolkit entries (@Kinfe123) -
#4667
c590a21- feat: support disabled MCP toolkit tools (@Kinfe123) -
#4898
a84cf6d- feat: plumb an optional serverId through MCP Apps metadata and host calls for multi-MCP routing (@okisdev) -
#4806
9f99c46- feat: preserve providerMetadata on text, reasoning, and tool-call message parts (@DLOVRIC2)The AI SDK message converter already kept
providerMetadataon source parts but
dropped it on text, reasoning, and tool-call parts (where the AI SDK surfaces it
ascallProviderMetadata). Provider- or app-scoped metadata such as agent
attribution now survives the conversion to assistant-ui messages. -
#4650
e3aba86- fix: make the default attachment adapter work without FileReader (Node, react-ink, SSR) by sharing a single getFileDataURL from @assistant-ui/core/internal, whose base64 fallback chunks large inputs and works on runtimes without Buffer (@ShobhitPatra) -
#4901
25f9eb2- refactor: host the streaming-stable tool-args stringifier in @assistant-ui/core/internal (@ShobhitPatra) -
#4744
ef81c86- fix: include thread ids in thread list runtime errors (@Kinfe123) -
#4943
5ade3a5- fix: keep tool-args key-order caches independent for keys containing dots or brackets (@okisdev) -
#4956
1f284ac- fix: generate unique IDs for built-in file attachments (@Kinfe123) -
#4957
65ba32a- fix: complete unsupported title generation streams (@Kinfe123) -
Updated dependencies [
43b8ce8,1e926b6,d6c7571,4d7a447,ca751f4,38bf104,19b2a00,0686f4e,c2d2271,84e8ddf,d03e5cf,5325f09]:- assistant-stream@0.3.26
0.2.20#
Patch Changes#
-
#4653
523e0b5- fix: skip malformed generative UI component nodes (@Kinfe123) -
Updated dependencies [
f833bc1]:- assistant-stream@0.3.25
0.2.19#
Patch Changes#
-
#4497
ddc40b7- fix: tolerate reasoning and image content blocks that omit their declared fields (@okisdev) -
#4466
ea52de0- refactor: add an internal createRuntimeExtras helper shared by external-store adapter authors (@okisdev) -
#4548
29c6fdb- feat(core): add shared client-side streaming timing primitive (useStreamingTiming+ purestepStreamingTiming) (@okisdev) -
#4543
d0987a3- external-store: addunstable_onBranchChangeadapter callback that fires on explicitswitchToBranch, emitting the canonical (persisted) head and visible message ids, deduped by head (@AVGVSTVS96) -
#4310
0c51b90- feat: addunstable_interactables API; restore and deprecate the previous interactables API (@AVGVSTVS96)The redesigned interactables API is now available as an additive
unstable_*surface for building editable, in-message UI while preserving the existing stable API for compatibility.unstable_useInteractable(name, config)registers an interactable and returns its state plus methods in one hook.- Each unstable interactable name gets one stable
update_{name}tool. When multiple instances share a name, the tool targets an instance byid. - Thread-scoped interactables rendered inside message parts expose
version, including the state for that message, whether it is the latest tool-driven version, andrestore(). - Added
unstable_interactableTool(...)for defining a creating tool and its in-message render UI together. - Added
unstable_useInteractableVersions(id, name)for version history UIs. - Persistence adapters can now provide
load()and be passed directly tounstable_Interactables({ persistence }).
The previous
useAssistantInteractable/useInteractableState/InteractablesAPI remains available unchanged and is marked deprecated. Existing apps do not need to migrate immediately.Migration notes for the unstable API:
- const id = useAssistantInteractable("taskBoard", config); - const [state, { setState }] = useInteractableState(id, initialState); + const [state, { id, setState }] = unstable_useInteractable("taskBoard", config);- Use
unstable_interactables: unstable_Interactables()when registering the unstable scope. unstable_useInteractableState(id)is intended for secondary readers and returnsundefineduntil the owner registers.- The unstable API uses per-name update tools (
update_{name}) with anidparameter instead of legacy per-instance tools (update_{name}_{id}). - A top-level
idfield instateSchemais reserved for instance addressing. Rename domain state fields toitemId,recordId, etc. if the model should edit them. - Model selection should be represented as ordinary state in the unstable API; the legacy
selectedregistration prop andsetSelectedmethod remain available on the deprecated stable API.
-
#4482
3a8f685- feat: addonThreadIdChangeto the remote thread list runtime sothreadIdcan be used as a managed/controlled value (e.g. synced to a URL). Only the settled remote ID is emitted; the transient optimistic local ID is never surfaced. (@Yonom) -
#4567
ec6adf4- fix: make PartPrimitive.Messages props a discriminated union so rendering with neither components nor children is a compile error (@ephraimduncan) -
#4542
4acd4c0- add unstable id-keyed thread message rendering APIs for virtualized and custom message lists.unstable_useThreadMessageIds()returns the thread's message ids (stable array identity across content-only updates), andThreadPrimitive.Unstable_MessageByIdrenders a single message by id with the same component surface asMessageByIndex. A missing or removed id rendersnullinstead of throwing. (@AVGVSTVS96) -
Updated dependencies [
cefcf27]:- assistant-stream@0.3.24
0.2.18#
Patch Changes#
-
#4426
68dfbaa- chore: markgenerateIdandfromThreadMessageLikeas experimental (@okisdev)these two utilities became public in #4414. they now carry an
@deprecatedJSDoc noting the API is experimental and may change without notice, matching how the other unstable public utilities (e.g.bindExternalStoreMessage) are flagged. the distribution packages (@assistant-ui/react,@assistant-ui/react-native,@assistant-ui/react-ink) re-export them, so the annotation lands in their published types too. -
#4420
fe24ad6- feat(react-ag-ui): apply external state fromThreadHistoryAdapter.load()(@dkachur1)onSwitchToThreadalready applies returnedstatevialoadExternalState, but the historyload()path did not, so state restored on a fresh page load was dropped.ThreadHistoryAdapter.load()may now return an optionalstate, andAgUiThreadRuntimeCoreapplies it β making both load paths symmetric.
0.2.17#
Patch Changes#
-
#4414
344f737- feat: exportfromThreadMessageLikeandgenerateIdfrom the public API (@okisdev)these two utilities were only reachable via
@assistant-ui/core/internal, so materializing aThreadMessageLikeinto aThreadMessage, or generating an id for a hand-built message, meant reaching into internals (the first-party ag-ui and a2a runtimes already did). they are now exported from@assistant-ui/core,@assistant-ui/react,@assistant-ui/react-native, and@assistant-ui/react-ink. also removes the now-redundant duplicate listing of both from the unstableINTERNALnamespace (the one in-repo consumer, the with-ffmpeg example, now uses the public export). -
#4415
a2e21ee- perf: sync the external-storemessageRepositoryincrementally instead of clear()+import() (@okisdev)when an
ExternalStoreAdapterdrives the thread viamessageRepository, each update tore the whole repository down (clear()) and rebuilt it from scratch (import()). it now diffs against the current repository (add or update incoming messages, delete the ones no longer present), so unchanged messages keep their existing per-message repository state instead of being recreated, and short-circuits when onlyisRunningflips on an unchanged repository reference. behavior is unchanged; this removes the teardown/rebuild churn on high-frequency streaming that previously pushed consumers to subclass the runtime core.
0.2.16#
Patch Changes#
-
#4392
4cc7eaa- chore: update peer and dependency ranges for @assistant-ui/tap 0.9 (@Yonom) -
Updated dependencies [
434bba5]:- assistant-stream@0.3.23
0.2.15#
Patch Changes#
-
#4367
c207bcd- feat: add reasoningEffort to LanguageModelConfig (@AVGVSTVS96) -
#4385
ae59baf- feat: precompile packages with React Compiler (@Yonom)- aui-build runs React Compiler over packages that depend on tap and remaps
react/compiler-runtimeto the tap shim subpath, so compiled hooks and components work both in React components and inside tap resource renders @assistant-ui/tap/react-shimexportsuseMemoCache(tap inside a resource render,React.__COMPILER_RUNTIME.cotherwise, with a React 18 polyfill); new@assistant-ui/tap/react-shim/compiler-runtimesubpath mirrorsreact/compiler-runtime'scexport- tap implements
useSyncExternalStoreand a no-opuseDebugValue;useSubscribablenow builds onuseSyncExternalStoreso its store reads stay visible to the compiler AssistantProviderBaseopts out via"use no memo"because the runtime receives options through an effect inside a re-rendered child element
- aui-build runs React Compiler over packages that depend on tap and remaps
-
#4378
4583ca7- feat: approval options vocabulary on tool approvals.ToolCallMessagePart.approvalgains request-suppliedoptions(machine-readable kinds allow-once / allow-always / reject-once / reject-always, open to_-prefixed custom kinds), a recordedoptionId, and a terminalresolution("cancelled" | "expired") for non-decision outcomes.respondToApprovaladditionally accepts{ optionId }, resolved in core against the option's kind; custom kinds require an explicitapproved.ExternalThreadgains anonRespondToToolApprovalcallback. The kit approval bar renders supplied options with an opt-in confirmation step showing the grants an option would persist. Persistence stays host-owned. (@okisdev) -
#4379
94cc028- feat: per-tool-call timing and stall detection.ToolCallMessagePartgains atimingfield ({ startedAt, completedAt? }in epoch ms), auto-populated by the assistant-stream accumulator at part start and result, and accepted onThreadMessageLikefor external-store hosts. NewuseToolCallElapsed()hook returns the call's elapsed milliseconds, ticking once per second while running;unstable_useMessageStallDetection({ thresholdMs })reports mid-run output stalls by watching a message content fingerprint. The kitToolFallbacktrigger renders the duration when timing is present. (@okisdev) -
Updated dependencies [
94cc028]:- assistant-stream@0.3.22
0.2.14#
Patch Changes#
-
#4340
ab8e5bc- fix: exclude reasoning parts from copied message text (@serhiizghama)getCopyTextfiltered parts with"text" in part, which also matchedreasoningparts (they carry atextfield), leaking the model's chain-of-thought into the clipboard. Both copy paths now delegate to the canonicalgetThreadMessageText, so copy returns onlytype: "text"content β consistent with the rest of the runtime. -
#4359
59d252f- feat: branch switching for the ExternalThread client (@okisdev)ExternalThreadaccepts an optionalbranchesadapter (ExternalThreadBranchAdapterin@assistant-ui/core, re-exported from@assistant-ui/react):getBranches(messageId)returns ordered sibling branch ids andswitchToBranch(branchId)makes a sibling visible by swapping themessagesarray. messages with more than one sibling get realbranchNumber/branchCount, which is what shows the branch picker;capabilities.switchToBranchis set for parity with the legacy external store. without the adapter, behavior is unchanged. -
#4347
feecac3- feat: support tool approvals on the local runtime (@okisdev)LocalRuntime.respondToToolApprovalpreviously threw "Local runtime does not support tool approvals". the local runtime now implements the approval gate natively, treating theChatModelAdapteras the server side of the protocol: the adapter emitsapproval: { id }on a tool call part and ends the run withrequires-action. a pending approval pauses the run (previouslyshouldContinueignored approvals, so an unlisted tool call carrying one re-invoked the adapter in a loop). denying records the decision and synthesizes an error result ({ error: reason || "Tool approval denied" }withisError: true, matching the AI SDK v6 denial shape); approving records the decision and resumes the run once every gate on the message is decided, with the decisions readable viaunstable_getMessage(). tool calls carrying an approval are exempt from theunstable_humanToolNamesresult requirement, and a gated call that receives a result viaaddToolResultcounts as resolved, so neither combination deadlocks.resumed runs (from
respondToToolApprovalandaddToolResultalike) now go through the same run loop asstartRun: they continue multi-step turns instead of stalling after one roundtrip, emitrunStart/runEndevents, mark the message queue busy so a concurrent send no longer aborts the in-flight roundtrip, and regenerate suggestions on completion.addToolResultalso notifies subscribers when it records a result without resuming.resumeToolCallstill throws, now with an error that points at the supported alternatives, and theunstable_humanToolNamesJSDoc no longer describes the pause as an approval (#4339). -
#4325
5a4f20e- chore: update @assistant-ui/tap dependency ranges to ^0.7.0 (@Yonom) -
#4328
f10b8ae- feat: exposelastMessageAton thread list items, populated from the cloud thread list adapter (@okisdev) -
#4351
1fb5862- fix: stable identity for grouped message parts across reorders (@okisdev)tool groups (and chain-of-thought groups) in
MessagePrimitive.Partsand group nodes inMessagePrimitive.GroupedPartsare now keyed by the id of their first part (toolCallId) instead of their positional index, and tool parts inside a group are keyed by their own id. when a message's parts array re-orders between live streaming and the settled shape, group and part React identity now survives the re-slice, so collapse/open state no longer resets. groups whose first part has no id keep their structural key, and duplicate ids fall back to structural keys, so keys stay unique.
0.2.13#
Patch Changes#
-
#4315
60ef0e9- feat: add runtime support for deleting messages (@Yonom) -
#4318
1b6a0d6- feat(tap): resources carry all hook arguments; elements are{ hook, args }(@Yonom)A
ResourceElementis now{ hook, args }(was{ type, props }): the underlying hook plus the full tuple of arguments to call it with. This lets a resource take multiple positional arguments, exactly like a hook, and makes hosting justhook(...args):const usePair = (a: number, b: string) => ({ a, b }); const Pair = resource(usePair); const element = Pair(1, "hi"); // { hook: usePair, args: [1, "hi"] }The single-object case is unchanged ergonomically (
Counter({ initialValue: 0 })still works; itsargsis just[{ initialValue: 0 }]), so existing resources and call sites are unaffected.resource()'s overloads collapse into one variadic signature, and thefnSymbol/callResourceFnindirection is gone (the element holds the hook directly;renderResourceFibercallsfiber.hook(...args)).Breaking (internal/advanced):
- The second type parameter of
Resource/ResourceElement/ContravariantResourcenow means the argument tupleA extends readonly unknown[]rather than a single payloadP. Explicit two-arg annotations must wrap the payload in a tuple (e.g.ResourceElement<R, [Props]>). - A resource's identity is now its hook. Reading
element.propsbecomeselement.args[0]; readingelement.typebecomeselement.hook.attachTransformScopesis now keyed by (and called with) the hook rather than the factory. useResource(element, deps)'s second arg is unchanged in behavior (renamedargsDeps).
- The second type parameter of
-
#4318
1b6a0d6- refactor: adopt the extracted-hook convention for resources (@Yonom)A resource body is a hook, so resources are now authored as a
use-prefixed hook
wrapped withresource():const useCounter = () => { ... }; const Counter = resource(useCounter);resource()turns a hook into a Resource;useResource(Counter(props))turns it
back into a hook call. Extracting the body to ause-prefixed hook lets React's
stock rules-of-hooks and exhaustive-deps lint resource bodies directly. No
public API or runtime behavior changes.
0.2.12#
Patch Changes#
- Updated dependencies:
- @assistant-ui/tap@0.6.1
0.2.11#
Patch Changes#
-
#4271
2a84174- feat: exposejoinStrategyonuseAISDKRuntime/useChatRuntime(@okisdev)the new AI SDK runtime always merged consecutive
role: "assistant"UIMessages into a single rendered turn, with no supported way to opt out (the converter acceptsjoinStrategybut the runtime never forwarded it, andAISDKMessageConverteris not exported). this follows up on #1633, where the same knob shipped on the legacyuseVercelUseChatRuntimeasunstable_joinStrategy. passjoinStrategy: "none"to keep proactive or history loaded consecutive assistant messages as separate turns.core now exports a shared
JoinStrategytype so the"concat-content" | "none"union has a single source of truth across the converter and the runtimes. -
#4255
a0a0769- feat: check the generative compiler version against the core package compatibility range (@Yonom) -
#4260
19c5b5f- fix: make defineToolkit usable for plain runtime toolkits (@Yonom) -
#4246
dbdfb15- feat: message queuing for external-store, langgraph, and local runtimes (@okisdev)the composer can now stay usable while a run is in progress: a message sent during a run is held in
composer.queue(rendered viaComposerPrimitive.Queue/QueueItemPrimitive.*) and processed once the run settles. external-store adapters opt in by providing aqueueadapter (typically built with the newcreateMessageQueuehelper);useLangGraphRuntimeanduseLocalRuntimeopt in viaunstable_enableMessageQueue.ExternalThreadQueueAdapternow lives in@assistant-ui/core(still re-exported from@assistant-ui/react). -
#4249
ca191dc- feat: add externalTool for render-only generative toolkit entries (@Yonom) -
#4256
44ff4bf- feat: rename hitlTool to humanTool while keeping deprecated compatibility aliases (@Yonom) -
#4245
26a365b- fix: makeSimpleTextAttachmentAdapterandSimpleImageAttachmentAdapterwork withoutFileReader. they read files via the browser onlyFileReader, so sending an attachment in a non browser runtime (e.g.@assistant-ui/react-inkin a terminal) threwReferenceError: FileReader is not defined. the adapters now feature detect: they keep usingFileReaderwhen it exists (browser, and React Native whose Blob polyfill provides it) and fall back tofile.text()/file.arrayBuffer()in Node. output is byte identical across all three environments, so@assistant-ui/react,@assistant-ui/react-native, and@assistant-ui/react-inkall keep re-exporting the same core implementation. (@ShobhitPatra) -
Updated dependencies [
15878d8]:- assistant-stream@0.3.21
0.2.10#
Patch Changes#
-
#4234
4145caa- fix: inferdefineToolkitstreamCall argument readers from Standard Schema parameters (@Yonom) -
#4212
5fe118d- feat: add MCP server support to generative toolkits (@Yonom) -
#4213
dcd5897- feat: add provider-executed tool support to generative toolkits (@Yonom) -
#4208
0558db2- feat: addupdateCustomto thread list runtimes, adapters, and clients (@okisdev) -
#4214
69540af- feat: add renderText helpers for tool call status text (@Yonom) -
#4199
d9b3119- feat: adefineToolkitentry may now be an already-formedToolDefinition(carrying its owntype), not only an inline definition whosetypethe compiler infers. This is what lets a factory likenew JSONGenerativeUI({ library }).present()be used directly as a tool. (@Yonom)Renames the authoring types to match
defineToolkit:ToolkitDeclarationβToolkitDefinition, and addsToolkitDefinitionEntry(the union of an inline tool definition and a pre-formedToolDefinition). The per-tool inline type is now an internalToolkitDefinitionInputand is no longer exported. -
#4236
ae54c55- feat: addstubTool()and experimentaluseAuiToolOverrides()for locally executed generative toolkit tools (@Yonom) -
#4235
7640b31- Deprecate component tool registration APIs in favor of toolkit registrations. (@Yonom) -
Updated dependencies [
cba2b42,58f80e0,78ff336,5fe118d,dcd5897,ae54c55]:- assistant-stream@0.3.20
- assistant-cloud@0.1.31
- @assistant-ui/store@0.2.13
- @assistant-ui/tap@0.5.14
0.2.9#
Patch Changes#
-
#4176
27ae936- feat: add theToolkitDeclaration/ToolkitDeclarationDefinitiontypes for authoring a toolkit permissively (a backend tool may declaredescription/parameters/execute); the canonicalToolkitkeeps those fields erased. Author withdefineToolkit()from@assistant-ui/react, which the"use generative"compiler strips per build. (@Yonom) -
#4176
27ae936- feat: move thedefineToolkitandhitluse-generative markers from@assistant-ui/nextinto@assistant-ui/core/react, so they ship once from every distribution (@assistant-ui/react,@assistant-ui/react-native,@assistant-ui/react-ink) and stay portable across build targets. Import them from@assistant-ui/reactinstead of@assistant-ui/next; they remain no-op markers stripped at build time by a"use generative"compiler. (@Yonom) -
Updated dependencies [
27ae936]:- assistant-stream@0.3.19
0.2.8#
Patch Changes#
-
#4172
1315789- feat: add theToolkitDeclaration/ToolkitDeclarationDefinitiontypes for authoring a toolkit permissively (a backend tool may declaredescription/parameters/execute); the canonicalToolkitkeeps those fields erased. Author withdefineToolkit()from@assistant-ui/next, which the"use generative"compiler strips per build. (@Yonom) -
#4151
299d448- chore: drop stalebiome-ignorepragmas now that the repo lints with oxlint (@okisdev) -
#4136
4429aa3- centralize thread-level shared options forwarding across runtime wrapper hooks. follow-up to #4135. (@okisdev)new public exports from
@assistant-ui/core(re-exported from@assistant-ui/react):ExternalStoreSharedOptions, a typedPickoverExternalStoreAdaptercovering the four thread-level optional fields every wrapper forwards:isDisabled,isSendDisabled,unstable_capabilities,suggestions.pickExternalStoreSharedOptions(options), plucks those four fields from a wider options object. the body usessatisfies Required<...>so adding a key to the type without copying it in the function is a compile error rather than a silent missing-field bug.useExternalStoreSharedOptions(options)(from@assistant-ui/core/react), a memoized variant for wrappers that wrap their store inuseMemo. lets the wrapper list a single stablesharedreference as a dep instead of enumerating the four fields. samesatisfiesguard internally so the destructure stays in sync with the type.
internal: every runtime wrapper hook (
useChatRuntime,useAISDKRuntime,useLangGraphRuntime,useA2ARuntime,useAgUiRuntime,useAdkRuntime,useStreamRuntime,useOpenCodeRuntime) now uses these helpers instead of inlining the conditional spreads added in #4135. each wrapper sheds 20 to 40 lines of duplicated declarations and conditional spreads; future additions to the shared option set propagate through a single edit inpickExternalStoreSharedOptionsinstead of touching every wrapper. no user-facing behavior change. -
#4160
e76611f- feat: addindicatorsupport toMessagePrimitive.GroupedParts. (@Yonom)Restores loading-state handling that was dropped from the grouped renderer.
GroupedPartsnow emits a synthetic{ part: { type: "indicator" } }render call you handle withcase "indicator"in yourswitch (part.type)β render a "thinkingβ¦" dot or any loading affordance.- The indicator is only ever emitted while the message is running, so its presence alone means "render loading UI here" β there's no
statusto branch on. - New
indicatorprop restricts which running states qualify:"never","empty"(no parts yet),"no-text"(default β last part isn'ttext/reasoning, e.g. the model ended on a tool call), or"always"(any running state).
- The indicator is only ever emitted while the message is running, so its presence alone means "render loading UI here" β there's no
-
#4161
76f7d16- perf: memoize theRuntimeAdapterProvidercontext value so adapter consumers no longer re-render on every parent render whenadaptersis stable. (@Yonom) -
#4162
eef724e- fix: drop phantom sibling messages when an external store swaps an optimistic message id mid-run (#4037). (@Yonom)Messages can now be flagged
metadata.isOptimistic. Optimistic messages are treated as ephemeral: they only ever live on the current head branch (the repository evicts off-branch optimistic messages whenever the head moves) and they are never written to persisted state (export()omits them). The AI SDK v6 adapter flags the streaming assistant message as optimistic, so when its client-generated id is replaced by a server-provided one mid-run, the stale placeholder no longer lingers as a phantom branch (e.g.BranchPickershowing2/2on a turn the user never branched). Unlike the reverted blanket id-diff (#4040), only explicitly-optimistic messages are affected, so legitimateonEdit/onReload/switchToBranchbranches are preserved. -
#4167
fcb6baf- feat: add adisplaypresentation hint to tools and a"standalone-tool-call"key togroupPartByType. (@Yonom)Tool UIs fall into three buckets: prompting the user (human-in-the-loop), informing the user (generative UI), and traces of what the model is doing (routine frontend/backend tool calls). The first two should be surfaced on their own; the last belongs folded into the chain-of-thought trace. The new
displayfield on a tool lets you place a tool in the right bucket without overloadingtype:const toolkit = { ask_user: { type: "human", render: AskUI }, // standalone (forced β can't opt out) search_web: { type: "frontend", render: SearchUI }, // inline trace (default) checkout: { type: "frontend", render: CheckoutUI, display: "standalone", // opt in }, } satisfies Toolkit;display?: "standalone" | "inline"is a client-only presentation hint (it never reaches the model). Defaults to"inline".humantools are always"standalone"and cannot opt out (the type only allows"standalone"). MCP-app tool calls and the built-in generative-UI tool are standalone too. Every other tool defaults to inline and opts in explicitly.groupPartByTypegains a synthetic"standalone-tool-call"key that matches all of the above.MessagePrimitive.GroupedPartspasses the live tool-UI registry to thegroupByfunction as a secondcontextargument ({ toolUIs }), and the helper reads it to resolve the registry-driven cases; MCP-app calls are detected from the part alone.- The
"mcp-app"key ongroupPartByTypeis deprecated in favor of"standalone-tool-call"(a superset). It still works for back-compat.
The shadcn
thread.tsxtemplate is updated to use"standalone-tool-call": []in place of"mcp-app": []. -
Updated dependencies [
1315789,299d448,2dec3ae,fcb6baf,c4d3eea,331f2f7]:- assistant-stream@0.3.18
- @assistant-ui/store@0.2.13
- @assistant-ui/tap@0.5.14
- assistant-cloud@0.1.30
0.2.7#
Patch Changes#
-
#4121
7395092- feat: detect and diagnose duplicate@assistant-ui/coreinstalls (@Yonom)- In dev mode (
NODE_ENV !== "production"),@assistant-ui/corenow emits a singleconsole.warnwhen it detects a second copy of itself loaded into the same JavaScript runtime. Mismatched transitive versions are a common source of subtle bugs (lost tool registrations, broken context lookups, failedinstanceofchecks β see issue #4101). The warning points users atnpx assistant-ui doctor. - New
assistant-ui doctorCLI command. It walksnode_modulesrecursively (including nested copies), surfaces every duplicate version of any@assistant-ui/*,assistant-streamorassistant-cloudpackage, queries the npm registry for the latest versions and reports outdated installs. Use--no-networkto skip the registry check.
- In dev mode (
-
#4118
a6e0653- feat(core): build a client-side tool-invocations pipeline directly intouseExternalStoreRuntime. Tool-call parts in messages now firestreamCall/executeautomatically for any external-store runtime that opts in. Opt in per-adapter viaunstable_enableToolInvocations: true(off by default β most external-store runtimes either run tools server-side or already wire their own client-side dispatch path; double-firing is the risk). The_store.isLoadingflag signals when initial history is loaded: snapshots observed whileisLoading === trueare treated as historical (no fire), matching the contract that callers likeimportExternalStatealready rely on. Six in-tree runtimes (useAssistantTransportRuntime,useAISDKRuntime,useLangGraphRuntime,useStreamRuntime,useAgUiRuntime,useAdkRuntime) are migrated to the embedded tracker; the standaloneuseToolInvocationsReact hook is removed. AddsExternalStoreAdapter.setToolStatusesso adapters can mirror the tracker's per-tool-call status into local React state for converter metadata. Auto-aborts in-flight tool calls on new turns (append()withstartRun,startRun()) so a tool that finishes after the user moves on can no longer feed a stale result into the next turn. (@Yonom) -
Updated dependencies [
cabfc71]:- @assistant-ui/tap@0.5.13
- @assistant-ui/store@0.2.12
0.2.6#
Patch Changes#
-
#4120
372d4f0- feat: simplifyMessagePrimitive.GroupedPartsAPI and addgroupPartByTypehelper. (@Yonom)- New
groupPartByType({ ... })helper builds agroupByfrom apart.type β group-key pathlookup. The map keys are typed againstPartState["type"](autocomplete + typo rejection), missing keys leave the part ungrouped, and the returned function carries an internal memo fingerprint so the tree survives unrelated re-renders even when reconstructed inline. - Special map key
"mcp-app"matches tool-call parts that point at an assistant-ui MCP app resource (ui://...). It takes precedence over the"tool-call"entry for those parts, so MCP apps can be routed separately (e.g. rendered outside a chain-of-thought wrapper). groupBysignature simplified from(part, index, parts) => string | string[] | null | undefinedto(part) => readonly \group-${string}`[] | null. The 2nd/3rd args were unused in practice. Arrays are required (no bare-string shorthand);nullis accepted as an alias for[]` to soften the migration.- Internal memoization now uses the helper's memo fingerprint when present, otherwise rebuilds the tree per render (O(n), cheap). The previous "pass a stable reference" advice is dropped β inline
groupByis fine. - Docs and examples updated to lead with
groupPartByType. ThegetMcpAppFromToolPartbranch inpackages/uiswitches to"mcp-app": []via the helper.
- New
-
#4107
32ae846- feat: surface AI SDK v6 tool approvals as a first-classrespondToApprovalprop on tool components. tool-call parts in theapproval-requestedstate now carrypart.approval = { id, isAutomatic? }; tool components callrespondToApproval({ approved, reason? })to ack the gate without threadingchatHelpersthrough application context. also fixes a transientrequires-actionflicker for theapproval-respondedstate and tightens the external-message converter so interrupt vs pending tool calls are distinguished by an actualinterrupt/approvalfield rather than byresult === undefined. (@okisdev) -
Updated dependencies [
d4f1db4]:- assistant-stream@0.3.17
0.2.5#
Patch Changes#
-
#3967
0a0c306- feat(core, react): addMessagePrimitive.GenerativeUIprimitive (@samdickson22)A new first-class primitive for rendering agent-described React UI from a JSON
spec, with a consumer-provided component allowlist as the security boundary.The agent emits a new
generative-uimessage part containing a tree of
components by name;MessagePrimitive.GenerativeUIwalks the spec and resolves
each name against the registry you pass in. Unknown names throw a typed
GenerativeUIRenderError(or invoke the optionalFallback). Composes with
MessagePrimitive.Partsvia the newcomponents.generativeUIoption, and
supports streaming partial specs.<MessagePrimitive.Parts components={{ generativeUI: { components: { Card, Button } }, }} /> -
#3651
6a0ecb2- feat(react-ink): add file storage adapter (@ShobhitPatra) -
#4072
e4634a5- fix(core): replay the latchedinitializethread event to late subscribers.ensureInitializedemitsinitializeonce during construction, so a runtime seeded with non-emptymessages(e.g.useChatRuntime({ messages })underuseRemoteThreadListRuntime) fired it before the title binder's effect subscribed, and therunEndβgenerateTitlewiring was never installed.unstable_on("initialize", ...)now schedules a one-off replay (on a microtask, re-checking the subscription) when the thread has already initialized, mirroring a BehaviorSubject, so late subscribers (the title binder, andThreadViewport'sthread.initializetop-anchor reset) no longer miss it. (@okisdev) -
#3867
325de4c- relaxthread-message-likeimage validation to accepthttps://andblob:URLs (andsvg+xmldata URIs) alongside base64data:URIs, so assistant-authored images served from a URL render. (@samdickson22) -
#4099
f2ec01c- feat(core, react): opt-out of auto-unarchive when switching threads (@adityamohta)switchToThread(andThreadListItemRuntime.switchTo) now accept an optional{ unarchive?: boolean }argument. The default remainstrue, preserving the existing behavior of auto-unarchiving an archived thread when it becomes the main thread. Passunarchive: falseto keep the thread archived after switching β useful when the UI lets users preview an archived conversation without restoring it.// existing behavior β archived thread becomes regular await threadList.switchToThread(threadId); // new β keep status as archived await threadList.switchToThread(threadId, { unarchive: false }); // same option on the item runtime await threadListItem.switchTo({ unarchive: false }); -
Updated dependencies [
13a12c4,01244a5,1e21076]:- assistant-stream@0.3.16
- assistant-cloud@0.1.29
- @assistant-ui/store@0.2.12
- @assistant-ui/tap@0.5.12
0.2.4#
Patch Changes#
-
#4077
221d320- fix(core|MessageParts,GroupedParts): key part fibers by absolute part index (@Yonom)Inside
MessagePrimitive.GroupedPartsand the auto-grouped
toolGroup/reasoningGroupranges ofMessagePrimitive.Parts,
leaf fibers were keyed by their structural position in the
group tree rather than by the underlying part's absolute index.
When the parts list reshaped (e.g., a thread switch with a
different group layout), React reused the same fiber at a given
structural slot but with a differentindexprop, keeping the
prior tap subscription alive against an index that may now point
at a different part or be out of range β surfacing as
tapClientLookup: Index N out of boundsor
MessagePartText can only be used inside text or reasoning message parts. Keying by part index instead causes React to unmount the
fiber when the part underneath actually changes.
0.2.3#
Patch Changes#
-
#4023
94548fa- docs: add JSDoc for core runtime and assistant tool APIs (@AVGVSTVS96) -
#3513
8b6fc88- fix: guardnavigator.clipboardavailability and swallow write rejections inActionBarPrimitive.Copy. Previously, copy clicks in SSR, non-HTTPS contexts, or older browsers without the Clipboard API threw aReferenceError, and permission-denied rejections surfaced as unhandled promise rejections. The web copyToClipboard implementation in@assistant-ui/reactnow early-rejects when the API is unavailable, anduseActionBarCopyin@assistant-ui/coresilently absorbs the rejection so the rest of the UI is unaffected. (@JustAnOkapi) -
#4057
179895f- fix(core): firestreamCallfor already-resolved tool calls observed after the initial snapshot, and promote in-progress tool calls from the initial snapshot once they change. Previously the runtime silently skippedstreamCallwhenever a tool-call part arrived already-resolved (history reload, thread switch, mid-run resume, PTC sub-call surfacing), forcing fragile render-effect fallbacks.executestays suppressed for these cases so side effects don't double-run. (@Yonom)Also collapses the per-tool-call ref soup inside
useToolInvocationsinto a single discriminatedToolCallEntrymap keyed by logical tool-call id, with execution-lifecycle bookkeeping tracked separately by physical stream id. RemovesignoredToolIds,lastToolStates,toolCallIdAliasesRefidentity entries, the parallelrestoredSignaturesRef/preResolvedToolCallIdsRef/startedExecutionToolCallIdsRefsets, and the early-return that suppressedstreamCallfor already-resolved tool calls.reset()semantics are unchanged; integrators that already callreset()on history reload don't need to change. -
#3958
7a8bf26- refactor: hoistMessagePartPrimitiveInProgressto@assistant-ui/core/reactso@assistant-ui/react,@assistant-ui/react-ink, and other distributions can share the same implementation.@assistant-ui/react'sMessagePartPrimitive.InProgressis unchanged for callers; it now re-exports from core. (@ShobhitPatra) -
#3636
3b2bbce- feat(core): expose modelName and toolNames in ModelContextState (@ShobhitPatra) -
Updated dependencies [
845c7c1,db721df,94548fa,94548fa]:- assistant-cloud@0.1.28
- @assistant-ui/store@0.2.11
- assistant-stream@0.3.15
- @assistant-ui/tap@0.5.11
0.2.2#
Patch Changes#
- #4024
19d4d94- feat: add native MCP Apps renderer βMcpAppRenderercomposes intoToolsto render MCP UI resources inline in chat over a JSON-RPC postMessage bridge onSafeContentFrame. Adds anmcpfield toToolCallMessagePartand forwardscallProviderMetadata.mcp.appthrough the AI SDK message converter. (@Yonom)
0.2.1#
Patch Changes#
-
#3984
35d0146- feat(composer): exposecanSendstate andisSendDisabledadapter input (@okisdev)ComposerState.canSend(read-only) is now derivable viauseAuiState((s) => s.composer.canSend)and<AuiIf condition={(s) => s.composer.canSend}/>. it reflects whether the composer is in a state where send is permitted; cross-thread gating (isRunning,capabilities.queue) continues to be layered on top byuseComposerSend.ExternalStoreAdapter.isSendDisabledis a new optional input alongsideisDisabled. whentrue, the thread composer's input remains usable butsend()becomes a no-op andcanSendisfalse. use this to gate sending on external React state (e.g. while tool config is loading) without disabling the input itself. edit composers (saving in-progress message edits) intentionally ignore this flag, since it is a thread-scoped gate.BaseComposerRuntimeCore.send()now early-returns when!canSend, so theCmd/Ctrl+Shift+Entersteer hotkey, form-requestSubmit(), and directaui.composer().send()calls are all gated by the same flag. the same gating is wired through the tap-basedExternalThreadclient via a newisSendDisabledprop onExternalThreadProps. -
#4008
fa4510a- feat: support multi-modal tool results viatoModelOutput(@okisdev)frontend tools can now project their execution output into multi-modal model content (text + image / pdf / arbitrary file parts), aligning with the AI SDK v6
toModelOutputcallback. previously, tool results were always serialized as a single JSON value, so a "read pdf" style tool had no way to send the PDF back to a multi-modal model.assistant-streamexports a newToolModelContentParttype ({ type: "text", text } | { type: "file", data, mediaType, filename? }) and aToolModelOutputFunction<TArgs, TResult>callback type.Tool.toModelOutputis wired throughunstable_runPendingToolsandToolExecutionStream, attaching the resultingmodelContentto thetool-callpart on the assistant message.@assistant-ui/corere-exportsToolModelContentPartand adds an optionalmodelContent?: readonly ToolModelContentPart[]field onToolCallMessagePart. existing tools and renderers are unchanged.@assistant-ui/react-ai-sdk'sfrontendTools(...)helper now also registers atoModelOutputon each forwarded tool. it transparently unwraps an envelope thatuseAISDKRuntimewrites when a frontend-executed tool producedmodelContent, turning it into AI SDK's{ type: "content", value: [...] }output. plain (non-envelope) outputs fall back to the existing{ type: "text" | "json", value }shape, so behavior for tools withouttoModelOutputis unchanged.
route handlers that adopt
toModelOutputalso need to passtoolstoconvertToModelMessages(this is the AI SDK's documented pattern):const aiSDKTools = { ...frontendTools(tools ?? {}) }; streamText({ messages: await convertToModelMessages(messages, { tools: aiSDKTools }), tools: aiSDKTools, });templates and existing examples are unchanged. they keep the simpler
convertToModelMessages(messages)form because none of the tools they ship with usetoModelOutput. the new tools guide page documents how to opt in.reserved key. when a frontend tool defines
toModelOutput, its result is persisted in the AI SDK chat as{ __aui_modelContent: ToolModelContentPart[], value: <your result> }. tools must not return objects whose top-level key is literally__aui_modelContent, orconvertMessagewill misread the result. the prefix is namespaced for this reason.read/write compatibility for persisted threads. the envelope is recognized by
@assistant-ui/react-ai-sdkfrom this version onward. if you persist UI messages and read them from multiple environments, upgrade every reader before any writer starts producingtoModelOutput; otherwise older readers will treat the envelope object as theresultand break the affected toolrenderfunctions. -
#3972
c9dd16c- fix:useExternalStoreRuntimeno longer crashes with "Entry not available in the store" when the adapter setsthreadIdto a value that isn't present inthreads/archivedThreads. The runtime now synthesizes a regular thread item formainThreadId, so thin adapters (e.g.useAgUiRuntime) that only exposethreadIdresolve correctly on first render and after switching threads. Closes #3971. (@okisdev) -
#3674
dea8bc7- fix(core): guard MessagePrimitive.Attachments against missing user message attachments (@cewinharhar) -
#3634
9c3d24d- Support AI SDKsource-documentparts by preserving them as assistant-ui (@sicko7947)
document source message parts across conversion and cloud serialization,
including the legacy React cloud encoder. -
Updated dependencies [
9ecda1d,fa4510a]:- assistant-stream@0.3.14
0.2.0#
Minor Changes#
-
#3970
040d469- chore: drop APIs deprecated in v0.11/v0.12 (@Yonom)See the v0.14 migration guide for the full removal list and replacements.
useAssistantApi/useAssistantState/useAssistantEvent/AssistantIfremoved (useuseAui/useAuiState/useAuiEvent/AuiIf).getExternalStoreMessage(singular) removed (usegetExternalStoreMessages).MessageState.submittedFeedbackremoved (usemessage.metadata.submittedFeedback).ThreadRuntime.startRun(parentId)positional overload removed (pass{ parentId }).ThreadRuntime.unstable_loadExternalStateremoved (useimportExternalState).ThreadRuntime.unstable_resumeRunremoved (useresumeRun).ThreadRuntime.getModelConfigremoved (usegetModelContext).AssistantRuntime.threadList/switchToNewThread/switchToThread/registerModelConfigProvider/resetremoved (usethreads/threads.switchToNewThread/threads.switchToThread/registerModelContextProvider/thread.reset).ChatModelRunOptions.configremoved (usecontext).useLocalThreadRuntimealias removed (useuseLocalRuntime).unstable_useRemoteThreadListRuntime/unstable_useCloudThreadListAdapter/unstable_RemoteThreadListAdapter/unstable_InMemoryThreadListAdapteraliases removed (drop theunstable_prefix).react-langgraphonSwitchToThreadremoved (useload).toAISDKTools/getEnabledToolsremoved (usetoToolsJSONSchemafromassistant-stream).
0.1.18#
Patch Changes#
-
#3953
7098bab- Add cursor-based pagination to the thread list.RemoteThreadListAdapter.list()accepts an optional{ after }cursor and may returnnextCursoron the response. The runtime exposesloadMore(),hasMore, andisLoadingMorethrough both the legacyThreadListRuntimeAPI and the tap-onlyaui.threads()path;ThreadListRuntimeCore.loadMore?(),hasMore?, andisLoadingMore?are optional, so non-paginating cores (local, external-store, single-thread, in-memory) remain conformant. (@okisdev)@assistant-ui/reactships a matchingThreadListPrimitive.LoadMorebutton built oncreateActionButton, plus auseThreadListLoadMoreprimitive hook. Consumers wanting anIntersectionObserversentinel can reads.threads.hasMore/isLoadingMorefromuseAuiStateand callaui.threads().loadMore()directly.In-flight
loadMore()calls dedup via a single promise. The existing_loadGenerationcounter drops stale append callbacks when areload()interleaves aloadMore(). The loadMore reducer captures the active adapter so a mid-flight adapter swap cannot leak a stale page. Empty-stringnextCursoris normalised toundefined.reload()pre-clears the cursor so consumers readinghasMoredirectly during a reload do not observe a stale value.Adapter rejections are surfaced via
console.errorin both the initial-load andloadMorepaths, matching the pattern inRemoteThreadListHookInstanceManageranduseToolInvocations. -
Updated dependencies [
b090acb,5fdf17e]:- assistant-stream@0.3.13
- @assistant-ui/store@0.2.10
- @assistant-ui/tap@0.5.11
- assistant-cloud@0.1.27
0.1.17#
Patch Changes#
-
#3916
0bbf5dd- chore: drop./*wildcard export and surface internal attachment status types (@Yonom)The
./*wildcard inexportswas exposing the entire dist tree as importable subpaths, which inadvertently leaked internal modules (e.g.@assistant-ui/core/tests/*,@assistant-ui/core/types/*) as public API. Removing it.Two attachment status types that were previously only reachable through the wildcard (
PendingAttachmentStatus,CompleteAttachmentStatus) are now re-exported from the package root so that consumers' inferred types remain portable. -
#3917
98f165c- feat: enrichcomposer.attachmentAddErrorevent with typed payload (@okisdev)The event now carries
{ reason, message, attachmentId?, error? }so subscribers can branch on the failure mode (no-adapter/not-accepted/adapter-error). The bridge no longer relies on afindLastheuristic to recover the failed attachment id.Several state-derivable events are now annotated
@deprecatedbecause they duplicate state observation:composer.send,composer.attachmentAdd,thread.runStart,thread.runEnd,thread.initialize,threadListItem.switchedTo,threadListItem.switchedAway. They continue to fire for backward compatibility; new code should observe state viauseAuiStateinstead. -
#3914
62ec5bd- fix: add typesVersions to support moduleResolution: node (@shashank-100)Users with
moduleResolution: nodein their tsconfig were seeingProperty 'message' does not exist on type 'AssistantState'because theexportsmap sub-paths (e.g.@assistant-ui/core/react) are ignored by legacy node module resolution. AddingtypesVersionsmakes TypeScript resolve sub-path types correctly under all moduleResolution modes. -
#3853
6a919c1- feat: add<MessagePrimitive.GroupedParts>for hierarchical adjacent grouping of message parts (@Yonom)Introduces a new primitive that coalesces adjacent parts into groups via a user-supplied
groupBy(part) β "group-β¦" | readonly "group-β¦"[] | null. Adjacent parts sharing a key-path prefix coalesce up to that prefix; ungrouped parts render as direct leaves.The render function takes
{ part, children }and dispatches on a singleswitch (part.type)."group-β¦"cases wrapchildren(the recursively-rendered subtree); real part types ("text","tool-call","reasoning", β¦) render the part directly with the sameEnrichedPartStateenrichments (toolUI,addResult,resume,dataRendererUI) that<MessagePrimitive.Parts>provides.GroupPartis intentionally minimal:{ type, status, indices }. The render function is invoked once per group node and once per individual leaf part, so users never have to nest a<MessagePrimitive.Parts>call.The
groupByreturn type is constrained to`group-${string}`so the unified switch can never collide with a real part type. The component infers a literalTKeyper call site, sopart.typenarrows to the exact union of group keys plus part types.For leaf parts,
childrenis a sentinel that throws if rendered β accidental fall-through likedefault: return children;errors loudly instead of silently rendering nothing. Returningnullfrom a leaf case is fine.Deprecates the legacy
components.ToolGroup,components.ReasoningGroup, andcomponents.ChainOfThoughtprops on<Parts>, and<MessagePrimitive.Unstable_PartsGrouped>for adjacent grouping β all still work for backwards compatibility.
0.1.16#
Patch Changes#
-
#3895
549037a- fix(core): emit attachmentAddError when no adapter is configured or file type is rejected (@okisdev) -
#3896
976aec5- fix(core): respectadapter.acceptwhen adding externalCreateAttachment(@okisdev)composer.addAttachmentpreviously bypassed the configuredAttachmentAdapterforCreateAttachmentdescriptors, including theadapter.acceptcontent-type check. It now validates the descriptor'scontentType(or filename extension) againstadapter.acceptwhen an adapter is configured, throwing and emittingcomposer.attachmentAddErroron mismatch. Without an adapter, external attachments are still added as-is, preserving the existing "no adapter required" guarantee for external sources. -
#3716
25b97d5- fix(core): show loading state for empty parts children API (@ShobhitPatra) -
#3891
2008fc9- fix(core): hoist remote thread runtime binder out ofunstable_Provider(@okisdev)RemoteThreadListAdapter.unstable_Provideris now allowed to render any subtree it likes; the runtime binding (composer state,__internal_setGetInitializePromise,runEnd β generateTitlelistener) executes outside it. This fixesEMPTY_THREAD_ERRORwhen the Provider deferschildren(e.g. behind a history-loading state) and avoids the history-switch regression seen when only the binder, but not the init listeners, were hoisted. Adds a dev-mode warning when the Provider does not renderchildrenwithin ~100ms. -
#3889
88fcd35- feat: addcustomslot toRemoteThreadMetadataandThreadListItemState(@okisdev)allows adapter authors to carry arbitrary backend session data through
list()/fetch()and surface it on the thread list item state. matches the existingcustom: Record<string, unknown>convention used onThreadMessage,RunConfig, andChatModelRunResult. consumers can intersect a typed shape at their own boundary, e.g.RemoteThreadMetadata & { custom: { workspaceId: string } }. -
Updated dependencies [
005f83f]:- @assistant-ui/store@0.2.9
- @assistant-ui/tap@0.5.10
0.1.15#
Patch Changes#
-
#3857
c7a274e- fix(core): edit composer no longer re-injects original file parts when user message attachments are modified. Non-text content parts on user messages are lifted into_attachmentsso attachment removals take effect and files aren't duplicated on resend; non-user messages keep the existing content pass-through. (@okisdev) -
#3796
ca8f526- feat(react-langgraph): add uiComponents option for static and dynamic data renderers (@ShobhitPatra)Add
uiComponentsoption touseLangGraphRuntimefor registering static data renderers by name and afallbackrenderer for dynamic loading (e.g. LangSmith'sLoadExternalComponent), directly from the runtime hook.Core
DataRenderersscope also gains afallbacksstack (plussetFallbackDataUImethod) that the adapter registers into; resolution isrenderers[name][0]βfallbacks[0]β inlineFallback. -
#3873
c56f98f- feat(core): addreload()method onThreadListRuntimeandaui.threads()that re-invokes the remote adapter'slist()and refreshes the thread list. Use this after asynchronous auth (e.g. OIDC, better-auth) completes to recover from an initial load that ran before the authenticated user was available. A generation counter ensures a mid-flight response from a superseded load cannot overwrite a newer reload's state. (@okisdev) -
#3855
974d15e- fix:useExternalStoreRuntimenow correctly initializesmainThreadId,threadIds, andarchivedThreadIdsfrom the adapter on first render. Previously they stayed atDEFAULT_THREAD_IDuntil the user switched threads, soisMainwasfalseon initial load. Closes #2577. (@okisdev) -
#3859
4b19d42- fix(core):switchToThreadcould duplicate a thread or leave it in boththreadIdsandarchivedThreadIdswhen it raced withlist(). Both arrays are now filtered before the status-keyed append, matching theupdateStatusReducerpattern. (@bilaltahseen) -
#3858
da0f598- fix:useAISDKRuntimenow throws when the suppliedThreadHistoryAdapteromitswithFormat, instead of silently dropping all history load/append/update calls. The optional-call chainhistoryAdapter.withFormat?.(β¦).load()previously short-circuited toundefined. ThewithFormat-wrapped adapter is now memoized, and the persist effect short-circuits when no adapter is supplied (avoiding a redundant thread subscription).ThreadHistoryAdapter.withFormatgains a JSDoc note clarifying that it is required on the AI SDK path. (@okisdev) -
#3831
d53ff4f- chore: remove decorative separator comments across packages (@okisdev) -
#3872
20f8404- feat(core): let runtimes provide an explicitisRunningthat overrides the last-message-status heuristic.ExternalStoreAdapter.isRunningnow flows through tothread.isRunningdirectly, so applications can keep the thread in a running state even after the last assistant message has completed (e.g. while non-message stream chunks like suggestions, step-finish, or metadata updates are still arriving). When a runtime does not provideisRunning, the previous last-message-based behavior is preserved. (@okisdev) -
#3834
17958c9- refactor: unify mention/slash under behavior sub-primitives; delete Mention/SlashCommand aliases and theexecutefield onUnstable_TriggerItem; split TriggerPopoverResource; rename react-lexicalMentionNode/MentionPlugin/MentionChipProvider/mentionChipprop toDirectiveNode/DirectivePlugin/DirectiveChipProvider/directiveChip; fix IME/Unicode/copy-paste/undo bugs. Breaking (Unstable_APIs): replaceonSelect={{type:"insertDirective",formatter}}with<Unstable_TriggerPopover.Directive formatter={...}>; replaceonSelect={{type:"action",handler}}with<Unstable_TriggerPopover.Action onExecute={...}>. Renameunstable_useToolMentionAdapterβunstable_useMentionAdapterwith newitems/categories/includeModelContextToolsoptions.unstable_useSlashCommandAdapternow returns{ adapter, action }βexecutestays in the hook closure instead of on the item. Rename CSS classaui-mention-chipβaui-directive-chipand attributesdata-mention-*βdata-directive-*. (@okisdev) -
Updated dependencies [
ce865bc,055dda5,d53ff4f]:- assistant-stream@0.3.12
- assistant-cloud@0.1.27
- @assistant-ui/store@0.2.8
- @assistant-ui/tap@0.5.9
0.1.14#
Patch Changes#
- f20b9ca: feat: add ExportedMessageRepository.fromBranchableArray() for constructing branching message trees from ThreadMessageLike messages
- c988db8: chore: update dependencies
- Updated dependencies [c988db8]
- assistant-stream@0.3.11
- assistant-cloud@0.1.26
- @assistant-ui/store@0.2.7
- @assistant-ui/tap@0.5.8
0.1.13#
Patch Changes#
-
42bc640: feat: support edit lineage and startRun in EditComposer send flow
- Add
SendOptionswithstartRunflag tocomposer.send() - Expose
parentIdandsourceIdonEditComposerState - Add
EditComposerRuntimeCoreinterface extendingComposerRuntimeCore - Bypass text-unchanged guard when
startRunis explicitly set ComposerSendOptionsextendsSendOptionsfor consistent layering
- Add
-
87e7761: feat: generalize mention system into trigger popover architecture with slash command support
- Introduce
ComposerInputPluginprotocol to decouple ComposerInput from mention-specific code - Extract generic
TriggerPopoverResourcefromMentionResourcesupporting multiple trigger characters - Add
Unstable_TriggerItem,Unstable_TriggerCategory,Unstable_TriggerAdaptergeneric types - Add
Unstable_SlashCommandAdapter,Unstable_SlashCommandItemtypes - Add
ComposerPrimitive.Unstable_TriggerPopoverRootand related primitives - Add
ComposerPrimitive.Unstable_SlashCommandRootand related primitives - Add
unstable_useSlashCommandAdapterhook for building slash command adapters - Refactor
MentionResourceas thin wrapper aroundTriggerPopoverResource - Alias
Unstable_MentionItem/Unstable_MentionAdapterto generic trigger types - Update
react-lexicalKeyboardPluginto use plugin protocol - All existing
Unstable_Mention*APIs remain unchanged
- Introduce
-
Updated dependencies [376bb00]
- assistant-cloud@0.1.25
- @assistant-ui/tap@0.5.7
- @assistant-ui/store@0.2.6
0.1.12#
Patch Changes#
- 19b1024: fix(core): move initialThreadId/threadId handling from constructor to __internal_load to prevent SSR crash
0.1.11#
Patch Changes#
- de29641: fix(core): start RemoteThreadList isLoading as true
- a8bf84b: feat(core): expose
getLoadThreadsPromise()onThreadListRuntimepublic API - 5fd5c3d: feat(core): add reactive
threadIdoption touseRemoteThreadListRuntimefor URL-based routing - ec50e8a: fix(core): prevent resolved history tool calls from re-executing
- Updated dependencies [2c5cd97]
- assistant-stream@0.3.10
0.1.10#
Patch Changes#
-
6554892: feat: add useAssistantContext for dynamic context injection
Register a callback-based context provider that injects computed text into the system prompt at evaluation time, ensuring the prompt always reflects current application state.
-
9103282: fix: resolve biome lint warnings (optional chaining, unused suppressions)
-
876f75d: feat: add interactable state persistence
Add persistence API to interactables with exportState/importState, debounced setPersistenceAdapter, per-id isPending/error tracking, flush() for immediate sync, and auto-flush on component unregister.
-
bdce66f: chore: update dependencies
-
4abb898: refactor: align interactables with codebase conventions
- Rename
useInteractabletouseAssistantInteractable(registration only, returns id) - Add
useInteractableStatehook for reading/writing interactable state - Remove
makeInteractableand related types - Rename
UseInteractableConfigtoAssistantInteractableProps - Extract
buildInteractableModelContextfromInteractablesresource - Add
with-interactablesexample to CLI
- Rename
-
209ae81: chore: remove aui-source export condition from package.json exports
-
af70d7f: feat: add useToolArgsStatus hook for per-prop streaming status
Add a convenience hook that derives per-property streaming completion status from tool call args using structural partial JSON analysis.
-
Updated dependencies [dffb6b4]
-
Updated dependencies [9103282]
-
Updated dependencies [bdce66f]
-
Updated dependencies [209ae81]
-
Updated dependencies [2dd0c9f]
- assistant-stream@0.3.9
- assistant-cloud@0.1.24
- @assistant-ui/store@0.2.6
- @assistant-ui/tap@0.5.6
0.1.9#
Patch Changes#
-
781f28d: feat: accept all file types and validate against adapter's accept constraint
-
3227e71: feat: add interactables with partial updates, multi-instance, and selection
useInteractable(name, config)hook andmakeInteractablefactory for registering AI-controllable UIInteractables()scope resource with auto-generated update tools and system prompt injection- Partial updates β auto-generated tools use partial schemas so AI only sends changed fields
- Multi-instance support β same name with different IDs get separate
update_{name}_{id}tools - Selection β
setSelected(true)marks an interactable as focused, surfaced as(SELECTED)in system prompt
-
0f55ce8: fix(core): hide phantom empty bubble when user message has no text content
-
83a15f7: feat(core): stream interactable state updates as tool args arrive
-
52403c3: chore: update dependencies
-
ffa3a0f: feat(core): add attachmentAddError composer event
-
Updated dependencies [3227e71]
-
Updated dependencies [52403c3]
- assistant-stream@0.3.8
- assistant-cloud@0.1.23
- @assistant-ui/store@0.2.5
- @assistant-ui/tap@0.5.5
0.1.8#
Patch Changes#
-
1406aed: fix(core): prevent stale list() response from undoing concurrent delete/archive/unarchive in OptimisticState
-
9480f30: fix(core): stop thread runtime on delete to prevent store crash
-
28a987a: feat: SingleThreadList resource
refactor: attachTransformScopes should mutate the scopes instead of cloning it -
736344c: chore: update dependencies
-
ff3be2a: Add @-mention system with cursor-aware trigger detection, keyboard navigation, search, and Lexical rich editor support
-
70b19f3: feat: add native queue and steer support
- Add
queueadapter toExternalThreadPropsfor runtimes that support message queuing - Add
QueueItemPrimitive.Text,.Steer,.Removeprimitives for rendering queue items - Add
ComposerPrimitive.Queuefor rendering the queue list within the composer - Add
ComposerSendOptionswithsteerflag tocomposer.send() - Add
capabilities.queuetoRuntimeCapabilities ComposerPrimitive.Sendstays enabled during runs when queue is supported- Cmd/Ctrl+Shift+Enter hotkey sends with
steer: true(interrupt current run) - Add
queueItemscope toScopeRegistry - Add
queuefield toComposerStateandqueueItem()method toComposerMethods
- Add
-
Updated dependencies [28a987a]
-
Updated dependencies [736344c]
-
Updated dependencies [c71cb58]
- @assistant-ui/store@0.2.4
- assistant-stream@0.3.7
- @assistant-ui/tap@0.5.4
0.1.7#
Patch Changes#
- 7ecc497: feat: children API for primitives with part.toolUI, part.dataRendererUI, and MessagePrimitive.Quote
0.1.6#
Patch Changes#
-
1ed9867: feat: move resumeRun to stable
-
427ffaa: refactor: drop all barrel files
-
349f3c7: chore: update deps
-
02614aa: feat: add multi-agent support
ReadonlyThreadProviderandMessagePartPrimitive.Messagesfor rendering sub-agent messagesassistant-stream: addmessagesfield totool-resultchunks,ToolResponseLike, andToolCallParttypes, enabling sub-agent messages to flow through the streaming protocol
-
6cc4122: refactor: use primitive hooks
-
642bcda: Add
quote.tsxregistry components andinjectQuoteContexthelper -
Updated dependencies [427ffaa]
-
Updated dependencies [349f3c7]
-
Updated dependencies [02614aa]
- assistant-stream@0.3.6
- assistant-cloud@0.1.22
- @assistant-ui/store@0.2.3
- @assistant-ui/tap@0.5.3
0.1.5#
Patch Changes#
- 990e41d: refactor: code sharing between the multiple platforms
0.1.4#
Patch Changes#
- f032ea5: fix: restore
typeof processruntime guard in useCloudThreadListAdapter - Updated dependencies [2828b67]
- assistant-stream@0.3.5
0.1.3#
Patch Changes#
- 5ae74fe: fix: prevent double-submit when ComposerPrimitive.Send child has type="submit"
- 8ed9d6f: Refactor React Native component API: move shared runtime logic (remote thread list, external store, cloud adapters, message converter, tool invocations) into @assistant-ui/core for reuse across React and React Native
- 01bee2b: Remove zod dependency by using assistant-stream's toJSONSchema utility for schema serialization in AssistantFrameProvider
0.1.2#
Patch Changes#
- 03714af: fix: DataRenderers not in scope
0.1.1#
Patch Changes#
-
a638f05: refactor(core): depend on @assistant-ui/store, register chat scopes via module augmentation
-
28f39fe: Support custom content types via
data-*prefix in ThreadMessageLike (auto-converted to DataMessagePart), widenBaseAttachment.typeto accept custom strings, makecontentTypeoptional -
36ef3a2: chore: update dependencies
-
6692226: feat: support external source attachments in composer
addAttachment()now accepts either aFileor aCreateAttachmentdescriptor, allowing users to add attachments from external sources (URLs, API data, CMS references) without creating dummyFileobjects or requiring anAttachmentAdapter. -
c31c0fa: Extract shared React code (model-context, client, types, providers, RuntimeAdapter) into
@assistant-ui/core/reactsub-path so both@assistant-ui/reactand@assistant-ui/react-nativere-export from one source. -
fc98475: feat(core): move
@assistant-ui/tapto peerDependencies to fix npm deduplication -
374f83a: fix(core): stabilize object references in ExternalStoreThreadRuntimeCore to prevent infinite re-render loop
-
1672be8: feat: bindExternalStoreMessage
-
14769af: refactor: move RuntimeAdapter base logic to @assistant-ui/core; re-export missing core APIs from distribution packages
-
Updated dependencies [36ef3a2]
-
Updated dependencies [fc98475]
-
Updated dependencies [a638f05]
- assistant-stream@0.3.4
- @assistant-ui/store@0.2.1
- @assistant-ui/tap@0.5.1
0.1.0#
Minor Changes#
- 60bbe53: feat(core): ready for release
Patch Changes#
-
546c053: feat(core): extract subscribable, utils, and model-context; add public/internal API split
-
a7039e3: feat(core): extract remote-thread-list and assistant-transport utilities to @assistant-ui/core
-
16c10fd: feat(core): extract runtime and adapters to @assistant-ui/core
-
40a67b6: feat(core): add message, attachment, and utility type definitions
-
b181803: feat(core): introduce @assistant-ui/core package
Extract framework-agnostic core from @assistant-ui/react. Replace React ComponentType references with framework-agnostic types and decouple AssistantToolProps/AssistantInstructionsConfig from React hook files.
-
4d7f712: feat(core): move runtime-to-client bridge to core/store for framework reuse
-
ecc29ec: feat(core): move scope types and client implementations to @assistant-ui/core/store
-
6e97999: feat(core): move store tap infrastructure to @assistant-ui/core/store
-
Updated dependencies [b65428e]
-
Updated dependencies [b65428e]
-
Updated dependencies [b65428e]
-
Updated dependencies [6bd6419]
-
Updated dependencies [b65428e]
-
Updated dependencies [61b54e9]
-
Updated dependencies [b65428e]
-
Updated dependencies [93910bd]
-
Updated dependencies [b65428e]
- @assistant-ui/tap@0.5.0
- assistant-stream@0.3.3