@artooi/ag-ui-web-component 0.22.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -36
- package/README.md +7 -7
- package/dist/ag-ui-web-component.bundle.js +145 -118
- package/dist/ag-ui-web-component.bundle.js.map +3 -3
- package/dist/constants.d.ts +65 -78
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts +93 -126
- 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 +20 -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 +8 -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.js +347 -401
- 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 +13 -5
- package/dist/ui/attachment_chips.d.ts.map +1 -1
- package/dist/ui/attachment_tray.d.ts +6 -6
- package/dist/ui/attachment_tray.d.ts.map +1 -1
- 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 +71 -80
- package/src/core/ag_ui_chat.ts +242 -292
- package/src/core/agui_client.ts +60 -71
- package/src/core/attachment.ts +9 -14
- package/src/core/conversation_store.ts +25 -33
- package/src/core/create_http_agent.ts +18 -22
- package/src/core/remote_conversation_store.ts +14 -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/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 +19 -10
- package/src/ui/attachment_tray.ts +8 -7
- 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 +122 -93
- 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
|
@@ -40,6 +40,10 @@ var ICON_STOP = `<svg class="glyph glyph--solid" viewBox="0 0 24 24" aria-hidden
|
|
|
40
40
|
var ICON_ATTACH = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M17 8.5V15a5 5 0 0 1-10 0V7a3 3 0 0 1 6 0v7.5a1 1 0 0 1-2 0V8.5"/></svg>`;
|
|
41
41
|
var ICON_VOICE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4a3 3 0 0 1 3 3v5a3 3 0 0 1-6 0V7a3 3 0 0 1 3-3z"/><path d="M5 11v1a7 7 0 0 0 14 0v-1"/><path d="M12 19v3"/></svg>`;
|
|
42
42
|
var ICON_LAUNCHER = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H9l-5 4z"/></svg>`;
|
|
43
|
+
var ICON_FILE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/></svg>`;
|
|
44
|
+
var ICON_FILE_IMAGE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="4.5" width="17" height="15" rx="2.5"/><circle cx="9" cy="10" r="1.5"/><path d="M4.5 17.5 9 13.5l3.5 3 3-2.5 4.5 4"/></svg>`;
|
|
45
|
+
var ICON_FILE_PDF = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><rect class="glyph--solid" x="7.5" y="13.5" width="9" height="4.5" rx="1"/></svg>`;
|
|
46
|
+
var ICON_FILE_TEXT = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M8.5 13.5h7M8.5 17h4.5"/></svg>`;
|
|
43
47
|
|
|
44
48
|
// src/skills/fill_template.ts
|
|
45
49
|
var PLACEHOLDER_RE = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
@@ -79,8 +83,8 @@ var ClientToolRegistry = class {
|
|
|
79
83
|
/**
|
|
80
84
|
* Register a tool, replacing any existing one with the same name.
|
|
81
85
|
*
|
|
82
|
-
* Idempotent on the name so re-fired host
|
|
83
|
-
* double-invoke
|
|
86
|
+
* Idempotent on the name so a re-fired host ref or React StrictMode's
|
|
87
|
+
* double-invoke replaces rather than throws.
|
|
84
88
|
*/
|
|
85
89
|
register(tool) {
|
|
86
90
|
this.#tools.set(tool.name, tool);
|
|
@@ -723,7 +727,7 @@ function renderChip(ref) {
|
|
|
723
727
|
const icon = document.createElement("span");
|
|
724
728
|
icon.className = "attachment-chip-icon";
|
|
725
729
|
icon.setAttribute("part", "attachment-chip-icon");
|
|
726
|
-
icon.
|
|
730
|
+
icon.innerHTML = iconFor(ref.mime);
|
|
727
731
|
icon.setAttribute("aria-hidden", "true");
|
|
728
732
|
const name = document.createElement("span");
|
|
729
733
|
name.className = "attachment-chip-name";
|
|
@@ -739,15 +743,15 @@ function renderChip(ref) {
|
|
|
739
743
|
}
|
|
740
744
|
function iconFor(mime) {
|
|
741
745
|
if (mime.startsWith("image/")) {
|
|
742
|
-
return
|
|
746
|
+
return ICON_FILE_IMAGE;
|
|
743
747
|
}
|
|
744
748
|
if (mime === "application/pdf") {
|
|
745
|
-
return
|
|
749
|
+
return ICON_FILE_PDF;
|
|
746
750
|
}
|
|
747
751
|
if (mime.startsWith("text/")) {
|
|
748
|
-
return
|
|
752
|
+
return ICON_FILE_TEXT;
|
|
749
753
|
}
|
|
750
|
-
return
|
|
754
|
+
return ICON_FILE;
|
|
751
755
|
}
|
|
752
756
|
function formatBytes(bytes) {
|
|
753
757
|
if (bytes < 1024) {
|
|
@@ -913,7 +917,7 @@ var AttachmentTray = class {
|
|
|
913
917
|
const icon = document.createElement("span");
|
|
914
918
|
icon.className = "attachment-chip-icon";
|
|
915
919
|
icon.setAttribute("part", "attachment-chip-icon");
|
|
916
|
-
icon.
|
|
920
|
+
icon.innerHTML = iconFor(item.file.type);
|
|
917
921
|
icon.setAttribute("aria-hidden", "true");
|
|
918
922
|
const name = document.createElement("span");
|
|
919
923
|
name.className = "attachment-chip-name";
|
|
@@ -4473,12 +4477,11 @@ var STYLES = `
|
|
|
4473
4477
|
only the alias is used by the rules below.
|
|
4474
4478
|
|
|
4475
4479
|
The indirection is what makes ancestor theming work. Declaring the public
|
|
4476
|
-
name on :host would set it
|
|
4477
|
-
always beats one inherited from an ancestor
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
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.
|
|
4482
4485
|
|
|
4483
4486
|
Two invariants hold this together:
|
|
4484
4487
|
1. No rule outside this file's :host blocks may reference a public name
|
|
@@ -4505,11 +4508,9 @@ var STYLES = `
|
|
|
4505
4508
|
--_border: var(--ag-ui-border, #e2e2ec);
|
|
4506
4509
|
--_radius: var(--ag-ui-radius, 12px);
|
|
4507
4510
|
|
|
4508
|
-
/* Body text and raised chrome
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
transparent box. The defaults below restate exactly that, so this is a
|
|
4512
|
-
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. */
|
|
4513
4514
|
--_text: var(--ag-ui-text, var(--_fg));
|
|
4514
4515
|
--_surface: var(--ag-ui-surface, transparent);
|
|
4515
4516
|
|
|
@@ -4562,9 +4563,9 @@ var STYLES = `
|
|
|
4562
4563
|
--_launcher-inset: var(--ag-ui-launcher-inset, auto 0 0 auto);
|
|
4563
4564
|
|
|
4564
4565
|
/* Motion. One duration and two curves drive every collapse, expand and
|
|
4565
|
-
slide-over, so the
|
|
4566
|
-
|
|
4567
|
-
|
|
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. */
|
|
4568
4569
|
--_motion: var(--ag-ui-motion, 0.28s);
|
|
4569
4570
|
--_ease: var(--ag-ui-ease, cubic-bezier(0.32, 0.72, 0, 1));
|
|
4570
4571
|
--_ease-pop: var(--ag-ui-ease-pop, cubic-bezier(0.34, 1.36, 0.64, 1));
|
|
@@ -4588,7 +4589,7 @@ var STYLES = `
|
|
|
4588
4589
|
/* Reading-column width for placement="page" (full-bleed, centred content). */
|
|
4589
4590
|
--_content-max-width: var(--ag-ui-content-max-width, 820px);
|
|
4590
4591
|
/* Slim rail the sidebar placement collapses to. Only that placement reads
|
|
4591
|
-
it, but it is declared here so
|
|
4592
|
+
it, but it is declared here so every alias has a default in one place. */
|
|
4592
4593
|
--_rail-width: var(--ag-ui-rail-width, 52px);
|
|
4593
4594
|
|
|
4594
4595
|
position: var(--_position);
|
|
@@ -4680,11 +4681,11 @@ var STYLES = `
|
|
|
4680
4681
|
--_radius: var(--ag-ui-radius, 0);
|
|
4681
4682
|
}
|
|
4682
4683
|
|
|
4683
|
-
/* Page: full-bleed background with a centred reading column
|
|
4684
|
-
"full"
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
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. */
|
|
4688
4689
|
:host([placement="page"]) {
|
|
4689
4690
|
--_inset: var(--ag-ui-inset, 0);
|
|
4690
4691
|
--_width: var(--ag-ui-width, 100vw);
|
|
@@ -4702,9 +4703,8 @@ var STYLES = `
|
|
|
4702
4703
|
padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));
|
|
4703
4704
|
}
|
|
4704
4705
|
|
|
4705
|
-
/* The rows between the message list and the composer
|
|
4706
|
-
|
|
4707
|
-
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
|
|
4708
4708
|
margin-based, so each gets its own inline axis nudged by the same gutter. */
|
|
4709
4709
|
:host([placement="page"]) .skill-chips,
|
|
4710
4710
|
:host([placement="page"]) .attachment-tray {
|
|
@@ -4813,13 +4813,12 @@ var STYLES = `
|
|
|
4813
4813
|
visibility var(--_motion) var(--_ease);
|
|
4814
4814
|
}
|
|
4815
4815
|
|
|
4816
|
-
/* The launcher grows out of the corner the panel shrank into.
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
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. */
|
|
4823
4822
|
:host([collapsed]) .launcher {
|
|
4824
4823
|
opacity: 1;
|
|
4825
4824
|
transform: none;
|
|
@@ -4980,20 +4979,18 @@ var STYLES = `
|
|
|
4980
4979
|
|
|
4981
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
|
|
4982
4981
|
Collapsing shrinks the widget to the round floating launcher: the panel
|
|
4983
|
-
scales
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
The host box keeps its expanded size
|
|
4988
|
-
a dragged --ag-ui-width would
|
|
4989
|
-
paints there once the panel is gone, so the box only has to stop
|
|
4990
|
-
clicks: pointer events go to none
|
|
4991
|
-
|
|
4992
|
-
Two placements collapse
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
floating circle would escape the layout, and page is a full-screen route
|
|
4996
|
-
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. */
|
|
4997
4994
|
:host([collapsed]) {
|
|
4998
4995
|
pointer-events: none;
|
|
4999
4996
|
}
|
|
@@ -5004,11 +5001,11 @@ var STYLES = `
|
|
|
5004
5001
|
visibility: hidden;
|
|
5005
5002
|
}
|
|
5006
5003
|
|
|
5007
|
-
/* visibility
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
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. */
|
|
5012
5009
|
.chat {
|
|
5013
5010
|
transform-origin: bottom right;
|
|
5014
5011
|
transition:
|
|
@@ -5035,10 +5032,9 @@ var STYLES = `
|
|
|
5035
5032
|
visibility: visible;
|
|
5036
5033
|
}
|
|
5037
5034
|
|
|
5038
|
-
/* These two keep the header bar, so the launcher must stay out of the way
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
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. */
|
|
5042
5038
|
:host([collapsed]:is([placement="embedded"], [placement="page"])) .launcher {
|
|
5043
5039
|
visibility: hidden;
|
|
5044
5040
|
opacity: 0;
|
|
@@ -5078,7 +5074,7 @@ var STYLES = `
|
|
|
5078
5074
|
and the pending indicator so a whole answer reads (and can be boxed) as one
|
|
5079
5075
|
unit. A flex column on the message-list gap, stretched to the list width so
|
|
5080
5076
|
its children keep their own left/right alignment. data-answer-well opts into
|
|
5081
|
-
the bordered "well"; without it the
|
|
5077
|
+
the bordered "well"; without it the turn renders as a flat stack. */
|
|
5082
5078
|
.answer {
|
|
5083
5079
|
display: flex;
|
|
5084
5080
|
flex-direction: column;
|
|
@@ -5204,13 +5200,9 @@ var STYLES = `
|
|
|
5204
5200
|
position: relative;
|
|
5205
5201
|
}
|
|
5206
5202
|
|
|
5207
|
-
/*
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
back to the initial transparent, and the hover/copied colour to the
|
|
5211
|
-
inherited body colour. The defaults chosen upstream (transparent, and the
|
|
5212
|
-
body foreground) reproduce that, so the rename repaints nothing. A raised
|
|
5213
|
-
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. */
|
|
5214
5206
|
.code-copy {
|
|
5215
5207
|
position: absolute;
|
|
5216
5208
|
top: 4px;
|
|
@@ -5256,12 +5248,10 @@ var STYLES = `
|
|
|
5256
5248
|
color: var(--_muted);
|
|
5257
5249
|
}
|
|
5258
5250
|
|
|
5259
|
-
/* Markdown tables. table/thead/tbody/tr/th/td are all in
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
width-constrained, so without this the columns either crush or push the
|
|
5264
|
-
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. */
|
|
5265
5255
|
.message--assistant table {
|
|
5266
5256
|
display: block;
|
|
5267
5257
|
width: fit-content;
|
|
@@ -5518,8 +5508,6 @@ var STYLES = `
|
|
|
5518
5508
|
color: var(--_muted);
|
|
5519
5509
|
}
|
|
5520
5510
|
|
|
5521
|
-
/* The record of a human decision on a gated call. An approved call used to
|
|
5522
|
-
look exactly like one that was never gated. */
|
|
5523
5511
|
.skill-item-token {
|
|
5524
5512
|
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
5525
5513
|
font-size: 0.92em;
|
|
@@ -5527,6 +5515,8 @@ var STYLES = `
|
|
|
5527
5515
|
margin-right: 6px;
|
|
5528
5516
|
}
|
|
5529
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. */
|
|
5530
5520
|
.tool-call-decision {
|
|
5531
5521
|
flex: none;
|
|
5532
5522
|
font-size: 11px;
|
|
@@ -5549,10 +5539,8 @@ var STYLES = `
|
|
|
5549
5539
|
}
|
|
5550
5540
|
|
|
5551
5541
|
/* Display modes are pure visibility over one DOM shape, selected from the host
|
|
5552
|
-
attribute rather than a value stamped on the card
|
|
5553
|
-
|
|
5554
|
-
re-read it, the way data-answer-well behaves. Baking the structure per mode
|
|
5555
|
-
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.
|
|
5556
5544
|
|
|
5557
5545
|
Default (no attribute) is the full mode: arguments always visible, result
|
|
5558
5546
|
behind the toggle. */
|
|
@@ -5649,20 +5637,19 @@ var STYLES = `
|
|
|
5649
5637
|
}
|
|
5650
5638
|
|
|
5651
5639
|
/* Then the measurement corrects it. Which edges are held still belongs to the
|
|
5652
|
-
host's layout
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
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. */
|
|
5666
5653
|
:host([data-resize-anchor$="-left"]) .resize-handle {
|
|
5667
5654
|
left: auto;
|
|
5668
5655
|
right: 0;
|
|
@@ -5723,10 +5710,9 @@ var STYLES = `
|
|
|
5723
5710
|
}
|
|
5724
5711
|
|
|
5725
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
|
|
5726
|
-
One surface owns the border, the background and the focus ring; the field
|
|
5727
|
-
its tool row sit inside it
|
|
5728
|
-
textarea's height
|
|
5729
|
-
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. */
|
|
5730
5716
|
.input-row {
|
|
5731
5717
|
display: flex;
|
|
5732
5718
|
padding: 12px;
|
|
@@ -5919,11 +5905,25 @@ var STYLES = `
|
|
|
5919
5905
|
display: contents;
|
|
5920
5906
|
}
|
|
5921
5907
|
|
|
5908
|
+
/* The padding is the only separation the tray gets: its slot is display:
|
|
5909
|
+
contents, so the tray is a direct child of the .chat column, and that column
|
|
5910
|
+
sets no gap. The bottom value keeps a chip off the composer's top edge.
|
|
5911
|
+
The inline value here is only the default: the page placement overrides
|
|
5912
|
+
padding-inline further down to compute its reading-column gutter, and wins
|
|
5913
|
+
on specificity whichever way this declaration is written. Read the two
|
|
5914
|
+
together before changing either. */
|
|
5922
5915
|
.attachment-tray {
|
|
5923
5916
|
display: flex;
|
|
5924
5917
|
flex-wrap: wrap;
|
|
5925
5918
|
gap: 6px;
|
|
5926
|
-
padding: 8px 12px
|
|
5919
|
+
padding: 8px 12px;
|
|
5920
|
+
}
|
|
5921
|
+
|
|
5922
|
+
/* The tray sets the hidden property while empty, and an author display beats
|
|
5923
|
+
the UA stylesheet's rule for it, so without this the empty tray keeps
|
|
5924
|
+
laying out and its padding is permanent dead space above the composer. */
|
|
5925
|
+
.attachment-tray[hidden] {
|
|
5926
|
+
display: none;
|
|
5927
5927
|
}
|
|
5928
5928
|
|
|
5929
5929
|
.attachment-chips {
|
|
@@ -5959,15 +5959,28 @@ var STYLES = `
|
|
|
5959
5959
|
overflow-wrap: anywhere;
|
|
5960
5960
|
}
|
|
5961
5961
|
|
|
5962
|
+
/* A chip carries its own text colour because it carries its own background.
|
|
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. */
|
|
5962
5969
|
.attachment-chip {
|
|
5963
5970
|
display: inline-flex;
|
|
5964
5971
|
align-items: center;
|
|
5965
5972
|
gap: 6px;
|
|
5973
|
+
/* Without this the 100% below caps the content box, so the chip still
|
|
5974
|
+
overflows its container by its own padding and border. Invisible while a
|
|
5975
|
+
character cap kept names short; routine once the container is what bounds
|
|
5976
|
+
the name. */
|
|
5977
|
+
box-sizing: border-box;
|
|
5966
5978
|
max-width: 100%;
|
|
5967
5979
|
padding: 4px 8px;
|
|
5968
5980
|
border: 1px solid var(--_border);
|
|
5969
5981
|
border-radius: 999px;
|
|
5970
5982
|
background: var(--_assistant-bg);
|
|
5983
|
+
color: var(--_text);
|
|
5971
5984
|
font-size: 0.85em;
|
|
5972
5985
|
position: relative;
|
|
5973
5986
|
}
|
|
@@ -5977,11 +5990,31 @@ var STYLES = `
|
|
|
5977
5990
|
color: var(--_danger);
|
|
5978
5991
|
}
|
|
5979
5992
|
|
|
5993
|
+
/* The type mark. Painted from currentColor, so it carries the chip's state
|
|
5994
|
+
with it and turns red along with an errored one; muted by opacity rather
|
|
5995
|
+
than a colour, which is what keeps that true. Sized from the chip's own text
|
|
5996
|
+
rather than --ag-ui-glyph-size, the way an icon holder's glyph takes the
|
|
5997
|
+
holder's size: the composer's 18px buttons would make a chip button-height. */
|
|
5998
|
+
.attachment-chip-icon {
|
|
5999
|
+
display: inline-flex;
|
|
6000
|
+
flex: none;
|
|
6001
|
+
opacity: 0.75;
|
|
6002
|
+
}
|
|
6003
|
+
|
|
6004
|
+
.attachment-chip-icon .glyph {
|
|
6005
|
+
width: 1.25em;
|
|
6006
|
+
height: 1.25em;
|
|
6007
|
+
}
|
|
6008
|
+
|
|
6009
|
+
/* No character cap: the chip is already max-width 100%, so its container is
|
|
6010
|
+
what bounds the name, and a fixed cap only truncated names the chip had room
|
|
6011
|
+
for. min-width: 0 is what lets the flex item shrink past its content, so the
|
|
6012
|
+
ellipsis appears at the container edge instead of the chip overflowing. */
|
|
5980
6013
|
.attachment-chip-name {
|
|
5981
6014
|
overflow: hidden;
|
|
5982
6015
|
text-overflow: ellipsis;
|
|
5983
6016
|
white-space: nowrap;
|
|
5984
|
-
|
|
6017
|
+
min-width: 0;
|
|
5985
6018
|
}
|
|
5986
6019
|
|
|
5987
6020
|
.attachment-chip-size {
|
|
@@ -6626,9 +6659,9 @@ var ThoughtsBlock = class {
|
|
|
6626
6659
|
this.#body.textContent = buffer;
|
|
6627
6660
|
}
|
|
6628
6661
|
/**
|
|
6629
|
-
* Fold the region away
|
|
6630
|
-
*
|
|
6631
|
-
*
|
|
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.
|
|
6632
6665
|
*/
|
|
6633
6666
|
collapse() {
|
|
6634
6667
|
if (this.#collapsed) {
|
|
@@ -6986,11 +7019,8 @@ var ToolCallCard = class {
|
|
|
6986
7019
|
}
|
|
6987
7020
|
/**
|
|
6988
7021
|
* Record that a human approved or declined this call, as a line in the card.
|
|
6989
|
-
*
|
|
6990
|
-
*
|
|
6991
|
-
* result saying so, while an approved one simply ran, making the transcript
|
|
6992
|
-
* of a gated call byte-identical to one that was never gated. The prompt is
|
|
6993
|
-
* 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.
|
|
6994
7024
|
*/
|
|
6995
7025
|
recordDecision(kind) {
|
|
6996
7026
|
this.element.setAttribute("data-decision", kind);
|
|
@@ -7105,11 +7135,10 @@ var VoiceInput = class {
|
|
|
7105
7135
|
this.#recorder?.stop();
|
|
7106
7136
|
}
|
|
7107
7137
|
/**
|
|
7108
|
-
* Tear the control down
|
|
7109
|
-
*
|
|
7110
|
-
*
|
|
7111
|
-
*
|
|
7112
|
-
* 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.
|
|
7113
7142
|
*/
|
|
7114
7143
|
dispose() {
|
|
7115
7144
|
this.#disposed = true;
|
|
@@ -7191,10 +7220,9 @@ var AgUiClient = class {
|
|
|
7191
7220
|
#resolveInterrupts;
|
|
7192
7221
|
#onPersist;
|
|
7193
7222
|
/**
|
|
7194
|
-
* Message ids the server has already closed, so a reuse can be reported.
|
|
7195
|
-
*
|
|
7196
|
-
*
|
|
7197
|
-
* 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.
|
|
7198
7226
|
*/
|
|
7199
7227
|
#closedMessageIds = /* @__PURE__ */ new Set();
|
|
7200
7228
|
#connectionLostMessage;
|
|
@@ -7244,9 +7272,8 @@ var AgUiClient = class {
|
|
|
7244
7272
|
* tools (bounded by {@link MAX_TOOL_ROUNDS}).
|
|
7245
7273
|
*
|
|
7246
7274
|
* `attachments` ride on the user message as a non-standard field so the
|
|
7247
|
-
* default
|
|
7248
|
-
*
|
|
7249
|
-
* unknown message field), then reads bytes via the `read_attachment` tool.
|
|
7275
|
+
* default store round-trips them for history replay; see
|
|
7276
|
+
* {@link messageAttachments}.
|
|
7250
7277
|
*/
|
|
7251
7278
|
async send(content, attachments = []) {
|
|
7252
7279
|
const message = { id: randomUUID2(), role: "user", content };
|
|
@@ -7260,7 +7287,7 @@ var AgUiClient = class {
|
|
|
7260
7287
|
/**
|
|
7261
7288
|
* Resume the run loop after a navigating tool's result was supplied
|
|
7262
7289
|
* post-reload (via {@link addToolResult}). Unlike {@link send}, adds no user
|
|
7263
|
-
* message
|
|
7290
|
+
* message; it continues the conversation already in history.
|
|
7264
7291
|
*/
|
|
7265
7292
|
async resume() {
|
|
7266
7293
|
await this.#run();
|
|
@@ -7402,9 +7429,9 @@ var AgUiClient = class {
|
|
|
7402
7429
|
onActivitySnapshotEvent({ event }) {
|
|
7403
7430
|
h.onActivity(event.activityType, event.content);
|
|
7404
7431
|
},
|
|
7405
|
-
//
|
|
7406
|
-
//
|
|
7407
|
-
//
|
|
7432
|
+
// `@ag-ui/client` maps the deprecated THINKING_* events onto these
|
|
7433
|
+
// REASONING_* callbacks, so the reasoning family alone covers both
|
|
7434
|
+
// protocol versions.
|
|
7408
7435
|
onReasoningStartEvent() {
|
|
7409
7436
|
h.onReasoningStart();
|
|
7410
7437
|
},
|
|
@@ -7559,12 +7586,11 @@ var SessionStorageStore = class {
|
|
|
7559
7586
|
return `${this.#root}:${suffix}`;
|
|
7560
7587
|
}
|
|
7561
7588
|
/**
|
|
7562
|
-
* One-time move of
|
|
7563
|
-
* namespace, so an existing conversation isn't orphaned
|
|
7564
|
-
*
|
|
7565
|
-
*
|
|
7566
|
-
*
|
|
7567
|
-
* 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.
|
|
7568
7594
|
*/
|
|
7569
7595
|
#migrateLegacyKeys() {
|
|
7570
7596
|
const legacyRoot = `${KEY_ROOT}:`;
|
|
@@ -7645,12 +7671,10 @@ function createHttpAgent(options) {
|
|
|
7645
7671
|
headers: options.headers ?? {},
|
|
7646
7672
|
initialState: { ...options.initialState ?? {} },
|
|
7647
7673
|
// HttpAgent invokes its configured fetch as a method (`this.fetch(...)`),
|
|
7648
|
-
//
|
|
7649
|
-
//
|
|
7650
|
-
//
|
|
7651
|
-
//
|
|
7652
|
-
// reaches the stream even though the agent instance is cached, and applies
|
|
7653
|
-
// 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.
|
|
7654
7678
|
fetch: (url, init) => {
|
|
7655
7679
|
const fresh = options.getHeaders?.();
|
|
7656
7680
|
if (fresh === void 0) {
|
|
@@ -7663,7 +7687,7 @@ function createHttpAgent(options) {
|
|
|
7663
7687
|
return fetch(url, withCredentials({ ...init, headers }, options.credentials));
|
|
7664
7688
|
},
|
|
7665
7689
|
// Spread conditionally: under `exactOptionalPropertyTypes` an explicit
|
|
7666
|
-
// `undefined` is not assignable to
|
|
7690
|
+
// `undefined` is not assignable to an optional field.
|
|
7667
7691
|
...options.threadId !== void 0 ? { threadId: options.threadId } : {},
|
|
7668
7692
|
...options.initialMessages !== void 0 ? { initialMessages: [...options.initialMessages] } : {}
|
|
7669
7693
|
});
|
|
@@ -7749,9 +7773,9 @@ var RemoteConversationStore = class {
|
|
|
7749
7773
|
return {
|
|
7750
7774
|
threadId: row.thread_id,
|
|
7751
7775
|
title: this.#renamed.get(row.thread_id) ?? row.title,
|
|
7752
|
-
// `null`
|
|
7753
|
-
// signal
|
|
7754
|
-
//
|
|
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.
|
|
7755
7779
|
updatedAt: row.updated_at === null ? Number.NaN : Date.parse(row.updated_at),
|
|
7756
7780
|
preview: row.preview
|
|
7757
7781
|
};
|
|
@@ -7795,10 +7819,9 @@ var RunIndex = class {
|
|
|
7795
7819
|
this.#credentials = credentials;
|
|
7796
7820
|
}
|
|
7797
7821
|
/**
|
|
7798
|
-
* The user's runs, or `[]` when the endpoint is unreachable or
|
|
7799
|
-
*
|
|
7800
|
-
*
|
|
7801
|
-
* 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.
|
|
7802
7825
|
*/
|
|
7803
7826
|
async list() {
|
|
7804
7827
|
try {
|
|
@@ -7836,9 +7859,9 @@ var RunIndex = class {
|
|
|
7836
7859
|
/**
|
|
7837
7860
|
* `<mount>/<verb>/<runId>/`, derived from the index URL's own prefix.
|
|
7838
7861
|
*
|
|
7839
|
-
*
|
|
7840
|
-
*
|
|
7841
|
-
*
|
|
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.
|
|
7842
7865
|
*/
|
|
7843
7866
|
#sibling(verb, runId) {
|
|
7844
7867
|
const prefix = this.#url.slice(0, -"runs/".length);
|
|
@@ -7973,29 +7996,23 @@ var AgUiChat = class extends HTMLElement {
|
|
|
7973
7996
|
/** Agent factory; override to inject a custom or fake agent (tests). */
|
|
7974
7997
|
agentFactory = createHttpAgent;
|
|
7975
7998
|
/**
|
|
7976
|
-
* Static extra HTTP headers, sent with
|
|
7977
|
-
*
|
|
7978
|
-
*
|
|
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.
|
|
7979
8002
|
*
|
|
7980
|
-
*
|
|
7981
|
-
*
|
|
7982
|
-
*
|
|
7983
|
-
* re-assignment updates it, so a token captured here is pinned until the host
|
|
7984
|
-
* 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.
|
|
7985
8006
|
*/
|
|
7986
8007
|
headers = {};
|
|
7987
8008
|
/**
|
|
7988
|
-
* Live header source,
|
|
7989
|
-
* supply rotating credentials
|
|
7990
|
-
*
|
|
7991
|
-
* Set it to a function and each request calls it afresh: a token refreshed by
|
|
7992
|
-
* the host between two requests reaches the second one, with nothing to
|
|
7993
|
-
* 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.
|
|
7994
8012
|
*
|
|
7995
|
-
* Composes with {@link headers} rather than replacing it:
|
|
7996
|
-
*
|
|
7997
|
-
* `Authorization`
|
|
7998
|
-
* 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.
|
|
7999
8016
|
*/
|
|
8000
8017
|
getHeaders = null;
|
|
8001
8018
|
/**
|
|
@@ -8009,37 +8026,31 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8009
8026
|
autoConfirm = false;
|
|
8010
8027
|
/**
|
|
8011
8028
|
* When true, the built-in `ask_user` frontend tool is offered to the agent:
|
|
8012
|
-
* calling it renders an inline question card
|
|
8013
|
-
*
|
|
8014
|
-
*
|
|
8015
|
-
* 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.
|
|
8016
8032
|
*/
|
|
8017
8033
|
askUser = false;
|
|
8018
8034
|
/**
|
|
8019
|
-
* Optional full replacement for the `ask_user` question UI
|
|
8020
|
-
*
|
|
8021
|
-
*
|
|
8022
|
-
* resolves with the answer. Unset (default) uses the built-in
|
|
8023
|
-
* {@link requestQuestion} card — style that via the `strings` override and the
|
|
8024
|
-
* `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}.
|
|
8025
8038
|
*/
|
|
8026
8039
|
askUserRenderer = null;
|
|
8027
8040
|
/**
|
|
8028
|
-
* Optional full replacement for the server-side-tool approval UI
|
|
8029
|
-
*
|
|
8030
|
-
* card
|
|
8031
|
-
* `
|
|
8032
|
-
*
|
|
8033
|
-
* `::part()`s. The gate itself is enabled server-side; this only changes how
|
|
8034
|
-
* 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.
|
|
8035
8046
|
*/
|
|
8036
8047
|
approvalRenderer = null;
|
|
8037
8048
|
/**
|
|
8038
|
-
* Optional per-call confirmation predicate. When set
|
|
8039
|
-
*
|
|
8040
|
-
*
|
|
8041
|
-
* static `x-destructive` flag
|
|
8042
|
-
*
|
|
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.
|
|
8043
8054
|
*/
|
|
8044
8055
|
confirmPredicate = null;
|
|
8045
8056
|
/**
|
|
@@ -8057,14 +8068,14 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8057
8068
|
...this.#toolRegistry.tools()
|
|
8058
8069
|
];
|
|
8059
8070
|
/**
|
|
8060
|
-
* Per-run context provider. Defaults to the compact page map
|
|
8061
|
-
* {@link getPageMap} provider is set and {@link autoInjectPageMap} is on
|
|
8062
|
-
*
|
|
8063
|
-
*
|
|
8071
|
+
* Per-run context provider. Defaults to the compact page map, when a
|
|
8072
|
+
* {@link getPageMap} provider is set and {@link autoInjectPageMap} is on.
|
|
8073
|
+
*
|
|
8074
|
+
* Attachments are deliberately not restated here: the server derives its own
|
|
8075
|
+
* manifest from the refs riding the messages.
|
|
8064
8076
|
*/
|
|
8065
8077
|
getContext = () => [
|
|
8066
|
-
...createPageMapContext(this.getPageMap, this.autoInjectPageMap)
|
|
8067
|
-
...this.#attachmentContext()
|
|
8078
|
+
...createPageMapContext(this.getPageMap, this.autoInjectPageMap)
|
|
8068
8079
|
];
|
|
8069
8080
|
/**
|
|
8070
8081
|
* Navigable routes the agent can jump to via the built-in `route.*` tools.
|
|
@@ -8089,21 +8100,17 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8089
8100
|
conversationStore = new SessionStorageStore();
|
|
8090
8101
|
/**
|
|
8091
8102
|
* How attached files are uploaded. `null` (default) uses the built-in
|
|
8092
|
-
* multipart `POST` to `data-attachments-url
|
|
8093
|
-
*
|
|
8094
|
-
*
|
|
8095
|
-
*
|
|
8096
|
-
* wire (refs are transport-agnostic). When set, the 📎 affordance appears even
|
|
8097
|
-
* 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.
|
|
8098
8107
|
*/
|
|
8099
8108
|
uploadHandler = null;
|
|
8100
8109
|
/**
|
|
8101
8110
|
* How recorded voice clips are transcribed. `null` (default) POSTs the clip
|
|
8102
|
-
* to `data-transcribe-url
|
|
8103
|
-
*
|
|
8104
|
-
*
|
|
8105
|
-
* touching the mic button. When set, the 🎤 affordance appears even with no
|
|
8106
|
-
* `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`.
|
|
8107
8114
|
*/
|
|
8108
8115
|
transcribeHandler = null;
|
|
8109
8116
|
/**
|
|
@@ -8122,12 +8129,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8122
8129
|
*/
|
|
8123
8130
|
skillContext = () => ({});
|
|
8124
8131
|
/**
|
|
8125
|
-
* Friendly display labels for tool-call cards, keyed by tool name
|
|
8126
|
-
*
|
|
8127
|
-
*
|
|
8128
|
-
*
|
|
8129
|
-
* only the tool-call name). Client tools should prefer `x-summary` on their
|
|
8130
|
-
* 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`.
|
|
8131
8136
|
*/
|
|
8132
8137
|
toolSummaries = {};
|
|
8133
8138
|
/**
|
|
@@ -8196,8 +8201,6 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8196
8201
|
#voice = null;
|
|
8197
8202
|
/** Whether the element is currently in the DOM; gates the connect-time warning. */
|
|
8198
8203
|
#connected = false;
|
|
8199
|
-
/** Refs attached to the message currently being sent (the context manifest). */
|
|
8200
|
-
#runAttachments = [];
|
|
8201
8204
|
#client = null;
|
|
8202
8205
|
// Seed for the next client. Once one exists it owns the live value (the
|
|
8203
8206
|
// agent applies STATE_SNAPSHOT / STATE_DELTA into it), so this is only the
|
|
@@ -8301,13 +8304,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8301
8304
|
* Continue `runId` as a **new** run, seeded server-side from its snapshot.
|
|
8302
8305
|
*
|
|
8303
8306
|
* Uses a short-lived agent pointed at the resume / fork endpoint and seeded
|
|
8304
|
-
* with
|
|
8305
|
-
*
|
|
8306
|
-
*
|
|
8307
|
-
*
|
|
8308
|
-
* "only the new turn" can't be got wrong by forgetting to clear it. The
|
|
8309
|
-
* fresh `run_id` the endpoints also require comes free — a new agent mints
|
|
8310
|
-
* 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.
|
|
8311
8311
|
*
|
|
8312
8312
|
* Handlers are the element's own, so the continuation streams into the same
|
|
8313
8313
|
* transcript the user is looking at.
|
|
@@ -8388,10 +8388,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8388
8388
|
* when the server streams `STATE_SNAPSHOT` / `STATE_DELTA`. Assigning seeds
|
|
8389
8389
|
* the next run; reading returns whatever the agent last applied.
|
|
8390
8390
|
*
|
|
8391
|
-
* Listen for {@link STATE_EVENT} to react to server-driven changes.
|
|
8392
|
-
*
|
|
8393
|
-
* Not to be confused with {@link registerPageState}, which exposes host
|
|
8394
|
-
* 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.
|
|
8395
8393
|
*/
|
|
8396
8394
|
get sharedState() {
|
|
8397
8395
|
return this.#client?.state ?? this.#sharedState;
|
|
@@ -8407,11 +8405,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8407
8405
|
}
|
|
8408
8406
|
}
|
|
8409
8407
|
/**
|
|
8410
|
-
* @deprecated Renamed to {@link registerPageState}
|
|
8411
|
-
* AG-UI shared-state sync
|
|
8412
|
-
*
|
|
8413
|
-
* page state. Behaviour is unchanged; this alias will be removed in a future
|
|
8414
|
-
* 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.
|
|
8415
8411
|
*/
|
|
8416
8412
|
registerStateHook(binding) {
|
|
8417
8413
|
this.registerPageState(binding);
|
|
@@ -8478,10 +8474,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8478
8474
|
/**
|
|
8479
8475
|
* The built-in `ask_user` frontend tool, or `[]` when {@link askUser} is off.
|
|
8480
8476
|
*
|
|
8481
|
-
*
|
|
8482
|
-
*
|
|
8483
|
-
*
|
|
8484
|
-
* 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.
|
|
8485
8480
|
*/
|
|
8486
8481
|
#askUserTool() {
|
|
8487
8482
|
if (!this.askUser) {
|
|
@@ -8557,19 +8552,18 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8557
8552
|
* `credentials` mode (`"omit"` / `"same-origin"` / `"include"`). Mirrored to
|
|
8558
8553
|
* the `credentials` attribute, so markup embeds can set it without script.
|
|
8559
8554
|
*
|
|
8560
|
-
* `null` (the default) leaves the browser's
|
|
8561
|
-
*
|
|
8562
|
-
*
|
|
8563
|
-
*
|
|
8564
|
-
*
|
|
8565
|
-
*
|
|
8566
|
-
* `
|
|
8567
|
-
* (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.
|
|
8568
8562
|
*
|
|
8569
8563
|
* Read per request, so a late assignment applies to everything after it.
|
|
8570
|
-
* `"omit"` cannot be honoured by the built-in
|
|
8571
|
-
*
|
|
8572
|
-
*
|
|
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.
|
|
8573
8567
|
*/
|
|
8574
8568
|
get credentials() {
|
|
8575
8569
|
const attr = this.getAttribute("credentials");
|
|
@@ -8670,25 +8664,21 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8670
8664
|
* The catalog requests the element issues on startup: the tool labels
|
|
8671
8665
|
* (`data-tools-url`) and the backend skills (`data-skills-url`).
|
|
8672
8666
|
*
|
|
8673
|
-
* Deliberately one microtask behind `connectedCallback`. A
|
|
8674
|
-
*
|
|
8675
|
-
*
|
|
8676
|
-
*
|
|
8677
|
-
*
|
|
8678
|
-
*
|
|
8679
|
-
*
|
|
8680
|
-
*
|
|
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.
|
|
8681
8678
|
*
|
|
8682
|
-
*
|
|
8683
|
-
*
|
|
8684
|
-
*
|
|
8685
|
-
* {@link reload} once configured, because a longer timer would hide that race
|
|
8686
|
-
* rather than close it. And it deliberately excludes the *history* replay,
|
|
8687
|
-
* which stays in `connectedCallback`: the replay renders into the transcript,
|
|
8688
|
-
* so deferring it lets a `sendMessage()` issued in the same task land first
|
|
8689
|
-
* and the replay then duplicate it. The thread history is therefore the one
|
|
8690
|
-
* request that can still go out before a ref is attached — {@link reload}
|
|
8691
|
-
* 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.
|
|
8692
8682
|
*/
|
|
8693
8683
|
#startup() {
|
|
8694
8684
|
if (!this.#connected) {
|
|
@@ -8702,15 +8692,13 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8702
8692
|
* the backend skill catalog and the thread's history — with the transport
|
|
8703
8693
|
* configuration as it stands now.
|
|
8704
8694
|
*
|
|
8705
|
-
*
|
|
8706
|
-
*
|
|
8707
|
-
* startup requests
|
|
8708
|
-
* "try again, properly authenticated" without removing and re-inserting the
|
|
8709
|
-
* 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.
|
|
8710
8698
|
*
|
|
8711
|
-
* A reload, not a merge
|
|
8712
|
-
*
|
|
8713
|
-
*
|
|
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.
|
|
8714
8702
|
*/
|
|
8715
8703
|
async reload() {
|
|
8716
8704
|
this.#cancelRun();
|
|
@@ -8719,12 +8707,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8719
8707
|
await Promise.all([this.#fetchToolCatalog(), this.#fetchSkills(), this.#rehydrate()]);
|
|
8720
8708
|
}
|
|
8721
8709
|
/**
|
|
8722
|
-
* Tear down live resources when the element leaves the DOM
|
|
8723
|
-
*
|
|
8724
|
-
*
|
|
8725
|
-
*
|
|
8726
|
-
* removed `<ag-ui-chat>` leaks a streaming request, uploads, and a live
|
|
8727
|
-
* `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.
|
|
8728
8714
|
*/
|
|
8729
8715
|
disconnectedCallback() {
|
|
8730
8716
|
this.#connected = false;
|
|
@@ -8735,14 +8721,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8735
8721
|
/**
|
|
8736
8722
|
* Read an opt-in flag attribute the way HTML reads a boolean attribute.
|
|
8737
8723
|
*
|
|
8738
|
-
* Present means on
|
|
8739
|
-
*
|
|
8740
|
-
*
|
|
8741
|
-
*
|
|
8742
|
-
* reaches for first — silently *disabled* the feature it names, with nothing
|
|
8743
|
-
* to indicate why the chips never appeared.
|
|
8744
|
-
*
|
|
8745
|
-
* `="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.
|
|
8746
8728
|
*/
|
|
8747
8729
|
#flag(name) {
|
|
8748
8730
|
const value = this.getAttribute(name);
|
|
@@ -8884,22 +8866,6 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8884
8866
|
}
|
|
8885
8867
|
});
|
|
8886
8868
|
}
|
|
8887
|
-
/** The one-line manifest of the message's attachments, for the run context. */
|
|
8888
|
-
#attachmentContext() {
|
|
8889
|
-
if (this.#runAttachments.length === 0) {
|
|
8890
|
-
return [];
|
|
8891
|
-
}
|
|
8892
|
-
const lines = this.#runAttachments.map(
|
|
8893
|
-
(ref) => `- ${ref.name} (id: ${ref.id}, ${ref.mime || "unknown type"}, ${ref.size} bytes)`
|
|
8894
|
-
);
|
|
8895
|
-
return [
|
|
8896
|
-
{
|
|
8897
|
-
description: "Files the user attached to this message",
|
|
8898
|
-
value: `${lines.join("\n")}
|
|
8899
|
-
Use the read_attachment tool with an id to read a file's contents.`
|
|
8900
|
-
}
|
|
8901
|
-
];
|
|
8902
|
-
}
|
|
8903
8869
|
/**
|
|
8904
8870
|
* When `data-threads-url` is set, route thread enumeration / load / rename /
|
|
8905
8871
|
* delete through that server endpoint (wrapping the current store as the
|
|
@@ -8984,21 +8950,16 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8984
8950
|
/**
|
|
8985
8951
|
* Act on a picked skill.
|
|
8986
8952
|
*
|
|
8987
|
-
* A skill
|
|
8988
|
-
*
|
|
8989
|
-
*
|
|
8990
|
-
*
|
|
8991
|
-
* then never reaches the browser at all: a skill is often where a project's
|
|
8992
|
-
* internal workflow is written down most plainly, and a catalog endpoint is a
|
|
8993
|
-
* 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 shape — a skill often states a project's internal
|
|
8956
|
+
* workflow most plainly, and a catalog endpoint is a plain GET.
|
|
8994
8957
|
*
|
|
8995
|
-
* A skill
|
|
8996
|
-
*
|
|
8997
|
-
* Right for a user-facing convenience, and for placeholders only the page can
|
|
8998
|
-
* 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.
|
|
8999
8960
|
*
|
|
9000
|
-
* Either way a pick
|
|
9001
|
-
*
|
|
8961
|
+
* Either way a pick sends; `sendImmediately: false` opts into pre-filling the
|
|
8962
|
+
* composer instead.
|
|
9002
8963
|
*/
|
|
9003
8964
|
#applySkill(skill) {
|
|
9004
8965
|
if (skill.prompt === void 0) {
|
|
@@ -9110,18 +9071,13 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9110
9071
|
}
|
|
9111
9072
|
}
|
|
9112
9073
|
/**
|
|
9113
|
-
* 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.
|
|
9114
9077
|
*
|
|
9115
|
-
*
|
|
9116
|
-
*
|
|
9117
|
-
*
|
|
9118
|
-
* the page's own CSS puts it — flex-start, flex-end, a grid cell. Mapping
|
|
9119
|
-
* placement to a corner got this wrong for any host that right-aligns the
|
|
9120
|
-
* element, and the symptom is bad enough to read as a broken control: the
|
|
9121
|
-
* panel shrinks when dragged outward, travelling by its opposite corner.
|
|
9122
|
-
*
|
|
9123
|
-
* So: nudge the size by a pixel, see which edges stayed put, and undo. One
|
|
9124
|
-
* 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.
|
|
9125
9081
|
*/
|
|
9126
9082
|
#measureAnchor() {
|
|
9127
9083
|
const before = this.getBoundingClientRect();
|
|
@@ -9155,14 +9111,13 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9155
9111
|
/**
|
|
9156
9112
|
* Write a dragged size onto the host, on the axes this placement leaves free.
|
|
9157
9113
|
*
|
|
9158
|
-
*
|
|
9159
|
-
*
|
|
9160
|
-
*
|
|
9161
|
-
*
|
|
9162
|
-
* `100vh`. The cascade cannot arbitrate this
|
|
9163
|
-
*
|
|
9164
|
-
*
|
|
9165
|
-
* 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.
|
|
9166
9121
|
*/
|
|
9167
9122
|
#applySize(size) {
|
|
9168
9123
|
const axis = this.#resizeAxis();
|
|
@@ -9235,12 +9190,10 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9235
9190
|
* Open the thread-history drawer: the imperative route to the control that
|
|
9236
9191
|
* renders as `::part(history-button)`.
|
|
9237
9192
|
*
|
|
9238
|
-
* A host that hides `::part(header)`
|
|
9239
|
-
*
|
|
9240
|
-
*
|
|
9241
|
-
*
|
|
9242
|
-
* {@link openCheckpoints}, {@link newChat}, {@link toggleCollapsed} and
|
|
9243
|
-
* {@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}.
|
|
9244
9197
|
*/
|
|
9245
9198
|
openThreads() {
|
|
9246
9199
|
void this.#refreshDrawer();
|
|
@@ -9279,7 +9232,6 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9279
9232
|
this.#toolCards.clear();
|
|
9280
9233
|
this.#serverSettled.clear();
|
|
9281
9234
|
this.#initialMessages = [];
|
|
9282
|
-
this.#runAttachments = [];
|
|
9283
9235
|
this.#attachTray?.clear();
|
|
9284
9236
|
this.#messages.replaceChildren(this.#emptyWrap);
|
|
9285
9237
|
this.#updateEmptyState();
|
|
@@ -9342,23 +9294,17 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9342
9294
|
/**
|
|
9343
9295
|
* Notice a previous run that never produced a response.
|
|
9344
9296
|
*
|
|
9345
|
-
* {@link AgUiClient.send} persists the user's message
|
|
9346
|
-
* run, so a transcript
|
|
9347
|
-
*
|
|
9348
|
-
*
|
|
9349
|
-
* of the transcript already says so, which is why this needs no
|
|
9350
|
-
* {@link ClientConversationStore} method and no `pagehide` listener (neither
|
|
9351
|
-
* 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.
|
|
9352
9301
|
*
|
|
9353
|
-
*
|
|
9354
|
-
* checkpoint and resumes,
|
|
9355
|
-
* 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.
|
|
9356
9304
|
*
|
|
9357
|
-
* Deliberately a notice
|
|
9358
|
-
*
|
|
9359
|
-
*
|
|
9360
|
-
* executed before the interruption would run a second time. Saying plainly
|
|
9361
|
-
* 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.
|
|
9362
9308
|
*/
|
|
9363
9309
|
/**
|
|
9364
9310
|
* Build a round's context, recording which page it describes.
|
|
@@ -9411,19 +9357,16 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9411
9357
|
if (text2 !== "") {
|
|
9412
9358
|
this.appendMessage(MESSAGE_ROLE.ASSISTANT, text2).classList.add("message--restored");
|
|
9413
9359
|
}
|
|
9414
|
-
const
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
if (this.#noticeIfSkillLoad(restored)) {
|
|
9423
|
-
continue;
|
|
9424
|
-
}
|
|
9425
|
-
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;
|
|
9426
9368
|
}
|
|
9369
|
+
this.#cardFor(restored);
|
|
9427
9370
|
}
|
|
9428
9371
|
return;
|
|
9429
9372
|
}
|
|
@@ -9434,8 +9377,11 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9434
9377
|
}
|
|
9435
9378
|
}
|
|
9436
9379
|
}
|
|
9437
|
-
/** Parse a tool call's JSON `arguments`
|
|
9380
|
+
/** Parse a tool call's JSON `arguments` from history into an object. */
|
|
9438
9381
|
#parseArgs(raw) {
|
|
9382
|
+
if (typeof raw !== "string") {
|
|
9383
|
+
return {};
|
|
9384
|
+
}
|
|
9439
9385
|
try {
|
|
9440
9386
|
const parsed = JSON.parse(raw);
|
|
9441
9387
|
if (typeof parsed === "object" && parsed !== null) {
|
|
@@ -9464,13 +9410,12 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9464
9410
|
/**
|
|
9465
9411
|
* Append a message bubble and return it.
|
|
9466
9412
|
*
|
|
9467
|
-
* Assistant content
|
|
9468
|
-
*
|
|
9469
|
-
* 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.
|
|
9470
9415
|
*
|
|
9471
|
-
* Assistant bubbles land in the current answer group, opening one if
|
|
9472
|
-
*
|
|
9473
|
-
*
|
|
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.
|
|
9474
9419
|
*/
|
|
9475
9420
|
appendMessage(role, content) {
|
|
9476
9421
|
const bubble = document.createElement("div");
|
|
@@ -9663,12 +9608,9 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9663
9608
|
* Build a header control button: a named slot a host can project markup into,
|
|
9664
9609
|
* with the built-in glyph as the slot's fallback.
|
|
9665
9610
|
*
|
|
9666
|
-
* The
|
|
9667
|
-
*
|
|
9668
|
-
*
|
|
9669
|
-
* supply a brand `<img>` or `<svg>`. This is the same slot-with-fallback
|
|
9670
|
-
* idiom the header icon already uses, so existing embeds render exactly as
|
|
9671
|
-
* 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.
|
|
9672
9614
|
*/
|
|
9673
9615
|
#headerButton(modifier, label, glyph) {
|
|
9674
9616
|
const button2 = document.createElement("button");
|
|
@@ -9869,19 +9811,16 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9869
9811
|
* Send a message as if the user had typed it — renders the user bubble,
|
|
9870
9812
|
* dispatches {@link SUBMIT_EVENT}, and starts the run.
|
|
9871
9813
|
*
|
|
9872
|
-
* The programmatic half of the composer, for a host driving its own input
|
|
9873
|
-
*
|
|
9874
|
-
*
|
|
9875
|
-
* 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.
|
|
9876
9817
|
*
|
|
9877
|
-
* `attachments` are durable {@link AttachmentRef}s —
|
|
9878
|
-
*
|
|
9879
|
-
* {@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.
|
|
9880
9820
|
*
|
|
9881
|
-
* No-ops while a run is in flight
|
|
9882
|
-
*
|
|
9883
|
-
*
|
|
9884
|
-
* 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.
|
|
9885
9824
|
*/
|
|
9886
9825
|
async sendMessage(content, attachments = []) {
|
|
9887
9826
|
if (this.#running || content === "" && attachments.length === 0) {
|
|
@@ -9891,7 +9830,6 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9891
9830
|
if (attachments.length > 0) {
|
|
9892
9831
|
bubble.appendChild(renderAttachmentChips(attachments));
|
|
9893
9832
|
}
|
|
9894
|
-
this.#runAttachments = attachments;
|
|
9895
9833
|
this.dispatchEvent(
|
|
9896
9834
|
new CustomEvent(SUBMIT_EVENT, {
|
|
9897
9835
|
detail: { content, attachments },
|
|
@@ -9906,11 +9844,11 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9906
9844
|
* picker and drag-and-drop do — validation, progress chip, and all.
|
|
9907
9845
|
*
|
|
9908
9846
|
* Returns `false` when uploads are not configured (no `data-attachments-url`
|
|
9909
|
-
* and no {@link uploadHandler})
|
|
9910
|
-
*
|
|
9847
|
+
* and no {@link uploadHandler}) — the only signal a host gets, since the tray
|
|
9848
|
+
* does not exist to report anything then.
|
|
9911
9849
|
*
|
|
9912
9850
|
* Uploading is asynchronous: watch {@link ATTACHMENT_EVENT} for the resulting
|
|
9913
|
-
* {@link AttachmentRef}
|
|
9851
|
+
* {@link AttachmentRef} and pass it to {@link sendMessage} once `pending`
|
|
9914
9852
|
* reaches zero.
|
|
9915
9853
|
*/
|
|
9916
9854
|
attachFile(file) {
|
|
@@ -10055,12 +9993,11 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
10055
9993
|
* Render an approval card per server-side-tool interrupt and collect the
|
|
10056
9994
|
* user's decisions (approve → run it, deny → decline it).
|
|
10057
9995
|
*
|
|
10058
|
-
* The run is suspended on these cards
|
|
9996
|
+
* The run is suspended on these cards. A Stop while any is open aborts the
|
|
10059
9997
|
* shared {@link #confirmAbort} controller, resolving every still-open card as
|
|
10060
|
-
* denied
|
|
10061
|
-
*
|
|
10062
|
-
*
|
|
10063
|
-
* 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.
|
|
10064
10001
|
*/
|
|
10065
10002
|
async #resolveInterrupts(interrupts) {
|
|
10066
10003
|
const responses = {};
|
|
@@ -10169,7 +10106,6 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
10169
10106
|
this.#hidePending();
|
|
10170
10107
|
this.#setRunning(false);
|
|
10171
10108
|
this.#streamingBubble = null;
|
|
10172
|
-
this.#runAttachments = [];
|
|
10173
10109
|
for (const card of this.#toolCards.values()) {
|
|
10174
10110
|
if (!card.settled) {
|
|
10175
10111
|
card.settle(TOOL_CALL_STATUS.DONE, this.#strings.noResult);
|
|
@@ -10295,6 +10231,16 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
10295
10231
|
return card;
|
|
10296
10232
|
}
|
|
10297
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
|
+
}
|
|
10298
10244
|
function skillNameFrom(call) {
|
|
10299
10245
|
if (call.name !== LOAD_CAPABILITY_TOOL) {
|
|
10300
10246
|
return null;
|
|
@@ -10347,7 +10293,7 @@ function setControlValue(el, value) {
|
|
|
10347
10293
|
}
|
|
10348
10294
|
|
|
10349
10295
|
// src/version.ts
|
|
10350
|
-
var VERSION = "0.
|
|
10296
|
+
var VERSION = "0.23.1";
|
|
10351
10297
|
export {
|
|
10352
10298
|
ATTACHMENT_EVENT,
|
|
10353
10299
|
AgUiChat,
|