@artooi/ag-ui-web-component 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +149 -36
- package/README.md +140 -9
- package/dist/ag-ui-web-component.bundle.js +113 -122
- package/dist/ag-ui-web-component.bundle.js.map +3 -3
- package/dist/constants.d.ts +71 -85
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts +105 -127
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/agui_client.d.ts +24 -30
- package/dist/core/agui_client.d.ts.map +1 -1
- package/dist/core/attachment.d.ts +9 -14
- package/dist/core/attachment.d.ts.map +1 -1
- package/dist/core/conversation_store.d.ts +38 -27
- package/dist/core/conversation_store.d.ts.map +1 -1
- package/dist/core/create_http_agent.d.ts +13 -15
- package/dist/core/create_http_agent.d.ts.map +1 -1
- package/dist/core/remote_conversation_store.d.ts +10 -9
- package/dist/core/remote_conversation_store.d.ts.map +1 -1
- package/dist/core/run_index.d.ts +11 -20
- package/dist/core/run_index.d.ts.map +1 -1
- package/dist/core/transcribe_audio.d.ts +8 -8
- package/dist/core/transcribe_audio.d.ts.map +1 -1
- package/dist/core/upload_attachment.d.ts +15 -18
- package/dist/core/upload_attachment.d.ts.map +1 -1
- package/dist/core/utils.d.ts +4 -6
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/dom/animations.d.ts +22 -30
- package/dist/dom/animations.d.ts.map +1 -1
- package/dist/dom/dom_driver.d.ts +7 -7
- package/dist/dom/native_setter.d.ts +2 -2
- package/dist/dom/native_setter.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +357 -383
- package/dist/index.js.map +2 -2
- package/dist/skills/fill_template.d.ts +4 -5
- package/dist/skills/fill_template.d.ts.map +1 -1
- package/dist/skills/parse_skills.d.ts.map +1 -1
- package/dist/skills/skill.d.ts +7 -8
- package/dist/skills/skill.d.ts.map +1 -1
- package/dist/tools/client_tool_registry.d.ts +2 -2
- package/dist/tools/page_action_tools.d.ts +7 -10
- package/dist/tools/page_action_tools.d.ts.map +1 -1
- package/dist/tools/page_state.d.ts +5 -8
- package/dist/tools/page_state.d.ts.map +1 -1
- package/dist/tools/route_map.d.ts +7 -10
- package/dist/tools/route_map.d.ts.map +1 -1
- package/dist/ui/approval_card.d.ts +15 -20
- package/dist/ui/approval_card.d.ts.map +1 -1
- package/dist/ui/attach_copy_buttons.d.ts +4 -10
- package/dist/ui/attach_copy_buttons.d.ts.map +1 -1
- package/dist/ui/attachment_chips.d.ts +7 -10
- package/dist/ui/attachment_chips.d.ts.map +1 -1
- package/dist/ui/attachment_tray.d.ts +6 -6
- package/dist/ui/checkpoint_menu.d.ts +7 -8
- package/dist/ui/checkpoint_menu.d.ts.map +1 -1
- package/dist/ui/confirmation_card.d.ts +10 -15
- package/dist/ui/confirmation_card.d.ts.map +1 -1
- package/dist/ui/question_card.d.ts +12 -15
- package/dist/ui/question_card.d.ts.map +1 -1
- package/dist/ui/relative_time.d.ts +5 -7
- package/dist/ui/relative_time.d.ts.map +1 -1
- package/dist/ui/render_markdown.d.ts +8 -8
- package/dist/ui/render_markdown.d.ts.map +1 -1
- package/dist/ui/resize_handle.d.ts +21 -34
- package/dist/ui/resize_handle.d.ts.map +1 -1
- package/dist/ui/run_notice.d.ts +5 -7
- package/dist/ui/run_notice.d.ts.map +1 -1
- package/dist/ui/skills_menu.d.ts +4 -5
- package/dist/ui/skills_menu.d.ts.map +1 -1
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/thoughts_block.d.ts +9 -11
- package/dist/ui/thoughts_block.d.ts.map +1 -1
- package/dist/ui/thread_drawer.d.ts +6 -5
- package/dist/ui/thread_drawer.d.ts.map +1 -1
- package/dist/ui/tool_call_card.d.ts +17 -25
- package/dist/ui/tool_call_card.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +6 -12
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/dist/ui/voice_input.d.ts +10 -11
- package/dist/ui/voice_input.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +74 -87
- package/src/core/ag_ui_chat.ts +313 -269
- package/src/core/agui_client.ts +60 -71
- package/src/core/attachment.ts +9 -14
- package/src/core/conversation_store.ts +55 -33
- package/src/core/create_http_agent.ts +18 -22
- package/src/core/remote_conversation_store.ts +28 -15
- package/src/core/run_index.ts +14 -23
- package/src/core/transcribe_audio.ts +9 -10
- package/src/core/upload_attachment.ts +18 -21
- package/src/core/utils.ts +4 -6
- package/src/dom/animations.ts +33 -43
- package/src/dom/dom_driver.ts +7 -7
- package/src/dom/native_setter.ts +11 -12
- package/src/index.ts +3 -0
- package/src/skills/fill_template.ts +4 -5
- package/src/skills/parse_skills.ts +3 -4
- package/src/skills/skill.ts +7 -8
- package/src/tools/client_tool_registry.ts +2 -2
- package/src/tools/page_action_tools.ts +12 -15
- package/src/tools/page_state.ts +5 -8
- package/src/tools/route_map.ts +15 -19
- package/src/ui/approval_card.ts +15 -20
- package/src/ui/attach_copy_buttons.ts +9 -18
- package/src/ui/attachment_chips.ts +7 -10
- package/src/ui/attachment_tray.ts +6 -6
- package/src/ui/checkpoint_menu.ts +7 -8
- package/src/ui/confirmation_card.ts +10 -15
- package/src/ui/question_card.ts +12 -15
- package/src/ui/relative_time.ts +5 -7
- package/src/ui/render_markdown.ts +25 -51
- package/src/ui/resize_handle.ts +25 -38
- package/src/ui/run_notice.ts +9 -12
- package/src/ui/skills_menu.ts +4 -5
- package/src/ui/styles.ts +92 -101
- package/src/ui/thoughts_block.ts +11 -13
- package/src/ui/thread_drawer.ts +6 -5
- package/src/ui/tool_call_card.ts +22 -32
- package/src/ui/ui_strings.ts +6 -12
- package/src/ui/voice_input.ts +10 -11
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ var TOGGLE_EVENT = "ag-ui-toggle";
|
|
|
5
5
|
var UNREAD_EVENT = "ag-ui-unread";
|
|
6
6
|
var STATE_EVENT = "ag-ui-state";
|
|
7
7
|
var ATTACHMENT_EVENT = "ag-ui-attachments";
|
|
8
|
+
var RUN_FINISHED_EVENT = "ag-ui-run-finished";
|
|
8
9
|
var MESSAGE_ROLE = {
|
|
9
10
|
USER: "user",
|
|
10
11
|
ASSISTANT: "assistant"
|
|
@@ -83,8 +84,8 @@ var ClientToolRegistry = class {
|
|
|
83
84
|
/**
|
|
84
85
|
* Register a tool, replacing any existing one with the same name.
|
|
85
86
|
*
|
|
86
|
-
* Idempotent on the name so re-fired host
|
|
87
|
-
* double-invoke
|
|
87
|
+
* Idempotent on the name so a re-fired host ref or React StrictMode's
|
|
88
|
+
* double-invoke replaces rather than throws.
|
|
88
89
|
*/
|
|
89
90
|
register(tool) {
|
|
90
91
|
this.#tools.set(tool.name, tool);
|
|
@@ -4477,12 +4478,11 @@ var STYLES = `
|
|
|
4477
4478
|
only the alias is used by the rules below.
|
|
4478
4479
|
|
|
4479
4480
|
The indirection is what makes ancestor theming work. Declaring the public
|
|
4480
|
-
name on :host would set it
|
|
4481
|
-
always beats one inherited from an ancestor
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
inherited normally while a value aimed at the element still wins over it.
|
|
4481
|
+
name on :host would set it on the host element, and a value on an element
|
|
4482
|
+
always beats one inherited from an ancestor, so tokens put on a wrapper
|
|
4483
|
+
would have no effect. Reading the public name with the default as a var()
|
|
4484
|
+
fallback leaves it undeclared on the element, so an ancestor's value
|
|
4485
|
+
inherits normally while one aimed at the element still wins.
|
|
4486
4486
|
|
|
4487
4487
|
Two invariants hold this together:
|
|
4488
4488
|
1. No rule outside this file's :host blocks may reference a public name
|
|
@@ -4509,11 +4509,9 @@ var STYLES = `
|
|
|
4509
4509
|
--_border: var(--ag-ui-border, #e2e2ec);
|
|
4510
4510
|
--_radius: var(--ag-ui-radius, 12px);
|
|
4511
4511
|
|
|
4512
|
-
/* Body text and raised chrome
|
|
4513
|
-
|
|
4514
|
-
|
|
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. */
|
|
4512
|
+
/* Body text and raised chrome, read only by the code-block copy button.
|
|
4513
|
+
The defaults restate what it inherits, so a host that sets neither sees
|
|
4514
|
+
no repaint \u2014 see the note on .code-copy. */
|
|
4517
4515
|
--_text: var(--ag-ui-text, var(--_fg));
|
|
4518
4516
|
--_surface: var(--ag-ui-surface, transparent);
|
|
4519
4517
|
|
|
@@ -4566,9 +4564,9 @@ var STYLES = `
|
|
|
4566
4564
|
--_launcher-inset: var(--ag-ui-launcher-inset, auto 0 0 auto);
|
|
4567
4565
|
|
|
4568
4566
|
/* Motion. One duration and two curves drive every collapse, expand and
|
|
4569
|
-
slide-over, so the
|
|
4570
|
-
|
|
4571
|
-
|
|
4567
|
+
slide-over, so the widget accelerates and settles as one thing. The
|
|
4568
|
+
default curve decelerates into place; the pop curve overshoots slightly,
|
|
4569
|
+
for something arriving. */
|
|
4572
4570
|
--_motion: var(--ag-ui-motion, 0.28s);
|
|
4573
4571
|
--_ease: var(--ag-ui-ease, cubic-bezier(0.32, 0.72, 0, 1));
|
|
4574
4572
|
--_ease-pop: var(--ag-ui-ease-pop, cubic-bezier(0.34, 1.36, 0.64, 1));
|
|
@@ -4592,7 +4590,7 @@ var STYLES = `
|
|
|
4592
4590
|
/* Reading-column width for placement="page" (full-bleed, centred content). */
|
|
4593
4591
|
--_content-max-width: var(--ag-ui-content-max-width, 820px);
|
|
4594
4592
|
/* Slim rail the sidebar placement collapses to. Only that placement reads
|
|
4595
|
-
it, but it is declared here so
|
|
4593
|
+
it, but it is declared here so every alias has a default in one place. */
|
|
4596
4594
|
--_rail-width: var(--ag-ui-rail-width, 52px);
|
|
4597
4595
|
|
|
4598
4596
|
position: var(--_position);
|
|
@@ -4684,11 +4682,11 @@ var STYLES = `
|
|
|
4684
4682
|
--_radius: var(--ag-ui-radius, 0);
|
|
4685
4683
|
}
|
|
4686
4684
|
|
|
4687
|
-
/* Page: full-bleed background with a centred reading column
|
|
4688
|
-
"full"
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4685
|
+
/* Page: full-bleed background with a centred reading column capped at
|
|
4686
|
+
--ag-ui-content-max-width, where "full" is edge-to-edge and left-aligned.
|
|
4687
|
+
The column comes from symmetric auto padding on the scroll area and
|
|
4688
|
+
composer rather than a per-row wrapper, so user pills still right-align and
|
|
4689
|
+
the assistant well spans the column. */
|
|
4692
4690
|
:host([placement="page"]) {
|
|
4693
4691
|
--_inset: var(--ag-ui-inset, 0);
|
|
4694
4692
|
--_width: var(--ag-ui-width, 100vw);
|
|
@@ -4706,9 +4704,8 @@ var STYLES = `
|
|
|
4706
4704
|
padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));
|
|
4707
4705
|
}
|
|
4708
4706
|
|
|
4709
|
-
/* The rows between the message list and the composer
|
|
4710
|
-
|
|
4711
|
-
with the column too \u2014 chips are padding-based, the palette/hint/tray are
|
|
4707
|
+
/* The rows between the message list and the composer line up with the column
|
|
4708
|
+
too. Chips and tray are padding-based while palette and hint are
|
|
4712
4709
|
margin-based, so each gets its own inline axis nudged by the same gutter. */
|
|
4713
4710
|
:host([placement="page"]) .skill-chips,
|
|
4714
4711
|
:host([placement="page"]) .attachment-tray {
|
|
@@ -4817,13 +4814,12 @@ var STYLES = `
|
|
|
4817
4814
|
visibility var(--_motion) var(--_ease);
|
|
4818
4815
|
}
|
|
4819
4816
|
|
|
4820
|
-
/* The launcher grows out of the corner the panel shrank into.
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
must stay reachable. */
|
|
4817
|
+
/* The launcher grows out of the corner the panel shrank into. It stays laid
|
|
4818
|
+
out at rest rather than display:none, which is what lets it animate both in
|
|
4819
|
+
and out: an unrendered element has no before-change style to transition
|
|
4820
|
+
from, and one flipping display to none cannot transition at all. visibility
|
|
4821
|
+
keeps it unpaintable, untabbable and unclickable in between, so the expanded
|
|
4822
|
+
panel's own controls underneath stay reachable. */
|
|
4827
4823
|
:host([collapsed]) .launcher {
|
|
4828
4824
|
opacity: 1;
|
|
4829
4825
|
transform: none;
|
|
@@ -4984,20 +4980,18 @@ var STYLES = `
|
|
|
4984
4980
|
|
|
4985
4981
|
/* \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
4982
|
Collapsing shrinks the widget to the round floating launcher: the panel
|
|
4987
|
-
scales
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
The host box keeps its expanded size
|
|
4992
|
-
a dragged --ag-ui-width would
|
|
4993
|
-
paints there once the panel is gone, so the box only has to stop
|
|
4994
|
-
clicks: pointer events go to none
|
|
4995
|
-
|
|
4996
|
-
Two placements collapse
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
floating circle would escape the layout, and page is a full-screen route
|
|
5000
|
-
with no corner to float in. */
|
|
4983
|
+
scales toward the launcher's corner and fades, the launcher pops in from the
|
|
4984
|
+
same point. Both halves are transform and opacity only, so the morph runs on
|
|
4985
|
+
the compositor and never reflows the host page.
|
|
4986
|
+
|
|
4987
|
+
The host box keeps its expanded size, since animating it would animate
|
|
4988
|
+
layout and a dragged --ag-ui-width would fight the launcher's own size.
|
|
4989
|
+
Nothing paints there once the panel is gone, so the box only has to stop
|
|
4990
|
+
swallowing clicks: pointer events go to none and the launcher takes them.
|
|
4991
|
+
|
|
4992
|
+
Two placements collapse differently: "sidebar" slides to its rail (below),
|
|
4993
|
+
while "embedded" and "page" keep the header bar, having no corner for a
|
|
4994
|
+
floating circle that would escape the host's layout. */
|
|
5001
4995
|
:host([collapsed]) {
|
|
5002
4996
|
pointer-events: none;
|
|
5003
4997
|
}
|
|
@@ -5008,11 +5002,11 @@ var STYLES = `
|
|
|
5008
5002
|
visibility: hidden;
|
|
5009
5003
|
}
|
|
5010
5004
|
|
|
5011
|
-
/* visibility
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5005
|
+
/* visibility keeps the panel out of the tab order and the a11y tree at rest
|
|
5006
|
+
without display:none killing the transition. It interpolates so any progress
|
|
5007
|
+
below 1 still counts as visible: the panel stays on screen for the whole
|
|
5008
|
+
collapse, flips hidden exactly at the end, and on expand is visible from the
|
|
5009
|
+
first frame. */
|
|
5016
5010
|
.chat {
|
|
5017
5011
|
transform-origin: bottom right;
|
|
5018
5012
|
transition:
|
|
@@ -5039,10 +5033,9 @@ var STYLES = `
|
|
|
5039
5033
|
visibility: visible;
|
|
5040
5034
|
}
|
|
5041
5035
|
|
|
5042
|
-
/* These two keep the header bar, so the launcher must stay out of the way
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
whatever the page happens to position. */
|
|
5036
|
+
/* These two keep the header bar, so the launcher must stay out of the way: an
|
|
5037
|
+
embedded host is position: static, which would let an absolutely-positioned
|
|
5038
|
+
circle escape the layout and land against whatever the page positions. */
|
|
5046
5039
|
:host([collapsed]:is([placement="embedded"], [placement="page"])) .launcher {
|
|
5047
5040
|
visibility: hidden;
|
|
5048
5041
|
opacity: 0;
|
|
@@ -5082,7 +5075,7 @@ var STYLES = `
|
|
|
5082
5075
|
and the pending indicator so a whole answer reads (and can be boxed) as one
|
|
5083
5076
|
unit. A flex column on the message-list gap, stretched to the list width so
|
|
5084
5077
|
its children keep their own left/right alignment. data-answer-well opts into
|
|
5085
|
-
the bordered "well"; without it the
|
|
5078
|
+
the bordered "well"; without it the turn renders as a flat stack. */
|
|
5086
5079
|
.answer {
|
|
5087
5080
|
display: flex;
|
|
5088
5081
|
flex-direction: column;
|
|
@@ -5208,13 +5201,9 @@ var STYLES = `
|
|
|
5208
5201
|
position: relative;
|
|
5209
5202
|
}
|
|
5210
5203
|
|
|
5211
|
-
/*
|
|
5212
|
-
|
|
5213
|
-
|
|
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. */
|
|
5204
|
+
/* The only reader of --ag-ui-surface and --ag-ui-text. Their defaults are
|
|
5205
|
+
transparent and the body foreground, which is what this button rendered as
|
|
5206
|
+
before either token existed; changing them repaints only this control. */
|
|
5218
5207
|
.code-copy {
|
|
5219
5208
|
position: absolute;
|
|
5220
5209
|
top: 4px;
|
|
@@ -5260,12 +5249,10 @@ var STYLES = `
|
|
|
5260
5249
|
color: var(--_muted);
|
|
5261
5250
|
}
|
|
5262
5251
|
|
|
5263
|
-
/* Markdown tables. table/thead/tbody/tr/th/td are all in
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
width-constrained, so without this the columns either crush or push the
|
|
5268
|
-
layout sideways. */
|
|
5252
|
+
/* Markdown tables. table/thead/tbody/tr/th/td are all in the sanitizer's
|
|
5253
|
+
ALLOWED_TAGS, so an agent can emit one. A wide table must scroll inside its
|
|
5254
|
+
own box rather than stretch the message: the bubble is width-constrained, so
|
|
5255
|
+
without this the columns either crush or push the layout sideways. */
|
|
5269
5256
|
.message--assistant table {
|
|
5270
5257
|
display: block;
|
|
5271
5258
|
width: fit-content;
|
|
@@ -5406,18 +5393,28 @@ var STYLES = `
|
|
|
5406
5393
|
color: var(--_tool-fg);
|
|
5407
5394
|
}
|
|
5408
5395
|
|
|
5396
|
+
/* Wraps, because the name is the only flexible child and every badge the row
|
|
5397
|
+
gains is taken out of it. An approved call adds a third fixed badge, which in
|
|
5398
|
+
a sidebar-width panel left the name 37px and broke it mid-word. Badges drop to
|
|
5399
|
+
their own row instead. */
|
|
5409
5400
|
.tool-call-head {
|
|
5410
5401
|
display: flex;
|
|
5402
|
+
flex-wrap: wrap;
|
|
5411
5403
|
align-items: center;
|
|
5412
5404
|
justify-content: space-between;
|
|
5413
5405
|
gap: 8px;
|
|
5414
5406
|
}
|
|
5415
5407
|
|
|
5416
5408
|
.tool-call-name {
|
|
5417
|
-
|
|
5418
|
-
|
|
5409
|
+
/* An auto basis, and a min-width floor rather than zero: the name may shrink,
|
|
5410
|
+
but not below something readable, so wrapping moves a badge instead of
|
|
5411
|
+
shredding a word. Breaking anywhere still applies to a name that cannot fit
|
|
5412
|
+
on a line of its own, which is what keeps a long unbroken tool name inside
|
|
5413
|
+
the card. */
|
|
5414
|
+
flex: 1 1 auto;
|
|
5415
|
+
min-width: 6ch;
|
|
5419
5416
|
font-weight: 600;
|
|
5420
|
-
|
|
5417
|
+
overflow-wrap: anywhere;
|
|
5421
5418
|
}
|
|
5422
5419
|
|
|
5423
5420
|
/* Leading status icon. Empty in the DOM \u2014 the glyph/spinner is drawn
|
|
@@ -5522,8 +5519,6 @@ var STYLES = `
|
|
|
5522
5519
|
color: var(--_muted);
|
|
5523
5520
|
}
|
|
5524
5521
|
|
|
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
5522
|
.skill-item-token {
|
|
5528
5523
|
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
5529
5524
|
font-size: 0.92em;
|
|
@@ -5531,6 +5526,8 @@ var STYLES = `
|
|
|
5531
5526
|
margin-right: 6px;
|
|
5532
5527
|
}
|
|
5533
5528
|
|
|
5529
|
+
/* The lasting record of a human decision on a gated call \u2014 without it an
|
|
5530
|
+
approved call looks exactly like one that was never gated. */
|
|
5534
5531
|
.tool-call-decision {
|
|
5535
5532
|
flex: none;
|
|
5536
5533
|
font-size: 11px;
|
|
@@ -5553,10 +5550,8 @@ var STYLES = `
|
|
|
5553
5550
|
}
|
|
5554
5551
|
|
|
5555
5552
|
/* Display modes are pure visibility over one DOM shape, selected from the host
|
|
5556
|
-
attribute rather than a value stamped on the card
|
|
5557
|
-
|
|
5558
|
-
re-read it, the way data-answer-well behaves. Baking the structure per mode
|
|
5559
|
-
meant the setting only reached cards created afterwards.
|
|
5553
|
+
attribute rather than a value stamped on the card at build time, so flipping
|
|
5554
|
+
data-tool-display re-styles cards already on screen. See ToolCallCard.
|
|
5560
5555
|
|
|
5561
5556
|
Default (no attribute) is the full mode: arguments always visible, result
|
|
5562
5557
|
behind the toggle. */
|
|
@@ -5653,20 +5648,19 @@ var STYLES = `
|
|
|
5653
5648
|
}
|
|
5654
5649
|
|
|
5655
5650
|
/* Then the measurement corrects it. Which edges are held still belongs to the
|
|
5656
|
-
host's layout
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
embedded panel its host right-aligns. */
|
|
5651
|
+
host's layout, not to placement -- a floating panel a host right-aligns is
|
|
5652
|
+
anchored bottom-left -- so the element measures them and stamps a single
|
|
5653
|
+
hyphenated "<y>-<x>" token here. Equal specificity to the rules above, so
|
|
5654
|
+
source order is what lets the measured value win.
|
|
5655
|
+
|
|
5656
|
+
Two traps, both of which silently draw the grip on the corner that moves:
|
|
5657
|
+
|
|
5658
|
+
Never write these as [data-resize-anchor~="left"]. The stamped value is one
|
|
5659
|
+
hyphenated token and ~= matches whitespace-separated words, so it can never
|
|
5660
|
+
match.
|
|
5661
|
+
|
|
5662
|
+
Each rule must set both sides of its axis, not only the side it moves, or it
|
|
5663
|
+
cannot undo a placement guess that flipped the other way. */
|
|
5670
5664
|
:host([data-resize-anchor$="-left"]) .resize-handle {
|
|
5671
5665
|
left: auto;
|
|
5672
5666
|
right: 0;
|
|
@@ -5727,10 +5721,9 @@ var STYLES = `
|
|
|
5727
5721
|
}
|
|
5728
5722
|
|
|
5729
5723
|
/* \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
|
|
5731
|
-
its tool row sit inside it
|
|
5732
|
-
textarea's height
|
|
5733
|
-
and turned Send into a full-height slab. */
|
|
5724
|
+
One surface owns the border, the background and the focus ring; the field
|
|
5725
|
+
and its tool row sit inside it, rather than being siblings stretched to the
|
|
5726
|
+
textarea's height. */
|
|
5734
5727
|
.input-row {
|
|
5735
5728
|
display: flex;
|
|
5736
5729
|
padding: 12px;
|
|
@@ -5978,13 +5971,12 @@ var STYLES = `
|
|
|
5978
5971
|
}
|
|
5979
5972
|
|
|
5980
5973
|
/* 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:
|
|
5982
|
-
composer tray it
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
Overridden below for an errored chip, which must keep its red. */
|
|
5974
|
+
The same chip renders in two places with opposite inherited colours: the
|
|
5975
|
+
composer tray gives it the panel's, a sent user bubble gives it the user
|
|
5976
|
+
foreground, which is white on the stock light theme and near-invisible
|
|
5977
|
+
against the chip. Pairing the colour with the background it belongs to makes
|
|
5978
|
+
both placements read alike. Overridden below for an errored chip, which
|
|
5979
|
+
keeps its red. */
|
|
5988
5980
|
.attachment-chip {
|
|
5989
5981
|
display: inline-flex;
|
|
5990
5982
|
align-items: center;
|
|
@@ -6678,9 +6670,9 @@ var ThoughtsBlock = class {
|
|
|
6678
6670
|
this.#body.textContent = buffer;
|
|
6679
6671
|
}
|
|
6680
6672
|
/**
|
|
6681
|
-
* Fold the region away
|
|
6682
|
-
*
|
|
6683
|
-
*
|
|
6673
|
+
* Fold the region away when the answer's first text token arrives, flipping
|
|
6674
|
+
* the header label to its settled form. Idempotent, since the per-token text
|
|
6675
|
+
* handler calls it repeatedly.
|
|
6684
6676
|
*/
|
|
6685
6677
|
collapse() {
|
|
6686
6678
|
if (this.#collapsed) {
|
|
@@ -7038,11 +7030,8 @@ var ToolCallCard = class {
|
|
|
7038
7030
|
}
|
|
7039
7031
|
/**
|
|
7040
7032
|
* Record that a human approved or declined this call, as a line in the card.
|
|
7041
|
-
*
|
|
7042
|
-
*
|
|
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.
|
|
7033
|
+
* The prompt disappears once answered, so this is the only lasting trace that
|
|
7034
|
+
* the call was gated at all.
|
|
7046
7035
|
*/
|
|
7047
7036
|
recordDecision(kind) {
|
|
7048
7037
|
this.element.setAttribute("data-decision", kind);
|
|
@@ -7157,11 +7146,10 @@ var VoiceInput = class {
|
|
|
7157
7146
|
this.#recorder?.stop();
|
|
7158
7147
|
}
|
|
7159
7148
|
/**
|
|
7160
|
-
* Tear the control down
|
|
7161
|
-
*
|
|
7162
|
-
*
|
|
7163
|
-
*
|
|
7164
|
-
* detached element.
|
|
7149
|
+
* Tear the control down, for a host element removed mid-recording. Stops any
|
|
7150
|
+
* live `MediaRecorder`, releases the mic tracks so the browser's recording
|
|
7151
|
+
* indicator clears, and suppresses the pending transcription — a
|
|
7152
|
+
* disconnected control must not fire `onText` into a detached element.
|
|
7165
7153
|
*/
|
|
7166
7154
|
dispose() {
|
|
7167
7155
|
this.#disposed = true;
|
|
@@ -7243,10 +7231,9 @@ var AgUiClient = class {
|
|
|
7243
7231
|
#resolveInterrupts;
|
|
7244
7232
|
#onPersist;
|
|
7245
7233
|
/**
|
|
7246
|
-
* Message ids the server has already closed, so a reuse can be reported.
|
|
7247
|
-
*
|
|
7248
|
-
*
|
|
7249
|
-
* case a per-run set would miss entirely.
|
|
7234
|
+
* Message ids the server has already closed, so a reuse can be reported. Per
|
|
7235
|
+
* client rather than per run — the merge happens across runs, which a per-run
|
|
7236
|
+
* set would miss entirely.
|
|
7250
7237
|
*/
|
|
7251
7238
|
#closedMessageIds = /* @__PURE__ */ new Set();
|
|
7252
7239
|
#connectionLostMessage;
|
|
@@ -7296,9 +7283,8 @@ var AgUiClient = class {
|
|
|
7296
7283
|
* tools (bounded by {@link MAX_TOOL_ROUNDS}).
|
|
7297
7284
|
*
|
|
7298
7285
|
* `attachments` ride on the user message as a non-standard field so the
|
|
7299
|
-
* default
|
|
7300
|
-
*
|
|
7301
|
-
* unknown message field), then reads bytes via the `read_attachment` tool.
|
|
7286
|
+
* default store round-trips them for history replay; see
|
|
7287
|
+
* {@link messageAttachments}.
|
|
7302
7288
|
*/
|
|
7303
7289
|
async send(content, attachments = []) {
|
|
7304
7290
|
const message = { id: randomUUID2(), role: "user", content };
|
|
@@ -7312,7 +7298,7 @@ var AgUiClient = class {
|
|
|
7312
7298
|
/**
|
|
7313
7299
|
* Resume the run loop after a navigating tool's result was supplied
|
|
7314
7300
|
* post-reload (via {@link addToolResult}). Unlike {@link send}, adds no user
|
|
7315
|
-
* message
|
|
7301
|
+
* message; it continues the conversation already in history.
|
|
7316
7302
|
*/
|
|
7317
7303
|
async resume() {
|
|
7318
7304
|
await this.#run();
|
|
@@ -7454,9 +7440,9 @@ var AgUiClient = class {
|
|
|
7454
7440
|
onActivitySnapshotEvent({ event }) {
|
|
7455
7441
|
h.onActivity(event.activityType, event.content);
|
|
7456
7442
|
},
|
|
7457
|
-
//
|
|
7458
|
-
//
|
|
7459
|
-
//
|
|
7443
|
+
// `@ag-ui/client` maps the deprecated THINKING_* events onto these
|
|
7444
|
+
// REASONING_* callbacks, so the reasoning family alone covers both
|
|
7445
|
+
// protocol versions.
|
|
7460
7446
|
onReasoningStartEvent() {
|
|
7461
7447
|
h.onReasoningStart();
|
|
7462
7448
|
},
|
|
@@ -7508,6 +7494,7 @@ var THREAD_SUFFIX = "thread";
|
|
|
7508
7494
|
var THREADS_SUFFIX = "threads";
|
|
7509
7495
|
var MESSAGES_SUFFIX = "messages:";
|
|
7510
7496
|
var CHECKPOINT_SUFFIX = "checkpoint:";
|
|
7497
|
+
var MINTED_SUFFIX = "minted:";
|
|
7511
7498
|
var TITLE_LIMIT = 60;
|
|
7512
7499
|
var PREVIEW_LIMIT = 100;
|
|
7513
7500
|
var DEFAULT_TITLE = "New conversation";
|
|
@@ -7527,13 +7514,18 @@ var SessionStorageStore = class {
|
|
|
7527
7514
|
}
|
|
7528
7515
|
const id = randomUUID3();
|
|
7529
7516
|
sessionStorage.setItem(key, id);
|
|
7517
|
+
sessionStorage.setItem(this.#key(MINTED_SUFFIX + id), "1");
|
|
7530
7518
|
return id;
|
|
7531
7519
|
}
|
|
7520
|
+
isUnsent(threadId) {
|
|
7521
|
+
return sessionStorage.getItem(this.#key(MINTED_SUFFIX + threadId)) !== null && sessionStorage.getItem(this.#key(MESSAGES_SUFFIX + threadId)) === null;
|
|
7522
|
+
}
|
|
7532
7523
|
loadMessages(threadId) {
|
|
7533
7524
|
return Promise.resolve(this.#readJson(this.#key(MESSAGES_SUFFIX + threadId)));
|
|
7534
7525
|
}
|
|
7535
7526
|
saveMessages(threadId, messages) {
|
|
7536
7527
|
sessionStorage.setItem(this.#key(MESSAGES_SUFFIX + threadId), JSON.stringify(messages));
|
|
7528
|
+
sessionStorage.removeItem(this.#key(MINTED_SUFFIX + threadId));
|
|
7537
7529
|
this.#touchThread(threadId, messages);
|
|
7538
7530
|
}
|
|
7539
7531
|
loadCheckpoint(threadId) {
|
|
@@ -7550,6 +7542,7 @@ var SessionStorageStore = class {
|
|
|
7550
7542
|
clear(threadId) {
|
|
7551
7543
|
sessionStorage.removeItem(this.#key(MESSAGES_SUFFIX + threadId));
|
|
7552
7544
|
sessionStorage.removeItem(this.#key(CHECKPOINT_SUFFIX + threadId));
|
|
7545
|
+
sessionStorage.removeItem(this.#key(MINTED_SUFFIX + threadId));
|
|
7553
7546
|
this.#writeThreads(this.#readThreads().filter((thread) => thread.threadId !== threadId));
|
|
7554
7547
|
if (sessionStorage.getItem(this.#key(THREAD_SUFFIX)) === threadId) {
|
|
7555
7548
|
sessionStorage.removeItem(this.#key(THREAD_SUFFIX));
|
|
@@ -7611,12 +7604,11 @@ var SessionStorageStore = class {
|
|
|
7611
7604
|
return `${this.#root}:${suffix}`;
|
|
7612
7605
|
}
|
|
7613
7606
|
/**
|
|
7614
|
-
* One-time move of
|
|
7615
|
-
* namespace, so an existing conversation isn't orphaned
|
|
7616
|
-
*
|
|
7617
|
-
*
|
|
7618
|
-
*
|
|
7619
|
-
* second namespace finds it gone and starts fresh.
|
|
7607
|
+
* One-time move of un-namespaced `ag-ui-chat:*` keys into this instance's
|
|
7608
|
+
* namespace, so an existing conversation isn't orphaned. Only this store's own
|
|
7609
|
+
* keys move — the element's `collapsed` / `theme` keys are left alone. The
|
|
7610
|
+
* first namespaced instance to mount adopts the data; a second namespace
|
|
7611
|
+
* finds it gone and starts fresh.
|
|
7620
7612
|
*/
|
|
7621
7613
|
#migrateLegacyKeys() {
|
|
7622
7614
|
const legacyRoot = `${KEY_ROOT}:`;
|
|
@@ -7697,12 +7689,10 @@ function createHttpAgent(options) {
|
|
|
7697
7689
|
headers: options.headers ?? {},
|
|
7698
7690
|
initialState: { ...options.initialState ?? {} },
|
|
7699
7691
|
// HttpAgent invokes its configured fetch as a method (`this.fetch(...)`),
|
|
7700
|
-
//
|
|
7701
|
-
//
|
|
7702
|
-
//
|
|
7703
|
-
//
|
|
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.
|
|
7692
|
+
// rebinding the global `fetch` to the agent instance — "Illegal invocation"
|
|
7693
|
+
// in browsers. The wrapper keeps `fetch` a free call, and is also where the
|
|
7694
|
+
// per-request `getHeaders()` overlay and the cookie policy go, the agent's
|
|
7695
|
+
// own config having no seam for either.
|
|
7706
7696
|
fetch: (url, init) => {
|
|
7707
7697
|
const fresh = options.getHeaders?.();
|
|
7708
7698
|
if (fresh === void 0) {
|
|
@@ -7715,7 +7705,7 @@ function createHttpAgent(options) {
|
|
|
7715
7705
|
return fetch(url, withCredentials({ ...init, headers }, options.credentials));
|
|
7716
7706
|
},
|
|
7717
7707
|
// Spread conditionally: under `exactOptionalPropertyTypes` an explicit
|
|
7718
|
-
// `undefined` is not assignable to
|
|
7708
|
+
// `undefined` is not assignable to an optional field.
|
|
7719
7709
|
...options.threadId !== void 0 ? { threadId: options.threadId } : {},
|
|
7720
7710
|
...options.initialMessages !== void 0 ? { initialMessages: [...options.initialMessages] } : {}
|
|
7721
7711
|
});
|
|
@@ -7741,6 +7731,10 @@ var RemoteConversationStore = class {
|
|
|
7741
7731
|
setActiveThread(threadId) {
|
|
7742
7732
|
this.#local.setActiveThread(threadId);
|
|
7743
7733
|
}
|
|
7734
|
+
/** Delegated, so wrapping a store does not lose what it knows about its own ids. */
|
|
7735
|
+
isUnsent(threadId) {
|
|
7736
|
+
return this.#local.isUnsent?.(threadId) === true;
|
|
7737
|
+
}
|
|
7744
7738
|
saveMessages(threadId, messages) {
|
|
7745
7739
|
this.#local.saveMessages(threadId, messages);
|
|
7746
7740
|
}
|
|
@@ -7768,6 +7762,9 @@ var RemoteConversationStore = class {
|
|
|
7768
7762
|
return rows.filter((row) => !this.#dropped.has(row.thread_id)).map((row) => this.#toMeta(row));
|
|
7769
7763
|
}
|
|
7770
7764
|
async loadMessages(threadId) {
|
|
7765
|
+
if (this.#local.isUnsent?.(threadId) === true) {
|
|
7766
|
+
return null;
|
|
7767
|
+
}
|
|
7771
7768
|
const response = await this.#get(`${this.#url}${encodeURIComponent(threadId)}/`);
|
|
7772
7769
|
if (response === null || !response.ok) {
|
|
7773
7770
|
return this.#local.loadMessages(threadId);
|
|
@@ -7801,9 +7798,9 @@ var RemoteConversationStore = class {
|
|
|
7801
7798
|
return {
|
|
7802
7799
|
threadId: row.thread_id,
|
|
7803
7800
|
title: this.#renamed.get(row.thread_id) ?? row.title,
|
|
7804
|
-
// `null`
|
|
7805
|
-
// signal
|
|
7806
|
-
//
|
|
7801
|
+
// `null` and an unparseable date both become NaN, Date.parse's own
|
|
7802
|
+
// signal, which `relativeTime` renders as a neutral label rather than an
|
|
7803
|
+
// epoch-0 or NaN duration.
|
|
7807
7804
|
updatedAt: row.updated_at === null ? Number.NaN : Date.parse(row.updated_at),
|
|
7808
7805
|
preview: row.preview
|
|
7809
7806
|
};
|
|
@@ -7847,10 +7844,9 @@ var RunIndex = class {
|
|
|
7847
7844
|
this.#credentials = credentials;
|
|
7848
7845
|
}
|
|
7849
7846
|
/**
|
|
7850
|
-
* The user's runs, or `[]` when the endpoint is unreachable or
|
|
7851
|
-
*
|
|
7852
|
-
*
|
|
7853
|
-
* the user can do nothing about.
|
|
7847
|
+
* The user's runs, or `[]` when the endpoint is unreachable or errors — the
|
|
7848
|
+
* caller renders its empty state rather than a transport fault the user can
|
|
7849
|
+
* do nothing about.
|
|
7854
7850
|
*/
|
|
7855
7851
|
async list() {
|
|
7856
7852
|
try {
|
|
@@ -7888,9 +7884,9 @@ var RunIndex = class {
|
|
|
7888
7884
|
/**
|
|
7889
7885
|
* `<mount>/<verb>/<runId>/`, derived from the index URL's own prefix.
|
|
7890
7886
|
*
|
|
7891
|
-
*
|
|
7892
|
-
*
|
|
7893
|
-
*
|
|
7887
|
+
* String surgery on the trailing `runs/` rather than `new URL`, because the
|
|
7888
|
+
* configured value may be root-relative (`/agent/runs/`), the common case in
|
|
7889
|
+
* a Django template, and `new URL` needs an absolute base.
|
|
7894
7890
|
*/
|
|
7895
7891
|
#sibling(verb, runId) {
|
|
7896
7892
|
const prefix = this.#url.slice(0, -"runs/".length);
|
|
@@ -8025,29 +8021,23 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8025
8021
|
/** Agent factory; override to inject a custom or fake agent (tests). */
|
|
8026
8022
|
agentFactory = createHttpAgent;
|
|
8027
8023
|
/**
|
|
8028
|
-
* Static extra HTTP headers, sent with
|
|
8029
|
-
*
|
|
8030
|
-
*
|
|
8024
|
+
* Static extra HTTP headers, sent with every request this element makes: the
|
|
8025
|
+
* agent run, the thread index and its messages, the tool and skill catalogs,
|
|
8026
|
+
* the run index, uploads and transcription.
|
|
8031
8027
|
*
|
|
8032
|
-
*
|
|
8033
|
-
*
|
|
8034
|
-
*
|
|
8035
|
-
* re-assignment updates it, so a token captured here is pinned until the host
|
|
8036
|
-
* remembers to assign again.
|
|
8028
|
+
* For values fixed for the element's lifetime. A rotating credential belongs
|
|
8029
|
+
* in {@link getHeaders} instead — only a re-assignment updates this, so a
|
|
8030
|
+
* token captured here is pinned until the host assigns again.
|
|
8037
8031
|
*/
|
|
8038
8032
|
headers = {};
|
|
8039
8033
|
/**
|
|
8040
|
-
* Live header source,
|
|
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.
|
|
8034
|
+
* Live header source, called afresh immediately before every request — the
|
|
8035
|
+
* way to supply rotating credentials, with nothing to re-assign or keep in
|
|
8036
|
+
* sync.
|
|
8046
8037
|
*
|
|
8047
|
-
* Composes with {@link headers} rather than replacing it:
|
|
8048
|
-
*
|
|
8049
|
-
* `Authorization`
|
|
8050
|
-
* the other.
|
|
8038
|
+
* Composes with {@link headers} rather than replacing it: merged per key with
|
|
8039
|
+
* `getHeaders()` winning, so a static `X-Client` and a rotating
|
|
8040
|
+
* `Authorization` are configured independently and neither drops the other.
|
|
8051
8041
|
*/
|
|
8052
8042
|
getHeaders = null;
|
|
8053
8043
|
/**
|
|
@@ -8061,37 +8051,31 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8061
8051
|
autoConfirm = false;
|
|
8062
8052
|
/**
|
|
8063
8053
|
* When true, the built-in `ask_user` frontend tool is offered to the agent:
|
|
8064
|
-
* calling it renders an inline question card
|
|
8065
|
-
*
|
|
8066
|
-
*
|
|
8067
|
-
* change the advertised catalog until a host asks for it.
|
|
8054
|
+
* calling it renders an inline question card and returns the user's answer.
|
|
8055
|
+
* Off by default, like the other built-in tool groups, so the advertised
|
|
8056
|
+
* catalog does not change until a host asks for it.
|
|
8068
8057
|
*/
|
|
8069
8058
|
askUser = false;
|
|
8070
8059
|
/**
|
|
8071
|
-
* Optional full replacement for the `ask_user` question UI
|
|
8072
|
-
*
|
|
8073
|
-
*
|
|
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.
|
|
8060
|
+
* Optional full replacement for the `ask_user` question UI, resolving with
|
|
8061
|
+
* the answer; the same seam as {@link approvalRenderer}, styled via `strings`
|
|
8062
|
+
* and the `question*` `::part()`s when left unset. Requires {@link askUser}.
|
|
8077
8063
|
*/
|
|
8078
8064
|
askUserRenderer = null;
|
|
8079
8065
|
/**
|
|
8080
|
-
* Optional full replacement for the server-side-tool approval UI
|
|
8081
|
-
*
|
|
8082
|
-
* card
|
|
8083
|
-
* `
|
|
8084
|
-
*
|
|
8085
|
-
* `::part()`s. The gate itself is enabled server-side; this only changes how
|
|
8086
|
-
* the decision is collected.
|
|
8066
|
+
* Optional full replacement for the server-side-tool approval UI: an approval
|
|
8067
|
+
* interrupt invokes this instead of the built-in {@link requestApproval}
|
|
8068
|
+
* card, resolving `true` to approve or `false` to deny. Style the built-in
|
|
8069
|
+
* card via `strings` and the `approval*` `::part()`s instead. The gate itself
|
|
8070
|
+
* is enabled server-side; this only changes how the decision is collected.
|
|
8087
8071
|
*/
|
|
8088
8072
|
approvalRenderer = null;
|
|
8089
8073
|
/**
|
|
8090
|
-
* Optional per-call confirmation predicate. When set
|
|
8091
|
-
*
|
|
8092
|
-
*
|
|
8093
|
-
* static `x-destructive` flag
|
|
8094
|
-
*
|
|
8074
|
+
* Optional per-call confirmation predicate. When set it is authoritative,
|
|
8075
|
+
* deciding from the tool name and args whether this particular call needs
|
|
8076
|
+
* confirmation — so one tool can be instant for some args and confirmed for
|
|
8077
|
+
* others, which a static `x-destructive` flag cannot express. When unset the
|
|
8078
|
+
* `x-destructive` flag decides. `autoConfirm` short-circuits both.
|
|
8095
8079
|
*/
|
|
8096
8080
|
confirmPredicate = null;
|
|
8097
8081
|
/**
|
|
@@ -8112,11 +8096,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8112
8096
|
* Per-run context provider. Defaults to the compact page map, when a
|
|
8113
8097
|
* {@link getPageMap} provider is set and {@link autoInjectPageMap} is on.
|
|
8114
8098
|
*
|
|
8115
|
-
*
|
|
8116
|
-
*
|
|
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.
|
|
8099
|
+
* Attachments are deliberately not restated here: the server derives its own
|
|
8100
|
+
* manifest from the refs riding the messages.
|
|
8120
8101
|
*/
|
|
8121
8102
|
getContext = () => [
|
|
8122
8103
|
...createPageMapContext(this.getPageMap, this.autoInjectPageMap)
|
|
@@ -8144,21 +8125,17 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8144
8125
|
conversationStore = new SessionStorageStore();
|
|
8145
8126
|
/**
|
|
8146
8127
|
* How attached files are uploaded. `null` (default) uses the built-in
|
|
8147
|
-
* multipart `POST` to `data-attachments-url
|
|
8148
|
-
*
|
|
8149
|
-
*
|
|
8150
|
-
*
|
|
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.
|
|
8128
|
+
* multipart `POST` to `data-attachments-url`; a custom {@link UploadHandler}
|
|
8129
|
+
* swaps the transport without changing the tray, the chips, or the AG-UI
|
|
8130
|
+
* wire. When set, the 📎 affordance appears even with no
|
|
8131
|
+
* `data-attachments-url`, and the handler owns its own endpoint and headers.
|
|
8153
8132
|
*/
|
|
8154
8133
|
uploadHandler = null;
|
|
8155
8134
|
/**
|
|
8156
8135
|
* How recorded voice clips are transcribed. `null` (default) POSTs the clip
|
|
8157
|
-
* to `data-transcribe-url
|
|
8158
|
-
*
|
|
8159
|
-
*
|
|
8160
|
-
* touching the mic button. When set, the 🎤 affordance appears even with no
|
|
8161
|
-
* `data-transcribe-url`.
|
|
8136
|
+
* to `data-transcribe-url`; a custom {@link TranscribeHandler} swaps the
|
|
8137
|
+
* transport without touching the mic button. When set, the 🎤 affordance
|
|
8138
|
+
* appears even with no `data-transcribe-url`.
|
|
8162
8139
|
*/
|
|
8163
8140
|
transcribeHandler = null;
|
|
8164
8141
|
/**
|
|
@@ -8177,12 +8154,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8177
8154
|
*/
|
|
8178
8155
|
skillContext = () => ({});
|
|
8179
8156
|
/**
|
|
8180
|
-
* Friendly display labels for tool-call cards, keyed by tool name
|
|
8181
|
-
*
|
|
8182
|
-
*
|
|
8183
|
-
*
|
|
8184
|
-
* only the tool-call name). Client tools should prefer `x-summary` on their
|
|
8185
|
-
* schema; this map is the seam for everything else.
|
|
8157
|
+
* Friendly display labels for tool-call cards, keyed by tool name. The
|
|
8158
|
+
* fallback when a tool has no `x-summary` in its own schema, which chiefly
|
|
8159
|
+
* means server-side tools: AG-UI streams only the tool-call name, so their
|
|
8160
|
+
* schema never reaches the browser. Client tools should prefer `x-summary`.
|
|
8186
8161
|
*/
|
|
8187
8162
|
toolSummaries = {};
|
|
8188
8163
|
/**
|
|
@@ -8216,6 +8191,12 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8216
8191
|
* the real output with the generic "executed on the server" fallback.
|
|
8217
8192
|
*/
|
|
8218
8193
|
#serverSettled = /* @__PURE__ */ new Set();
|
|
8194
|
+
/**
|
|
8195
|
+
* Tool calls made during the current interaction, in the order they started,
|
|
8196
|
+
* so {@link RUN_FINISHED_EVENT} can report them once the whole thing settles.
|
|
8197
|
+
* Spans tool rounds and an approval interrupt; cleared when the event fires.
|
|
8198
|
+
*/
|
|
8199
|
+
#runTools = [];
|
|
8219
8200
|
#root;
|
|
8220
8201
|
#chat;
|
|
8221
8202
|
#messages;
|
|
@@ -8354,13 +8335,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8354
8335
|
* Continue `runId` as a **new** run, seeded server-side from its snapshot.
|
|
8355
8336
|
*
|
|
8356
8337
|
* Uses a short-lived agent pointed at the resume / fork endpoint and seeded
|
|
8357
|
-
* with
|
|
8358
|
-
*
|
|
8359
|
-
*
|
|
8360
|
-
*
|
|
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.
|
|
8338
|
+
* with no history, because those endpoints supply the prior turns from the
|
|
8339
|
+
* snapshot and re-sending them would duplicate. A separate agent makes that
|
|
8340
|
+
* structural — the main agent keeps its own history — and mints the fresh
|
|
8341
|
+
* `run_id` the endpoints also require.
|
|
8364
8342
|
*
|
|
8365
8343
|
* Handlers are the element's own, so the continuation streams into the same
|
|
8366
8344
|
* transcript the user is looking at.
|
|
@@ -8441,10 +8419,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8441
8419
|
* when the server streams `STATE_SNAPSHOT` / `STATE_DELTA`. Assigning seeds
|
|
8442
8420
|
* the next run; reading returns whatever the agent last applied.
|
|
8443
8421
|
*
|
|
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*.
|
|
8422
|
+
* Listen for {@link STATE_EVENT} to react to server-driven changes. Distinct
|
|
8423
|
+
* from {@link registerPageState}, which exposes host state as ordinary tools.
|
|
8448
8424
|
*/
|
|
8449
8425
|
get sharedState() {
|
|
8450
8426
|
return this.#client?.state ?? this.#sharedState;
|
|
@@ -8460,11 +8436,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8460
8436
|
}
|
|
8461
8437
|
}
|
|
8462
8438
|
/**
|
|
8463
|
-
* @deprecated Renamed to {@link registerPageState}
|
|
8464
|
-
* AG-UI shared-state sync
|
|
8465
|
-
*
|
|
8466
|
-
* page state. Behaviour is unchanged; this alias will be removed in a future
|
|
8467
|
-
* major.
|
|
8439
|
+
* @deprecated Renamed to {@link registerPageState} — the old name read as
|
|
8440
|
+
* AG-UI shared-state sync. Behaviour is unchanged; the alias will be removed
|
|
8441
|
+
* in a future major.
|
|
8468
8442
|
*/
|
|
8469
8443
|
registerStateHook(binding) {
|
|
8470
8444
|
this.registerPageState(binding);
|
|
@@ -8531,10 +8505,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8531
8505
|
/**
|
|
8532
8506
|
* The built-in `ask_user` frontend tool, or `[]` when {@link askUser} is off.
|
|
8533
8507
|
*
|
|
8534
|
-
*
|
|
8535
|
-
*
|
|
8536
|
-
*
|
|
8537
|
-
* tool result — no new protocol, reusing the machinery already in place.
|
|
8508
|
+
* The agent calls it, the client executes it locally through the normal
|
|
8509
|
+
* frontend-tool path by rendering a {@link requestQuestion} card, and the
|
|
8510
|
+
* answer flows back as the tool result. No new protocol.
|
|
8538
8511
|
*/
|
|
8539
8512
|
#askUserTool() {
|
|
8540
8513
|
if (!this.askUser) {
|
|
@@ -8610,19 +8583,18 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8610
8583
|
* `credentials` mode (`"omit"` / `"same-origin"` / `"include"`). Mirrored to
|
|
8611
8584
|
* the `credentials` attribute, so markup embeds can set it without script.
|
|
8612
8585
|
*
|
|
8613
|
-
* `null` (the default) leaves the browser's
|
|
8614
|
-
*
|
|
8615
|
-
*
|
|
8616
|
-
*
|
|
8617
|
-
*
|
|
8618
|
-
*
|
|
8619
|
-
* `
|
|
8620
|
-
* (non-wildcard) `Access-Control-Allow-Origin` on the server.
|
|
8586
|
+
* `null` (the default) leaves the browser's `same-origin` default in place,
|
|
8587
|
+
* which sends no cookies at all to an endpoint on a different origin — and
|
|
8588
|
+
* the request goes out anonymously rather than failing, so the symptom is a
|
|
8589
|
+
* 401 from a server that looks correctly configured. A cookie-authenticated
|
|
8590
|
+
* cross-origin deployment wants `"include"`, plus
|
|
8591
|
+
* `Access-Control-Allow-Credentials: true` and a concrete, non-wildcard
|
|
8592
|
+
* `Access-Control-Allow-Origin` on the server.
|
|
8621
8593
|
*
|
|
8622
8594
|
* Read per request, so a late assignment applies to everything after it.
|
|
8623
|
-
* `"omit"` cannot be honoured by the built-in
|
|
8624
|
-
*
|
|
8625
|
-
*
|
|
8595
|
+
* `"omit"` cannot be honoured by the built-in upload transport, an
|
|
8596
|
+
* `XMLHttpRequest` with only a two-state cookie switch; every other endpoint
|
|
8597
|
+
* honours all three modes.
|
|
8626
8598
|
*/
|
|
8627
8599
|
get credentials() {
|
|
8628
8600
|
const attr = this.getAttribute("credentials");
|
|
@@ -8723,25 +8695,21 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8723
8695
|
* The catalog requests the element issues on startup: the tool labels
|
|
8724
8696
|
* (`data-tools-url`) and the backend skills (`data-skills-url`).
|
|
8725
8697
|
*
|
|
8726
|
-
* Deliberately one microtask behind `connectedCallback`. A
|
|
8727
|
-
*
|
|
8728
|
-
*
|
|
8729
|
-
*
|
|
8730
|
-
*
|
|
8731
|
-
*
|
|
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.
|
|
8698
|
+
* Deliberately one microtask behind `connectedCallback`. A framework ref is
|
|
8699
|
+
* attached after the node is inserted but within the same commit, so a
|
|
8700
|
+
* request issued from `connectedCallback` itself goes out before `headers`,
|
|
8701
|
+
* {@link getHeaders} or {@link credentials} exist and 401s in a way that
|
|
8702
|
+
* reads as a server fault. A microtask lands after that commit, still before
|
|
8703
|
+
* paint.
|
|
8734
8704
|
*
|
|
8735
|
-
*
|
|
8736
|
-
*
|
|
8737
|
-
*
|
|
8738
|
-
*
|
|
8739
|
-
*
|
|
8740
|
-
*
|
|
8741
|
-
* so deferring it
|
|
8742
|
-
*
|
|
8743
|
-
* request that can still go out before a ref is attached — {@link reload}
|
|
8744
|
-
* covers it.
|
|
8705
|
+
* It is not a fix for configuration arriving later than the commit (a passive
|
|
8706
|
+
* effect, an awaited token fetch): configure before insertion, or call
|
|
8707
|
+
* {@link reload}, since a longer timer would hide that race rather than close
|
|
8708
|
+
* it.
|
|
8709
|
+
*
|
|
8710
|
+
* The history replay stays in `connectedCallback` on purpose. It renders into
|
|
8711
|
+
* the transcript, so deferring it would let a `sendMessage()` in the same
|
|
8712
|
+
* task land first and be duplicated by the replay.
|
|
8745
8713
|
*/
|
|
8746
8714
|
#startup() {
|
|
8747
8715
|
if (!this.#connected) {
|
|
@@ -8755,15 +8723,13 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8755
8723
|
* the backend skill catalog and the thread's history — with the transport
|
|
8756
8724
|
* configuration as it stands now.
|
|
8757
8725
|
*
|
|
8758
|
-
*
|
|
8759
|
-
*
|
|
8760
|
-
* startup requests
|
|
8761
|
-
* "try again, properly authenticated" without removing and re-inserting the
|
|
8762
|
-
* node.
|
|
8726
|
+
* For a host that can only configure the element after the fact (a token
|
|
8727
|
+
* fetched in a passive effect, an async auth handshake), this re-issues the
|
|
8728
|
+
* startup requests authenticated, without removing and re-inserting the node.
|
|
8763
8729
|
*
|
|
8764
|
-
* A reload, not a merge
|
|
8765
|
-
*
|
|
8766
|
-
*
|
|
8730
|
+
* A reload, not a merge: the in-flight run is cancelled and the transcript is
|
|
8731
|
+
* rebuilt from persisted history, so anything streamed since is dropped. Call
|
|
8732
|
+
* it once, when configuration lands, not between turns.
|
|
8767
8733
|
*/
|
|
8768
8734
|
async reload() {
|
|
8769
8735
|
this.#cancelRun();
|
|
@@ -8772,12 +8738,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8772
8738
|
await Promise.all([this.#fetchToolCatalog(), this.#fetchSkills(), this.#rehydrate()]);
|
|
8773
8739
|
}
|
|
8774
8740
|
/**
|
|
8775
|
-
* Tear down live resources when the element leaves the DOM
|
|
8776
|
-
*
|
|
8777
|
-
*
|
|
8778
|
-
*
|
|
8779
|
-
* removed `<ag-ui-chat>` leaks a streaming request, uploads, and a live
|
|
8780
|
-
* `MediaRecorder`.
|
|
8741
|
+
* Tear down live resources when the element leaves the DOM: cancel the
|
|
8742
|
+
* in-flight run so its stream closes, abort in-flight uploads so they do not
|
|
8743
|
+
* orphan server-side files, and release the mic so the browser's recording
|
|
8744
|
+
* indicator clears. Without this a removed element leaks all three.
|
|
8781
8745
|
*/
|
|
8782
8746
|
disconnectedCallback() {
|
|
8783
8747
|
this.#connected = false;
|
|
@@ -8788,14 +8752,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8788
8752
|
/**
|
|
8789
8753
|
* Read an opt-in flag attribute the way HTML reads a boolean attribute.
|
|
8790
8754
|
*
|
|
8791
|
-
* Present means on
|
|
8792
|
-
*
|
|
8793
|
-
*
|
|
8794
|
-
*
|
|
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.
|
|
8755
|
+
* Present means on: bare (`data-prompt-chips`), empty (`=""`), or any value
|
|
8756
|
+
* except the literal `"false"`. Comparing against `"true"` instead would make
|
|
8757
|
+
* the bare spelling every native boolean attribute uses silently disable the
|
|
8758
|
+
* feature it names. `="false"` still turns it off.
|
|
8799
8759
|
*/
|
|
8800
8760
|
#flag(name) {
|
|
8801
8761
|
const value = this.getAttribute(name);
|
|
@@ -9021,21 +8981,16 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9021
8981
|
/**
|
|
9022
8982
|
* Act on a picked skill.
|
|
9023
8983
|
*
|
|
9024
|
-
* A skill
|
|
9025
|
-
*
|
|
9026
|
-
*
|
|
9027
|
-
*
|
|
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.
|
|
8984
|
+
* A skill with no `prompt` is server-resolved: picking it sends the bare
|
|
8985
|
+
* `/name` token for the agent to expand, so the wording never reaches the
|
|
8986
|
+
* browser. Prefer that shape — a skill often states a project's internal
|
|
8987
|
+
* workflow most plainly, and a catalog endpoint is a plain GET.
|
|
9031
8988
|
*
|
|
9032
|
-
* A skill
|
|
9033
|
-
*
|
|
9034
|
-
* Right for a user-facing convenience, and for placeholders only the page can
|
|
9035
|
-
* supply.
|
|
8989
|
+
* A skill carrying a `prompt` has the client fill its `{placeholder}`s from
|
|
8990
|
+
* the page instead, which is right for placeholders only the page can supply.
|
|
9036
8991
|
*
|
|
9037
|
-
* Either way a pick
|
|
9038
|
-
*
|
|
8992
|
+
* Either way a pick sends; `sendImmediately: false` opts into pre-filling the
|
|
8993
|
+
* composer instead.
|
|
9039
8994
|
*/
|
|
9040
8995
|
#applySkill(skill) {
|
|
9041
8996
|
if (skill.prompt === void 0) {
|
|
@@ -9147,18 +9102,13 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9147
9102
|
}
|
|
9148
9103
|
}
|
|
9149
9104
|
/**
|
|
9150
|
-
* Which edges the layout is holding still, by measuring rather than guessing
|
|
9151
|
-
*
|
|
9152
|
-
*
|
|
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.
|
|
9105
|
+
* Which edges the layout is holding still, by measuring rather than guessing:
|
|
9106
|
+
* nudge the size by a pixel, see which edges stayed put, and undo. One forced
|
|
9107
|
+
* reflow per drag.
|
|
9159
9108
|
*
|
|
9160
|
-
*
|
|
9161
|
-
*
|
|
9109
|
+
* `placement` cannot answer this — an embedded panel goes wherever the page's
|
|
9110
|
+
* CSS puts it — and see {@link createResizeHandle} for why guessing produces
|
|
9111
|
+
* a visibly broken control.
|
|
9162
9112
|
*/
|
|
9163
9113
|
#measureAnchor() {
|
|
9164
9114
|
const before = this.getBoundingClientRect();
|
|
@@ -9192,14 +9142,13 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9192
9142
|
/**
|
|
9193
9143
|
* Write a dragged size onto the host, on the axes this placement leaves free.
|
|
9194
9144
|
*
|
|
9195
|
-
*
|
|
9196
|
-
*
|
|
9197
|
-
*
|
|
9198
|
-
*
|
|
9199
|
-
* `100vh`. The cascade cannot arbitrate this
|
|
9200
|
-
*
|
|
9201
|
-
*
|
|
9202
|
-
* persisted size is only ever applied to the ones it does not.
|
|
9145
|
+
* Writing the custom property rather than inline `width` / `height` does not
|
|
9146
|
+
* by itself leave placement in charge: an inline custom property still
|
|
9147
|
+
* outranks a `:host([placement=…])` rule setting the same property, so a
|
|
9148
|
+
* height dragged while floating would cap a docked sidebar asking for
|
|
9149
|
+
* `100vh`. The cascade cannot arbitrate this, so the axis check must — a
|
|
9150
|
+
* placement owns the axes it fixes, and a persisted size is applied only to
|
|
9151
|
+
* the ones it leaves free.
|
|
9203
9152
|
*/
|
|
9204
9153
|
#applySize(size) {
|
|
9205
9154
|
const axis = this.#resizeAxis();
|
|
@@ -9272,12 +9221,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9272
9221
|
* Open the thread-history drawer: the imperative route to the control that
|
|
9273
9222
|
* renders as `::part(history-button)`.
|
|
9274
9223
|
*
|
|
9275
|
-
* A host that hides `::part(header)`
|
|
9276
|
-
*
|
|
9277
|
-
*
|
|
9278
|
-
*
|
|
9279
|
-
* {@link openCheckpoints}, {@link newChat}, {@link toggleCollapsed} and
|
|
9280
|
-
* {@link toggleTheme}.
|
|
9224
|
+
* A host that hides `::part(header)` for its own title bar hides the history,
|
|
9225
|
+
* new-chat and collapse buttons with it. Each has a method so that chrome can
|
|
9226
|
+
* be rebuilt: this one, {@link openCheckpoints}, {@link newChat},
|
|
9227
|
+
* {@link toggleCollapsed} and {@link toggleTheme}.
|
|
9281
9228
|
*/
|
|
9282
9229
|
openThreads() {
|
|
9283
9230
|
void this.#refreshDrawer();
|
|
@@ -9378,23 +9325,17 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9378
9325
|
/**
|
|
9379
9326
|
* Notice a previous run that never produced a response.
|
|
9380
9327
|
*
|
|
9381
|
-
* {@link AgUiClient.send} persists the user's message
|
|
9382
|
-
* run, so a transcript
|
|
9383
|
-
*
|
|
9384
|
-
*
|
|
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).
|
|
9328
|
+
* {@link AgUiClient.send} persists the user's message before starting the
|
|
9329
|
+
* run, so a transcript ending on that user message means nothing came back.
|
|
9330
|
+
* The transcript's shape alone detects it, needing no store method and no
|
|
9331
|
+
* `pagehide` listener — neither of which fires on a crash or force-quit.
|
|
9388
9332
|
*
|
|
9389
|
-
*
|
|
9390
|
-
* checkpoint and resumes,
|
|
9391
|
-
* reaching here.
|
|
9333
|
+
* An agent-initiated reload is not this case: a navigating tool leaves a
|
|
9334
|
+
* checkpoint and resumes, so the caller returns early on one.
|
|
9392
9335
|
*
|
|
9393
|
-
* Deliberately a notice
|
|
9394
|
-
*
|
|
9395
|
-
*
|
|
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.
|
|
9336
|
+
* Deliberately a notice, never a resume. AG-UI has no resume-an-aborted-run
|
|
9337
|
+
* primitive, and re-sending the accumulated messages is semantically a new
|
|
9338
|
+
* run, so any server-side tool already executed would run a second time.
|
|
9398
9339
|
*/
|
|
9399
9340
|
/**
|
|
9400
9341
|
* Build a round's context, recording which page it describes.
|
|
@@ -9447,19 +9388,16 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9447
9388
|
if (text2 !== "") {
|
|
9448
9389
|
this.appendMessage(MESSAGE_ROLE.ASSISTANT, text2).classList.add("message--restored");
|
|
9449
9390
|
}
|
|
9450
|
-
const
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
if (this.#noticeIfSkillLoad(restored)) {
|
|
9459
|
-
continue;
|
|
9460
|
-
}
|
|
9461
|
-
this.#cardFor(restored);
|
|
9391
|
+
for (const call of restoredToolCalls(message.toolCalls)) {
|
|
9392
|
+
const restored = {
|
|
9393
|
+
id: call.id,
|
|
9394
|
+
name: call.function.name,
|
|
9395
|
+
args: this.#parseArgs(call.function.arguments)
|
|
9396
|
+
};
|
|
9397
|
+
if (this.#noticeIfSkillLoad(restored)) {
|
|
9398
|
+
continue;
|
|
9462
9399
|
}
|
|
9400
|
+
this.#cardFor(restored);
|
|
9463
9401
|
}
|
|
9464
9402
|
return;
|
|
9465
9403
|
}
|
|
@@ -9470,8 +9408,11 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9470
9408
|
}
|
|
9471
9409
|
}
|
|
9472
9410
|
}
|
|
9473
|
-
/** Parse a tool call's JSON `arguments`
|
|
9411
|
+
/** Parse a tool call's JSON `arguments` from history into an object. */
|
|
9474
9412
|
#parseArgs(raw) {
|
|
9413
|
+
if (typeof raw !== "string") {
|
|
9414
|
+
return {};
|
|
9415
|
+
}
|
|
9475
9416
|
try {
|
|
9476
9417
|
const parsed = JSON.parse(raw);
|
|
9477
9418
|
if (typeof parsed === "object" && parsed !== null) {
|
|
@@ -9500,13 +9441,12 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9500
9441
|
/**
|
|
9501
9442
|
* Append a message bubble and return it.
|
|
9502
9443
|
*
|
|
9503
|
-
* Assistant content
|
|
9504
|
-
*
|
|
9505
|
-
* rendering user-authored markup).
|
|
9444
|
+
* Assistant content renders as sanitised markdown/HTML; user content stays
|
|
9445
|
+
* literal text, which also avoids rendering user-authored markup.
|
|
9506
9446
|
*
|
|
9507
|
-
* Assistant bubbles land in the current answer group, opening one if
|
|
9508
|
-
*
|
|
9509
|
-
*
|
|
9447
|
+
* Assistant bubbles land in the current answer group, opening one if needed;
|
|
9448
|
+
* a user bubble closes the prior group and sits directly in the list, the
|
|
9449
|
+
* well wrapping only the assistant turn.
|
|
9510
9450
|
*/
|
|
9511
9451
|
appendMessage(role, content) {
|
|
9512
9452
|
const bubble = document.createElement("div");
|
|
@@ -9699,12 +9639,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9699
9639
|
* Build a header control button: a named slot a host can project markup into,
|
|
9700
9640
|
* with the built-in glyph as the slot's fallback.
|
|
9701
9641
|
*
|
|
9702
|
-
* The
|
|
9703
|
-
*
|
|
9704
|
-
*
|
|
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.
|
|
9642
|
+
* The slot is what lets a host replace the mark with its own `<img>` or
|
|
9643
|
+
* `<svg>` rather than only restyle it through the `part`; the same
|
|
9644
|
+
* slot-with-fallback idiom the header icon uses.
|
|
9708
9645
|
*/
|
|
9709
9646
|
#headerButton(modifier, label, glyph) {
|
|
9710
9647
|
const button2 = document.createElement("button");
|
|
@@ -9905,19 +9842,16 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9905
9842
|
* Send a message as if the user had typed it — renders the user bubble,
|
|
9906
9843
|
* dispatches {@link SUBMIT_EVENT}, and starts the run.
|
|
9907
9844
|
*
|
|
9908
|
-
* The programmatic half of the composer, for a host driving its own input
|
|
9909
|
-
*
|
|
9910
|
-
*
|
|
9911
|
-
* here; Send itself now reads the composer, clears it, and calls this.
|
|
9845
|
+
* The programmatic half of the composer, for a host driving its own input.
|
|
9846
|
+
* Everything the built-in Send does happens here; Send reads the composer,
|
|
9847
|
+
* clears it, and calls this.
|
|
9912
9848
|
*
|
|
9913
|
-
* `attachments` are durable {@link AttachmentRef}s —
|
|
9914
|
-
*
|
|
9915
|
-
* {@link ATTACHMENT_EVENT} reports. Pass them to attach files to the message.
|
|
9849
|
+
* `attachments` are durable {@link AttachmentRef}s — what {@link attachFile}
|
|
9850
|
+
* resolves to and what {@link ATTACHMENT_EVENT} reports.
|
|
9916
9851
|
*
|
|
9917
|
-
* No-ops while a run is in flight
|
|
9918
|
-
*
|
|
9919
|
-
*
|
|
9920
|
-
* composer stays in charge of its own state.
|
|
9852
|
+
* No-ops on an empty message, and while a run is in flight, since a second
|
|
9853
|
+
* concurrent run would orphan the first. Unlike the built-in Send it does not
|
|
9854
|
+
* consult the tray: what you pass is what is sent.
|
|
9921
9855
|
*/
|
|
9922
9856
|
async sendMessage(content, attachments = []) {
|
|
9923
9857
|
if (this.#running || content === "" && attachments.length === 0) {
|
|
@@ -9941,11 +9875,11 @@ var AgUiChat = class extends HTMLElement {
|
|
|
9941
9875
|
* picker and drag-and-drop do — validation, progress chip, and all.
|
|
9942
9876
|
*
|
|
9943
9877
|
* Returns `false` when uploads are not configured (no `data-attachments-url`
|
|
9944
|
-
* and no {@link uploadHandler})
|
|
9945
|
-
*
|
|
9878
|
+
* and no {@link uploadHandler}) — the only signal a host gets, since the tray
|
|
9879
|
+
* does not exist to report anything then.
|
|
9946
9880
|
*
|
|
9947
9881
|
* Uploading is asynchronous: watch {@link ATTACHMENT_EVENT} for the resulting
|
|
9948
|
-
* {@link AttachmentRef}
|
|
9882
|
+
* {@link AttachmentRef} and pass it to {@link sendMessage} once `pending`
|
|
9949
9883
|
* reaches zero.
|
|
9950
9884
|
*/
|
|
9951
9885
|
attachFile(file) {
|
|
@@ -10090,12 +10024,11 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10090
10024
|
* Render an approval card per server-side-tool interrupt and collect the
|
|
10091
10025
|
* user's decisions (approve → run it, deny → decline it).
|
|
10092
10026
|
*
|
|
10093
|
-
* The run is suspended on these cards
|
|
10027
|
+
* The run is suspended on these cards. A Stop while any is open aborts the
|
|
10094
10028
|
* shared {@link #confirmAbort} controller, resolving every still-open card as
|
|
10095
|
-
* denied
|
|
10096
|
-
*
|
|
10097
|
-
*
|
|
10098
|
-
* result will ever arrive for it.
|
|
10029
|
+
* denied. An approved tool runs on the follow-up resume run and streams its
|
|
10030
|
+
* result into the same pending card; a denied one settles here, since no
|
|
10031
|
+
* result will ever arrive.
|
|
10099
10032
|
*/
|
|
10100
10033
|
async #resolveInterrupts(interrupts) {
|
|
10101
10034
|
const responses = {};
|
|
@@ -10103,8 +10036,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10103
10036
|
this.#hidePending();
|
|
10104
10037
|
for (const interrupt of interrupts) {
|
|
10105
10038
|
const request = {};
|
|
10106
|
-
|
|
10107
|
-
|
|
10039
|
+
const phrase = confirmPhrase(interrupt) ?? interrupt.message;
|
|
10040
|
+
if (phrase !== void 0) {
|
|
10041
|
+
request.message = phrase;
|
|
10108
10042
|
}
|
|
10109
10043
|
const card = interrupt.toolCallId !== void 0 ? this.#toolCards.get(interrupt.toolCallId) : void 0;
|
|
10110
10044
|
const toolName = card?.element.getAttribute("data-tool-name");
|
|
@@ -10162,6 +10096,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10162
10096
|
if (this.#noticeIfSkillLoad(call)) {
|
|
10163
10097
|
return;
|
|
10164
10098
|
}
|
|
10099
|
+
this.#runTools.push({ id: call.id, name: call.name });
|
|
10165
10100
|
this.#cardFor(call);
|
|
10166
10101
|
},
|
|
10167
10102
|
onActivity: (activityType, content) => {
|
|
@@ -10215,9 +10150,33 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10215
10150
|
}
|
|
10216
10151
|
this.#currentGroup = null;
|
|
10217
10152
|
this.#thoughts = null;
|
|
10153
|
+
this.#dispatchRunFinished();
|
|
10218
10154
|
}
|
|
10219
10155
|
};
|
|
10220
10156
|
}
|
|
10157
|
+
/**
|
|
10158
|
+
* Tell the host the interaction is over and what ran in it.
|
|
10159
|
+
*
|
|
10160
|
+
* Last thing in `onSettled`, so a listener that refetches sees a transcript
|
|
10161
|
+
* that has already stopped changing. `side` is read from the streamed-result
|
|
10162
|
+
* bookkeeping rather than from the tool list: whether a call executed on the
|
|
10163
|
+
* server is a fact about the run, and a name can appear on both sides across a
|
|
10164
|
+
* conversation.
|
|
10165
|
+
*/
|
|
10166
|
+
#dispatchRunFinished() {
|
|
10167
|
+
const tools = this.#runTools.map(({ id, name }) => ({
|
|
10168
|
+
name,
|
|
10169
|
+
side: this.#serverSettled.has(id) ? "server" : "client"
|
|
10170
|
+
}));
|
|
10171
|
+
this.#runTools = [];
|
|
10172
|
+
this.dispatchEvent(
|
|
10173
|
+
new CustomEvent(RUN_FINISHED_EVENT, {
|
|
10174
|
+
detail: { tools },
|
|
10175
|
+
bubbles: true,
|
|
10176
|
+
composed: true
|
|
10177
|
+
})
|
|
10178
|
+
);
|
|
10179
|
+
}
|
|
10221
10180
|
/** A muted "⏹ Stopped" line in the transcript (distinct from the ⚠️ error bubble). */
|
|
10222
10181
|
#appendStoppedNote() {
|
|
10223
10182
|
const note = document.createElement("div");
|
|
@@ -10329,6 +10288,20 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10329
10288
|
return card;
|
|
10330
10289
|
}
|
|
10331
10290
|
};
|
|
10291
|
+
function confirmPhrase(interrupt) {
|
|
10292
|
+
const phrase = interrupt.metadata?.[X_CONFIRM_KEY];
|
|
10293
|
+
return typeof phrase === "string" && phrase.trim() !== "" ? phrase : void 0;
|
|
10294
|
+
}
|
|
10295
|
+
function restoredToolCalls(value) {
|
|
10296
|
+
return Array.isArray(value) ? value.filter(isRestoredToolCall) : [];
|
|
10297
|
+
}
|
|
10298
|
+
function isRestoredToolCall(value) {
|
|
10299
|
+
if (typeof value !== "object" || value === null) {
|
|
10300
|
+
return false;
|
|
10301
|
+
}
|
|
10302
|
+
const call = value;
|
|
10303
|
+
return typeof call.id === "string" && typeof call.function?.name === "string";
|
|
10304
|
+
}
|
|
10332
10305
|
function skillNameFrom(call) {
|
|
10333
10306
|
if (call.name !== LOAD_CAPABILITY_TOOL) {
|
|
10334
10307
|
return null;
|
|
@@ -10381,7 +10354,7 @@ function setControlValue(el, value) {
|
|
|
10381
10354
|
}
|
|
10382
10355
|
|
|
10383
10356
|
// src/version.ts
|
|
10384
|
-
var VERSION = "0.
|
|
10357
|
+
var VERSION = "0.24.0";
|
|
10385
10358
|
export {
|
|
10386
10359
|
ATTACHMENT_EVENT,
|
|
10387
10360
|
AgUiChat,
|
|
@@ -10396,6 +10369,7 @@ export {
|
|
|
10396
10369
|
MAX_TOOL_ROUNDS,
|
|
10397
10370
|
MESSAGE_ROLE,
|
|
10398
10371
|
PAGE_ACTIONS,
|
|
10372
|
+
RUN_FINISHED_EVENT,
|
|
10399
10373
|
RemoteConversationStore,
|
|
10400
10374
|
RunIndex,
|
|
10401
10375
|
STATE_EVENT,
|