@artooi/ag-ui-web-component 0.23.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 (121) hide show
  1. package/CHANGELOG.md +73 -36
  2. package/README.md +7 -7
  3. package/dist/ag-ui-web-component.bundle.js +98 -117
  4. package/dist/ag-ui-web-component.bundle.js.map +3 -3
  5. package/dist/constants.d.ts +56 -85
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/core/ag_ui_chat.d.ts +90 -127
  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 +290 -378
  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 +7 -10
  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/checkpoint_menu.d.ts +7 -8
  54. package/dist/ui/checkpoint_menu.d.ts.map +1 -1
  55. package/dist/ui/confirmation_card.d.ts +10 -15
  56. package/dist/ui/confirmation_card.d.ts.map +1 -1
  57. package/dist/ui/question_card.d.ts +12 -15
  58. package/dist/ui/question_card.d.ts.map +1 -1
  59. package/dist/ui/relative_time.d.ts +5 -7
  60. package/dist/ui/relative_time.d.ts.map +1 -1
  61. package/dist/ui/render_markdown.d.ts +8 -8
  62. package/dist/ui/render_markdown.d.ts.map +1 -1
  63. package/dist/ui/resize_handle.d.ts +21 -34
  64. package/dist/ui/resize_handle.d.ts.map +1 -1
  65. package/dist/ui/run_notice.d.ts +5 -7
  66. package/dist/ui/run_notice.d.ts.map +1 -1
  67. package/dist/ui/skills_menu.d.ts +4 -5
  68. package/dist/ui/skills_menu.d.ts.map +1 -1
  69. package/dist/ui/styles.d.ts +1 -1
  70. package/dist/ui/styles.d.ts.map +1 -1
  71. package/dist/ui/thoughts_block.d.ts +9 -11
  72. package/dist/ui/thoughts_block.d.ts.map +1 -1
  73. package/dist/ui/thread_drawer.d.ts +6 -5
  74. package/dist/ui/thread_drawer.d.ts.map +1 -1
  75. package/dist/ui/tool_call_card.d.ts +17 -25
  76. package/dist/ui/tool_call_card.d.ts.map +1 -1
  77. package/dist/ui/ui_strings.d.ts +6 -12
  78. package/dist/ui/ui_strings.d.ts.map +1 -1
  79. package/dist/ui/voice_input.d.ts +10 -11
  80. package/dist/ui/voice_input.d.ts.map +1 -1
  81. package/package.json +1 -1
  82. package/src/constants.ts +58 -87
  83. package/src/core/ag_ui_chat.ts +239 -267
  84. package/src/core/agui_client.ts +60 -71
  85. package/src/core/attachment.ts +9 -14
  86. package/src/core/conversation_store.ts +25 -33
  87. package/src/core/create_http_agent.ts +18 -22
  88. package/src/core/remote_conversation_store.ts +14 -15
  89. package/src/core/run_index.ts +14 -23
  90. package/src/core/transcribe_audio.ts +9 -10
  91. package/src/core/upload_attachment.ts +18 -21
  92. package/src/core/utils.ts +4 -6
  93. package/src/dom/animations.ts +33 -43
  94. package/src/dom/dom_driver.ts +7 -7
  95. package/src/dom/native_setter.ts +11 -12
  96. package/src/skills/fill_template.ts +4 -5
  97. package/src/skills/parse_skills.ts +3 -4
  98. package/src/skills/skill.ts +7 -8
  99. package/src/tools/client_tool_registry.ts +2 -2
  100. package/src/tools/page_action_tools.ts +12 -15
  101. package/src/tools/page_state.ts +5 -8
  102. package/src/tools/route_map.ts +15 -19
  103. package/src/ui/approval_card.ts +15 -20
  104. package/src/ui/attach_copy_buttons.ts +9 -18
  105. package/src/ui/attachment_chips.ts +7 -10
  106. package/src/ui/attachment_tray.ts +6 -6
  107. package/src/ui/checkpoint_menu.ts +7 -8
  108. package/src/ui/confirmation_card.ts +10 -15
  109. package/src/ui/question_card.ts +12 -15
  110. package/src/ui/relative_time.ts +5 -7
  111. package/src/ui/render_markdown.ts +25 -51
  112. package/src/ui/resize_handle.ts +25 -38
  113. package/src/ui/run_notice.ts +9 -12
  114. package/src/ui/skills_menu.ts +4 -5
  115. package/src/ui/styles.ts +79 -98
  116. package/src/ui/thoughts_block.ts +11 -13
  117. package/src/ui/thread_drawer.ts +6 -5
  118. package/src/ui/tool_call_card.ts +22 -32
  119. package/src/ui/ui_strings.ts +6 -12
  120. package/src/ui/voice_input.ts +10 -11
  121. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -83,8 +83,8 @@ var ClientToolRegistry = class {
83
83
  /**
84
84
  * Register a tool, replacing any existing one with the same name.
85
85
  *
86
- * Idempotent on the name so re-fired host refs / React StrictMode's
87
- * double-invoke don't throw re-registering is a replace, not an error.
86
+ * Idempotent on the name so a re-fired host ref or React StrictMode's
87
+ * double-invoke replaces rather than throws.
88
88
  */
89
89
  register(tool) {
90
90
  this.#tools.set(tool.name, tool);
@@ -4477,12 +4477,11 @@ var STYLES = `
4477
4477
  only the alias is used by the rules below.
4478
4478
 
4479
4479
  The indirection is what makes ancestor theming work. Declaring the public
4480
- name on :host would set it *on the host element*, and a value on an element
4481
- always beats one inherited from an ancestor \u2014 so a page that put the tokens
4482
- on a wrapper would see no effect at all, which is the one thing the API is
4483
- documented to support. Reading the public name with the default as a var()
4484
- fallback leaves it undeclared on the element, so an ancestor's value is
4485
- inherited normally while a value aimed at the element still wins over it.
4480
+ name on :host would set it on the host element, and a value on an element
4481
+ always beats one inherited from an ancestor, so tokens put on a wrapper
4482
+ would have no effect. Reading the public name with the default as a var()
4483
+ fallback leaves it undeclared on the element, so an ancestor's value
4484
+ inherits normally while one aimed at the element still wins.
4486
4485
 
4487
4486
  Two invariants hold this together:
4488
4487
  1. No rule outside this file's :host blocks may reference a public name
@@ -4509,11 +4508,9 @@ var STYLES = `
4509
4508
  --_border: var(--ag-ui-border, #e2e2ec);
4510
4509
  --_radius: var(--ag-ui-radius, 12px);
4511
4510
 
4512
- /* Body text and raised chrome. Both are referenced by the code-block copy
4513
- button; neither had a default before, so the declarations reading them
4514
- were dropped and the button fell back to the inherited colour over a
4515
- transparent box. The defaults below restate exactly that, so this is a
4516
- rename with no repaint \u2014 see the note on .code-copy. */
4511
+ /* Body text and raised chrome, read only by the code-block copy button.
4512
+ The defaults restate what it inherits, so a host that sets neither sees
4513
+ no repaint \u2014 see the note on .code-copy. */
4517
4514
  --_text: var(--ag-ui-text, var(--_fg));
4518
4515
  --_surface: var(--ag-ui-surface, transparent);
4519
4516
 
@@ -4566,9 +4563,9 @@ var STYLES = `
4566
4563
  --_launcher-inset: var(--ag-ui-launcher-inset, auto 0 0 auto);
4567
4564
 
4568
4565
  /* Motion. One duration and two curves drive every collapse, expand and
4569
- slide-over, so the whole widget accelerates and settles as one thing.
4570
- The default curve is a long-tailed ease-out (a fast start that decelerates
4571
- into place); the pop curve overshoots slightly, for something arriving. */
4566
+ slide-over, so the widget accelerates and settles as one thing. The
4567
+ default curve decelerates into place; the pop curve overshoots slightly,
4568
+ for something arriving. */
4572
4569
  --_motion: var(--ag-ui-motion, 0.28s);
4573
4570
  --_ease: var(--ag-ui-ease, cubic-bezier(0.32, 0.72, 0, 1));
4574
4571
  --_ease-pop: var(--ag-ui-ease-pop, cubic-bezier(0.34, 1.36, 0.64, 1));
@@ -4592,7 +4589,7 @@ var STYLES = `
4592
4589
  /* Reading-column width for placement="page" (full-bleed, centred content). */
4593
4590
  --_content-max-width: var(--ag-ui-content-max-width, 820px);
4594
4591
  /* Slim rail the sidebar placement collapses to. Only that placement reads
4595
- it, but it is declared here so invariant 2 holds for every alias. */
4592
+ it, but it is declared here so every alias has a default in one place. */
4596
4593
  --_rail-width: var(--ag-ui-rail-width, 52px);
4597
4594
 
4598
4595
  position: var(--_position);
@@ -4684,11 +4681,11 @@ var STYLES = `
4684
4681
  --_radius: var(--ag-ui-radius, 0);
4685
4682
  }
4686
4683
 
4687
- /* Page: full-bleed background with a centred reading column. Unlike
4688
- "full" (edge-to-edge, left-aligned messages) the content sits in a column
4689
- capped at --ag-ui-content-max-width. The column is produced by symmetric auto
4690
- padding on the scroll area + composer (no per-row wrapper), so user pills
4691
- still right-align and the assistant well spans the column. */
4684
+ /* Page: full-bleed background with a centred reading column capped at
4685
+ --ag-ui-content-max-width, where "full" is edge-to-edge and left-aligned.
4686
+ The column comes from symmetric auto padding on the scroll area and
4687
+ composer rather than a per-row wrapper, so user pills still right-align and
4688
+ the assistant well spans the column. */
4692
4689
  :host([placement="page"]) {
4693
4690
  --_inset: var(--ag-ui-inset, 0);
4694
4691
  --_width: var(--ag-ui-width, 100vw);
@@ -4706,9 +4703,8 @@ var STYLES = `
4706
4703
  padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));
4707
4704
  }
