@artooi/ag-ui-web-component 0.31.0 → 0.32.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 +64 -1
- package/dist/ag-ui-web-component.bundle.js +57 -48
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +26 -7
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/agui_client.d.ts +25 -0
- package/dist/core/agui_client.d.ts.map +1 -1
- package/dist/index.js +119 -1
- package/dist/index.js.map +2 -2
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/subagent_panel.d.ts +9 -0
- package/dist/ui/subagent_panel.d.ts.map +1 -1
- package/dist/ui/subagent_update.d.ts +9 -0
- package/dist/ui/subagent_update.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +19 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/constants.ts +26 -7
- package/src/core/ag_ui_chat.ts +91 -1
- package/src/core/agui_client.ts +41 -0
- package/src/ui/styles.ts +9 -0
- package/src/ui/subagent_panel.ts +14 -0
- package/src/ui/subagent_update.ts +9 -0
- package/src/ui/ui_strings.ts +22 -0
- package/src/version.ts +1 -1
package/src/core/ag_ui_chat.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
RUN_FINISHED_EVENT,
|
|
23
23
|
STATE_EVENT,
|
|
24
24
|
SUBAGENT_CUSTOM_NAME,
|
|
25
|
+
SUBAGENT_PHASE,
|
|
25
26
|
SUBMIT_EVENT,
|
|
26
27
|
SUGGESTIONS_ACTIVITY_TYPE,
|
|
27
28
|
TOGGLE_EVENT,
|
|
@@ -82,7 +83,7 @@ import { renderRunNotice } from "../ui/run_notice.js";
|
|
|
82
83
|
import { SkillsMenu } from "../ui/skills_menu.js";
|
|
83
84
|
import { createStickToBottom, type StickToBottom } from "../ui/stick_to_bottom.js";
|
|
84
85
|
import { STYLES } from "../ui/styles.js";
|
|
85
|
-
import { SubAgentPanel } from "../ui/subagent_panel.js";
|
|
86
|
+
import { SubAgentPanel, type SubAgentPhase, type SubAgentUpdate } from "../ui/subagent_panel.js";
|
|
86
87
|
import { subAgentUpdate } from "../ui/subagent_update.js";
|
|
87
88
|
import { renderSuggestionChips } from "../ui/suggestion_chips.js";
|
|
88
89
|
import { ThoughtsBlock } from "../ui/thoughts_block.js";
|
|
@@ -630,6 +631,17 @@ export class AgUiChat extends HTMLElement {
|
|
|
630
631
|
* approval prompt already uses.
|
|
631
632
|
*/
|
|
632
633
|
readonly #subagentPanels = new Map<string, SubAgentPanel>();
|
|
634
|
+
/**
|
|
635
|
+
* Which delegation each live `subagentRunId` belongs to.
|
|
636
|
+
*
|
|
637
|
+
* The protocol's closing events -- `SUBAGENT_FINISHED` and `SUBAGENT_ERROR`
|
|
638
|
+
* -- carry the child's run id and nothing else, while everything drawn here
|
|
639
|
+
* is keyed on the parent's `delegate_task` call id. `SUBAGENT_STARTED` is the
|
|
640
|
+
* one event carrying both, so the pairing is recorded there and read back on
|
|
641
|
+
* the close. A close naming a run this never saw open is dropped, which is
|
|
642
|
+
* the same refusal a step for an undrawn card gets.
|
|
643
|
+
*/
|
|
644
|
+
readonly #subagentRunDelegations = new Map<string, string>();
|
|
633
645
|
/**
|
|
634
646
|
* Call ids whose card was already settled from a streamed server-side result
|
|
635
647
|
* (`TOOL_CALL_RESULT`), so the post-run executeTool sweep doesn't overwrite
|
|
@@ -2473,6 +2485,7 @@ export class AgUiChat extends HTMLElement {
|
|
|
2473
2485
|
// the correct half of that split -- a delegation that was live before this
|
|
2474
2486
|
// transcript was wiped is not live now.
|
|
2475
2487
|
this.#subagentPanels.clear();
|
|
2488
|
+
this.#subagentRunDelegations.clear();
|
|
2476
2489
|
this.#serverSettled.clear();
|
|
2477
2490
|
this.#cardElements.clear();
|
|
2478
2491
|
this.#activityBlocks.clear();
|
|
@@ -3945,6 +3958,32 @@ export class AgUiChat extends HTMLElement {
|
|
|
3945
3958
|
}),
|
|
3946
3959
|
);
|
|
3947
3960
|
},
|
|
3961
|
+
// The delegation's own lifetime, on the protocol's events rather than the
|
|
3962
|
+
// CUSTOM channel its steps ride. Both end at the same panel.
|
|
3963
|
+
onSubAgentStarted: (subagentRunId, agent, parentToolCallId) => {
|
|
3964
|
+
// A delegation naming no parent call names no card, and a floating
|
|
3965
|
+
// panel is exactly what attaching to the card was chosen over.
|
|
3966
|
+
if (parentToolCallId === null) {
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
this.#subagentRunDelegations.set(subagentRunId, parentToolCallId);
|
|
3970
|
+
this.#applySubAgent({
|
|
3971
|
+
delegationId: parentToolCallId,
|
|
3972
|
+
agent: agent === "" ? null : agent,
|
|
3973
|
+
phase: SUBAGENT_PHASE.STARTED,
|
|
3974
|
+
status: this.#strings.subAgentDelegatedTo.replace("{agent}", agent),
|
|
3975
|
+
tool: null,
|
|
3976
|
+
});
|
|
3977
|
+
},
|
|
3978
|
+
onSubAgentFinished: (subagentRunId) => {
|
|
3979
|
+
this.#closeSubAgent(subagentRunId, SUBAGENT_PHASE.FINISHED, null);
|
|
3980
|
+
},
|
|
3981
|
+
onSubAgentError: (subagentRunId, message) => {
|
|
3982
|
+
// The server's own words, which the contract keeps to the sub-agent's
|
|
3983
|
+
// name. Passed through as the status line and set with textContent
|
|
3984
|
+
// downstream, never parsed as markup.
|
|
3985
|
+
this.#closeSubAgent(subagentRunId, SUBAGENT_PHASE.FAILED, message);
|
|
3986
|
+
},
|
|
3948
3987
|
onMessagesSnapshot: () => {
|
|
3949
3988
|
// Honoured for persistence and announced, not re-rendered.
|
|
3950
3989
|
//
|
|
@@ -4144,6 +4183,57 @@ export class AgUiChat extends HTMLElement {
|
|
|
4144
4183
|
if (update === null) {
|
|
4145
4184
|
return;
|
|
4146
4185
|
}
|
|
4186
|
+
this.#applySubAgent(update);
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4189
|
+
/**
|
|
4190
|
+
* Fold one already-narrowed update into the delegation's panel.
|
|
4191
|
+
*
|
|
4192
|
+
* The join point of the two carriers, and the reason it is separate from
|
|
4193
|
+
* {@link #reportSubAgent}: a `CUSTOM` step arrives as `unknown` and has to be
|
|
4194
|
+
* vouched for, while a lifecycle event arrives typed off the protocol and has
|
|
4195
|
+
* nothing left to check. Both end up here, so the panel has one way in and
|
|
4196
|
+
* the phases stay a single state machine regardless of which wire they came
|
|
4197
|
+
* from.
|
|
4198
|
+
*/
|
|
4199
|
+
/**
|
|
4200
|
+
* Settle the delegation a closing lifecycle event names.
|
|
4201
|
+
*
|
|
4202
|
+
* `status` is the server's text on a failure and `null` on a success, where
|
|
4203
|
+
* the wording is this element's own -- the protocol's finish event carries no
|
|
4204
|
+
* message, which is the better shape for a localised UI and the reason
|
|
4205
|
+
* {@link UiStrings.subAgentFinished} exists.
|
|
4206
|
+
*
|
|
4207
|
+
* The pairing is deliberately not deleted on close. A panel outlives the
|
|
4208
|
+
* delegation it drew, the map is cleared with the transcript alongside the
|
|
4209
|
+
* panels, and forgetting the id here would only make a duplicate close draw
|
|
4210
|
+
* nothing instead of drawing the same settled row again.
|
|
4211
|
+
*/
|
|
4212
|
+
#closeSubAgent(subagentRunId: string, phase: SubAgentPhase, status: string | null): void {
|
|
4213
|
+
const delegationId = this.#subagentRunDelegations.get(subagentRunId);
|
|
4214
|
+
if (delegationId === undefined) {
|
|
4215
|
+
// A close naming a delegation this never saw open -- the same refusal a
|
|
4216
|
+
// step for an undrawn card gets, and the same reason.
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
const agent = this.#subagentPanels.get(delegationId)?.agent ?? null;
|
|
4220
|
+
this.#applySubAgent({
|
|
4221
|
+
delegationId,
|
|
4222
|
+
agent,
|
|
4223
|
+
phase,
|
|
4224
|
+
status: status === null ? this.#finishedLine(agent) : status,
|
|
4225
|
+
tool: null,
|
|
4226
|
+
});
|
|
4227
|
+
}
|
|
4228
|
+
|
|
4229
|
+
/** The row's line for a delegation that completed, named if its name is known. */
|
|
4230
|
+
#finishedLine(agent: string | null): string {
|
|
4231
|
+
return agent === null
|
|
4232
|
+
? this.#strings.subAgentWorking
|
|
4233
|
+
: this.#strings.subAgentFinished.replace("{agent}", agent);
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
#applySubAgent(update: SubAgentUpdate): void {
|
|
4147
4237
|
const card = this.#toolCards.get(update.delegationId);
|
|
4148
4238
|
if (card === undefined) {
|
|
4149
4239
|
return;
|
package/src/core/agui_client.ts
CHANGED
|
@@ -127,6 +127,31 @@ export interface AgUiClientHandlers {
|
|
|
127
127
|
* be the thing the open field exists to avoid.
|
|
128
128
|
*/
|
|
129
129
|
onCustomEvent(name: string, value: unknown): void;
|
|
130
|
+
/**
|
|
131
|
+
* A delegated sub-agent started, inside the run.
|
|
132
|
+
*
|
|
133
|
+
* The protocol's own event, unlike the steps that follow it on
|
|
134
|
+
* {@link SUBAGENT_CUSTOM_NAME}. `parentToolCallId` links the delegation to the
|
|
135
|
+
* `delegate_task` call that spawned it -- the field AG-UI provides for the
|
|
136
|
+
* "agents as tools" shape -- and is `null` when the server did not send one,
|
|
137
|
+
* which a host reads as a delegation it has nothing to attach to.
|
|
138
|
+
*
|
|
139
|
+
* `subagentRunId` names the child run and is the only id the two closing
|
|
140
|
+
* events carry, so a host that wants to close what it opened has to remember
|
|
141
|
+
* the pairing.
|
|
142
|
+
*/
|
|
143
|
+
onSubAgentStarted(subagentRunId: string, name: string, parentToolCallId: string | null): void;
|
|
144
|
+
/** The delegation named by `subagentRunId` completed. */
|
|
145
|
+
onSubAgentFinished(subagentRunId: string): void;
|
|
146
|
+
/**
|
|
147
|
+
* The delegation named by `subagentRunId` failed.
|
|
148
|
+
*
|
|
149
|
+
* `message` is server text and required by the protocol, but it is not an
|
|
150
|
+
* exception's words: `django-ag-ui` sends only which sub-agent failed, on the
|
|
151
|
+
* same reasoning that redacts a `RUN_ERROR`. Render it as text, never as
|
|
152
|
+
* markup.
|
|
153
|
+
*/
|
|
154
|
+
onSubAgentError(subagentRunId: string, message: string): void;
|
|
130
155
|
onError(message: string): void;
|
|
131
156
|
/**
|
|
132
157
|
* Fired when the user cancelled the run ({@link AgUiClient.cancel}) — the
|
|
@@ -567,6 +592,22 @@ export class AgUiClient {
|
|
|
567
592
|
onCustomEvent({ event }) {
|
|
568
593
|
h.onCustomEvent(event.name, event.value);
|
|
569
594
|
},
|
|
595
|
+
// The delegation lifecycle. Forwarded rather than interpreted here, for
|
|
596
|
+
// the reason every other subscriber in this block is thin: this file
|
|
597
|
+
// adapts the protocol to the handler surface, and what a delegation looks
|
|
598
|
+
// like on screen is the element's business.
|
|
599
|
+
//
|
|
600
|
+
// `parentToolCallId` is optional on the wire and normalised to `null` so
|
|
601
|
+
// the handler has one absent-value to check rather than two.
|
|
602
|
+
onSubagentStartedEvent({ event }) {
|
|
603
|
+
h.onSubAgentStarted(event.subagentRunId, event.name, event.parentToolCallId ?? null);
|
|
604
|
+
},
|
|
605
|
+
onSubagentFinishedEvent({ event }) {
|
|
606
|
+
h.onSubAgentFinished(event.subagentRunId);
|
|
607
|
+
},
|
|
608
|
+
onSubagentErrorEvent({ event }) {
|
|
609
|
+
h.onSubAgentError(event.subagentRunId, event.message);
|
|
610
|
+
},
|
|
570
611
|
onMessagesSnapshotEvent({ event }) {
|
|
571
612
|
h.onMessagesSnapshot(event.messages as readonly Message[]);
|
|
572
613
|
},
|
package/src/ui/styles.ts
CHANGED
|
@@ -524,6 +524,15 @@ export const STYLES = `
|
|
|
524
524
|
floating circle that would escape the host's layout. */
|
|
525
525
|
:host([collapsed]) {
|
|
526
526
|
pointer-events: none;
|
|
527
|
+
/* A collapsed host has to be allowed to shrink, and in the layout hosts
|
|
528
|
+
actually use it is not. Every collapse path here works by letting the host
|
|
529
|
+
size to its content -- the in-flow ones set height: auto, the floating one
|
|
530
|
+
leaves only the launcher -- and a flex or grid parent whose align-items is
|
|
531
|
+
the default stretch value overrides all of it. The panel then hides and the box
|
|
532
|
+
it occupied stays: a header bar over several hundred pixels of nothing.
|
|
533
|
+
Every known consumer hit this, because putting the element in a flex column
|
|
534
|
+
beside the page content is the obvious way to embed it. */
|
|
535
|
+
align-self: start;
|
|
527
536
|
}
|
|
528
537
|
|
|
529
538
|
:host([collapsed]) .chat {
|
package/src/ui/subagent_panel.ts
CHANGED
|
@@ -82,6 +82,18 @@ export class SubAgentPanel {
|
|
|
82
82
|
/** The panel's root; append this into the delegating card's slot. */
|
|
83
83
|
readonly element: HTMLDivElement;
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* The child agent's name, as the last update that carried one gave it.
|
|
87
|
+
*
|
|
88
|
+
* Read back rather than only written to the DOM, because the two carriers
|
|
89
|
+
* split the name away from the close: `SUBAGENT_STARTED` names the agent and
|
|
90
|
+
* `SUBAGENT_FINISHED` carries only an id, so whoever words the closing line
|
|
91
|
+
* has to recover the name from what the delegation already told it.
|
|
92
|
+
*/
|
|
93
|
+
get agent(): string | null {
|
|
94
|
+
return this.#agent;
|
|
95
|
+
}
|
|
96
|
+
|
|
85
97
|
/**
|
|
86
98
|
* The collapsed row, which is the expander as well as the status.
|
|
87
99
|
*
|
|
@@ -94,6 +106,7 @@ export class SubAgentPanel {
|
|
|
94
106
|
readonly #steps: HTMLDivElement;
|
|
95
107
|
/** The child's tool calls, keyed by the child's own call id. */
|
|
96
108
|
readonly #stepRows = new Map<string, HTMLDivElement>();
|
|
109
|
+
#agent: string | null = null;
|
|
97
110
|
|
|
98
111
|
constructor(strings: UiStrings = DEFAULT_UI_STRINGS) {
|
|
99
112
|
this.element = document.createElement("div");
|
|
@@ -151,6 +164,7 @@ export class SubAgentPanel {
|
|
|
151
164
|
report(update: SubAgentUpdate): void {
|
|
152
165
|
this.element.setAttribute("data-phase", update.phase);
|
|
153
166
|
if (update.agent !== null) {
|
|
167
|
+
this.#agent = update.agent;
|
|
154
168
|
this.element.setAttribute("data-agent", update.agent);
|
|
155
169
|
}
|
|
156
170
|
if (update.status !== null) {
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
* renderer: the panel's job is drawing, and a value that reaches it has already
|
|
6
6
|
* been vouched for.
|
|
7
7
|
*
|
|
8
|
+
* **The three lifecycle phases are still accepted here, deliberately.** A current
|
|
9
|
+
* server sends only `tool_call` and `tool_result` on this carrier -- the
|
|
10
|
+
* delegation's lifetime moved to the protocol's `SUBAGENT_*` events -- but a
|
|
11
|
+
* server one release older sends all five, and this element is published and
|
|
12
|
+
* vendored separately from it. Continuing to narrow the older shape costs
|
|
13
|
+
* nothing (the panel needs those phases as visual states regardless) and is the
|
|
14
|
+
* difference between a mixed-version pair that degrades and one that shows a
|
|
15
|
+
* delegation which never opens.
|
|
16
|
+
*
|
|
8
17
|
* Defensive about the payload, not about the name. A `CUSTOM` event's `value` is
|
|
9
18
|
* `unknown` by the protocol, so a server can put anything there, and a malformed
|
|
10
19
|
* announcement must not take a run down with it — the same rule the invalidation
|
package/src/ui/ui_strings.ts
CHANGED
|
@@ -140,6 +140,25 @@ export interface UiStrings {
|
|
|
140
140
|
* must never be blank.
|
|
141
141
|
*/
|
|
142
142
|
subAgentWorking: string;
|
|
143
|
+
/**
|
|
144
|
+
* The row's line while a delegation is running. Token: `{agent}`.
|
|
145
|
+
*
|
|
146
|
+
* Worded here rather than on the wire, unlike the two step phases. The
|
|
147
|
+
* protocol's `SUBAGENT_STARTED` carries the sub-agent's `name` and no rendered
|
|
148
|
+
* status -- which is the better shape for a localised UI, and the reason this
|
|
149
|
+
* string exists at all.
|
|
150
|
+
*/
|
|
151
|
+
subAgentDelegatedTo: string;
|
|
152
|
+
/** The row's line once a delegation completed. Token: `{agent}`. */
|
|
153
|
+
subAgentFinished: string;
|
|
154
|
+
/**
|
|
155
|
+
* The row's line for a delegation that failed and named no agent.
|
|
156
|
+
*
|
|
157
|
+
* A fallback only: `SUBAGENT_ERROR` carries a required `message`, which the
|
|
158
|
+
* server fills with the sub-agent's name and nothing else, and that text is
|
|
159
|
+
* what the row shows. This covers a server that sent an empty one.
|
|
160
|
+
*/
|
|
161
|
+
subAgentFailed: string;
|
|
143
162
|
/** `aria-label` of the region holding the sub-agent's own tool calls. */
|
|
144
163
|
subAgentSteps: string;
|
|
145
164
|
|
|
@@ -332,6 +351,9 @@ export const DEFAULT_UI_STRINGS: UiStrings = {
|
|
|
332
351
|
details: "Details",
|
|
333
352
|
|
|
334
353
|
subAgentWorking: "Working…",
|
|
354
|
+
subAgentDelegatedTo: "Delegated to {agent}",
|
|
355
|
+
subAgentFinished: "{agent} finished",
|
|
356
|
+
subAgentFailed: "The sub-agent failed",
|
|
335
357
|
subAgentSteps: "Steps the sub-agent took",
|
|
336
358
|
|
|
337
359
|
approvalEditArgs: "Edit the arguments before approving",
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION: string = "0.
|
|
1
|
+
export const VERSION: string = "0.32.0";
|