@artooi/ag-ui-web-component 0.22.0 → 0.23.1

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 (122) hide show
  1. package/CHANGELOG.md +134 -36
  2. package/README.md +7 -7
  3. package/dist/ag-ui-web-component.bundle.js +145 -118
  4. package/dist/ag-ui-web-component.bundle.js.map +3 -3
  5. package/dist/constants.d.ts +65 -78
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/core/ag_ui_chat.d.ts +93 -126
  8. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  9. package/dist/core/agui_client.d.ts +24 -30
  10. package/dist/core/agui_client.d.ts.map +1 -1
  11. package/dist/core/attachment.d.ts +9 -14
  12. package/dist/core/attachment.d.ts.map +1 -1
  13. package/dist/core/conversation_store.d.ts +20 -27
  14. package/dist/core/conversation_store.d.ts.map +1 -1
  15. package/dist/core/create_http_agent.d.ts +13 -15
  16. package/dist/core/create_http_agent.d.ts.map +1 -1
  17. package/dist/core/remote_conversation_store.d.ts +8 -9
  18. package/dist/core/remote_conversation_store.d.ts.map +1 -1
  19. package/dist/core/run_index.d.ts +11 -20
  20. package/dist/core/run_index.d.ts.map +1 -1
  21. package/dist/core/transcribe_audio.d.ts +8 -8
  22. package/dist/core/transcribe_audio.d.ts.map +1 -1
  23. package/dist/core/upload_attachment.d.ts +15 -18
  24. package/dist/core/upload_attachment.d.ts.map +1 -1
  25. package/dist/core/utils.d.ts +4 -6
  26. package/dist/core/utils.d.ts.map +1 -1
  27. package/dist/dom/animations.d.ts +22 -30
  28. package/dist/dom/animations.d.ts.map +1 -1
  29. package/dist/dom/dom_driver.d.ts +7 -7
  30. package/dist/dom/native_setter.d.ts +2 -2
  31. package/dist/dom/native_setter.d.ts.map +1 -1
  32. package/dist/index.js +347 -401
  33. package/dist/index.js.map +2 -2
  34. package/dist/skills/fill_template.d.ts +4 -5
  35. package/dist/skills/fill_template.d.ts.map +1 -1
  36. package/dist/skills/parse_skills.d.ts.map +1 -1
  37. package/dist/skills/skill.d.ts +7 -8
  38. package/dist/skills/skill.d.ts.map +1 -1
  39. package/dist/tools/client_tool_registry.d.ts +2 -2
  40. package/dist/tools/page_action_tools.d.ts +7 -10
  41. package/dist/tools/page_action_tools.d.ts.map +1 -1
  42. package/dist/tools/page_state.d.ts +5 -8
  43. package/dist/tools/page_state.d.ts.map +1 -1
  44. package/dist/tools/route_map.d.ts +7 -10
  45. package/dist/tools/route_map.d.ts.map +1 -1
  46. package/dist/ui/approval_card.d.ts +15 -20
  47. package/dist/ui/approval_card.d.ts.map +1 -1
  48. package/dist/ui/attach_copy_buttons.d.ts +4 -10
  49. package/dist/ui/attach_copy_buttons.d.ts.map +1 -1
  50. package/dist/ui/attachment_chips.d.ts +13 -5
  51. package/dist/ui/attachment_chips.d.ts.map +1 -1
  52. package/dist/ui/attachment_tray.d.ts +6 -6
  53. package/dist/ui/attachment_tray.d.ts.map +1 -1
  54. package/dist/ui/checkpoint_menu.d.ts +7 -8
  55. package/dist/ui/checkpoint_menu.d.ts.map +1 -1
  56. package/dist/ui/confirmation_card.d.ts +10 -15
  57. package/dist/ui/confirmation_card.d.ts.map +1 -1
  58. package/dist/ui/question_card.d.ts +12 -15
  59. package/dist/ui/question_card.d.ts.map +1 -1
  60. package/dist/ui/relative_time.d.ts +5 -7
  61. package/dist/ui/relative_time.d.ts.map +1 -1
  62. package/dist/ui/render_markdown.d.ts +8 -8
  63. package/dist/ui/render_markdown.d.ts.map +1 -1
  64. package/dist/ui/resize_handle.d.ts +21 -34
  65. package/dist/ui/resize_handle.d.ts.map +1 -1
  66. package/dist/ui/run_notice.d.ts +5 -7
  67. package/dist/ui/run_notice.d.ts.map +1 -1
  68. package/dist/ui/skills_menu.d.ts +4 -5
  69. package/dist/ui/skills_menu.d.ts.map +1 -1
  70. package/dist/ui/styles.d.ts +1 -1
  71. package/dist/ui/styles.d.ts.map +1 -1
  72. package/dist/ui/thoughts_block.d.ts +9 -11
  73. package/dist/ui/thoughts_block.d.ts.map +1 -1
  74. package/dist/ui/thread_drawer.d.ts +6 -5
  75. package/dist/ui/thread_drawer.d.ts.map +1 -1
  76. package/dist/ui/tool_call_card.d.ts +17 -25
  77. package/dist/ui/tool_call_card.d.ts.map +1 -1
  78. package/dist/ui/ui_strings.d.ts +6 -12
  79. package/dist/ui/ui_strings.d.ts.map +1 -1
  80. package/dist/ui/voice_input.d.ts +10 -11
  81. package/dist/ui/voice_input.d.ts.map +1 -1
  82. package/package.json +1 -1
  83. package/src/constants.ts +71 -80
  84. package/src/core/ag_ui_chat.ts +242 -292
  85. package/src/core/agui_client.ts +60 -71
  86. package/src/core/attachment.ts +9 -14
  87. package/src/core/conversation_store.ts +25 -33
  88. package/src/core/create_http_agent.ts +18 -22
  89. package/src/core/remote_conversation_store.ts +14 -15
  90. package/src/core/run_index.ts +14 -23
  91. package/src/core/transcribe_audio.ts +9 -10
  92. package/src/core/upload_attachment.ts +18 -21
  93. package/src/core/utils.ts +4 -6
  94. package/src/dom/animations.ts +33 -43
  95. package/src/dom/dom_driver.ts +7 -7
  96. package/src/dom/native_setter.ts +11 -12
  97. package/src/skills/fill_template.ts +4 -5
  98. package/src/skills/parse_skills.ts +3 -4
  99. package/src/skills/skill.ts +7 -8
  100. package/src/tools/client_tool_registry.ts +2 -2
  101. package/src/tools/page_action_tools.ts +12 -15
  102. package/src/tools/page_state.ts +5 -8
  103. package/src/tools/route_map.ts +15 -19
  104. package/src/ui/approval_card.ts +15 -20
  105. package/src/ui/attach_copy_buttons.ts +9 -18
  106. package/src/ui/attachment_chips.ts +19 -10
  107. package/src/ui/attachment_tray.ts +8 -7
  108. package/src/ui/checkpoint_menu.ts +7 -8
  109. package/src/ui/confirmation_card.ts +10 -15
  110. package/src/ui/question_card.ts +12 -15
  111. package/src/ui/relative_time.ts +5 -7
  112. package/src/ui/render_markdown.ts +25 -51
  113. package/src/ui/resize_handle.ts +25 -38
  114. package/src/ui/run_notice.ts +9 -12
  115. package/src/ui/skills_menu.ts +4 -5
  116. package/src/ui/styles.ts +122 -93
  117. package/src/ui/thoughts_block.ts +11 -13
  118. package/src/ui/thread_drawer.ts +6 -5
  119. package/src/ui/tool_call_card.ts +22 -32
  120. package/src/ui/ui_strings.ts +6 -12
  121. package/src/ui/voice_input.ts +10 -11
  122. package/src/version.ts +1 -1