4708
4705
 
4709
- /* The rows between the message list and the composer (skill chips, the
4710
- /-command palette, the missing-placeholder hint, the upload tray) line up
4711
- with the column too \u2014 chips are padding-based, the palette/hint/tray are
4706
+ /* The rows between the message list and the composer line up with the column
4707
+ too. Chips and tray are padding-based while palette and hint are
4712
4708
  margin-based, so each gets its own inline axis nudged by the same gutter. */
4713
4709
  :host([placement="page"]) .skill-chips,
4714
4710
  :host([placement="page"]) .attachment-tray {
@@ -4817,13 +4813,12 @@ var STYLES = `
4817
4813
  visibility var(--_motion) var(--_ease);
4818
4814
  }
4819
4815
 
4820
- /* The launcher grows out of the corner the panel shrank into.
4821
- It is laid out at rest rather than display:none, which is what lets it
4822
- animate in *and* out: an element that was not rendered has no before-change
4823
- style to transition from, and one whose display flips to none cannot
4824
- transition at all. visibility keeps it unpaintable, untabbable and
4825
- unclickable in between -- the expanded panel's own controls sit under it and
4826
- must stay reachable. */
4816
+ /* The launcher grows out of the corner the panel shrank into. It stays laid
4817
+ out at rest rather than display:none, which is what lets it animate both in
4818
+ and out: an unrendered element has no before-change style to transition
4819
+ from, and one flipping display to none cannot transition at all. visibility
4820
+ keeps it unpaintable, untabbable and unclickable in between, so the expanded
4821
+ panel's own controls underneath stay reachable. */
4827
4822
  :host([collapsed]) .launcher {
4828
4823
  opacity: 1;
4829
4824
  transform: none;
@@ -4984,20 +4979,18 @@ var STYLES = `
4984
4979
 
4985
4980
  /* \u2500\u2500 Collapse \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
4986
4981
  Collapsing shrinks the widget to the round floating launcher: the panel
4987
- scales down toward the launcher's corner and fades out, the launcher pops in
4988
- from that same point. Both halves are transform and opacity only, so the
4989
- morph runs on the compositor and never reflows the host page.
4990
-
4991
- The host box keeps its expanded size. Animating it would animate layout, and
4992
- a dragged --ag-ui-width would then fight the launcher's own size. Nothing
4993
- paints there once the panel is gone, so the box only has to stop swallowing
4994
- clicks: pointer events go to none, and the launcher takes them back.
4995
-
4996
- Two placements collapse to something else and restore what they need:
4997
- "sidebar" slides to its rail (below), while "embedded" and "page" keep the
4998
- original header bar \u2014 embedded is laid out by the host page, where a
4999
- floating circle would escape the layout, and page is a full-screen route
5000
- with no corner to float in. */
4982
+ scales toward the launcher's corner and fades, the launcher pops in from the
4983
+ same point. Both halves are transform and opacity only, so the morph runs on
4984
+ the compositor and never reflows the host page.
4985
+
4986
+ The host box keeps its expanded size, since animating it would animate
4987
+ layout and a dragged --ag-ui-width would fight the launcher's own size.
4988
+ Nothing paints there once the panel is gone, so the box only has to stop
4989
+ swallowing clicks: pointer events go to none and the launcher takes them.
4990
+
4991
+ Two placements collapse differently: "sidebar" slides to its rail (below),
4992
+ while "embedded" and "page" keep the header bar, having no corner for a
4993
+ floating circle that would escape the host's layout. */
5001
4994
  :host([collapsed]) {
5002
4995
  pointer-events: none;
5003
4996
  }
@@ -5008,11 +5001,11 @@ var STYLES = `
5008
5001
  visibility: hidden;
5009
5002
  }
5010
5003
 
5011
- /* visibility is what keeps the panel out of the tab order and the a11y tree at
5012
- rest without display:none killing the transition. It interpolates so that any
5013
- progress below 1 still counts as visible: the panel stays on screen for the
5014
- whole collapse and flips hidden exactly at the end, and on expand it is
5015
- visible from the first frame. */
5004
+ /* visibility keeps the panel out of the tab order and the a11y tree at rest
5005
+ without display:none killing the transition. It interpolates so any progress
5006
+ below 1 still counts as visible: the panel stays on screen for the whole
5007
+ collapse, flips hidden exactly at the end, and on expand is visible from the
5008
+ first frame. */
5016
5009
  .chat {
5017
5010
  transform-origin: bottom right;
5018
5011
  transition:
@@ -5039,10 +5032,9 @@ var STYLES = `
5039
5032
  visibility: visible;
5040
5033
  }
5041
5034
 
5042
- /* These two keep the header bar, so the launcher must stay out of the way \u2014
5043
- an embedded host is position: static, which would otherwise leave an
5044
- absolutely-positioned circle to escape the layout entirely and land against
5045
- whatever the page happens to position. */
5035
+ /* These two keep the header bar, so the launcher must stay out of the way: an
5036
+ embedded host is position: static, which would let an absolutely-positioned
5037
+ circle escape the layout and land against whatever the page positions. */
5046
5038
  :host([collapsed]:is([placement="embedded"], [placement="page"])) .launcher {
5047
5039
  visibility: hidden;
5048
5040
  opacity: 0;
@@ -5082,7 +5074,7 @@ var STYLES = `
5082
5074
  and the pending indicator so a whole answer reads (and can be boxed) as one
5083
5075
  unit. A flex column on the message-list gap, stretched to the list width so
5084
5076
  its children keep their own left/right alignment. data-answer-well opts into
5085
- the bordered "well"; without it the layout is today's flat stack. */
5077
+ the bordered "well"; without it the turn renders as a flat stack. */
5086
5078
  .answer {
5087
5079
  display: flex;
5088
5080
  flex-direction: column;
@@ -5208,13 +5200,9 @@ var STYLES = `
5208
5200
  position: relative;
5209
5201
  }
5210
5202
 
5211
- /* This button is the only reader of --ag-ui-surface and --ag-ui-text, and
5212
- neither had a default until the alias layer gave them one. Both references
5213
- used to resolve to nothing, dropping the declaration: the background fell
5214
- back to the initial transparent, and the hover/copied colour to the
5215
- inherited body colour. The defaults chosen upstream (transparent, and the
5216
- body foreground) reproduce that, so the rename repaints nothing. A raised
5217
- surface behind the button is a separate design question. */
5203
+ /* The only reader of --ag-ui-surface and --ag-ui-text. Their defaults are
5204
+ transparent and the body foreground, which is what this button rendered as
5205
+ before either token existed; changing them repaints only this control. */
5218
5206
  .code-copy {
5219
5207
  position: absolute;
5220
5208
  top: 4px;
@@ -5260,12 +5248,10 @@ var STYLES = `
5260
5248
  color: var(--_muted);
5261
5249
  }
5262
5250
 
5263
- /* Markdown tables. table/thead/tbody/tr/th/td are all in
5264
- the sanitizer's ALLOWED_TAGS, so an agent emitting one renders it \u2014 and until
5265
- now rendered it entirely unstyled, overflowing the bubble. A wide table
5266
- scrolls inside its own box rather than stretching the message: the bubble is
5267
- width-constrained, so without this the columns either crush or push the
5268
- layout sideways. */
5251
+ /* Markdown tables. table/thead/tbody/tr/th/td are all in the sanitizer's
5252
+ ALLOWED_TAGS, so an agent can emit one. A wide table must scroll inside its
5253
+ own box rather than stretch the message: the bubble is width-constrained, so
5254
+ without this the columns either crush or push the layout sideways. */
5269
5255
  .message--assistant table {
5270
5256
  display: block;
5271
5257
  width: fit-content;
@@ -5522,8 +5508,6 @@ var STYLES = `
5522
5508
  color: var(--_muted);
5523
5509
  }
