@artooi/ag-ui-web-component 0.39.0 → 0.40.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +155 -1
  2. package/README.md +70 -12
  3. package/dist/ag-ui-web-component.bundle.js +168 -45
  4. package/dist/ag-ui-web-component.bundle.js.map +3 -3
  5. package/dist/core/ag_ui_chat.d.ts +7 -3
  6. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  7. package/dist/core/agui_client.d.ts +12 -0
  8. package/dist/core/agui_client.d.ts.map +1 -1
  9. package/dist/core/client_seed.d.ts +14 -2
  10. package/dist/core/client_seed.d.ts.map +1 -1
  11. package/dist/index.js +636 -231
  12. package/dist/index.js.map +2 -2
  13. package/dist/tools/tool_catalog.d.ts.map +1 -1
  14. package/dist/ui/composer/composer_attachments.d.ts +6 -1
  15. package/dist/ui/composer/composer_attachments.d.ts.map +1 -1
  16. package/dist/ui/composer/composer_voice.d.ts +3 -0
  17. package/dist/ui/composer/composer_voice.d.ts.map +1 -1
  18. package/dist/ui/excerpts/transcript_quote_offer.d.ts +7 -2
  19. package/dist/ui/excerpts/transcript_quote_offer.d.ts.map +1 -1
  20. package/dist/ui/history/conversation_history.d.ts +29 -3
  21. package/dist/ui/history/conversation_history.d.ts.map +1 -1
  22. package/dist/ui/placement/launcher_drag.d.ts +6 -0
  23. package/dist/ui/placement/launcher_drag.d.ts.map +1 -1
  24. package/dist/ui/placement/panel_placement.d.ts +1 -1
  25. package/dist/ui/placement/panel_placement.d.ts.map +1 -1
  26. package/dist/ui/styles.d.ts +1 -1
  27. package/dist/ui/styles.d.ts.map +1 -1
  28. package/dist/ui/transcript/transcript.d.ts +3 -2
  29. package/dist/ui/transcript/transcript.d.ts.map +1 -1
  30. package/dist/ui/ui_strings.d.ts +2 -0
  31. package/dist/ui/ui_strings.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/core/ag_ui_chat.ts +217 -64
  34. package/src/core/agui_client.ts +26 -14
  35. package/src/core/client_seed.ts +14 -2
  36. package/src/tools/tool_catalog.ts +63 -12
  37. package/src/ui/composer/composer_attachments.ts +64 -41
  38. package/src/ui/composer/composer_voice.ts +5 -0
  39. package/src/ui/excerpts/transcript_quote_offer.ts +26 -13
  40. package/src/ui/history/conversation_history.ts +125 -17
  41. package/src/ui/placement/launcher_drag.ts +104 -89
  42. package/src/ui/placement/panel_placement.ts +27 -3
  43. package/src/ui/styles.ts +137 -14
  44. package/src/ui/transcript/transcript.ts +10 -5
  45. package/src/ui/ui_strings.ts +3 -0
  46. package/src/version.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM,wruHA8jHlB,CAAC"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/ui/styles.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM,or8HAyrHlB,CAAC"}
