@artooi/ag-ui-web-component 0.41.2 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,208 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.42.0] — 2026-10-07
11
+
12
+ ### Fixed
13
+
14
+ - **A send is in flight from the moment it is taken, not from when its run
15
+ starts.** A send draws its turn and dispatches `ag-ui-submit` before it asks
16
+ the client for a run, and only the run counted. So a `sendMessage()` from an
17
+ `ag-ui-submit` listener, or a second call in the same task, passed every
18
+ guard and went out as a second request on the same client, with the
19
+ listener's turn drawn between the user's turn and its answer. Both are now
20
+ refused, so a listener that sends hears the event once, and the built-in
21
+ Send queues in that time as it does during a run. A listener that stops the
22
+ send -- a new chat, a thread switch, a change of `user-key`, moving the
23
+ element -- now stops it before its request is made. It used to go out into
24
+ the conversation that replaced it, which after a change of `user-key` put one
25
+ principal's turn at the top of the next one's conversation.
26
+ - **ArrowUp reaches a turn queued behind a run, and one sent to resume or
27
+ fork a run.** Arrow-key recall recorded only a turn the composer sent at
28
+ once. A turn typed while a run was going entered it only if Stop discarded
29
+ the queue, so ArrowUp skipped it while it waited and after the queue sent it.
30
+ A turn sent from the checkpoint panel never entered it, though it was typed
31
+ in the composer like any other. Both are now recorded as they leave the
32
+ composer, and a turn taken back from the queue stays recallable, as one Stop
33
+ declined to send already did. Stop no longer adds the queue again, so the
34
+ history holds each turn once. Queueing or continuing with a turn you walked
35
+ back to now starts the next walk from the newest turn, as sending one did.
36
+ Turns a host sends with `sendMessage` are still not recorded, and the purge a
37
+ change of `user-key` makes still clears them.
38
+ - **Retry and a checkpoint pick keep the rules a send keeps.** `retryLastTurn()`
39
+ checked only for a run in flight. A Retry made before a send's run had
40
+ started, or while a picked checkpoint was in flight, started a second run in
41
+ the same conversation. A Retry is now refused in both cases. It also counts
42
+ from the call, as a send does, so a `sendMessage()` or a second Retry made
43
+ before its run starts is refused and the built-in Send queues. A pick made
44
+ before a send's or a Retry's run has started is now refused with the same hint
45
+ as a pick during a run. A conversation store, or an activity or tool renderer
46
+ the Retry redraws through, that starts a new chat or changes `user-key` now
47
+ stops it, and `retryLastTurn()` returns `false`. The Retry used to go ahead,
48
+ drawing the old conversation into the new one and asking its answer again.
49
+ One new refusal follows from the same rule: a Retry from an
50
+ `ag-ui-run-finished` listener for a picked checkpoint's run returns `false`,
51
+ because the continuation is still in flight when that event fires. A
52
+ `sendMessage()` from the same place was already refused for that reason.
53
+ - **A recall walk ends on any write into the composer, not only on typing.**
54
+ Walking back to a past turn with Up and then quoting text, from the
55
+ transcript or from the page through `offerQuoteInPage`, or clicking a skill
56
+ chip that prefills the composer, left the walk running: the next Up replaced
57
+ what had just been written with an older turn, and Down emptied the box. The
58
+ walk now checks that the composer still holds the turn it put there, so any
59
+ other write ends it, including a host page writing the composer itself.
60
+ - **A `user-key` changed while the element is out of the document now hands
61
+ over when it is inserted again.** The attribute was acted on only while the
62
+ element was connected, and inserting it again is a reload that keeps the
63
+ composer's recall on purpose. So removing the element, changing the key and
64
+ inserting it again left the previous principal's stored conversation in
65
+ `sessionStorage`, their turns one ArrowUp away, their Always allow waivers
66
+ live, their shared state seeded into the next principal's first run, their
67
+ unread count on the launcher, and their threads in a drawer left open.
68
+ Connecting now compares the key the element's state belongs to with the
69
+ attribute, and runs the handover a live change runs when they differ. The
70
+ first key to arrive is still an adoption rather than a purge, and a move that
71
+ keeps the key, a key that goes away and comes back while detached, and a
72
+ first connect hand nothing over.
73
+ - **A Stop your own code makes while a turn is starting now stops it.** A
74
+ conversation store, a `getContext` or `getTools`, or the save that answers a
75
+ tool call left open, that started a new chat or changed `user-key` during a
76
+ send or a Retry stopped nothing: the request still went out into the
77
+ conversation being left, with all of its history. Nothing is sent now. On
78
+ `AgUiClient`, a `cancel()` from `onPersist`, `getContext` or `getTools` before
79
+ the request is honoured and fires `onCancelled` and `onSettled` as any Stop
80
+ does, and a `cancel()` with nothing in flight is still forgotten by the next
81
+ `send()` or `resume()`. A Retry stopped this way resolves `true`, because the
82
+ provider runs after the Retry has handed its turn to the client.
83
+ - **A Retry whose save the store refuses leaves the conversation as it was.**
84
+ `truncateToLastUser()` shortened the history before saving it, so a store
85
+ that threw left the answer on screen but out of the next request, and the
86
+ agent was then asked a follow-up about an answer it was never told it gave.
87
+ It now saves first, so a refused save changes nothing, and `retryLastTurn()`
88
+ rejects with the store's error.
89
+ - **A reload that resumes a run no longer lets a second run start beside it.**
90
+ A reload in the middle of a navigating tool's run resumes that run once the
91
+ conversation store answers, and with a remote store that answer is a real
92
+ request. A send, a Retry or a checkpoint pick made while it was out was not
93
+ refused: the send went out without the stored conversation and its save
94
+ replaced it, then the resume ran beside it on the same client, answering a
95
+ call the conversation no longer held. A restore that will resume now counts
96
+ as in flight from the moment it asks the store, so `sendMessage()` returns
97
+ without sending, the built-in Send queues the turn behind the resumed answer,
98
+ `retryLastTurn()` returns `false`, and a pick says why at the composer. New
99
+ chat while the store answers stands the resume down. A host calling
100
+ `sendMessage()` as the element connects, on a page a navigating tool
101
+ reloaded, now has that call refused, as it would be behind any run.
102
+ - **A conversation restore stops where New chat, leaving the page or host
103
+ code stopped it.** A restore stood down only for a newer restore or, when it
104
+ was about to resume a run, for the Stop New chat makes; a restore with
105
+ nothing to resume holds nothing for a Stop to let go of. So New chat pressed
106
+ while a remote store was still answering drew the conversation being left
107
+ into the new chat, and the first turn sent there carried that whole
108
+ conversation. An element removed meanwhile ran the host's renderers for a
109
+ node no longer on the page. An activity or tool renderer that started a new
110
+ chat during the replay had the rest of the old conversation drawn into the
111
+ new one, and after a reload mid-run, a renderer, the store's save of the
112
+ checkpoint or `navigationResult` doing the same still let the resume go out,
113
+ answering the navigating call from the new chat. Once any of these happens,
114
+ the restore now draws nothing more and resumes nothing. The navigation
115
+ checkpoint such a stop leaves behind is forgotten, so coming back to that
116
+ conversation later answers its navigating call as not finished rather than
117
+ resuming it from whatever page is current then. When the element only left
118
+ the page, the checkpoint is kept, and the run resumes once the element is
119
+ put back. That holds after a `reload()` the host made while the store was
120
+ answering, too: a restore standing down for a newer restore of the same
121
+ conversation leaves the checkpoint to it, and the restore that resumes is
122
+ the one that clears it.
123
+ - **A run stopped by a change of `user-key` no longer saves into the next
124
+ principal's storage.** The handover stopped the run, but a stopped run saves
125
+ what it had once its request closes, and by then the store had been purged
126
+ and scoped to whoever arrived. The previous principal's question and partial
127
+ answer were filed under their own thread id in the next principal's
128
+ namespace, and the history drawer listed a conversation titled with a
129
+ question the new user never asked. A tool result returned after the Stop, a
130
+ stopped checkpoint continuation, and a key changed while the element was
131
+ detached did the same. A state snapshot already read off the wire put the
132
+ previous principal's shared state back after the handover had emptied it, so
133
+ it went out on the next principal's first run. A client built before a
134
+ handover now writes nothing at all. A key's first arrival is still an
135
+ adoption, so a run in flight across it keeps saving into the namespace it
136
+ moved to, and New chat still files a stopped run's last save under the
137
+ conversation it left.
138
+ - **A change of `user-key` no longer replaces a conversation store the host
139
+ assigned after the element connected.** Connecting remembered the element's
140
+ own store, and a later key change rebuilt that store under the new namespace
141
+ whether or not it was still the one in use. A store the host assigned to a
142
+ connected element was swapped for a `sessionStorage` one, and a
143
+ `RemoteConversationStore` built with `cacheMessages: false` to keep message
144
+ bodies off the client started caching every one of them in the tab. A store
145
+ the host assigned is now left alone whenever it was assigned, and scopes
146
+ itself. The one exception is unchanged: a plain `SessionStorageStore`
147
+ assigned before connecting is the same kind as the element's own default,
148
+ so the element still namespaces it as its own.
149
+ - **A change of `user-key` clears the composer.** The transcript and recall
150
+ history were already cleared so the previous principal's words were not in
151
+ front of the next one, but a turn they had typed and not sent stayed in the
152
+ box, on a live change and on one made while detached. A handover now empties
153
+ the composer, which takes a quotation or a skill's template with it. It also
154
+ takes down the skill hint, closes a slash palette the text had opened, and on
155
+ a live change stops a voice recording in progress before it is transcribed.
156
+ The first arrival of a key, a move that keeps the key, and New chat leave the
157
+ text where it is.
158
+ - **A tool call whose run was stopped or handed over while it waited no longer
159
+ acts afterwards.** Dispatch awaited the host's `confirmPredicate`, the
160
+ confirmation card and the handler, and checked after none of them whether
161
+ the run was still going. A predicate that answered after Stop opened its
162
+ card or ran its handler for a run the user had ended, and a Confirm clicked
163
+ in the same task as Stop still ran the call. Across a change of `user-key`,
164
+ the previous principal's handler ran on the next principal's page, a
165
+ navigating tool's checkpoint went into the next principal's storage, and a
166
+ handler failing after the handover cleared their checkpoint instead of its
167
+ own. Such a call now settles as not finished and posts nothing, so the next
168
+ request answers it as not finished, and after a handover it draws and
169
+ writes nothing. Both checkpoint writes go to the thread the call was
170
+ dispatched under. A plain Stop while a handler runs still keeps its result,
171
+ since that action did happen on the page.
172
+ - **A voice clip that comes back after a change of `user-key` is dropped, not
173
+ written into the next principal's composer.** The mic checked whether it had
174
+ been taken down only before it posted the clip, so a transcript already on
175
+ its way when the key changed landed in the composer the change had just
176
+ emptied, and a failed one drew its error on the old button. The permission
177
+ prompt had the same gap: a mic granted after the key changed or the element
178
+ left the page started a recording nobody could see or stop, and its tracks
179
+ were never released, so the browser's recording indicator stayed lit.
180
+ Removing the element while a clip transcribes now drops that clip too, as
181
+ removing it mid-recording already did, and that holds for a move that keeps
182
+ the key.
183
+
184
+ ## [0.41.3] — 2026-10-07
185
+
186
+ ### Fixed
187
+
188
+ - **A resumed or forked run shows the turn it was sent with.** Picking Resume
189
+ or Fork in the checkpoint panel sent what the composer held and streamed the
190
+ answer, but drew no bubble for the turn, so the answer arrived under no
191
+ question. The save already held the turn, so a reload showed a question the
192
+ live transcript never had. The continuation now draws the turn the way Send
193
+ does, ahead of its answer, and tests hold that the live transcript and the
194
+ restored one agree after both a resume and a fork.
195
+ - **`ag-ui-submit` fires for a continued turn.** A host listens to it as "the
196
+ user sent something", and a turn sent with Resume or Fork is one: only the
197
+ endpoint differs. The event fires once the continuation is the run in flight,
198
+ so a `sendMessage()` from a listener is refused rather than starting a second
199
+ run beside it, and a listener that stops it -- a new chat, a thread switch,
200
+ moving the element -- stops it before its request is made. Its
201
+ `detail.attachments` is empty, because a continuation sends only the
202
+ composer's text.
203
+
204
+ ### Changed
205
+
206
+ - **Ships DOMPurify 3.4.16 and marked 18.0.14**, from the lockfile refresh
207
+ since 0.41.2. Both builds carry them inlined, the npm build as well as the
208
+ vendored bundle: only `@ag-ui/client` and `@ag-ui/core` are left to the
209
+ host's resolver, so a host's own lockfile does not choose which sanitiser
210
+ runs.
211
+
10
212
  ## [0.41.2] — 2026-09-23