5524
5510
 
5525
- /* The record of a human decision on a gated call. An approved call used to
5526
- look exactly like one that was never gated. */
5527
5511
  .skill-item-token {
5528
5512
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
5529
5513
  font-size: 0.92em;
@@ -5531,6 +5515,8 @@ var STYLES = `
5531
5515
  margin-right: 6px;
5532
5516
  }
5533
5517
 
5518
+ /* The lasting record of a human decision on a gated call \u2014 without it an
5519
+ approved call looks exactly like one that was never gated. */
5534
5520
  .tool-call-decision {
5535
5521
  flex: none;
5536
5522
  font-size: 11px;
@@ -5553,10 +5539,8 @@ var STYLES = `
5553
5539
  }
5554
5540
 
5555
5541
  /* Display modes are pure visibility over one DOM shape, selected from the host
5556
- attribute rather than a value stamped on the card when it was built. That is
5557
- what lets a host flip data-tool-display and have every card already on screen
5558
- re-read it, the way data-answer-well behaves. Baking the structure per mode
5559
- meant the setting only reached cards created afterwards.
5542
+ attribute rather than a value stamped on the card at build time, so flipping
5543
+ data-tool-display re-styles cards already on screen. See ToolCallCard.
5560
5544
 
5561
5545
  Default (no attribute) is the full mode: arguments always visible, result
5562
5546
  behind the toggle. */
@@ -5653,20 +5637,19 @@ var STYLES = `
5653
5637
  }
5654
5638
 
5655
5639
  /* Then the measurement corrects it. Which edges are held still belongs to the
5656
- host's layout rather than to placement -- a floating panel a host right-aligns
5657
- is anchored bottom-left, not bottom-right -- so the element measures the edges
5658
- that stay put and stamps them here as "<y>-<x>". Equal specificity to the
5659
- rules above, so source order is what lets the measured value win.
5660
-
5661
- These must not be written as [data-resize-anchor~="left"]: the stamped value
5662
- is one hyphenated token, and ~= matches whitespace-separated words, so such a
5663
- selector cannot ever match. It did not, which left the grip drawn at the
5664
- corner that moves while the cursor pointed along the right diagonal.
5665
-
5666
- Each rule also sets both sides of its axis rather than only the side it
5667
- moves. One that flipped a single way could not undo a placement guess that
5668
- had flipped the other, which put the grip on the anchored corner for an
5669
- embedded panel its host right-aligns. */
5640
+ host's layout, not to placement -- a floating panel a host right-aligns is
5641
+ anchored bottom-left -- so the element measures them and stamps a single
5642
+ hyphenated "<y>-<x>" token here. Equal specificity to the rules above, so
5643
+ source order is what lets the measured value win.
5644
+
5645
+ Two traps, both of which silently draw the grip on the corner that moves:
5646
+
5647
+ Never write these as [data-resize-anchor~="left"]. The stamped value is one
5648
+ hyphenated token and ~= matches whitespace-separated words, so it can never
5649
+ match.
5650
+
5651
+ Each rule must set both sides of its axis, not only the side it moves, or it
5652
+ cannot undo a placement guess that flipped the other way. */
5670
5653
  :host([data-resize-anchor$="-left"]) .resize-handle {
5671
5654
  left: auto;
5672
5655
  right: 0;
@@ -5727,10 +5710,9 @@ var STYLES = `
5727
5710
  }
5728
5711
 