@@ -42,9 +42,10 @@ export declare class Transcript {
42
42
  /**
43
43
  * Start following the foot of the list, and wire the jump button to it.
44
44
  * Called while rendering rather than at construction: the viewport has to
45
- * exist and the observer has to have something to observe.
45
+ * exist and the observer has to have something to observe. The button
46
+ * outlives a connection, so its listener goes under `signal`.
46
47
  */
47
- mountScroller(jumpButton: HTMLButtonElement): void;
48
+ mountScroller(jumpButton: HTMLButtonElement, signal: AbortSignal): void;
48
49
  /** Stop following, when the element leaves the document. */
49
50
  disposeScroller(): void;
50
51
  /** Keep the list at its foot, if the reader is there. */
@@ -1 +1 @@
1
- {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../../src/ui/transcript/transcript.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../../src/ui/transcript/transcript.ts"],"names":[],"mappings":"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"}
@@ -115,6 +115,8 @@ export interface UiStrings {
115
115
  notConnected: string;
116
116
  /** Composer hint when a run continuation was picked with an empty composer. */
117
117
  continueNeedsTurn: string;
118
+ /** Composer hint when a run continuation was picked while a run is in flight. */
119
+ continueWhileRunning: string;
118
120
  /** `aria-label` of the message textarea. */
119
121
  message: string;
120
122
  /** Placeholder of the message textarea. */
@@ -1 +1 @@
1
- {"version":3,"file":"ui_strings.d.ts","sourceRoot":"","sources":["../../src/ui/ui_strings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui_strings.d.ts","sourceRoot":"","sources":["../../src/ui/ui_strings.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artooi/ag-ui-web-component",
3
- "version": "0.39.0",
3
+ "version": "0.40.0",
4
4
  "description": "Framework-free <ag-ui-chat> Web Component over the AG-UI protocol. Drop-in chat sidebar with a pluggable client-side tool registry, DOM driver primitives, animations, and destructive-action confirmation modal.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,4 +1,4 @@
1
- import type { Context, Message, Tool } from "@ag-ui/core";
1
+ import type { Context, Tool } from "@ag-ui/core";
2
2
  import {
3
3
  ATTACHMENT_EVENT,
4
4
  CHART_ACTIVITY_TYPE,
@@ -242,6 +242,8 @@ export class AgUiChat extends HTMLElement {
242
242
  * Optional full replacement for the `ask_user` question UI, resolving with
243
243
  * the answer; the same seam as {@link approvalRenderer}, styled via `strings`
244
244
  * and the `question*` `::part()`s when left unset. Requires {@link askUser}.
245
+ * A renderer that throws or rejects hands the question to the built-in card,
246
+ * as a failing {@link approvalRenderer} does, unless Stop already fired.
245
247
  */
246
248
  askUserRenderer: QuestionRenderer | null = null;
247
249
 
@@ -585,11 +587,38 @@ export class AgUiChat extends HTMLElement {
585
587
  readonly #voice: ComposerVoice;
586
588
  /** Whether the element is currently in the DOM; gates the connect-time warning. */
587
589
  #connected = false;
590
+ /**
591
+ * Aborted when the element leaves the document, and replaced when it comes
592
+ * back.
593
+ *
594
+ * Every listener connecting adds to an element that outlives the connection
595
+ * -- the composer, Send, the launcher, the shell -- is added under this
596
+ * signal. Connecting runs again on every insertion, so a listener added
597
+ * without it is a second listener the next time: one click on Stop stopped
598
+ * the run three times, and one press of the built-in theme toggle flipped it
599
+ * twice, back to where it started.
600
+ */
601
+ #connection = new AbortController();
602
+ /**
603
+ * Whether the element has connected before, which makes this connection a
604
+ * re-insertion: there is a transcript on screen from last time, and the
605
+ * history replay would draw the conversation a second time beneath it.
606
+ */
607
+ #connectedBefore = false;
608
+ /**
609
+ * The remote store `data-threads-url` wrapped around the conversation store,
610
+ * and the store inside it, so connecting again can wrap that store rather
611
+ * than the wrapper.
612
+ */
613
+ #threadStore: { remote: RemoteConversationStore; inner: ClientConversationStore } | null = null;
588
614
 
589
615
  #client: AgUiClient | null = null;
590
616
  // Seed for the next client. Once one exists it owns the live value (the
591
617
  // agent applies STATE_SNAPSHOT / STATE_DELTA into it), so this is only the
592
- // starting point — `sharedState` reads through to the client when present.
618
+ // starting point — `sharedState` reads through to the client when present,
619
+ // and to a running checkpoint continuation before that. Every client mirrors
620
+ // its changes here, which is what the client built after a continuation is
621
+ // seeded from.
593
622
  #sharedState: Record<string, unknown> = {};
594
623
  // Whether an interaction is in flight (first onRunStart → onSettled). Drives
595
624
  // the Send⇄Stop button: `agent.isRunning` is false between frontend-tool
@@ -807,7 +836,12 @@ export class AgUiChat extends HTMLElement {
807
836
  },
808
837
  });
809
838
  this.#checkpoints = new CheckpointMenu((runId, verb) => {
810
- void this.#history.continueRun(runId, verb);
839
+ // Reported rather than dropped: the send fails when the host's store
840
+ // refuses the first save, and `continueRun` has already let go of the
841
+ // continuation by then, so the panel takes another pick.
842
+ void this.#history.continueRun(runId, verb).catch((error: unknown) => {
843
+ console.warn("<ag-ui-chat>: continuing a run failed", error);
844
+ });
811
845
  });
812
846
  this.#history = new ConversationHistory({
813
847
  element: this,
@@ -827,8 +861,14 @@ export class AgUiChat extends HTMLElement {
827
861
  requestCredentials: () => this.#requestCredentials(),
828
862
  appendMessage: (role, content) => this.appendMessage(role, content),
829
863
  autoGrow: () => autoGrow(this.#input),
864
+ continuationEnded: () => this.#flushQueued(),
865
+ client: () => this.#client,
830
866
  ensureClient: () => this.#ensureClient(),
831
867
  buildClient: (seed) => this.#buildClient(seed),
868
+ releaseClient: () => {
869
+ this.#client = null;
870
+ },
871
+ running: () => this.#running,
832
872
  cancelRun: () => this.#cancelRun(),
833
873
  resetState: () => this.#resetState(),
834
874
  setRunning: (running) => this.#setRunning(running),
@@ -952,14 +992,38 @@ export class AgUiChat extends HTMLElement {
952
992
  * from {@link registerPageState}, which exposes host state as ordinary tools.
953
993
  */
954
994
  get sharedState(): Readonly<Record<string, unknown>> {
955
- return this.#client?.state ?? this.#sharedState;
995
+ return this.#liveClient()?.state ?? this.#sharedState;
956
996
  }
957
997
 
958
998
  set sharedState(state: Readonly<Record<string, unknown>>) {
959
999
  this.#sharedState = { ...state };
960
1000
  // A client already exists for this conversation — push it through so the
961
1001
  // next run sends it, rather than silently waiting for a new conversation.
962
- this.#client?.setState(this.#sharedState);
1002
+ // A continuation in flight is that client while it runs: its next round
1003
+ // sends what it holds, and the getter reads it back from there.
1004
+ this.#liveClient()?.setState(this.#sharedState);
1005
+ }
1006
+
1007
+ /**
1008
+ * The client holding the conversation's live shared state: a checkpoint
1009
+ * continuation while one runs, otherwise the conversation's own client, and
1010
+ * `null` before either exists.
1011
+ *
1012
+ * The continuation first, because the state it streams is applied to its own
1013
+ * agent. Reading the conversation's client alone returned what the state was
1014
+ * before the continuation began, for as long as that client lived.
1015
+ *
1016
+ * It now lives no longer than the continuation's first save, which hands the
1017
+ * conversation to the next client built, seeded from the mirror every client
1018
+ * writes -- so the next run sends what the continuation left. That release
1019
+ * alone makes the getter's fallback give the same answer, and no test can
1020
+ * tell the two apart; reading the continuation keeps the getter right
1021
+ * without depending on when the other client is let go. The setter has no
1022
+ * such fallback, and is held by "reads the shared state it changed while it
1023
+ * runs, not the conversation's" in `ag_ui_chat_checkpoints.test.ts`.
1024
+ */
1025
+ #liveClient(): AgUiClient | null {
1026
+ return this.#history.continuation ?? this.#client;
963
1027
  }
964
1028
 
965
1029
  /** Bind a piece of host page state to `read_<name>` / `set_<name>` tools. */
@@ -1164,6 +1228,18 @@ export class AgUiChat extends HTMLElement {
1164
1228
  }
1165
1229
 
1166
1230
  connectedCallback(): void {
1231
+ // A fresh signal per connection: disconnecting aborted the last one, and
1232
+ // with it every listener the last connection added.
1233
+ this.#connection = new AbortController();
1234
+ // Coming back is a reload, not a merge, for the reason `reload()` is: the
1235
+ // run was cancelled on the way out, and the transcript is rebuilt below
1236
+ // from persisted history -- which could only be appended to what is still
1237
+ // showing. The composer's recall history is kept, because a move is not a
1238
+ // farewell and disconnecting put the queued messages there on purpose.
1239
+ if (this.#connectedBefore) {
1240
+ this.#resetConversation();
1241
+ }
1242
+ this.#connectedBefore = true;
1167
1243
  // Resolve the per-instance storage namespace before any key read/write, so
1168
1244
  // this instance doesn't share collapsed/theme/thread state with another on
1169
1245
  // the same origin.
@@ -1206,7 +1282,7 @@ export class AgUiChat extends HTMLElement {
1206
1282
  this.#skills.init();
1207
1283
  // Namespace the built-in default store too (a host-injected store is used
1208
1284
  // verbatim). Must precede #wireThreadStore, which wraps the current store.
1209
- this.conversationStore = this.#storage.scopeStore(this.conversationStore, this.userKey);
1285
+ this.conversationStore = this.#storage.scopeStore(this.#unwrappedStore(), this.userKey);
1210
1286
  window.addEventListener("resize", this.#onViewportResize);
1211
1287
  // The visual viewport changes without the window resizing -- a keyboard
1212
1288
  // opening, a pinch-zoom, the URL bar collapsing -- and `scroll` is what
@@ -1215,7 +1291,7 @@ export class AgUiChat extends HTMLElement {
1215
1291
  window.visualViewport?.addEventListener("scroll", this.#onViewportResize);
1216
1292
  this.#placement.publishVisualViewport();
1217
1293
  this.#wireThreadStore();
1218
- this.#attachments.wire();
1294
+ this.#attachments.wire(this.#connection.signal);
1219
1295
  this.#voice.wire();
1220
1296
  this.#history.adoptActiveThread();
1221
1297
  // The catalog requests go out a microtask later, so a host configuring
@@ -1290,6 +1366,7 @@ export class AgUiChat extends HTMLElement {
1290
1366
  */
1291
1367
  disconnectedCallback(): void {
1292
1368
  this.#connected = false;
1369
+ this.#connection.abort();
1293
1370
  window.removeEventListener("resize", this.#onViewportResize);
1294
1371
  window.visualViewport?.removeEventListener("resize", this.#onViewportResize);
1295
1372
  window.visualViewport?.removeEventListener("scroll", this.#onViewportResize);
@@ -1410,18 +1487,38 @@ export class AgUiChat extends HTMLElement {
1410
1487
  * thread id, the navigation checkpoint) keep their local store either way.
1411
1488
  */
1412
1489
  #wireThreadStore(): void {
1490
+ this.#threadStore = null;
1413
1491
  const url = this.getAttribute("data-threads-url");
1414
1492
  if (url !== null) {
1415
- this.conversationStore = new RemoteConversationStore(
1493
+ const inner = this.conversationStore;
1494
+ const remote = new RemoteConversationStore(
1416
1495
  url,
1417
1496
  () => this.#headersFor(url),
1418
- this.conversationStore,
1497
+ inner,
1419
1498
  () => this.#requestCredentials(),
1420
1499
  this.getAttribute("data-threads-cache") !== "false",
1421
1500
  );
1501
+ this.#threadStore = { remote, inner };
1502
+ this.conversationStore = remote;
1422
1503
  }
1423
1504
  }
1424
1505
 
1506
+ /**
1507
+ * The conversation store without the remote this element wrapped it in.
1508
+ *
1509
+ * An element removed and inserted again connects again, and wrapping the
1510
+ * wrapper stacked a second remote on the first, so every rename and delete
1511
+ * reached the server twice. Unwrapping first also lets a `data-threads-url`
1512
+ * removed while detached take the remote away. A store the host assigned
1513
+ * since is theirs, and comes back as it is.
1514
+ */
1515
+ #unwrappedStore(): ClientConversationStore {
1516
+ const wrapped = this.#threadStore;
1517
+ return wrapped !== null && this.conversationStore === wrapped.remote
1518
+ ? wrapped.inner
1519
+ : this.conversationStore;
1520
+ }
1521
+
1425
1522
  /**
1426
1523
  * Replace the host-supplied (client) skill catalog. Merged after the embedded
1427
1524
  * and fetched skills (so a client skill overrides a same-named server one).
@@ -1737,6 +1834,24 @@ export class AgUiChat extends HTMLElement {
1737
1834
 
1738
1835
  /** Drop the in-memory run + transcript, leaving the thread id untouched. */
1739
1836
  #resetState(): void {
1837
+ this.#resetConversation();
1838
+ // The composer's own history goes with the conversation it was typed
1839
+ // into. The path that makes this more than tidiness is the `user-key`
1840
+ // rescope, which purges storage and wipes the transcript precisely so the
1841
+ // previous principal's words are not visible to the next one -- and would
1842
+ // otherwise leave every one of them a single ArrowUp away.
1843
+ this.#sentDrafts.length = 0;
1844
+ this.#recallIndex = null;
1845
+ }
1846
+
1847
+ /**
1848
+ * Drop the in-memory run and transcript, and nothing the user typed.
1849
+ *
1850
+ * Split from {@link #resetState} for re-insertion, which rebuilds the
1851
+ * conversation from history but is not a new one, so the composer's recall
1852
+ * history stays.
1853
+ */
1854
+ #resetConversation(): void {
1740
1855
  this.#client = null;
1741
1856
  // Every path here has just cancelled the run, but a cancelled run ends
1742
1857
  // later: once its request closes, or once a host tool's handler returns.
@@ -1746,13 +1861,6 @@ export class AgUiChat extends HTMLElement {
1746
1861
  this.#runHandlers.detach();
1747
1862
  this.#clearTranscript();
1748
1863
  this.#history.forgetRestored();
1749
- // The composer's own history goes with the conversation it was typed
1750
- // into. The path that makes this more than tidiness is the `user-key`
1751
- // rescope, which purges storage and wipes the transcript precisely so the
1752
- // previous principal's words are not visible to the next one -- and would
1753
- // otherwise leave every one of them a single ArrowUp away.
1754
- this.#sentDrafts.length = 0;
1755
- this.#recallIndex = null;
1756
1864
  }
1757
1865
 
1758
1866
  /**
@@ -1835,7 +1943,19 @@ export class AgUiChat extends HTMLElement {
1835
1943
  return this.#transcript.append(role, content);
1836
1944
  }
1837
1945
 
1946
+ /**
1947
+ * Build the chrome, from the attributes as they stand.
1948
+ *
1949
+ * Runs on every connect, not once, because removing and re-inserting the
1950
+ * element is the documented way to apply a connect-time attribute written
1951
+ * late. So it has to build the same element the second time as the first:
1952
+ * the elements made here are new each time, the long-lived ones it fills
1953
+ * are filled with `replaceChildren` rather than appended to, and every
1954
+ * listener on a long-lived one goes under the connection's signal. Appending
1955
+ * gave a re-inserted element two headers and two composers.
1956
+ */
1838
1957
  #render(): void {
1958
+ const { signal } = this.#connection;
1839
1959
  this.#chat.className = "chat";
1840
1960
  this.#chat.setAttribute("part", "panel");
1841
1961
 
@@ -1901,7 +2021,7 @@ export class AgUiChat extends HTMLElement {
1901
2021
  this.#themeToggle.setAttribute("part", "header-button theme-toggle");
1902
2022
  this.#themeToggle.title = this.#strings.toggleTheme;
1903
2023
  this.#themeToggle.setAttribute("aria-label", this.#strings.toggleTheme);
1904
- this.#themeToggle.addEventListener("click", () => this.toggleTheme());
2024
+ this.#themeToggle.addEventListener("click", () => this.toggleTheme(), { signal });
1905
2025
  this.#syncThemeGlyph();
1906
2026
  controls.append(this.#themeToggle);
1907
2027
  }
@@ -1931,11 +2051,11 @@ export class AgUiChat extends HTMLElement {
1931
2051
  this.#jumpButton.textContent = this.#strings.jumpToLatest;
1932
2052
 
1933
2053
  // The quote offer, and the transcript's settled selections it listens for.
1934
- this.#excerpts.mount();
2054
+ this.#excerpts.mount(signal);
1935
2055
 
1936
2056
  // Built here rather than at field initialisation: the viewport has to exist
1937
2057
  // and the observer has to have something to observe.
1938
- this.#transcript.mountScroller(this.#jumpButton);
2058
+ this.#transcript.mountScroller(this.#jumpButton, signal);
1939
2059
 
1940
2060
  this.#announcer.mount();
1941
2061
 
@@ -1955,7 +2075,6 @@ export class AgUiChat extends HTMLElement {
1955
2075
  greetingSlot.append(this.#greetingText);
1956
2076
  greeting.append(greetingSlot);
1957
2077
  this.#syncGreeting();
1958
- this.#emptyWrap.append(greeting);
1959
2078
  const emptySlot = document.createElement("slot");
1960
2079
  emptySlot.name = "empty";
1961
2080
  // Fallback content, so a host that slots its own gets exactly that and
@@ -1967,7 +2086,7 @@ export class AgUiChat extends HTMLElement {
1967
2086
  if (starters !== null) {
1968
2087
  emptySlot.append(starters);
1969
2088
  }
1970
- this.#emptyWrap.append(emptySlot);
2089
+ this.#emptyWrap.replaceChildren(greeting, emptySlot);
1971
2090
  this.#queuedRow.className = "queued";
1972
2091
  this.#queuedRow.setAttribute("part", "queued");
1973
2092
  this.#queuedRow.setAttribute("role", "group");
@@ -1997,8 +2116,8 @@ export class AgUiChat extends HTMLElement {
1997
2116
  this.#input.setAttribute("aria-label", this.#strings.message);
1998
2117
  this.#input.rows = 1;
1999
2118
  this.#input.placeholder = this.#strings.inputPlaceholder;
2000
- this.#input.addEventListener("keydown", (event) => this.#onKeydown(event));
2001
- this.#input.addEventListener("input", () => this.#onInput());
2119
+ this.#input.addEventListener("keydown", (event) => this.#onKeydown(event), { signal });
2120
+ this.#input.addEventListener("input", () => this.#onInput(), { signal });
2002
2121
 
2003
2122
  // Icon-only, with both glyphs mounted at once and CSS showing the one the
2004
2123
  // state calls for — swapping a single glyph would leave a host that slotted
@@ -2006,22 +2125,26 @@ export class AgUiChat extends HTMLElement {
2006
2125
  this.#send.className = "send";
2007
2126
  this.#send.type = "button";
2008
2127
  this.#send.setAttribute("part", "send");
2009
- this.#send.append(
2128
+ this.#send.replaceChildren(
2010
2129
  glyphSlot("icon-send", "send-send", ICON_SEND),
2011
2130
  glyphSlot("icon-stop", "send-stop", ICON_STOP),
2012
2131
  );
2013
2132
  this.#send.title = this.#strings.send;
2014
2133
  this.#send.setAttribute("aria-label", this.#strings.send);
2015
2134
  this.#send.dataset["state"] = "idle";
2016
- this.#send.addEventListener("click", () => {
2017
- // One button, two states: Send while idle, Stop while a run is in
2018
- // flight (no layout change).
2019
- if (this.#running) {
2020
- this.#cancelRun();
2021
- return;
2022
- }
2023
- void this.#submit();
2024
- });
2135
+ this.#send.addEventListener(
2136
+ "click",
2137
+ () => {
2138
+ // One button, two states: Send while idle, Stop while a run is in
2139
+ // flight (no layout change).
2140
+ if (this.#running) {
2141
+ this.#cancelRun();
2142
+ return;
2143
+ }
2144
+ void this.#submit();
2145
+ },
2146
+ { signal },
2147
+ );
2025
2148
 
2026
2149
  this.#composerHint.className = "skill-hint";
2027
2150
  this.#composerHint.setAttribute("part", "skill-hint");
@@ -2033,17 +2156,19 @@ export class AgUiChat extends HTMLElement {
2033
2156
  this.#attachButton.className = "attach-btn";
2034
2157
  this.#attachButton.type = "button";
2035
2158
  this.#attachButton.setAttribute("part", "attach-button");
2036
- this.#attachButton.append(glyphSlot("icon-attach", "attach-glyph", ICON_ATTACH));
2159
+ this.#attachButton.replaceChildren(glyphSlot("icon-attach", "attach-glyph", ICON_ATTACH));
2037
2160
  this.#attachButton.title = this.#strings.attachFiles;
2038
2161
  this.#attachButton.setAttribute("aria-label", this.#strings.attachFiles);
2039
2162
  this.#attachButton.hidden = true;
2040
- this.#attachButton.addEventListener("click", () => this.#fileInput.click());
2163
+ this.#attachButton.addEventListener("click", () => this.#fileInput.click(), { signal });
2041
2164
 
2042
2165
  this.#fileInput.className = "attach-input";
2043
2166
  this.#fileInput.type = "file";
2044
2167
  this.#fileInput.multiple = true;
2045
2168
  this.#fileInput.hidden = true;
2046
- this.#fileInput.addEventListener("change", () => this.#attachments.onFilesPicked());
2169
+ this.#fileInput.addEventListener("change", () => this.#attachments.onFilesPicked(), {
2170
+ signal,
2171
+ });
2047
2172
 
2048
2173
  this.#attachSlot.className = "attachment-slot";
2049
2174
 
@@ -2063,9 +2188,9 @@ export class AgUiChat extends HTMLElement {
2063
2188
  this.#messagesWrap.className = "messages-wrap";
2064
2189
  // Sibling of the list inside a shared box, not a child of it: the
2065
2190
  // affordance offering to scroll must not scroll away with the content.
2066
- this.#messagesWrap.append(this.#messages, this.#jumpButton, this.#excerpts.button);
2191
+ this.#messagesWrap.replaceChildren(this.#messages, this.#jumpButton, this.#excerpts.button);
2067
2192
 
2068
- this.#chat.append(
2193
+ this.#chat.replaceChildren(
2069
2194
  header,
2070
2195
  this.#messagesWrap,
2071
2196
  this.#skillsMenu.palette,
@@ -2087,16 +2212,20 @@ export class AgUiChat extends HTMLElement {
2087
2212
  // button's own click, so closing here and toggling there would land back open.
2088
2213
  // Composed path rather than `target`, because the event is retargeted at the
2089
2214
  // shadow boundary and every one of these nodes is inside it.
2090
- this.#chat.addEventListener("pointerdown", (event) => {
2091
- if (!this.#checkpoints.open_) {
2092
- return;
2093
- }
2094
- const path = event.composedPath();
2095
- if (path.includes(this.#checkpoints.element) || path.includes(checkpoints)) {
2096
- return;
2097
- }
2098
- this.#checkpoints.close();
2099
- });
2215
+ this.#chat.addEventListener(
2216
+ "pointerdown",
2217
+ (event) => {
2218
+ if (!this.#checkpoints.open_) {
2219
+ return;
2220
+ }
2221
+ const path = event.composedPath();
2222
+ if (path.includes(this.#checkpoints.element) || path.includes(checkpoints)) {
2223
+ return;
2224
+ }
2225
+ this.#checkpoints.close();
2226
+ },
2227
+ { signal },
2228
+ );
2100
2229
 
2101
2230
  // What a collapsed widget shrinks to: a round floating button, or the slim
2102
2231
  // edge rail under `placement="sidebar"` — one element, shaped by CSS.
@@ -2120,20 +2249,20 @@ export class AgUiChat extends HTMLElement {
2120
2249
  this.#railLabel.setAttribute("part", "rail-label");
2121
2250
  this.#railLabel.setAttribute("aria-hidden", "true");
2122
2251
  this.#railLabel.textContent = this.getAttribute("title-text") ?? this.#strings.title;
2123
- this.#launcher.append(
2252
+ this.#launcher.replaceChildren(
2124
2253
  iconElement("launcher", "launcher-icon", ICON_LAUNCHER, readLauncherIconUrl(this)),
2125
2254
  this.#railLabel,
2126
2255
  this.#badge,
2127
2256
  );
2128
- this.#launcher.addEventListener("click", () => this.setCollapsed(false));
2129
- this.#placement.enableLauncherDrag();
2257
+ this.#launcher.addEventListener("click", () => this.setCollapsed(false), { signal });
2258
+ this.#placement.enableLauncherDrag(signal);
2130
2259
 
2131
2260
  this.#placement.mountResizeGrips(this.#chat);
2132
2261
  adoptStyles(this.#root);
2133
2262
  const probe = this.#placement.probe;
2134
2263
  probe.className = "viewport-probe";
2135
2264
  probe.setAttribute("aria-hidden", "true");
2136
- this.#root.append(probe, this.#announcer.region, this.#chat, this.#launcher);
2265
+ this.#root.replaceChildren(probe, this.#announcer.region, this.#chat, this.#launcher);
2137
2266
  }
2138
2267
 
2139
2268
  /**
@@ -2328,6 +2457,15 @@ export class AgUiChat extends HTMLElement {
2328
2457
  * other shape would be a second sender racing the guard above.
2329
2458
  */
2330
2459
  #flushQueued(): void {
2460
+ // Guarded here rather than at each caller, because this is what takes the
2461
+ // turn off the queue: a caller that ran while something was still in
2462
+ // flight would shift a turn off and lose it to the no-op in `sendMessage`.
2463
+ // A continuation settles its run before the element lets go of it, so the
2464
+ // settle below arrives while `continuation` is still set, and the release
2465
+ // that follows is what drains.
2466
+ if (this.#running || this.#history.continuation !== null) {
2467
+ return;
2468
+ }
2331
2469
  const next = this.#queued.shift();
2332
2470
  this.#renderQueued();
2333
2471
  if (next !== undefined) {
@@ -2378,11 +2516,16 @@ export class AgUiChat extends HTMLElement {
2378
2516
  // the first's still-pending tool cards. That is why this was a dead key --
2379
2517
  // Enter during a run did nothing at all, silently.
2380
2518
  //
2519
+ // A picked checkpoint counts as in flight from the pick, not from its
2520
+ // first event: `running` is a request behind it, and a turn sent in that
2521
+ // window ran against the conversation the continuation had already frozen
2522
+ // to save against, so one of the two saves dropped the other's turn.
2523
+ //
2381
2524
  // Queueing keeps the guard and gives the key something to do. Text only:
2382
2525
  // an attachment is settled state the tray is holding and the composer has
2383
2526
  // no second copy of, so parking it here would mean deciding what happens
2384
2527
  // when the user then removes the chip.
2385
- if (this.#running) {
2528
+ if (this.#running || this.#history.continuation !== null) {
2386
2529
  if (content !== "") {
2387
2530
  this.#queued.push(content);
2388
2531
  this.#renderQueued();
@@ -2432,12 +2575,18 @@ export class AgUiChat extends HTMLElement {
2432
2575
  * `attachments` are durable {@link AttachmentRef}s — what {@link attachFile}
2433
2576
  * resolves to and what {@link ATTACHMENT_EVENT} reports.
2434
2577
  *
2435
- * No-ops on an empty message, and while a run is in flight, since a second
2436
- * concurrent run would orphan the first. Unlike the built-in Send it does not
2437
- * consult the tray: what you pass is what is sent.
2578
+ * No-ops on an empty message, and while a run or a picked checkpoint's
2579
+ * continuation is in flight, since a second concurrent run would orphan the
2580
+ * first. Unlike the built-in Send it does not queue: it returns, and the
2581
+ * caller keeps what it tried to send. Nor does it consult the tray -- what
2582
+ * you pass is what is sent.
2438
2583
  */
2439
2584
  async sendMessage(content: string, attachments: readonly AttachmentRef[] = []): Promise<void> {
2440
- if (this.#running || (content === "" && attachments.length === 0)) {
2585
+ if (
2586
+ this.#running ||
2587
+ this.#history.continuation !== null ||
2588
+ (content === "" && attachments.length === 0)
2589
+ ) {
2441
2590
  return;
2442
2591
  }
2443
2592
  // Only a send travels. Every other way out of the empty state -- a restored
@@ -2522,7 +2671,8 @@ export class AgUiChat extends HTMLElement {
2522
2671
  this.#client = this.#buildClient({
2523
2672
  endpoint: this.endpoint,
2524
2673
  initialMessages: this.#history.restored,
2525
- persist: true,
2674
+ // Its history is the whole conversation, so nothing goes ahead of it.
2675
+ follows: [],
2526
2676
  });
2527
2677
  }
2528
2678
  return this.#client;
@@ -2564,12 +2714,15 @@ export class AgUiChat extends HTMLElement {
2564
2714
  getContext: () => this.#dispatch.buildContext(),
2565
2715
  executeTool: (call) => this.#dispatch.execute(call),
2566
2716
  resolveInterrupts: (interrupts) => this.#dispatch.resolveInterrupts(interrupts),
2567
- ...(seed.persist
2568
- ? {
2569
- onPersist: (messages: readonly Message[]) =>
2570
- this.conversationStore.saveMessages(threadId, messages),
2571
- }
2572
- : {}),
2717
+ // Every client saves the whole conversation, because a store keeps one
2718
+ // list per thread. For the conversation's own client that is its
2719
+ // history; a continuation holds only what it adds, and writes the
2720
+ // conversation it continues ahead of that.
2721
+ onPersist: (messages) => {
2722
+ const conversation = [...seed.follows, ...messages];
2723
+ this.conversationStore.saveMessages(threadId, conversation);
2724
+ seed.onSaved?.(conversation);
2725
+ },
2573
2726
  onStateChanged: (state) => this.#onSharedStateChanged(state),
2574
2727
  connectionLostMessage: this.#strings.connectionLost,
2575
2728
  unfinishedMessage: this.#strings.callNotFinished,