11
213
 
12
214
  ### Changed
@@ -4222,7 +4424,9 @@ hosts that both arrange the page the way it expects.
4222
4424
  ### Notes
4223
4425
  - First release — exercising the automated npm OIDC publish pipeline end-to-end.
4224
4426
 
4225
- [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.41.2...HEAD
4427
+ [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.42.0...HEAD
4428
+ [0.42.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.41.3...v0.42.0
4429
+ [0.41.3]: https://github.com/Artui/ag-ui-web-component/compare/v0.41.2...v0.41.3
4226
4430
  [0.41.2]: https://github.com/Artui/ag-ui-web-component/compare/v0.41.1...v0.41.2
4227
4431
  [0.41.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.41.0...v0.41.1
4228
4432
  [0.41.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.40.0...v0.41.0
package/README.md CHANGED
@@ -307,11 +307,28 @@ the `copyCode` / `copied` / `copyFailed` strings.
307
307
  `ag-ui-submit` event, run started. Use it for an "Ask about this order" button, a command
308
308
  palette, or a composer of your own replacing the built-in one. It no-ops for an entirely
309
309
  empty message, and while a run — or a checkpoint continuation picked from the panel — is in
310
- flight; a continuation counts from the pick, not from its first event, so the gap where two
311
- runs could start against one conversation is closed. Unlike the built-in Send it does **not**
312
- queue, so your composer keeps what it tried to send, and it does **not** consult the
313
- attachment tray: what you pass is what is sent, so your composer stays in charge of its own
314
- state.
310
+ flight. A continuation counts from the pick, and a send from the call rather than from when its
311
+ run starts, so a `sendMessage` from an `ag-ui-submit` listener, or a second call in the same
312
+ task, is refused rather than starting a second run. So is one made while a reload resumes a run
313
+ a navigating tool interrupted: the resume counts from the moment the element asks its
314
+ conversation store for the conversation, so a `sendMessage` while a remote store is still
315
+ answering is refused, and the built-in Send queues behind the resumed answer. Your own code
316
+ that runs on the way to the request — the conversation store's save, `getContext`, `getTools` —
317
+ can stop a send by starting a new chat or changing `user-key`, and then nothing is sent. Unlike
318
+ the built-in Send it does **not** queue, so your composer keeps what it tried to send, and it
319
+ does **not** consult the attachment tray: what you pass is what is sent, so your composer stays
320
+ in charge of its own state.
321
+
322
+ `retryLastTurn()` keeps the same rules, because it starts a run on the same conversation. It
323
+ returns `false` while a run, a send, another Retry, a continuation or a reload's resume is in
324
+ flight, and it counts from the call as a send does: until its run starts, a `sendMessage` or a
325
+ second Retry is refused, the built-in Send queues, and a checkpoint pick is refused. It also
326
+ returns `false` when your own code stops it before its run starts: a conversation store, or an
327
+ activity or tool renderer it redraws through, that starts a new chat or changes `user-key`. A
328
+ `getContext` or `getTools` that does the same stops it too, before anything is sent, but it runs
329
+ after the Retry has handed its turn to the client, so the call resolves `true`. A store that
330
+ throws from the Retry's save leaves the conversation as it was, and `retryLastTurn()` rejects
331
+ with its error.
315
332
 
316
333
  `attachFile(file)` queues a file into the tray exactly as the picker and drag-and-drop do, with
317
334
  the same validation and progress chip. It returns `false` when uploads are not configured
@@ -655,7 +672,10 @@ AG-UI has no server-side cancel route: cancelling **aborts the streaming request
655
672
  `cancel()` with no run in flight is a safe no-op. `newChat()` cancels any in-flight run before
656
673
  discarding the client, and so do switching conversations, `reload()` and removing the element. A
657
674
  [checkpoint continuation](#resuming-a-run) is the run in flight while it lasts, so Stop and all of
658
- these end it too.
675
+ these end it too. So does a turn that has not made its request yet: called from host code a send
676
+ or a resume runs on the way — the conversation store's save, `getContext`, `getTools` —
677
+ `cancel()` stops it before anything is sent, and `onCancelled()` and `onSettled()` fire as for any
678
+ other Stop.
659
679
 
660
680
  A cancelled run ends a moment later, once its request has closed or a running tool handler has
661
681
  returned. What it does then stays with the conversation it belonged to: its truncated exchange is
@@ -717,7 +737,8 @@ Whether a call is gated is decided in this order:
717
737
  for others, which a static flag can't express). **A predicate that throws or rejects refuses
718
738
  the call**: no card, the handler does not run, the tool card settles as declined, and the agent
719
739
  gets the `confirmCheckFailed` string as the result and carries on, as after a decline. The
720
- error goes to the console, never to the endpoint.
740
+ error goes to the console, never to the endpoint. A predicate still pending when the run is
741
+ stopped decides nothing: the call does not run, and its card settles as not finished.
721
742
  3. Else if the user has waived this tool name for the session, the call runs.
722
743
  4. Else the element falls back to [`isDestructive(parameters)`](src/tools/is_destructive.ts),
723
744
  which reads the `x-destructive` JSON-Schema flag.
@@ -1078,7 +1099,10 @@ matching JS API:
1078
1099
  server-backed store it stays on the server. Deleting one is the drawer row's own action. A chat
1079
1100
  nothing was ever sent in is the exception — it was never listed, so it is dropped rather than
1080
1101
  left behind. Focus moves to the composer, whichever control started the new chat, unless the
1081
- widget is collapsed, and the page is not scrolled to it.
1102
+ widget is collapsed, and the page is not scrolled to it. A restore still loading or replaying
1103
+ the conversation being left stops there, so nothing of it is drawn into the new chat, and a
1104
+ run it was about to resume after a reload is not resumed: coming back to that conversation
1105
+ later answers the interrupted call as not finished.
1082
1106
  - `describeSurface()` — where the panel is and what can be done to it: placement, collapsed,
1083
1107
  whether it can be moved, whether it fills the screen, its box and the viewport. `movable` folds
1084
1108
  the two reasons a move can fail into the one answer a caller needs.
@@ -1110,17 +1134,24 @@ that gap is parked too rather than racing it. What
1110
1134
  is waiting shows above the composer as chips, each of which takes its message
1111
1135
  back when pressed, and the next one is sent when the run settles. Stopping the
1112
1136
  run discards them: sending into a conversation someone has just stopped is the
1113
- opposite of what stopping meant. It is not thrown away, though — a queued
1114
- message has already left the composer, so it goes to the front of the recall
1115
- history below rather than nowhere.
1137
+ opposite of what stopping meant. Nothing is lost, though — a queued message
1138
+ entered the recall history below when it left the composer, so **Up** gets it
1139
+ back after a Stop, and after its chip is taken back.
1116
1140
 
1117
1141
  The composer also walks back through what you have already sent, on **Up** and
1118
- **Down** — the shape every shell and every coding agent uses. Only from an empty
1119
- composer and only with the skills palette closed: an arrow inside text is how you
1120
- move the caret, and taking it unconditionally would break editing to add a
1121
- shortcut. Arrowing forward past the newest turn empties the box again, so the way
1122
- out is the key that got you in. The history is this conversation's: starting a
1123
- new chat, switching threads or changing `user-key` clears it with the transcript.
1142
+ **Down** — the shape every shell and every coding agent uses. It holds every turn
1143
+ that left the composer: one sent at once, one queued behind a run (from the
1144
+ moment it is queued), and one sent to resume or fork a run from the checkpoint
1145
+ panel. A message sent with `sendMessage` is not in it, because it was never
1146
+ typed there. Only from an empty composer and only with the skills palette closed:
1147
+ an arrow inside text is how you move the caret, and taking it unconditionally
1148
+ would break editing to add a shortcut. Arrowing forward past the newest turn
1149
+ empties the box again, so the way out is the key that got you in. A walk lasts
1150
+ only while the composer holds the turn it put there: anything else that writes
1151
+ the box — typing, a quotation, a skill, dictation, or the host page itself — ends
1152
+ it, so the next arrow moves the caret in what was written rather than replacing
1153
+ it. The history is this conversation's: starting a new chat, switching threads
1154
+ or changing `user-key` clears it with the transcript.
1124
1155
 
1125
1156
  ### Collapsing to the launcher
1126
1157
 
@@ -1858,7 +1889,7 @@ chat.addEventListener("ag-ui-feedback", (e) => {
1858
1889
  analytics.track("assistant_rating", e.detail); // { content, rating }
1859
1890
  });
1860
1891
 
1861
- await chat.retryLastTurn(); // false when there is nothing to ask again
1892
+ await chat.retryLastTurn(); // false when there is nothing to ask again, or a run is in flight
1862
1893
  ```
1863
1894
 
1864
1895
  ## Quoting a selection
@@ -2091,6 +2122,16 @@ waived with *Always allow* are forgotten with it, so the next principal is asked
2091
2122
  sent on the next principal's first run, so a host that seeds shared state assigns it again for the
2092
2123
  principal who arrived.
2093
2124
 
2125
+ A handover also ends what the previous principal had in flight. Their run is stopped, and nothing
2126
+ it does afterwards is written into the next principal's storage or shared state: not the save a
2127
+ stopped run makes once its request closes, not a tool result that comes back after the Stop, not
2128
+ state already on its way. A tool call still waiting on `confirmPredicate` or its confirmation card
2129
+ does not run, one whose handler is still running draws nothing when it returns, and a navigating
2130
+ tool's checkpoint is never written into the next principal's thread. What they had typed into the
2131
+ composer and not sent is cleared with the transcript, quotations and skill templates included. A
2132
+ voice recording in progress is stopped before it is transcribed, and a clip already sent for
2133
+ transcription is dropped when its transcript comes back.
2134
+
2094
2135
  Set it live, from script, as part of signing out or in:
2095
2136
 
2096
2137
  ```js
@@ -2102,10 +2143,17 @@ out through its own router without remounting anything, so the host naming the n
2102
2143
  dropping the attribute — is the only signal the element will ever get. Removing the attribute
2103
2144
  purges too, so a sign-out that simply clears it is safe.
2104
2145
 
2146
+ It holds for an element that is out of the document too, such as a view a router keeps alive.
2147
+ Nothing is purged while it is detached: the handover runs when it is inserted again, against the
2148
+ key it has by then, so a key that changes and changes back while detached hands nothing over. An
2149
+ element that is never inserted again leaves the previous principal's conversation in
2150
+ `sessionStorage` under their key, where only an element naming that principal again can reach it.
2151
+
2105
2152
  The **first** value to arrive is treated as a host naming the user who was already there, not as a
2106
2153
  handover: the conversation in progress moves into the principal's namespace instead of being
2107
2154
  destroyed. So an element configured by an async auth handshake — the shape described in
2108
- [Framework hosts](#framework-hosts-configure-before-you-insert) — keeps what is on screen.
2155
+ [Framework hosts](#framework-hosts-configure-before-you-insert) — keeps what is on screen,
2156
+ including a run still streaming and whatever is in the composer.
2109
2157
 
2110
2158
  Two things it deliberately does not do. It does not scope the panel's own collapsed / dragged-size
2111
2159
  / theme preferences, which are this element's UI state and carry no conversation content. And it
@@ -2141,6 +2189,15 @@ chat.conversationStore = new RemoteConversationStore(
2141
2189
  );
2142
2190
  ```
2143
2191
 
2192
+ A conversation store you assign yourself is never replaced by a change of `user-key`, whether you
2193
+ assign it before the element connects or after. The one exception is a plain `SessionStorageStore`
2194
+ assigned before the element connects: that is the same kind as the element's own default, which is
2195
+ all connecting can see, so the element namespaces it as its own and moves it on every key change.
2196
+ Assign it after connecting, or wrap it, to keep it yours. A store that keeps its data somewhere
2197
+ the element cannot see has to scope itself; the element purges only its own `sessionStorage`
2198
+ namespace and clears what is on screen. If your store wraps a `SessionStorageStore`, build a new
2199
+ one per principal.
2200
+
2144
2201
  `SessionStorageStore.purge(namespace)` is the same primitive the element uses, for a host driving
2145
2202
  its own store from its own sign-out path.
2146
2203
 
@@ -2409,7 +2466,10 @@ Type the next turn in the composer, then pick a row:
2409
2466
  - **Resume** — continue that run.
2410
2467
  - **Fork** — branch it, leaving the original untouched.
2411
2468
 
2412
- Both send to the matching server endpoint and stream into the same transcript.
2469
+ Both send to the matching server endpoint and stream into the same transcript. The
2470
+ turn you typed is drawn there ahead of the answer and announced with `ag-ui-submit`,
2471
+ exactly as a send is, so a host that keeps its own record of what the user said sees
2472
+ continued turns too.
2413
2473
 
2414
2474
  Picking a row with an empty composer says so above the input and puts the caret
2415
2475
  there, rather than closing the panel over nothing: a continuation sends **only**