@@ -3,16 +3,13 @@ import type { AttachmentRef } from "./attachment.js";
3
3
  /**
4
4
  * The composer's upload contract: take a `File`, report `0..1` progress, and
5
5
  * resolve to a durable {@link AttachmentRef}. The built-in handler is
6
- * {@link uploadAttachment} (multipart POST); a host swaps in its own e.g. a
7
- * `tus-js-client` or direct-to-S3 adapter via `AgUiChat.uploadHandler`,
8
- * **without** touching the tray, the chips, or the AG-UI wire (refs are
9
- * transport-agnostic).
6
+ * {@link uploadAttachment}; a host swaps in its own (a `tus-js-client` or
7
+ * direct-to-S3 adapter) via `AgUiChat.uploadHandler` without touching the tray,
8
+ * the chips, or the AG-UI wire, refs being transport-agnostic.
10
9
  *
11
- * The optional third `signal` argument lets the tray abort an in-flight upload
12
- * when its chip is removed (or the element is torn down), so a cancelled upload
13
- * doesn't orphan a server-side file. It is non-breaking: existing two-argument
14
- * handlers keep working (the extra argument is simply ignored), and a custom
15
- * handler that honours it should abort its own transport when the signal fires.
10
+ * The optional `signal` fires when the tray removes a chip or the element is
11
+ * torn down; a handler that honours it should abort its own transport, so a
12
+ * cancelled upload doesn't orphan a server-side file.
16
13
  */