5729
5712
  /* \u2500\u2500 Composer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
5730
- One surface owns the border, the background and the focus ring; the field and
5731
- its tool row sit inside it. The row used to be four siblings stretched to the
5732
- textarea's height, which gave a paperclip the same visual weight as the field
5733
- and turned Send into a full-height slab. */
5713
+ One surface owns the border, the background and the focus ring; the field
5714
+ and its tool row sit inside it, rather than being siblings stretched to the
5715
+ textarea's height. */
5734
5716
  .input-row {
5735
5717
  display: flex;
5736
5718
  padding: 12px;
@@ -5978,13 +5960,12 @@ var STYLES = `
5978
5960
  }
5979
5961
 
5980
5962
  /* A chip carries its own text colour because it carries its own background.
5981
- The same chip renders in two places with opposite inherited colours: in the
5982
- composer tray it inherits the panel's, but on a sent user bubble it inherits
5983
- the user foreground, which is white on the stock light theme. Against the
5984
- assistant surface underneath that was a 1.13:1 filename \u2014 invisible, and only
5985
- the size stayed legible because it sets its own muted colour. Pair the colour
5986
- with the background it belongs to, and both placements read the same.
5987
- Overridden below for an errored chip, which must keep its red. */
5963
+ The same chip renders in two places with opposite inherited colours: the
5964
+ composer tray gives it the panel's, a sent user bubble gives it the user
5965
+ foreground, which is white on the stock light theme and near-invisible
5966
+ against the chip. Pairing the colour with the background it belongs to makes
5967
+ both placements read alike. Overridden below for an errored chip, which
5968
+ keeps its red. */
5988
5969
  .attachment-chip {
5989
5970
  display: inline-flex;
5990
5971
  align-items: center;
@@ -6678,9 +6659,9 @@ var ThoughtsBlock = class {
6678
6659
  this.#body.textContent = buffer;
6679
6660
  }
6680
6661
  /**
6681
- * Fold the region away — called when the answer's first text token arrives.
6682
- * Idempotent (the per-token text handler calls it repeatedly) and flips the
6683
- * header label from "thinking…" to the settled "Thoughts" affordance.
6662
+ * Fold the region away when the answer's first text token arrives, flipping
6663
+ * the header label to its settled form. Idempotent, since the per-token text
6664
+ * handler calls it repeatedly.
6684
6665
  */
6685
6666
  collapse() {
6686
6667
  if (this.#collapsed) {
@@ -7038,11 +7019,8 @@ var ToolCallCard = class {
7038
7019
  }
7039
7020
  /**
7040
7021
  * Record that a human approved or declined this call, as a line in the card.
7041
- *
7042
- * Approval used to leave no trace at all: a declined call became a tool
7043
- * result saying so, while an approved one simply ran, making the transcript
7044
- * of a gated call byte-identical to one that was never gated. The prompt is
7045
- * gone once answered, so this is where the decision lives.
7022
+ * The prompt disappears once answered, so this is the only lasting trace that
7023
+ * the call was gated at all.
7046
7024
  */
7047
7025
  recordDecision(kind) {
7048
7026
  this.element.setAttribute("data-decision", kind);
@@ -7157,11 +7135,10 @@ var VoiceInput = class {
7157
7135
  this.#recorder?.stop();
7158
7136
  }
7159
7137
  /**
7160
- * Tear the control down the teardown path when the host element is removed
7161
- * mid-recording. Stops any live `MediaRecorder`, releases the mic tracks (so
7162
- * the browser's recording indicator clears), and suppresses the pending
7163
- * transcription: a disconnected control must not fire `onText` back into a
7164
- * detached element.
7138
+ * Tear the control down, for a host element removed mid-recording. Stops any
7139
+ * live `MediaRecorder`, releases the mic tracks so the browser's recording
7140
+ * indicator clears, and suppresses the pending transcription — a
7141
+ * disconnected control must not fire `onText` into a detached element.
7165
7142
  */
7166
7143
  dispose() {
7167
7144
  this.#disposed = true;
@@ -7243,10 +7220,9 @@ var AgUiClient = class {
7243
7220
  #resolveInterrupts;
7244
7221
  #onPersist;
7245
7222
  /**
7246
- * Message ids the server has already closed, so a reuse can be reported.
7247
- *
7248
- * Per client rather than per run: the merge happens across runs, which is the
7249
- * case a per-run set would miss entirely.
7223
+ * Message ids the server has already closed, so a reuse can be reported. Per
7224
+ * client rather than per run — the merge happens across runs, which a per-run
7225
+ * set would miss entirely.
7250
7226
  */
7251
7227
  #closedMessageIds = /* @__PURE__ */ new Set();
7252
7228
  #connectionLostMessage;
@@ -7296,9 +7272,8 @@ var AgUiClient = class {
7296
7272
  * tools (bounded by {@link MAX_TOOL_ROUNDS}).
7297
7273
  *
7298
7274
  * `attachments` ride on the user message as a non-standard field so the
7299
- * default client store round-trips them for history replay; the agent learns
7300
- * the ids from the run context (the server's strict validation ignores the
7301
- * unknown message field), then reads bytes via the `read_attachment` tool.
7275
+ * default store round-trips them for history replay; see
7276
+ * {@link messageAttachments}.
7302
7277
  */
7303
7278
  async send(content, attachments = []) {
7304
7279
  const message = { id: randomUUID2(), role: "user", content };
@@ -7312,7 +7287,7 @@ var AgUiClient = class {
7312
7287
  /**
7313
7288
  * Resume the run loop after a navigating tool's result was supplied
7314
7289
  * post-reload (via {@link addToolResult}). Unlike {@link send}, adds no user
7315
- * message it simply continues the conversation already in history.
7290
+ * message; it continues the conversation already in history.
7316
7291
  */
7317
7292
  async resume() {
7318
7293
  await this.#run();
@@ -7454,9 +7429,9 @@ var AgUiClient = class {
7454
7429
  onActivitySnapshotEvent({ event }) {
7455
7430
  h.onActivity(event.activityType, event.content);
7456
7431
  },
7457
- // Reasoning. `@ag-ui/client` already maps the deprecated
7458
- // THINKING_* events onto these REASONING_* callbacks, so handling the
7459
- // reasoning family alone covers both protocol versions.
7432
+ // `@ag-ui/client` maps the deprecated THINKING_* events onto these
7433
+ // REASONING_* callbacks, so the reasoning family alone covers both
7434
+ // protocol versions.
7460
7435
  onReasoningStartEvent() {
7461
7436
  h.onReasoningStart();
7462
7437
  },
@@ -7611,12 +7586,11 @@ var SessionStorageStore = class {
7611
7586
  return `${this.#root}:${suffix}`;
7612
7587
  }
7613
7588
  /**
7614
- * One-time move of pre-namespacing (`ag-ui-chat:*`) keys into this instance's
7615
- * namespace, so an existing conversation isn't orphaned by the upgrade. Only
7616
- * this store's own keys move (thread pointer, drawer index, per-thread
7617
- * messages/checkpoints) the element's `collapsed`/`theme` keys are left
7618
- * alone. The first namespaced instance to mount adopts the legacy data; a
7619
- * second namespace finds it gone and starts fresh.
7589
+ * One-time move of un-namespaced `ag-ui-chat:*` keys into this instance's
7590
+ * namespace, so an existing conversation isn't orphaned. Only this store's own
7591
+ * keys move — the element's `collapsed` / `theme` keys are left alone. The
7592
+ * first namespaced instance to mount adopts the data; a second namespace
7593
+ * finds it gone and starts fresh.
7620
7594
  */
7621
7595
  #migrateLegacyKeys() {
7622
7596
  const legacyRoot = `${KEY_ROOT}:`;
@@ -7697,12 +7671,10 @@ function createHttpAgent(options) {
7697
7671
  headers: options.headers ?? {},
7698
7672
  initialState: { ...options.initialState ?? {} },
7699
7673
  // HttpAgent invokes its configured fetch as a method (`this.fetch(...)`),
7700
- // which would rebind the global `fetch` to the agent instance and trigger
7701
- // "Illegal invocation" in browsers. Wrap it so `fetch` is always called as
7702
- // a free function with the correct receiver. The wrapper also overlays
7703
- // `getHeaders()` per request, so header rotation (CSRF, short-lived JWT)
7704
- // reaches the stream even though the agent instance is cached, and applies
7705
- // the configured cookie policy — the agent's own config has no seam for it.
7674
+ // rebinding the global `fetch` to the agent instance "Illegal invocation"
7675
+ // in browsers. The wrapper keeps `fetch` a free call, and is also where the
7676
+ // per-request `getHeaders()` overlay and the cookie policy go, the agent's
7677
+ // own config having no seam for either.
7706
7678
  fetch: (url, init) => {
7707
7679
  const fresh = options.getHeaders?.();
7708
7680
  if (fresh === void 0) {
@@ -7715,7 +7687,7 @@ function createHttpAgent(options) {
7715
7687
  return fetch(url, withCredentials({ ...init, headers }, options.credentials));
7716
7688
  },
7717
7689
  // Spread conditionally: under `exactOptionalPropertyTypes` an explicit
7718
- // `undefined` is not assignable to these optional config fields.
7690
+ // `undefined` is not assignable to an optional field.
7719
7691
  ...options.threadId !== void 0 ? { threadId: options.threadId } : {},
7720
7692
  ...options.initialMessages !== void 0 ? { initialMessages: [...options.initialMessages] } : {}
7721
7693
  });
@@ -7801,9 +7773,9 @@ var RemoteConversationStore = class {
7801
7773
  return {
7802
7774
  threadId: row.thread_id,
7803
7775
  title: this.#renamed.get(row.thread_id) ?? row.title,
7804
- // `null` or an unparseable date both become `NaN` (Date.parse's own
7805
- // signal), which `relativeTime` renders as a neutral label rather than
7806
- // "~2950w ago" (epoch 0) or "NaNw ago".
7776
+ // `null` and an unparseable date both become NaN, Date.parse's own
7777
+ // signal, which `relativeTime` renders as a neutral label rather than an
7778
+ // epoch-0 or NaN duration.
7807
7779
  updatedAt: row.updated_at === null ? Number.NaN : Date.parse(row.updated_at),
7808
7780
  preview: row.preview
7809
7781
  };
@@ -7847,10 +7819,9 @@ var RunIndex = class {
7847
7819
  this.#credentials = credentials;
7848
7820
  }
7849
7821
  /**
7850
- * The user's runs, or `[]` when the endpoint is unreachable or answers with
7851
- * an error. A history affordance that cannot load is empty, never broken:
7852
- * the caller renders its empty state rather than surfacing a transport fault
7853
- * the user can do nothing about.
7822
+ * The user's runs, or `[]` when the endpoint is unreachable or errors — the
7823
+ * caller renders its empty state rather than a transport fault the user can
7824
+ * do nothing about.
7854
7825
  */
7855
7826
  async list() {
7856
7827
  try {
@@ -7888,9 +7859,9 @@ var RunIndex = class {
7888
7859
  /**
7889
7860
  * `<mount>/<verb>/<runId>/`, derived from the index URL's own prefix.
7890
7861
  *
7891
- * Built by string surgery on the trailing `runs/` rather than with `new URL`,
7892
- * because the configured value may be root-relative (`/agent/runs/`) the
7893
- * common case in a Django template and `new URL` needs an absolute base.
7862
+ * String surgery on the trailing `runs/` rather than `new URL`, because the
7863
+ * configured value may be root-relative (`/agent/runs/`), the common case in
7864
+ * a Django template, and `new URL` needs an absolute base.
7894
7865
  */
7895
7866
  #sibling(verb, runId) {
7896
7867
  const prefix = this.#url.slice(0, -"runs/".length);
@@ -8025,29 +7996,23 @@ var AgUiChat = class extends HTMLElement {
8025
7996
  /** Agent factory; override to inject a custom or fake agent (tests). */
8026
7997
  agentFactory = createHttpAgent;
8027
7998
  /**
8028
- * Static extra HTTP headers, sent with **every** request this element makes
8029
- * the agent run, the thread index and its messages, the tool and skill
8030
- * catalogs, the run index, uploads and transcription.
7999
+ * Static extra HTTP headers, sent with every request this element makes: the
8000
+ * agent run, the thread index and its messages, the tool and skill catalogs,
8001
+ * the run index, uploads and transcription.
8031
8002
  *
8032
- * Right for values fixed for the element's lifetime. A credential that
8033
- * rotates (a short-lived JWT, a re-issued CSRF token) belongs in
8034
- * {@link getHeaders} instead: this is read at request time, but only a
8035
- * re-assignment updates it, so a token captured here is pinned until the host
8036
- * remembers to assign again.
8003
+ * For values fixed for the element's lifetime. A rotating credential belongs
8004
+ * in {@link getHeaders} instead — only a re-assignment updates this, so a
8005
+ * token captured here is pinned until the host assigns again.
8037
8006
  */
8038
8007
  headers = {};
8039
8008
  /**
8040
- * Live header source, consulted immediately before every request — the way to
8041
- * supply rotating credentials.
8042
- *
8043
- * Set it to a function and each request calls it afresh: a token refreshed by
8044
- * the host between two requests reaches the second one, with nothing to
8045
- * re-assign and nothing to keep in sync.
8009
+ * Live header source, called afresh immediately before every request — the
8010
+ * way to supply rotating credentials, with nothing to re-assign or keep in
8011
+ * sync.
8046
8012
  *
8047
- * Composes with {@link headers} rather than replacing it: the two are merged
8048
- * per key with `getHeaders()` winning, so a static `X-Client` and a rotating
8049
- * `Authorization` can be configured independently and neither silently drops
8050
- * the other.
8013
+ * Composes with {@link headers} rather than replacing it: merged per key with
8014
+ * `getHeaders()` winning, so a static `X-Client` and a rotating
8015
+ * `Authorization` are configured independently and neither drops the other.
8051
8016
  */
8052
8017
  getHeaders = null;
8053
8018
  /**
@@ -8061,37 +8026,31 @@ var AgUiChat = class extends HTMLElement {
8061
8026
  autoConfirm = false;
8062
8027
  /**
8063
8028
  * When true, the built-in `ask_user` frontend tool is offered to the agent:
8064
- * calling it renders an inline question card (radio choices and/or a free-text
8065
- * field) and returns the user's answer. Off by default — like the other
8066
- * built-in tool groups (route / page-action), it is opt-in so it doesn't
8067
- * change the advertised catalog until a host asks for it.
8029
+ * calling it renders an inline question card and returns the user's answer.
8030
+ * Off by default, like the other built-in tool groups, so the advertised
8031
+ * catalog does not change until a host asks for it.
8068
8032
  */
8069
8033
  askUser = false;
8070
8034
  /**
8071
- * Optional full replacement for the `ask_user` question UI. When set, calling
8072
- * `ask_user` invokes this instead of the built-in inline card: the host
8073
- * renders whatever it likes (a native modal, a framework component, …) and
8074
- * resolves with the answer. Unset (default) uses the built-in
8075
- * {@link requestQuestion} card — style that via the `strings` override and the
8076
- * `question*` CSS `::part()`s. Requires {@link askUser} to be enabled.
8035
+ * Optional full replacement for the `ask_user` question UI, resolving with
8036
+ * the answer; the same seam as {@link approvalRenderer}, styled via `strings`
8037
+ * and the `question*` `::part()`s when left unset. Requires {@link askUser}.
8077
8038
  */
8078
8039
  askUserRenderer = null;
8079
8040
  /**
8080
- * Optional full replacement for the server-side-tool approval UI. When set, an
8081
- * approval interrupt invokes this instead of the built-in inline approval
8082
- * card: the host renders whatever it likes and resolves `true` to approve /
8083
- * `false` to deny. Unset (default) uses the built-in {@link requestApproval}
8084
- * card style that via the `strings` override and the `approval*` CSS
8085
- * `::part()`s. The gate itself is enabled server-side; this only changes how
8086
- * the decision is collected.
8041
+ * Optional full replacement for the server-side-tool approval UI: an approval
8042
+ * interrupt invokes this instead of the built-in {@link requestApproval}
8043
+ * card, resolving `true` to approve or `false` to deny. Style the built-in
8044
+ * card via `strings` and the `approval*` `::part()`s instead. The gate itself
8045
+ * is enabled server-side; this only changes how the decision is collected.
8087
8046
  */
8088
8047
  approvalRenderer = null;
8089
8048
  /**
8090
- * Optional per-call confirmation predicate. When set, it is authoritative:
8091
- * given a tool name + args it decides whether *this* call needs confirmation
8092
- * (so one tool can be instant for some args and confirmed for others — what a
8093
- * static `x-destructive` flag can't express). When unset, the `x-destructive`
8094
- * schema flag is used. `autoConfirm` short-circuits both.
8049
+ * Optional per-call confirmation predicate. When set it is authoritative,
8050
+ * deciding from the tool name and args whether this particular call needs
8051
+ * confirmation — so one tool can be instant for some args and confirmed for
8052
+ * others, which a static `x-destructive` flag cannot express. When unset the
8053
+ * `x-destructive` flag decides. `autoConfirm` short-circuits both.
8095
8054
  */
8096
8055
  confirmPredicate = null;
8097
8056
  /**
@@ -8112,11 +8071,8 @@ var AgUiChat = class extends HTMLElement {
8112
8071
  * Per-run context provider. Defaults to the compact page map, when a
8113
8072
  * {@link getPageMap} provider is set and {@link autoInjectPageMap} is on.
8114
8073
  *
8115
- * It used to append a one-line manifest of the message's attachments too.
8116
- * The server now derives that manifest from the refs riding the messages, so
8117
- * the client's copy only duplicated it, on exactly the turn a file was
8118
- * attached. Attachments still reach the agent; they reach it through the
8119
- * message, which is where they were already.
8074
+ * Attachments are deliberately not restated here: the server derives its own
8075
+ * manifest from the refs riding the messages.
8120
8076
  */
8121
8077
  getContext = () => [
8122
8078
  ...createPageMapContext(this.getPageMap, this.autoInjectPageMap)
@@ -8144,21 +8100,17 @@ var AgUiChat = class extends HTMLElement {
8144
8100
  conversationStore = new SessionStorageStore();
8145
8101
  /**
8146
8102
  * How attached files are uploaded. `null` (default) uses the built-in
8147
- * multipart `POST` to `data-attachments-url`. Set a custom
8148
- * {@link UploadHandler} `(file, onProgress) => Promise<AttachmentRef>` to
8149
- * swap the transport (e.g. a `tus-js-client` resumable adapter or
8150
- * direct-to-S3 multipart) without changing the tray, the chips, or the AG-UI
8151
- * wire (refs are transport-agnostic). When set, the 📎 affordance appears even
8152
- * with no `data-attachments-url`; the handler owns its own endpoint + headers.
8103
+ * multipart `POST` to `data-attachments-url`; a custom {@link UploadHandler}
8104
+ * swaps the transport without changing the tray, the chips, or the AG-UI
8105
+ * wire. When set, the 📎 affordance appears even with no
8106
+ * `data-attachments-url`, and the handler owns its own endpoint and headers.
8153
8107
  */
8154
8108
  uploadHandler = null;
8155
8109
  /**
8156
8110
  * How recorded voice clips are transcribed. `null` (default) POSTs the clip
8157
- * to `data-transcribe-url` (django-ag-ui's `TranscribeView`). Set a custom
8158
- * {@link TranscribeHandler} `(audio: Blob) => Promise<string>` to swap the
8159
- * transport (a different STT endpoint, a browser Web Speech adapter) without
8160
- * touching the mic button. When set, the 🎤 affordance appears even with no
8161
- * `data-transcribe-url`.
8111
+ * to `data-transcribe-url`; a custom {@link TranscribeHandler} swaps the
8112
+ * transport without touching the mic button. When set, the 🎤 affordance
8113
+ * appears even with no `data-transcribe-url`.
8162
8114
  */
8163
8115
  transcribeHandler = null;
8164
8116
  /**
@@ -8177,12 +8129,10 @@ var AgUiChat = class extends HTMLElement {
8177
8129
  */
8178
8130
  skillContext = () => ({});
8179
8131
  /**
8180
- * Friendly display labels for tool-call cards, keyed by tool name (e.g.
8181
- * `{ list_projects: "Search projects" }`). Used as a fallback when a tool has
8182
- * no `x-summary` in its own schema chiefly **server-side tools** (drf-mcp,
8183
- * `@tool` registry), whose schema never reaches the browser (AG-UI streams
8184
- * only the tool-call name). Client tools should prefer `x-summary` on their
8185
- * schema; this map is the seam for everything else.
8132
+ * Friendly display labels for tool-call cards, keyed by tool name. The
8133
+ * fallback when a tool has no `x-summary` in its own schema, which chiefly
8134
+ * means server-side tools: AG-UI streams only the tool-call name, so their
8135
+ * schema never reaches the browser. Client tools should prefer `x-summary`.
8186
8136
  */
8187
8137
  toolSummaries = {};
8188
8138
  /**
@@ -8354,13 +8304,10 @@ var AgUiChat = class extends HTMLElement {
8354
8304
  * Continue `runId` as a **new** run, seeded server-side from its snapshot.
8355
8305
  *
8356
8306
  * Uses a short-lived agent pointed at the resume / fork endpoint and seeded
8357
- * with **no** history, so the request carries only the turn typed here the
8358
- * contract those endpoints assume, since the server supplies the prior turns
8359
- * from the snapshot and re-sending them would duplicate. Building a separate
8360
- * agent makes that structural: the main agent keeps its own history, and
8361
- * "only the new turn" can't be got wrong by forgetting to clear it. The
8362
- * fresh `run_id` the endpoints also require comes free — a new agent mints
8363
- * one per run.
8307
+ * with no history, because those endpoints supply the prior turns from the
8308
+ * snapshot and re-sending them would duplicate. A separate agent makes that
8309
+ * structural the main agent keeps its own history and mints the fresh
8310
+ * `run_id` the endpoints also require.
8364
8311
  *
8365
8312
  * Handlers are the element's own, so the continuation streams into the same
8366
8313
  * transcript the user is looking at.
@@ -8441,10 +8388,8 @@ var AgUiChat = class extends HTMLElement {
8441
8388
  * when the server streams `STATE_SNAPSHOT` / `STATE_DELTA`. Assigning seeds
8442
8389
  * the next run; reading returns whatever the agent last applied.
8443
8390
  *
8444
- * Listen for {@link STATE_EVENT} to react to server-driven changes.
8445
- *
8446
- * Not to be confused with {@link registerPageState}, which exposes host
8447
- * state to the agent as ordinary *tools*.
8391
+ * Listen for {@link STATE_EVENT} to react to server-driven changes. Distinct
8392
+ * from {@link registerPageState}, which exposes host state as ordinary tools.
8448
8393
  */
8449
8394
  get sharedState() {
8450
8395
  return this.#client?.state ?? this.#sharedState;
@@ -8460,11 +8405,9 @@ var AgUiChat = class extends HTMLElement {
8460
8405
  }
8461
8406
  }
8462
8407
  /**
8463
- * @deprecated Renamed to {@link registerPageState}. The old name read as
8464
- * AG-UI shared-state sync (`STATE_SNAPSHOT` / `STATE_DELTA`), which this
8465
- * component does not implement — these are ordinary client tools over host
8466
- * page state. Behaviour is unchanged; this alias will be removed in a future
8467
- * major.
8408
+ * @deprecated Renamed to {@link registerPageState} the old name read as
8409
+ * AG-UI shared-state sync. Behaviour is unchanged; the alias will be removed
8410
+ * in a future major.
8468
8411
  */
8469
8412
  registerStateHook(binding) {
8470
8413
  this.registerPageState(binding);
@@ -8531,10 +8474,9 @@ var AgUiChat = class extends HTMLElement {
8531
8474
  /**
8532
8475
  * The built-in `ask_user` frontend tool, or `[]` when {@link askUser} is off.
8533
8476
  *
8534
- * A generic "ask the user a typed question" primitive: the agent calls it, the
8535
- * client executes it locally via the normal frontend-tool path (rendering a
8536
- * {@link requestQuestion} card), and the chosen/typed answer flows back as the
8537
- * tool result — no new protocol, reusing the machinery already in place.
8477
+ * The agent calls it, the client executes it locally through the normal
8478
+ * frontend-tool path by rendering a {@link requestQuestion} card, and the
8479
+ * answer flows back as the tool result. No new protocol.
8538
8480
  */
8539
8481
  #askUserTool() {
8540
8482
  if (!this.askUser) {
@@ -8610,19 +8552,18 @@ var AgUiChat = class extends HTMLElement {
8610
8552
  * `credentials` mode (`"omit"` / `"same-origin"` / `"include"`). Mirrored to
8611
8553
  * the `credentials` attribute, so markup embeds can set it without script.
8612
8554
  *
8613
- * `null` (the default) leaves the browser's default of `same-origin` in
8614
- * place. That default sends **no cookies at all** when the endpoints live on
8615
- * a different origin from the page app.example.com calling
8616
- * api.example.com is cross-origin and the request goes out anonymously
8617
- * rather than failing, so the symptom is a 401 from a server that looks
8618
- * correctly configured. A cookie-authenticated cross-origin deployment wants
8619
- * `"include"`, plus `Access-Control-Allow-Credentials: true` and a concrete
8620
- * (non-wildcard) `Access-Control-Allow-Origin` on the server.
8555
+ * `null` (the default) leaves the browser's `same-origin` default in place,
8556
+ * which sends no cookies at all to an endpoint on a different origin — and
8557
+ * the request goes out anonymously rather than failing, so the symptom is a
8558
+ * 401 from a server that looks correctly configured. A cookie-authenticated
8559
+ * cross-origin deployment wants `"include"`, plus
8560
+ * `Access-Control-Allow-Credentials: true` and a concrete, non-wildcard
8561
+ * `Access-Control-Allow-Origin` on the server.
8621
8562
  *
8622
8563
  * Read per request, so a late assignment applies to everything after it.
8623
- * `"omit"` cannot be honoured by the built-in **upload** transport, which is
8624
- * an `XMLHttpRequest` and only has a two-state cookie switch; every other
8625
- * endpoint honours all three modes.
8564
+ * `"omit"` cannot be honoured by the built-in upload transport, an
8565
+ * `XMLHttpRequest` with only a two-state cookie switch; every other endpoint
8566
+ * honours all three modes.
8626
8567
  */
8627
8568
  get credentials() {
8628
8569
  const attr = this.getAttribute("credentials");
@@ -8723,25 +8664,21 @@ var AgUiChat = class extends HTMLElement {
8723
8664
  * The catalog requests the element issues on startup: the tool labels
8724
8665
  * (`data-tools-url`) and the backend skills (`data-skills-url`).
8725
8666
  *
8726
- * Deliberately one microtask behind `connectedCallback`. A host that
8727
- * configures the element through a framework ref necessarily does so *after*
8728
- * inserting the node React attaches refs and runs layout effects in the
8729
- * same commit as the insertion, but strictly afterwards so a request issued
8730
- * from `connectedCallback` itself goes out before `headers`,
8731
- * {@link getHeaders} or {@link credentials} exist, and comes back 401 in a
8732
- * way that reads as a server fault rather than a mis-timed assignment. A
8733
- * microtask lands after that commit and still before paint.
8667
+ * Deliberately one microtask behind `connectedCallback`. A framework ref is
8668
+ * attached after the node is inserted but within the same commit, so a
8669
+ * request issued from `connectedCallback` itself goes out before `headers`,
8670
+ * {@link getHeaders} or {@link credentials} exist and 401s in a way that
8671
+ * reads as a server fault. A microtask lands after that commit, still before
8672
+ * paint.
8673
+ *
8674
+ * It is not a fix for configuration arriving later than the commit (a passive
8675
+ * effect, an awaited token fetch): configure before insertion, or call
8676
+ * {@link reload}, since a longer timer would hide that race rather than close
8677
+ * it.
8734
8678
  *
8735
- * Two things it is **not**. It is not a fix for configuration that arrives
8736
- * later than the commit (a passive `useEffect`, an awaited token fetch):
8737
- * configure before insertion (`createElement` configure `append`) or call
8738
- * {@link reload} once configured, because a longer timer would hide that race
8739
- * rather than close it. And it deliberately excludes the *history* replay,
8740
- * which stays in `connectedCallback`: the replay renders into the transcript,
8741
- * so deferring it lets a `sendMessage()` issued in the same task land first
8742
- * and the replay then duplicate it. The thread history is therefore the one
8743
- * request that can still go out before a ref is attached — {@link reload}
8744
- * covers it.
8679
+ * The history replay stays in `connectedCallback` on purpose. It renders into
8680
+ * the transcript, so deferring it would let a `sendMessage()` in the same
8681
+ * task land first and be duplicated by the replay.
8745
8682
  */
8746
8683
  #startup() {
8747
8684
  if (!this.#connected) {
@@ -8755,15 +8692,13 @@ var AgUiChat = class extends HTMLElement {
8755
8692
  * the backend skill catalog and the thread's history — with the transport
8756
8693
  * configuration as it stands now.
8757
8694
  *
8758
- * This is the answer for a host that can only configure the element after the
8759
- * fact (a token fetched in a passive effect, an async auth handshake): the
8760
- * startup requests already went out with whatever was set then, and this says
8761
- * "try again, properly authenticated" without removing and re-inserting the
8762
- * node.
8695
+ * For a host that can only configure the element after the fact (a token
8696
+ * fetched in a passive effect, an async auth handshake), this re-issues the
8697
+ * startup requests authenticated, without removing and re-inserting the node.
8763
8698
  *
8764
- * A reload, not a merge the in-flight run is cancelled and the transcript
8765
- * is rebuilt from the persisted history, so anything streamed since is
8766
- * dropped. Call it once, when configuration lands; not between turns.
8699
+ * A reload, not a merge: the in-flight run is cancelled and the transcript is
8700
+ * rebuilt from persisted history, so anything streamed since is dropped. Call
8701
+ * it once, when configuration lands, not between turns.
8767
8702
  */
8768
8703
  async reload() {
8769
8704
  this.#cancelRun();
@@ -8772,12 +8707,10 @@ var AgUiChat = class extends HTMLElement {
8772
8707
  await Promise.all([this.#fetchToolCatalog(), this.#fetchSkills(), this.#rehydrate()]);
8773
8708
  }
8774
8709
  /**
8775
- * Tear down live resources when the element leaves the DOM (a removed node, a
8776
- * client-side route swap): cancel the in-flight run so its SSE stream closes,
8777
- * abort any in-flight uploads so they don't orphan server-side files, and
8778
- * release the mic so the browser's recording indicator clears. Without this a
8779
- * removed `<ag-ui-chat>` leaks a streaming request, uploads, and a live
8780
- * `MediaRecorder`.
8710
+ * Tear down live resources when the element leaves the DOM: cancel the
8711
+ * in-flight run so its stream closes, abort in-flight uploads so they do not
8712
+ * orphan server-side files, and release the mic so the browser's recording
8713
+ * indicator clears. Without this a removed element leaks all three.
8781
8714
  */
8782
8715
  disconnectedCallback() {
8783
8716
  this.#connected = false;
@@ -8788,14 +8721,10 @@ var AgUiChat = class extends HTMLElement {
8788
8721
  /**
8789
8722
  * Read an opt-in flag attribute the way HTML reads a boolean attribute.
8790
8723
  *
8791
- * Present means on bare (`data-prompt-chips`), empty
8792
- * (`data-prompt-chips=""`) or any value except the literal `"false"`. These
8793
- * were compared against the string `"true"`, so writing the attribute bare —
8794
- * the spelling every native boolean attribute uses, and the one a reader
8795
- * reaches for first — silently *disabled* the feature it names, with nothing
8796
- * to indicate why the chips never appeared.
8797
- *
8798
- * `="false"` still turns it off, so an explicit opt-out keeps working.
8724
+ * Present means on: bare (`data-prompt-chips`), empty (`=""`), or any value
8725
+ * except the literal `"false"`. Comparing against `"true"` instead would make
8726
+ * the bare spelling every native boolean attribute uses silently disable the
8727
+ * feature it names. `="false"` still turns it off.
8799
8728
  */
8800
8729
  #flag(name) {
8801
8730
  const value = this.getAttribute(name);
@@ -9021,21 +8950,16 @@ var AgUiChat = class extends HTMLElement {
9021
8950
  /**
9022
8951
  * Act on a picked skill.
9023
8952
  *
9024
- * A skill that ships no `prompt` is **server-resolved**: the catalog carries
9025
- * only its name and label, and picking it sends the bare `/name` token for
9026
- * the agent to expandfrom the harness `Skills` capability, or from the
9027
- * server's own instructions. That is the shape to prefer, because the prompt
9028
- * then never reaches the browser at all: a skill is often where a project's
9029
- * internal workflow is written down most plainly, and a catalog endpoint is a
9030
- * plain GET.
8953
+ * A skill with no `prompt` is server-resolved: picking it sends the bare
8954
+ * `/name` token for the agent to expand, so the wording never reaches the
8955
+ * browser. Prefer that shapea skill often states a project's internal
8956
+ * workflow most plainly, and a catalog endpoint is a plain GET.
9031
8957
  *
9032
- * A skill that does carry a `prompt` keeps the older behaviour the client
9033
- * fills its `{placeholder}`s from the page and sends (or pre-fills) the text.
9034
- * Right for a user-facing convenience, and for placeholders only the page can
9035
- * supply.
8958
+ * A skill carrying a `prompt` has the client fill its `{placeholder}`s from
8959
+ * the page instead, which is right for placeholders only the page can supply.
9036
8960
  *
9037
- * Either way a pick now **sends**, rather than parking text in the composer
9038
- * for a second click; `sendImmediately: false` opts back into pre-filling.
8961
+ * Either way a pick sends; `sendImmediately: false` opts into pre-filling the
8962
+ * composer instead.
9039
8963
  */
9040
8964
  #applySkill(skill) {
9041
8965
  if (skill.prompt === void 0) {
@@ -9147,18 +9071,13 @@ var AgUiChat = class extends HTMLElement {
9147
9071
  }
9148
9072
  }
9149
9073
  /**
9150
- * Which edges the layout is holding still, by measuring rather than guessing.
9074
+ * Which edges the layout is holding still, by measuring rather than guessing:
9075
+ * nudge the size by a pixel, see which edges stayed put, and undo. One forced
9076
+ * reflow per drag.
9151
9077
  *
9152
- * A resize has to be computed from the edge that does not move, and which
9153
- * edge that is belongs to the **host's layout**, not to `placement`: a
9154
- * floating panel is pinned bottom-right, while an embedded one goes wherever
9155
- * the page's own CSS puts it — flex-start, flex-end, a grid cell. Mapping
9156
- * placement to a corner got this wrong for any host that right-aligns the
9157
- * element, and the symptom is bad enough to read as a broken control: the
9158
- * panel shrinks when dragged outward, travelling by its opposite corner.
9159
- *
9160
- * So: nudge the size by a pixel, see which edges stayed put, and undo. One
9161
- * forced reflow per drag, which is cheap next to being wrong.
9078
+ * `placement` cannot answer this an embedded panel goes wherever the page's
9079
+ * CSS puts it and see {@link createResizeHandle} for why guessing produces
9080
+ * a visibly broken control.
9162
9081
  */
9163
9082
  #measureAnchor() {
9164
9083
  const before = this.getBoundingClientRect();
@@ -9192,14 +9111,13 @@ var AgUiChat = class extends HTMLElement {
9192
9111
  /**
9193
9112
  * Write a dragged size onto the host, on the axes this placement leaves free.
9194
9113
  *
9195
- * Writing the custom property rather than inline `width` / `height` does
9196
- * **not** by itself leave placement in charge an inline custom property
9197
- * still outranks a `:host([placement=…])` rule setting the same property, so
9198
- * a height dragged while floating capped a docked sidebar that had asked for
9199
- * `100vh`. The cascade cannot arbitrate this; the axis check has to.
9200
- *
9201
- * So the rule is explicit: a placement owns the axes it fixes, and a
9202
- * persisted size is only ever applied to the ones it does not.
9114
+ * Writing the custom property rather than inline `width` / `height` does not
9115
+ * by itself leave placement in charge: an inline custom property still
9116
+ * outranks a `:host([placement=…])` rule setting the same property, so a
9117
+ * height dragged while floating would cap a docked sidebar asking for
9118
+ * `100vh`. The cascade cannot arbitrate this, so the axis check must — a
9119
+ * placement owns the axes it fixes, and a persisted size is applied only to
9120
+ * the ones it leaves free.
9203
9121
  */
9204
9122
  #applySize(size) {
9205
9123
  const axis = this.#resizeAxis();
@@ -9272,12 +9190,10 @@ var AgUiChat = class extends HTMLElement {
9272
9190
  * Open the thread-history drawer: the imperative route to the control that
9273
9191
  * renders as `::part(history-button)`.
9274
9192
  *
9275
- * A host that hides `::part(header)` to render its own title bar hides the
9276
- * history, new-chat and collapse buttons with it and thread switching then
9277
- * has no route at all, because those controls live inside the header. Each of
9278
- * them has a method, so a host chrome can rebuild the set: this one,
9279
- * {@link openCheckpoints}, {@link newChat}, {@link toggleCollapsed} and
9280
- * {@link toggleTheme}.
9193
+ * A host that hides `::part(header)` for its own title bar hides the history,
9194
+ * new-chat and collapse buttons with it. Each has a method so that chrome can
9195
+ * be rebuilt: this one, {@link openCheckpoints}, {@link newChat},
9196
+ * {@link toggleCollapsed} and {@link toggleTheme}.
9281
9197
  */
9282
9198
  openThreads() {
9283
9199
  void this.#refreshDrawer();
@@ -9378,23 +9294,17 @@ var AgUiChat = class extends HTMLElement {
9378
9294
  /**
9379
9295
  * Notice a previous run that never produced a response.
9380
9296
  *
9381
- * {@link AgUiClient.send} persists the user's message *before* starting the
9382
- * run, so a transcript whose last entry is that user message means nothing
9383
- * ever came back: the page navigated or reloaded mid-run, the tab closed, or
9384
- * the process died. No extra persistence is needed to detect it — the shape
9385
- * of the transcript already says so, which is why this needs no
9386
- * {@link ClientConversationStore} method and no `pagehide` listener (neither
9387
- * of which fires on a crash or a force-quit anyway).
9297
+ * {@link AgUiClient.send} persists the user's message before starting the
9298
+ * run, so a transcript ending on that user message means nothing came back.
9299
+ * The transcript's shape alone detects it, needing no store method and no
9300
+ * `pagehide` listener neither of which fires on a crash or force-quit.
9388
9301
  *
9389
- * The *agent*-initiated reload is not this case: a navigating tool leaves a
9390
- * checkpoint and resumes, which is why the caller returns early on one before
9391
- * reaching here.
9302
+ * An agent-initiated reload is not this case: a navigating tool leaves a
9303
+ * checkpoint and resumes, so the caller returns early on one.
9392
9304
  *
9393
- * Deliberately a notice and never a resume. AG-UI has no
9394
- * resume-an-aborted-run primitive; re-sending the accumulated messages is
9395
- * semantically a **new** run, so any server-side tool the agent had already
9396
- * executed before the interruption would run a second time. Saying plainly
9397
- * that the answer was lost is the honest option, and the user can re-ask.
9305
+ * Deliberately a notice, never a resume. AG-UI has no resume-an-aborted-run
9306
+ * primitive, and re-sending the accumulated messages is semantically a new
9307
+ * run, so any server-side tool already executed would run a second time.
9398
9308
  */
9399
9309
  /**
9400
9310
  * Build a round's context, recording which page it describes.
@@ -9447,19 +9357,16 @@ var AgUiChat = class extends HTMLElement {
9447
9357
  if (text2 !== "") {
9448
9358
  this.appendMessage(MESSAGE_ROLE.ASSISTANT, text2).classList.add("message--restored");
9449
9359
  }
9450
- const toolCalls = message.toolCalls;
9451
- if (toolCalls !== void 0) {
9452
- for (const call of toolCalls) {
9453
- const restored = {
9454
- id: call.id,
9455
- name: call.function.name,
9456
- args: this.#parseArgs(call.function.arguments)
9457
- };
9458
- if (this.#noticeIfSkillLoad(restored)) {
9459
- continue;
9460
- }
9461
- this.#cardFor(restored);
9360
+ for (const call of restoredToolCalls(message.toolCalls)) {
9361
+ const restored = {
9362
+ id: call.id,
9363
+ name: call.function.name,
9364
+ args: this.#parseArgs(call.function.arguments)
9365
+ };
9366
+ if (this.#noticeIfSkillLoad(restored)) {
9367
+ continue;
9462
9368
  }
9369
+ this.#cardFor(restored);
9463
9370
  }
9464
9371
  return;
9465
9372
  }
@@ -9470,8 +9377,11 @@ var AgUiChat = class extends HTMLElement {
9470
9377
  }
9471
9378
  }
9472
9379
  }
9473
- /** Parse a tool call's JSON `arguments` string from history into an object. */
9380
+ /** Parse a tool call's JSON `arguments` from history into an object. */
9474
9381
  #parseArgs(raw) {
9382
+ if (typeof raw !== "string") {
9383
+ return {};
9384
+ }
9475
9385
  try {
9476
9386
  const parsed = JSON.parse(raw);
9477
9387
  if (typeof parsed === "object" && parsed !== null) {
@@ -9500,13 +9410,12 @@ var AgUiChat = class extends HTMLElement {
9500
9410
  /**
9501
9411
  * Append a message bubble and return it.
9502
9412
  *
9503
- * Assistant content is rendered as sanitised markdown/HTML; user content
9504
- * stays literal text (no need to parse what the user typed, and it avoids
9505
- * rendering user-authored markup).
9413
+ * Assistant content renders as sanitised markdown/HTML; user content stays
9414
+ * literal text, which also avoids rendering user-authored markup.
9506
9415
  *
9507
- * Assistant bubbles land in the current answer group, opening one if
9508
- * needed; a user bubble closes the prior group and sits directly in the list
9509
- * (the well wraps the *assistant* turn, the user message precedes it).
9416
+ * Assistant bubbles land in the current answer group, opening one if needed;
9417
+ * a user bubble closes the prior group and sits directly in the list, the
9418
+ * well wrapping only the assistant turn.
9510
9419
  */
9511
9420
  appendMessage(role, content) {
9512
9421
  const bubble = document.createElement("div");
@@ -9699,12 +9608,9 @@ var AgUiChat = class extends HTMLElement {
9699
9608
  * Build a header control button: a named slot a host can project markup into,
9700
9609
  * with the built-in glyph as the slot's fallback.
9701
9610
  *
9702
- * The glyph used to be the button's own `textContent`, which left a host able
9703
- * to restyle the control through its `part` but unable to replace it — a CSS
9704
- * `content` override could swap one character for another, and nothing could
9705
- * supply a brand `<img>` or `<svg>`. This is the same slot-with-fallback
9706
- * idiom the header icon already uses, so existing embeds render exactly as
9707
- * before.
9611
+ * The slot is what lets a host replace the mark with its own `<img>` or
9612
+ * `<svg>` rather than only restyle it through the `part`; the same
9613
+ * slot-with-fallback idiom the header icon uses.
9708
9614
  */
9709
9615
  #headerButton(modifier, label, glyph) {
9710
9616
  const button2 = document.createElement("button");
@@ -9905,19 +9811,16 @@ var AgUiChat = class extends HTMLElement {
9905
9811
  * Send a message as if the user had typed it — renders the user bubble,
9906
9812
  * dispatches {@link SUBMIT_EVENT}, and starts the run.
9907
9813
  *
9908
- * The programmatic half of the composer, for a host driving its own input
9909
- * (a "Ask about this order" button, a command palette, a custom composer
9910
- * replacing the built-in one). Everything the built-in Send does happens
9911
- * here; Send itself now reads the composer, clears it, and calls this.
9814
+ * The programmatic half of the composer, for a host driving its own input.
9815
+ * Everything the built-in Send does happens here; Send reads the composer,
9816
+ * clears it, and calls this.
9912
9817
  *
9913
- * `attachments` are durable {@link AttachmentRef}s — the shape
9914
- * {@link attachFile}'s upload resolves to, and the shape
9915
- * {@link ATTACHMENT_EVENT} reports. Pass them to attach files to the message.
9818
+ * `attachments` are durable {@link AttachmentRef}s — what {@link attachFile}
9819
+ * resolves to and what {@link ATTACHMENT_EVENT} reports.
9916
9820
  *
9917
- * No-ops while a run is in flight (a second concurrent run would orphan the
9918
- * first) and for an entirely empty message. Unlike the built-in Send, this
9919
- * does **not** consult the tray: what you pass is what is sent, so a host
9920
- * composer stays in charge of its own state.
9821
+ * No-ops on an empty message, and while a run is in flight, since a second
9822
+ * concurrent run would orphan the first. Unlike the built-in Send it does not
9823
+ * consult the tray: what you pass is what is sent.
9921
9824
  */
9922
9825
  async sendMessage(content, attachments = []) {
9923
9826
  if (this.#running || content === "" && attachments.length === 0) {
@@ -9941,11 +9844,11 @@ var AgUiChat = class extends HTMLElement {
9941
9844
  * picker and drag-and-drop do — validation, progress chip, and all.
9942
9845
  *
9943
9846
  * Returns `false` when uploads are not configured (no `data-attachments-url`
9944
- * and no {@link uploadHandler}), which is the only way for a host to tell;
9945
- * the tray does not exist to report anything in that case.
9847
+ * and no {@link uploadHandler}) the only signal a host gets, since the tray
9848
+ * does not exist to report anything then.
9946
9849
  *
9947
9850
  * Uploading is asynchronous: watch {@link ATTACHMENT_EVENT} for the resulting
9948
- * {@link AttachmentRef}, and pass it to {@link sendMessage} once `pending`
9851
+ * {@link AttachmentRef} and pass it to {@link sendMessage} once `pending`
9949
9852
  * reaches zero.
9950
9853
  */
9951
9854
  attachFile(file) {
@@ -10090,12 +9993,11 @@ var AgUiChat = class extends HTMLElement {
10090
9993
  * Render an approval card per server-side-tool interrupt and collect the
10091
9994
  * user's decisions (approve → run it, deny → decline it).
10092
9995
  *
10093
- * The run is suspended on these cards; a Stop while any is open aborts the
9996
+ * The run is suspended on these cards. A Stop while any is open aborts the
10094
9997
  * shared {@link #confirmAbort} controller, resolving every still-open card as
10095
- * denied (and the client loop then sees the cancellation and stops). An
10096
- * approved tool runs on the follow-up (resume) run and streams its result
10097
- * back into the same pending card; a denied one is settled here, since no
10098
- * result will ever arrive for it.
9998
+ * denied. An approved tool runs on the follow-up resume run and streams its
9999
+ * result into the same pending card; a denied one settles here, since no
10000
+ * result will ever arrive.
10099
10001
  */
10100
10002
  async #resolveInterrupts(interrupts) {
10101
10003
  const responses = {};
@@ -10329,6 +10231,16 @@ var AgUiChat = class extends HTMLElement {
10329
10231
  return card;
10330
10232
  }
10331
10233
  };
10234
+ function restoredToolCalls(value) {
10235
+ return Array.isArray(value) ? value.filter(isRestoredToolCall) : [];
10236
+ }
10237
+ function isRestoredToolCall(value) {
10238
+ if (typeof value !== "object" || value === null) {
10239
+ return false;
10240
+ }
10241
+ const call = value;
10242
+ return typeof call.id === "string" && typeof call.function?.name === "string";
10243
+ }
10332
10244
  function skillNameFrom(call) {
10333
10245
  if (call.name !== LOAD_CAPABILITY_TOOL) {
10334
10246
  return null;
@@ -10381,7 +10293,7 @@ function setControlValue(el, value) {
10381
10293
  }
10382
10294
 
10383
10295
  // src/version.ts
10384
- var VERSION = "0.23.0";
10296
+ var VERSION = "0.23.1";
10385
10297
  export {
10386
10298
  ATTACHMENT_EVENT,
10387
10299
  AgUiChat,