17
14
  export type UploadHandler = (
18
15
  file: File,
@@ -28,11 +25,11 @@ export interface UploadOptions {
28
25
  readonly headers?: Record<string, string>;
29
26
  /**
30
27
  * Cookie policy, spelled as `fetch`'s `credentials` mode for consistency with
31
- * the component's other endpoints but carried by `XMLHttpRequest`, which
32
- * only has the two-state `withCredentials`. `"include"` sets it; every other
33
- * value leaves it off, which matches `"same-origin"`. `"omit"` therefore
34
- * **cannot** be honoured for a same-origin upload (XHR always sends cookies
35
- * there); use a custom {@link UploadHandler} if that matters.
28
+ * the other endpoints, but carried by `XMLHttpRequest`'s two-state
29
+ * `withCredentials`: `"include"` sets it and every other value leaves it off,
30
+ * matching `"same-origin"`. `"omit"` therefore cannot be honoured for a
31
+ * same-origin upload, XHR always sending cookies there; use a custom
32
+ * {@link UploadHandler} if that matters.
36
33
  */
37
34
  readonly credentials?: RequestCredentials;
38
35
  /** Progress callback, `0..1`, fired as the body uploads. */
@@ -45,10 +42,10 @@ export interface UploadOptions {
45
42
  * Upload one file to the attachments endpoint and resolve to its durable
46
43
  * {@link AttachmentRef}.
47
44
  *
48
- * Uses `XMLHttpRequest` (not `fetch`) for real upload-progress events: the file
49
- * is sent as multipart under the `file` field, with the element's `headers` so
50
- * CSRF / auth ride along exactly like the skills/tools fetches. A non-2xx
51
- * response or a network/abort error rejects, so the tray can show an error chip.
45
+ * Uses `XMLHttpRequest` rather than `fetch` for real upload-progress events.
46
+ * The file goes as multipart under the `file` field with the element's
47
+ * `headers`, so CSRF / auth ride along; a non-2xx response or a network/abort
48
+ * error rejects, letting the tray show an error chip.
52
49
  */
53
50
  export function uploadAttachment(file: File, options: UploadOptions): Promise<AttachmentRef> {
54
51
  return new Promise<AttachmentRef>((resolve, reject) => {
@@ -57,9 +54,9 @@ export function uploadAttachment(file: File, options: UploadOptions): Promise<At
57
54
 
58
55
  const xhr = new XMLHttpRequest();
59
56
  xhr.open("POST", options.url);
60
- // Cross-origin cookies ride only when asked for, exactly as with the fetch
61
- // sites; without this an upload to another subdomain is anonymous and 401s
62
- // while the run itself succeeds.
57
+ // Cross-origin cookies ride only when asked for, as at the fetch sites.
58
+ // Without this an upload to another subdomain goes anonymous and 401s while
59
+ // the run itself succeeds.
63
60
  xhr.withCredentials = options.credentials === "include";
64
61
  for (const [key, value] of Object.entries(options.headers ?? {})) {
65
62
  xhr.setRequestHeader(key, value);
package/src/core/utils.ts CHANGED
@@ -2,13 +2,11 @@
2
2
 
3
3
  /**
4
4
  * Overlay a `credentials` mode onto a fetch `init`, or hand the `init` back
5
- * untouched when the caller has none configured.
5
+ * untouched when none is configured.
6
6
  *
7
- * Absent and `undefined` are not the same thing here. `exactOptionalPropertyTypes`
8
- * rejects an explicit `credentials: undefined`, and writing one anyway would
9
- * state a mode where the point is to leave the browser's own default in place.
10
- * Every fetch this component makes has to make that choice, so it is made in one
11
- * place rather than repeated (and eventually forgotten) at each call site.
7
+ * Absent and `undefined` differ: `exactOptionalPropertyTypes` rejects an
8
+ * explicit `credentials: undefined`, and writing one anyway would state a mode
9
+ * where the point is to leave the browser's own default in place.
12
10
  */
13
11
  export function withCredentials(
14
12
  init: RequestInit | undefined,
@@ -28,12 +28,11 @@ function delay(ms: number): Promise<void> {
28
28
  /**
29
29
  * Whether the user has asked the OS/browser to minimise motion.
30
30
  *
31
- * Honoured by every primitive that *moves* something: the action animations
32
- * skip their hold delays, `scrollIntoCenterView` jumps instead of gliding, and
33
- * the focus flash drops its fade while still holding the ring long enough to be
34
- * seen — reduced motion asks for no animation, not for no feedback. The
35
- * character-typing and highlight primitives predate this and keep their
36
- * explicit-duration contract.
31
+ * Honoured by every primitive that moves something: hold delays are skipped,
32
+ * `scrollIntoCenterView` jumps instead of gliding, and the flash drops its fade
33
+ * but still holds the ring long enough to be seen — reduced motion asks for no
34
+ * animation, not for no feedback. `typeInto` and `highlightThenClick` keep
35
+ * their explicit-duration contract instead.
37
36
  */
38
37
  export function prefersReducedMotion(): boolean {
39
38
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
@@ -48,11 +47,11 @@ function motionDelay(ms: number): Promise<void> {
48
47
  }
49
48
 
50
49
  /**
51
- * Resolve the accent colour from the **target's** computed style.
50
+ * Resolve the accent colour from the target's own computed style.
52
51
  *
53
- * `--ag-ui-accent` inherits, so reading it off the element the agent is about
54
- * to touch picks up whatever the host's cascade produced there a themed page
55
- * gets flashed in its own colour instead of this package's indigo.
52
+ * `--ag-ui-accent` inherits, so reading it off the element about to be touched
53
+ * picks up whatever the host's cascade produced there, and a themed page is
54
+ * flashed in its own colour rather than this package's indigo.
56
55
  */
57
56
  function accentColor(el: HTMLElement, fallback: string): string {
58
57
  const themed = window.getComputedStyle(el).getPropertyValue(ACCENT_PROPERTY).trim();
@@ -72,8 +71,8 @@ export interface TypeOptions {
72
71
  }
73
72
 
74
73
  /**
75
- * Clear ``el`` and type ``value`` one character at a time, firing ``input``
76
- * events as a real user would, then a final ``change`` event.
74
+ * Clear `el` and type `value` one character at a time, firing an `input` event
75
+ * per character as a real user would, then a final `change`.
77
76
  */
78
77
  export async function typeInto(
79
78
  el: TextLikeElement,
@@ -98,7 +97,7 @@ export interface HighlightClickOptions {
98
97
  highlightMs?: number;
99
98
  }
100
99
 
101
- /** Outline ``el``, pause so the user sees it, then click and restore. */
100
+ /** Outline `el`, pause so the user sees it, then click and restore. */
102
101
  export async function highlightThenClick(
103
102
  el: HTMLElement,
104
103
  options: HighlightClickOptions = {},
@@ -128,12 +127,11 @@ const SCROLL_SETTLE_MS = 600;
128
127
  const SCROLL_START_MS = 100;
129
128
 
130
129
  /**
131
- * Scroll ``el`` to the vertical centre of the viewport.
130
+ * Scroll `el` to the vertical centre of the viewport.
132
131
  *
133
- * The returned promise resolves once the scroll has settled, so a caller can
134
- * hold its animation until the element has stopped moving — a ring drawn
135
- * mid-glide lands somewhere the user is not looking yet. Awaiting is optional;
136
- * the scroll itself is requested synchronously.
132
+ * Resolves once the scroll settles, so a caller can hold its animation until
133
+ * the element stops moving — a ring drawn mid-glide lands where the user is not
134
+ * looking yet. Awaiting is optional; the scroll is requested synchronously.
137
135
  */
138
136
  export function scrollIntoCenterView(el: HTMLElement, options: ScrollOptions = {}): Promise<void> {
139
137
  const reduced = prefersReducedMotion();
@@ -161,12 +159,10 @@ export function scrollIntoCenterView(el: HTMLElement, options: ScrollOptions = {
161
159
  // Neither event bubbles, and both fire on whichever ancestor actually
162
160
  // scrolled, so listen on the document in the capture phase.
163
161
  //
164
- // Two timeouts, because two things can go wrong. An element already in
165
- // view never scrolls and so never fires scrollend waiting the full
166
- // budget for it would add dead time to every action, hence the short
167
- // did-anything-move probe. Once something is moving, the longer budget
168
- // covers browsers that do not implement scrollend at all (Safari gained it
169
- // only recently).
162
+ // Two timeouts, for two failure modes: an element already in view never
163
+ // scrolls and so never fires scrollend (the short did-anything-move probe),
164
+ // and once something is moving the longer budget covers browsers without
165
+ // scrollend at all.
170
166
  timer = setTimeout(settle, SCROLL_START_MS);
171
167
  document.addEventListener("scroll", started, true);
172
168
  document.addEventListener("scrollend", settle, true);
@@ -180,10 +176,7 @@ const FLASH_MS = 1200;
180
176
  const FLASH_FADE_RATIO = 1 / 3;
181
177
 
182
178
  export interface FlashOptions {
183
- /**
184
- * Total milliseconds the ring is on screen, hold plus fade. Default 1200 —
185
- * long enough for someone who does not yet know where to look to find it.
186
- */
179
+ /** Total milliseconds the ring is on screen, hold plus fade. Default 1200. */
187
180
  flashMs?: number;
188
181
  /** Ring colour. Defaults to the target's `--ag-ui-accent`, else the package accent. */
189
182
  color?: string;
@@ -220,8 +213,8 @@ async function flashRing(
220
213
  const fadeMs = prefersReducedMotion() ? 0 : Math.round(flashMs * FLASH_FADE_RATIO);
221
214
  await delay(flashMs - fadeMs);
222
215
  if (fadeMs > 0) {
223
- // Setting the transition and the new colour in the same task is fine: the
224
- // browser starts transitions from the after-change style.
216
+ // Transition and new colour in the same task is fine: the browser starts
217
+ // transitions from the after-change style.
225
218
  el.style.transition = `outline-color ${fadeMs}ms ease-out`;
226
219
  el.style.outline = "3px solid transparent";
227
220
  await delay(fadeMs);
@@ -232,9 +225,9 @@ async function flashRing(
232
225
  }
233
226
 
234
227
  /**
235
- * Flash a ring around ``el`` without touching focus.
228
+ * Flash a ring around `el` without touching focus.
236
229
  *
237
- * Prefer this over {@link focusWithFlash} when the point is to *show* the user
230
+ * Prefer this over {@link focusWithFlash} when the point is to show the user
238
231
  * something: moving focus steals it from the composer, can fire blur validation
239
232
  * on whatever they were mid-edit in, and can close an open menu.
240
233
  */
@@ -243,11 +236,8 @@ export function flash(el: HTMLElement, options: FlashOptions = {}): Promise<void
243
236
  }
244
237
 
245
238
  /**
246
- * Focus ``el`` and flash a ring around it.
247
- *
248
- * Focus moves unless ``options.focus`` says otherwise — that is the documented
249
- * behaviour of this name. Use {@link flash} for a highlight that leaves focus
250
- * where the user put it.
239
+ * Focus `el` and flash a ring around it. Focus moves unless `options.focus`
240
+ * says otherwise; use {@link flash} to leave focus where the user put it.
251
241
  */
252
242
  export function focusWithFlash(el: HTMLElement, options: FlashOptions = {}): Promise<void> {
253
243
  return flashRing(el, options, true);
@@ -259,9 +249,9 @@ export interface PressOptions {
259
249
  }
260
250
 
261
251
  /**
262
- * Show a brief "pressed" affordance on a button/control — a slight scale-down
263
- * plus accent ring — then click it and restore. Reads as an actual press, not
264
- * just an outline (cf. {@link highlightThenClick}).
252
+ * Show a brief pressed affordance on a control — a slight scale-down plus
253
+ * accent ring — then click it and restore. Reads as a press rather than the
254
+ * plain outline {@link highlightThenClick} draws.
265
255
  */
266
256
  export async function pressThenClick(el: HTMLElement, options: PressOptions = {}): Promise<void> {
267
257
  const pressMs = options.pressMs ?? 140;
@@ -283,7 +273,7 @@ export interface SelectOptions {
283
273
  highlightMs?: number;
284
274
  }
285
275
 
286
- /** Find an option in ``el`` whose value or visible text equals ``value``. */
276
+ /** Find an option in `el` whose value or visible text equals `value`. */
287
277
  function findOption(el: HTMLSelectElement, value: string): HTMLOptionElement | null {
288
278
  for (const option of Array.from(el.options)) {
289
279
  if (option.value === value || option.text === value) {
@@ -295,7 +285,7 @@ function findOption(el: HTMLSelectElement, value: string): HTMLOptionElement | n
295
285
 
296
286
  /**
297
287
  * Outline a `<select>`, pause so the user sees the pick, then set it to the
298
- * option matching ``value`` (by value or visible text) and fire `input` +
288
+ * option matching `value` (by value or visible text) and fire `input` +
299
289
  * `change`. Throws when no option matches.
300
290
  */
301
291
  export async function selectOption(
@@ -326,7 +316,7 @@ export interface ToggleOptions {
326
316
  }
327
317
 
328
318
  /**
329
- * Flash a ring around a checkbox/radio, set its ``checked`` state, and fire
319
+ * Flash a ring around a checkbox/radio, set its `checked` state, and fire
330
320
  * `input` + `change` so frameworks observe the flip.
331
321
  */
332
322
  export async function toggleControl(
@@ -25,16 +25,16 @@ import { setNativeChecked, setNativeValue } from "./native_setter.js";
25
25
  */
26
26
 
27
27
  /**
28
- * A field has to hold focus to be typed into, so ``focus`` is not on offer
29
- * here everything else the flash takes is.
28
+ * Every flash option except `focus`, which is not on offer: a field has to hold
29
+ * focus to be typed into.
30
30
  */
31
31
  export interface FillFieldOptions extends TypeOptions, Omit<FlashOptions, "focus"> {}
32
32
 
33
33
  /**
34
- * Scroll to, focus (with a flash), and type ``value`` into a text field.
34
+ * Scroll to, focus (with a flash), and type `value` into a text field.
35
35
  *
36
- * The scroll is awaited: typing into an element that is still gliding past
37
- * shows the user nothing.
36
+ * The scroll is awaited typing into an element still gliding past shows the
37
+ * user nothing.
38
38
  */
39
39
  export async function fillField(
40
40
  el: TextLikeElement,
@@ -82,8 +82,8 @@ export async function toggleCheckbox(
82
82
  }
83
83
 
84
84
  /**
85
- * Set a `<select>` or checkbox value without typing animation, dispatching the
86
- * ``input`` and ``change`` events frameworks listen for.
85
+ * Set a `<select>` or checkbox value without animation, dispatching the `input`
86
+ * and `change` events frameworks listen for.
87
87
  */
88
88
  export function setControlValue(
89
89
  el: HTMLInputElement | HTMLSelectElement,
@@ -1,18 +1,17 @@
1
- // Set a control's `value` / `checked` through the **native prototype setter**,
2
- // so framework value-tracking sees the change. React (and Vue/Svelte) replace
3
- // the element's `value`/`checked` setter with a tracked one; assigning
4
- // `el.value = x` directly hits that override and the subsequent `input` event
5
- // carries no change, so the field looks filled but the framework's state stays
6
- // empty. Calling the original prototype setter, then dispatching `input`, makes
7
- // `fillField` / `typeInto` / `setControlValue` work on framework-controlled
8
- // inputs out of the box.
1
+ // Set a control's `value` / `checked` through the native prototype setter, so
2
+ // framework value-tracking sees the change. React (and Vue/Svelte) replace the
3
+ // element's own setter with a tracked one, so `el.value = x` hits that override
4
+ // and the following `input` event carries no change: the field looks filled
5
+ // while the framework's state stays empty. Calling the original prototype
6
+ // setter and then dispatching `input` avoids that.
9
7
 
10
8
  type ValueSetter = (this: HTMLElement, value: string) => void;
11
9
  type CheckedSetter = (this: HTMLElement, checked: boolean) => void;
12
10
 
13
- /** The original prototype setter for ``prop`` on ``proto``. */
11
+ /** The original prototype setter for `prop` on `proto`. */
14
12
  function prototypeSetter(proto: object, prop: string): (this: HTMLElement, value: never) => void {
15
- // Captured once at module load; DOM environments always define these.
13
+ // Captured once at module load; DOM environments always define these, which
14
+ // is what makes the descriptor cast safe.
16
15
  const setter = (Object.getOwnPropertyDescriptor(proto, prop) as PropertyDescriptor).set;
17
16
  return setter as unknown as (this: HTMLElement, value: never) => void;
18
17
  }
@@ -22,7 +21,7 @@ const setTextareaValue = prototypeSetter(HTMLTextAreaElement.prototype, "value")
22
21
  const setSelectValue = prototypeSetter(HTMLSelectElement.prototype, "value") as ValueSetter;
23
22
  const setInputChecked = prototypeSetter(HTMLInputElement.prototype, "checked") as CheckedSetter;
24
23
 
25
- /** Set ``el.value`` via the element's native prototype setter. */
24
+ /** Set `el.value` via the element's native prototype setter. */
26
25
  export function setNativeValue(
27
26
  el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,
28
27
  value: string,
@@ -36,7 +35,7 @@ export function setNativeValue(
36
35
  }
37
36
  }
38
37
 
39
- /** Set ``el.checked`` via the native prototype setter. */
38
+ /** Set `el.checked` via the native prototype setter. */
40
39
  export function setNativeChecked(el: HTMLInputElement, checked: boolean): void {
41
40
  setInputChecked.call(el, checked);
42
41
  }
@@ -9,12 +9,11 @@ export interface TemplateResult {
9
9
  const PLACEHOLDER_RE = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
10
10
 
11
11
  /**
12
- * Substitute `{name}` placeholders in ``template`` from ``values``.
12
+ * Substitute `{name}` placeholders in `template` from `values`.
13
13
  *
14
- * A placeholder whose value is missing, ``null``, or an empty string is left
15
- * verbatim and reported in ``missing`` the caller blocks send and tells the
16
- * user what's needed (e.g. "select rows first") rather than sending a
17
- * half-filled prompt.
14
+ * A placeholder whose value is missing, `null`, or an empty string is left
15
+ * verbatim and reported in `missing`, so the caller can block the send rather
16
+ * than dispatch a half-filled prompt.
18
17
  */
19
18
  export function fillTemplate(template: string, values: Record<string, unknown>): TemplateResult {
20
19
  const missing: string[] = [];
@@ -1,11 +1,10 @@
1
1
  import type { Skill } from "./skill.js";
2
2
 
3
3
  /**
4
- * Whether ``value`` has the required string fields of a {@link Skill}.
4
+ * Whether `value` has the required string fields of a {@link Skill}.
5
5
  *
6
- * `prompt` is optional and must stay so: a server-resolved skill deliberately
7
- * omits it, and requiring it here would silently drop exactly the skills whose
8
- * wording was kept off the client.
6
+ * `prompt` must stay optional: a server-resolved skill omits it, and requiring
7
+ * it would silently drop exactly the skills kept off the client.
9
8
  */
10
9
  function isSkill(value: unknown): value is Skill {
11
10
  if (typeof value !== "object" || value === null) {
@@ -15,17 +15,16 @@ export interface Skill {
15
15
  * The prompt to send. May contain `{placeholder}`s filled from the host's
16
16
  * skill context before send; an unfilled placeholder blocks send.
17
17
  *
18
- * **Omit it to keep the prompt on the server.** The skill then sends the bare
19
- * `/name` token and the agent resolves what it means, so the wording never
20
- * reaches the browser worth preferring for anything internal, since a
21
- * fetched catalog is a plain GET and an embedded one sits in the page source.
18
+ * Omit it to keep the prompt server-side: the skill then sends the bare
19
+ * `/name` token for the agent to resolve, and the wording never reaches the
20
+ * browser. Prefer that for anything internal a fetched catalog is a plain
21
+ * GET and an embedded one sits in the page source.
22
22
  */
23
23
  readonly prompt?: string;
24
24
  /**
25
- * Set `false` to pre-fill the composer instead of sending on pick. Only
26
- * meaningful for a skill that carries its own `prompt`; a server-resolved one
27
- * always sends. Defaults to sending — a chip that needs a second click to do
28
- * anything is a two-step shortcut.
25
+ * Set `false` to pre-fill the composer instead of sending on pick. Defaults
26
+ * to sending, and is only meaningful for a skill carrying its own `prompt`;
27
+ * a server-resolved one always sends.
29
28
  */
30
29
  readonly sendImmediately?: boolean;
31
30
  /** Also surface this skill as a chip (default false; the palette shows all). */
@@ -27,8 +27,8 @@ export class ClientToolRegistry {
27
27
  /**
28
28
  * Register a tool, replacing any existing one with the same name.
29
29
  *
30
- * Idempotent on the name so re-fired host refs / React StrictMode's
31
- * double-invoke don't throw re-registering is a replace, not an error.
30
+ * Idempotent on the name so a re-fired host ref or React StrictMode's
31
+ * double-invoke replaces rather than throws.
32
32
  */
33
33
  register(tool: ClientTool): void {
34
34
  this.#tools.set(tool.name, tool);
@@ -4,10 +4,8 @@ import type { ClientTool } from "./client_tool_registry.js";
4
4
 
5
5
  /**
6
6
  * Resolve a page-action target string to a host-page element, or `null` when it
7
- * matches nothing. The default (`document.querySelector`) treats the string as a
8
- * CSS selector; a host with a page map overrides it to map its own element ids,
9
- * the same way host packages wrap the DOM-driver primitives with environment-
10
- * aware lookups.
7
+ * matches nothing. The default treats the string as a CSS selector; a host with
8
+ * a page map overrides it to map its own element ids.
11
9
  */
12
10
  export type ResolvePageTarget = (target: string) => HTMLElement | null;
13
11
 
@@ -24,13 +22,12 @@ export const PAGE_ACTIONS = {
24
22
  * - `scroll_to` — scroll a target (`top` / `bottom` / a resolver target) into
25
23
  * view. Benign; no confirmation.
26
24
  * - `drag_and_drop` — drag one element onto another, firing the standard HTML5
27
- * drag sequence so the host page's own drop handler reacts. Not stamped
28
- * destructive: a drag rearranges transient state and the durable change
29
- * happens at the page's explicit commit. A host whose page persists *on drop*
30
- * gates it with the element's `confirmPredicate`.
25
+ * drag sequence so the host page's own drop handler reacts. Deliberately not
26
+ * stamped destructive: a drag rearranges transient state, and the durable
27
+ * change happens at the page's explicit commit. A host whose page persists on
28
+ * drop must gate it with the element's `confirmPredicate`.
31
29
  *
32
- * Both report a clean, model-readable error when a target resolves to nothing,
33
- * rather than throwing an opaque crash.
30
+ * Both report a model-readable error when a target resolves to nothing.
34
31
  */
35
32
  export function createPageActionTools(
36
33
  enabled: ReadonlySet<string>,
@@ -106,11 +103,11 @@ function dragTool(resolveTarget: ResolvePageTarget): ClientTool {
106
103
  }
107
104
 
108
105
  /**
109
- * Fire the standard HTML5 drag sequence `dragstart` on the source, then
110
- * `dragenter` / `dragover` / `drop` on the target, then `dragend` on the source —
111
- * sharing one {@link DataTransfer}. Dispatched as typed, bubbling events (the
112
- * `dataTransfer` is attached explicitly so a drop handler reads it in every
113
- * environment).
106
+ * Fire the standard HTML5 drag sequence in the order a page's own handlers
107
+ * expect — `dragstart` on the source, `dragenter` / `dragover` / `drop` on the
108
+ * target, `dragend` on the source — all sharing one {@link DataTransfer}, which
109
+ * is attached to each event explicitly so a drop handler reads it in every
110
+ * environment.
114
111
  */
115
112
  function dispatchDragSequence(from: HTMLElement, to: HTMLElement): void {
116
113
  const dataTransfer = new DataTransfer();
@@ -7,11 +7,9 @@ import type { ClientTool } from "./client_tool_registry.js";
7
7
  * Ergonomic sugar over `registerTool` for SPA state (Redux/Zustand/signals):
8
8
  * generates a read tool and, when `write` is given, a destructive set tool.
9
9
  *
10
- * This is **not** AG-UI shared state. `STATE_SNAPSHOT` / `STATE_DELTA` are
11
- * protocol events carrying state between agent and client; this is a pair of
12
- * ordinary client tools the agent calls like any other. The two are unrelated,
13
- * which is why this no longer carries the word "hook" — the old name read as
14
- * protocol state sync, which this component does not implement.
10
+ * Not AG-UI shared state. `STATE_SNAPSHOT` / `STATE_DELTA` are protocol events
11
+ * carrying state between agent and client; these are ordinary client tools the
12
+ * agent calls like any other.
15
13
  */
16
14
  export interface PageState {
17
15
  /** Base name; tools become `read_<name>` and `set_<name>`. */
@@ -59,9 +57,8 @@ export function createPageStateTools(binding: PageState): ClientTool[] {
59
57
  }
60
58
 
61
59
  /**
62
- * @deprecated Renamed to {@link PageState}. The old name read as AG-UI
63
- * shared-state sync (`STATE_SNAPSHOT` / `STATE_DELTA`), which this component
64
- * does not implement. Will be removed in a future major.
60
+ * @deprecated Renamed to {@link PageState} the old name read as AG-UI
61
+ * shared-state sync. Will be removed in a future major.
65
62
  */
66
63
  export type StateHook = PageState;
67
64
 
@@ -7,9 +7,8 @@ export interface Route {
7
7
  readonly id: string;
8
8
  /**
9
9
  * The URL path to navigate to. May contain `:name` placeholders for dynamic
10
- * segments (e.g. `/admin/shop/book/:pk/change/`); the agent fills them via
11
- * the `navigate_to_route` `params` argument. Real apps are mostly
12
- * parameterised — few pages have a truly static path.
10
+ * segments (e.g. `/admin/shop/book/:pk/change/`), which the agent fills via
11
+ * `navigate_to_route`'s `params` argument.
13
12
  */
14
13
  readonly path: string;
15
14
  /** Human label shown to the agent. */
@@ -33,20 +32,19 @@ const PATH_PARAM_RE = /:([A-Za-z_][A-Za-z0-9_]*)/g;
33
32
 
34
33
  /** The `:name` path-parameter names declared in a path template, in order. */
35
34
  function pathParamNames(path: string): string[] {
36
- // Slicing the ":" off the whole match rather than reading the capture group:
37
- // the group is mandatory, so under `noUncheckedIndexedAccess` indexing it
38
- // forces an `undefined` guard on a case the regex cannot produce an
39
- // unreachable branch no test can ever cover.
35
+ // Slice the ":" off the whole match rather than read the capture group: under
36
+ // `noUncheckedIndexedAccess`, indexing the group forces an `undefined` guard
37
+ // on a case the regex cannot produce, which no test can cover.
40
38
  return [...path.matchAll(PATH_PARAM_RE)].map((match) => match[0].slice(1));
41
39
  }
42
40
 
43
41
  /**
44
- * Substitute `:name` placeholders in ``path`` from ``params``.
42
+ * Substitute `:name` placeholders in `path` from `params`.
45
43
  *
46
- * Returns the concrete path plus the params *not* consumed by a placeholder, so
47
- * the caller can append those as a query string. Throws (referencing
48
- * ``routeId``) when a declared path param is missing or empty — a half-filled
49
- * path must never be navigated to.
44
+ * Returns the concrete path plus the params no placeholder consumed, for the
45
+ * caller to append as a query string. Throws (naming `routeId`) when a declared
46
+ * path param is missing or empty — a half-filled path must never be navigated
47
+ * to.
50
48
  */
51
49
  function fillPath(
52
50
  routeId: string,
@@ -79,13 +77,11 @@ function withQuery(path: string, params: Record<string, unknown>): string {
79
77
  * The built-in `route.*` tools, bound to live getters so a host can set
80
78
  * `routeMap` / `navigate` before or after mount.
81
79
  *
82
- * `list_routes` is read-only and advertises each route's dynamic
83
- * `pathParams` so the model knows what to supply. `navigate_to_route` is marked
84
- * `x-navigates` so an MPA reload checkpoints + resumes; it substitutes path
85
- * params into the template and appends any remaining params as a query string.
86
- * When the host supplies a `navigate(path)` callback (an SPA), the element
87
- * routes client-side instead and the run loop simply continues — see
88
- * `AgUiChat`'s execute path.
80
+ * `list_routes` is read-only and advertises each route's `pathParams` so the
81
+ * model knows what to supply. `navigate_to_route` fills those params, appends
82
+ * the rest as a query string, and is stamped `x-navigates` so an MPA reload
83
+ * checkpoints and resumes; with a host `navigate(path)` callback (an SPA) it
84
+ * routes client-side and the run loop continues instead.
89
85
  */
90
86
  export function createRouteTools(
91
87
  getRouteMap: () => RouteMap,
@@ -25,9 +25,8 @@ function actionButton(modifier: string, label: string): HTMLButtonElement {
25
25
  /** Options for {@link requestApproval}. */
26
26
  export interface ApprovalOptions {
27
27
  /**
28
- * Aborting this signal resolves the card as **denied** (buttons disabled,
29
- * `data-resolved="denied"`)the hook a Stop control uses to dismiss a
30
- * pending approval when the user cancels the whole run.
28
+ * Aborting this signal resolves the card as denied, with buttons disabled and
29
+ * `data-resolved="denied"` — how a Stop control dismisses a pending approval.
31
30
  */
32
31
  signal?: AbortSignal;
33
32
  /** Localized strings; defaults to the English {@link DEFAULT_UI_STRINGS}. */
@@ -36,13 +35,11 @@ export interface ApprovalOptions {
36
35
 
37
36
  /**
38
37
  * A fully custom renderer for a server-side-tool approval, set via
39
- * `AgUiChat.approvalRenderer`. Receives the {@link ApprovalRequest} (the
40
- * interrupt's message + tool name) and an `AbortSignal` that fires when the run
41
- * is stopped, and resolves `true` to approve or `false` to deny. When provided
42
- * it **replaces** the built-in {@link requestApproval} card entirely the host
43
- * owns the DOM, so it can render a native modal, a framework component, or
44
- * anything else. See the `strings` / `::part()` seams for styling the built-in
45
- * card instead of replacing it.
38
+ * `AgUiChat.approvalRenderer`. Receives the {@link ApprovalRequest} and an
39
+ * `AbortSignal` that fires when the run is stopped, and resolves `true` to
40
+ * approve or `false` to deny. Replaces the built-in {@link requestApproval}
41
+ * card entirely, the host owning the DOM; to restyle the built-in card instead,
42
+ * use the `strings` and `::part()` seams.
46
43
  */
47
44
  export type ApprovalRenderer = (
48
45
  request: ApprovalRequest,
@@ -50,17 +47,15 @@ export type ApprovalRenderer = (
50
47
  ) => Promise<boolean>;
51
48
 
52
49
  /**
53
- * Append an inline **approval** card to ``host`` and resolve when the user
54
- * decides whether a gated *server-side* tool may run.
50
+ * Append an inline approval card to `host` and resolve `true` to run a gated
51
+ * server-side tool or `false` to deny it.
55
52
  *
56
- * The server-side approval gate is distinct from the client-tool confirmation
57
- * card ({@link requestConfirmation}): a destructive server tool defers instead
58
- * of executing, and the run finishes on an AG-UI *interrupt* the client answers
59
- * with `resume[]`. This card is the browser half of that loop it reads
60
- * naturally after the tool-call card whose execution it gates, and resolves
61
- * ``true`` to approve (run the tool) or ``false`` to deny. The card stays in the
62
- * transcript as a resolved record (buttons disabled, `data-resolved` set)
63
- * rather than vanishing.
53
+ * Distinct from the client-tool confirmation card
54
+ * ({@link requestConfirmation}): a gated server tool defers instead of
55
+ * executing, so the run finishes on an AG-UI interrupt the client answers with
56
+ * `resume[]`, and this is the browser half of that loop. Unlike the
57
+ * confirmation card, this one stays in the transcript as a resolved record,
58
+ * buttons disabled and `data-resolved` set.
64
59
  */
65
60
  export function requestApproval(
66
61
  host: Node & ParentNode,