@artooi/ag-ui-web-component 0.1.1 → 0.2.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 +99 -1
- package/README.md +242 -50
- package/dist/ag-ui-web-component.bundle.js +451 -46
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +34 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/{ag_ui_chat.d.ts → core/ag_ui_chat.d.ts} +63 -6
- package/dist/core/ag_ui_chat.d.ts.map +1 -0
- package/dist/{agui_client.d.ts → core/agui_client.d.ts} +13 -0
- package/dist/core/agui_client.d.ts.map +1 -0
- package/dist/core/conversation_store.d.ts.map +1 -0
- package/dist/core/create_http_agent.d.ts.map +1 -0
- package/dist/core/define_ag_ui_chat.d.ts.map +1 -0
- package/dist/dom/animations.d.ts +71 -0
- package/dist/dom/animations.d.ts.map +1 -0
- package/dist/{dom_driver.d.ts → dom/dom_driver.d.ts} +7 -1
- package/dist/dom/dom_driver.d.ts.map +1 -0
- package/dist/dom/native_setter.d.ts +5 -0
- package/dist/dom/native_setter.d.ts.map +1 -0
- package/dist/index.d.ts +19 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3934 -373
- package/dist/index.js.map +4 -4
- package/dist/skills/fill_template.d.ts +17 -0
- package/dist/skills/fill_template.d.ts.map +1 -0
- package/dist/skills/parse_skills.d.ts +8 -0
- package/dist/skills/parse_skills.d.ts.map +1 -0
- package/dist/skills/skill.d.ts +24 -0
- package/dist/skills/skill.d.ts.map +1 -0
- package/dist/{client_tool_registry.d.ts → tools/client_tool_registry.d.ts} +6 -1
- package/dist/tools/client_tool_registry.d.ts.map +1 -0
- package/dist/tools/is_destructive.d.ts.map +1 -0
- package/dist/tools/is_navigates.d.ts.map +1 -0
- package/dist/tools/page_map.d.ts.map +1 -0
- package/dist/tools/route_map.d.ts +40 -0
- package/dist/tools/route_map.d.ts.map +1 -0
- package/dist/tools/state_hook.d.ts.map +1 -0
- package/dist/ui/confirmation_card.d.ts +22 -0
- package/dist/ui/confirmation_card.d.ts.map +1 -0
- package/dist/ui/render_markdown.d.ts +13 -0
- package/dist/ui/render_markdown.d.ts.map +1 -0
- package/dist/ui/reveal_words.d.ts +8 -0
- package/dist/ui/reveal_words.d.ts.map +1 -0
- package/dist/ui/skills_menu.d.ts +35 -0
- package/dist/ui/skills_menu.d.ts.map +1 -0
- package/dist/ui/styles.d.ts +2 -0
- package/dist/ui/styles.d.ts.map +1 -0
- package/dist/ui/tool_call_card.d.ts +35 -0
- package/dist/ui/tool_call_card.d.ts.map +1 -0
- package/package.json +5 -3
- package/src/constants.ts +38 -0
- package/src/core/ag_ui_chat.ts +851 -0
- package/src/{agui_client.ts → core/agui_client.ts} +19 -1
- package/src/{define_ag_ui_chat.ts → core/define_ag_ui_chat.ts} +1 -1
- package/src/dom/animations.ts +201 -0
- package/src/{dom_driver.ts → dom/dom_driver.ts} +35 -2
- package/src/dom/native_setter.ts +42 -0
- package/src/index.ts +61 -32
- package/src/skills/fill_template.ts +32 -0
- package/src/skills/parse_skills.ts +26 -0
- package/src/skills/skill.ts +23 -0
- package/src/{client_tool_registry.ts → tools/client_tool_registry.ts} +6 -4
- package/src/{is_destructive.ts → tools/is_destructive.ts} +1 -1
- package/src/{is_navigates.ts → tools/is_navigates.ts} +1 -1
- package/src/tools/route_map.ts +140 -0
- package/src/{state_hook.ts → tools/state_hook.ts} +1 -1
- package/src/ui/confirmation_card.ts +71 -0
- package/src/ui/render_markdown.ts +68 -0
- package/src/ui/reveal_words.ts +41 -0
- package/src/ui/skills_menu.ts +171 -0
- package/src/ui/styles.ts +631 -0
- package/src/{tool_call_card.ts → ui/tool_call_card.ts} +50 -19
- package/src/version.ts +1 -1
- package/dist/ag_ui_chat.d.ts.map +0 -1
- package/dist/agui_client.d.ts.map +0 -1
- package/dist/animations.d.ts +0 -33
- package/dist/animations.d.ts.map +0 -1
- package/dist/client_tool_registry.d.ts.map +0 -1
- package/dist/confirmation_modal.d.ts +0 -14
- package/dist/confirmation_modal.d.ts.map +0 -1
- package/dist/conversation_store.d.ts.map +0 -1
- package/dist/create_http_agent.d.ts.map +0 -1
- package/dist/define_ag_ui_chat.d.ts.map +0 -1
- package/dist/dom_driver.d.ts.map +0 -1
- package/dist/is_destructive.d.ts.map +0 -1
- package/dist/is_navigates.d.ts.map +0 -1
- package/dist/page_map.d.ts.map +0 -1
- package/dist/route_map.d.ts +0 -27
- package/dist/route_map.d.ts.map +0 -1
- package/dist/state_hook.d.ts.map +0 -1
- package/dist/styles.d.ts +0 -2
- package/dist/styles.d.ts.map +0 -1
- package/dist/tool_call_card.d.ts +0 -29
- package/dist/tool_call_card.d.ts.map +0 -1
- package/src/ag_ui_chat.ts +0 -411
- package/src/animations.ts +0 -86
- package/src/confirmation_modal.ts +0 -69
- package/src/route_map.ts +0 -83
- package/src/styles.ts +0 -296
- /package/dist/{conversation_store.d.ts → core/conversation_store.d.ts} +0 -0
- /package/dist/{create_http_agent.d.ts → core/create_http_agent.d.ts} +0 -0
- /package/dist/{define_ag_ui_chat.d.ts → core/define_ag_ui_chat.d.ts} +0 -0
- /package/dist/{is_destructive.d.ts → tools/is_destructive.d.ts} +0 -0
- /package/dist/{is_navigates.d.ts → tools/is_navigates.d.ts} +0 -0
- /package/dist/{page_map.d.ts → tools/page_map.d.ts} +0 -0
- /package/dist/{state_hook.d.ts → tools/state_hook.d.ts} +0 -0
- /package/src/{conversation_store.ts → core/conversation_store.ts} +0 -0
- /package/src/{create_http_agent.ts → core/create_http_agent.ts} +0 -0
- /package/src/{page_map.ts → tools/page_map.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,102 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] — 2026-06-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Server-side tool results in the card.** The element now subscribes to
|
|
14
|
+
AG-UI's `TOOL_CALL_RESULT` event and settles the matching tool-call card with
|
|
15
|
+
the real server output (honouring the `data-tool-display` mode), instead of
|
|
16
|
+
the generic "Executed on the server." placeholder — which remains only as a
|
|
17
|
+
fallback when no result event is streamed.
|
|
18
|
+
- **Tool calls and results survive a page refresh.** History replay now
|
|
19
|
+
reconstructs tool-call cards (from assistant `toolCalls`) and settles them
|
|
20
|
+
from the persisted `tool` result messages, so a rehydrated transcript shows
|
|
21
|
+
the full tool activity, not just the prose. Applies to every conversation
|
|
22
|
+
store (the data was already persisted; only the replay was incomplete).
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Pending indicator could hang after a server-only round.** A round whose
|
|
26
|
+
tool calls were all server-side re-showed the "thinking" indicator after the
|
|
27
|
+
run had already finished, leaving it stuck. The indicator is no longer shown
|
|
28
|
+
speculatively for server tools, and a terminal `onSettled` guarantee clears
|
|
29
|
+
it (and re-enables input) on every run-loop exit — including the
|
|
30
|
+
`MAX_TOOL_ROUNDS` ceiling and errors.
|
|
31
|
+
|
|
32
|
+
## [0.2.0] — 2026-06-02
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- **Markdown + HTML rendering** in assistant message bubbles (`renderMarkdown`),
|
|
36
|
+
sanitised with DOMPurify (scripts, event handlers, and `javascript:` URLs
|
|
37
|
+
stripped; links hardened with `target`/`rel`). User messages stay literal.
|
|
38
|
+
- **Pending indicator** — an animated "thinking" indicator shown while the agent
|
|
39
|
+
is awaited (before the first token and between tool rounds), honouring
|
|
40
|
+
`prefers-reduced-motion`.
|
|
41
|
+
- **New-chat button** in the header — clears the transcript, the persisted
|
|
42
|
+
conversation, and the in-memory run state, and mints a fresh thread.
|
|
43
|
+
- **Collapse seam** — a reflected `collapsed` attribute, a built-in header
|
|
44
|
+
toggle, a persisted (per-tab) collapsed state, and a `TOGGLE_EVENT`
|
|
45
|
+
(`ag-ui-toggle`) so a host can drive its own chrome.
|
|
46
|
+
- **Tool-call display modes** (`TOOL_DISPLAY`, `data-tool-display`): `minimal`
|
|
47
|
+
(name + status), `compact` (args + result behind one "Details" toggle), and
|
|
48
|
+
`full` (the default; original behaviour).
|
|
49
|
+
- **Richer action animations**: `pressThenClick`, `selectOption`,
|
|
50
|
+
`toggleControl` (+ `pressButton` / `selectControl` / `toggleCheckbox` driver
|
|
51
|
+
wrappers), all honouring `prefers-reduced-motion`.
|
|
52
|
+
- **Dynamic route syntax**: `Route.path` supports `:name` placeholders;
|
|
53
|
+
`navigate_to_route` substitutes path params (leftover params → query string)
|
|
54
|
+
and `list_routes` advertises each route's `pathParams`.
|
|
55
|
+
- `X_CONFIRM_KEY` (`x-confirm`) tool metadata for a human-readable confirmation
|
|
56
|
+
prompt.
|
|
57
|
+
- `setNativeValue` / `setNativeChecked` utilities (also used internally).
|
|
58
|
+
- **Theming** — a `theme` attribute (`light` / `dark` / `auto` / `code`); `auto`
|
|
59
|
+
follows `prefers-color-scheme`, `code` is a monospace terminal palette. Plus a
|
|
60
|
+
wider set of themeable `--ag-ui-*` variables.
|
|
61
|
+
- **Density + placement presets** — `density` (`comfortable` / `compact`) and
|
|
62
|
+
`placement` (`bottom-left` / `side` / `full` / `embedded`); `embedded` drops
|
|
63
|
+
the floating chrome and high z-index so the widget lives in the host layout.
|
|
64
|
+
- **Incoming-text animations** — `data-text-animation` (`none` / `fade` /
|
|
65
|
+
`word`), the last revealing assistant text word-by-word; honours
|
|
66
|
+
`prefers-reduced-motion`.
|
|
67
|
+
- **`confirmPredicate`** — a per-call `(toolName, args) => boolean | Promise`
|
|
68
|
+
hook deciding confirmation dynamically (authoritative over `x-destructive`).
|
|
69
|
+
- **Built-in `read_page` tool** — present when a `getPageMap` provider is set, so
|
|
70
|
+
the agent can re-read the page mid-turn after acting.
|
|
71
|
+
- **`x-summary`** tool metadata (`X_SUMMARY_KEY`) — a friendly label shown on the
|
|
72
|
+
tool-call card instead of the raw tool name.
|
|
73
|
+
- `observedAttributes` / `attributeChangedCallback` so a late `title-text`
|
|
74
|
+
change updates the header.
|
|
75
|
+
- Accessibility: `role="log"`/`aria-live` on the transcript, `role="status"` on
|
|
76
|
+
the pending indicator, `role="group"` on the confirmation card, input label.
|
|
77
|
+
- **Skills** — pre-defined prompts surfaced as **chips** (`data-prompt-chips`)
|
|
78
|
+
and/or a **`/`-command palette** (`data-slash-commands`), both opt-in over one
|
|
79
|
+
catalog. Catalog from the `skills` setter (`setSkills`), a `data-skills` JSON
|
|
80
|
+
embed, and/or a fetched `data-skills-url` (merged backend → embed → client).
|
|
81
|
+
Picking pre-fills the input (or auto-sends with `sendImmediately`); prompts
|
|
82
|
+
support `{placeholder}`s filled from `skillContext`, with a missing value
|
|
83
|
+
blocking the send and showing a hint. Exports the `Skill` type.
|
|
84
|
+
|
|
85
|
+
### Changed
|
|
86
|
+
- The destructive-action confirmation is now an **inline card in the transcript**
|
|
87
|
+
(Confirm / Cancel, with the `x-confirm` message) instead of a focus-stealing
|
|
88
|
+
modal overlay. `requestConfirmation` now renders inline; the
|
|
89
|
+
`confirmation_modal` module was removed.
|
|
90
|
+
- **Framework-controlled inputs now work.** `fillField` / `typeInto` /
|
|
91
|
+
`selectOption` / `toggleControl` / `setControlValue` set `value` / `checked`
|
|
92
|
+
through the **native prototype setter** before dispatching `input`, so
|
|
93
|
+
React/Vue/Svelte value-tracking sees the change (previously the field looked
|
|
94
|
+
filled but host state stayed empty).
|
|
95
|
+
- **Framework interop:** reflecting **property setters** for `endpoint`,
|
|
96
|
+
`toolDisplay`, and `collapsed` (React 19 assigns matching props as element
|
|
97
|
+
properties — getter-only props previously threw).
|
|
98
|
+
- `registerTool` is now **idempotent** — re-registering a tool name replaces it
|
|
99
|
+
instead of throwing (re-fired refs / React StrictMode).
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
- The Markdown/HTML allowlist now permits sanitised **`<img>`** (safe-scheme
|
|
103
|
+
`src`, no event handlers); `javascript:` srcs and disallowed tags (e.g.
|
|
104
|
+
`iframe`) are still stripped.
|
|
105
|
+
|
|
10
106
|
## [0.1.1] — 2026-06-01
|
|
11
107
|
|
|
12
108
|
### Changed
|
|
@@ -33,6 +129,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
33
129
|
### Notes
|
|
34
130
|
- First release — exercising the automated npm OIDC publish pipeline end-to-end.
|
|
35
131
|
|
|
36
|
-
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.
|
|
132
|
+
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.2.1...HEAD
|
|
133
|
+
[0.2.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.2.0...v0.2.1
|
|
134
|
+
[0.2.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.1.1...v0.2.0
|
|
37
135
|
[0.1.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.1.0...v0.1.1
|
|
38
136
|
[0.1.0]: https://github.com/Artui/ag-ui-web-component/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -17,8 +17,13 @@ It wraps [`@ag-ui/client`](https://www.npmjs.com/package/@ag-ui/client)'s `HttpA
|
|
|
17
17
|
- Generic **DOM-driver primitives** (`fillField`, `clickElement`, `setControlValue`) and
|
|
18
18
|
**animation primitives** (`typeInto`, `highlightThenClick`, …) so the agent can drive the page
|
|
19
19
|
at human-readable speed.
|
|
20
|
-
-
|
|
21
|
-
carries `x-destructive: true`) before the handler
|
|
20
|
+
- An **inline confirmation card** that intercepts tool calls needing confirmation (those whose
|
|
21
|
+
JSON Schema carries `x-destructive: true`, or a per-call `confirmPredicate`) before the handler
|
|
22
|
+
runs — rendered right in the transcript, never a modal overlay.
|
|
23
|
+
- **Markdown + HTML rendering** of assistant replies (sanitized `marked` + DOMPurify), with
|
|
24
|
+
themes, density/placement presets, incoming-text animations, tool-call display modes, an
|
|
25
|
+
animated thinking indicator, and an opt-in **skills** palette (prompt chips + `/`-commands).
|
|
26
|
+
- A **new-chat** button and a **collapse** toggle built into the header.
|
|
22
27
|
- An **MPA durability story**: a durable conversation store, a stable thread id, and a resumable
|
|
23
28
|
run loop that survives full page reloads (`x-navigates` + `navigationResult`).
|
|
24
29
|
- **Host seams** for SPAs: a route map, an auto-injected page map, state hooks, and an optional
|
|
@@ -36,12 +41,16 @@ No framework, no Django, no admin specifics live here. Downstream consumers (e.g
|
|
|
36
41
|
- [Core concepts](#core-concepts)
|
|
37
42
|
- [The run loop and the AG-UI client](#the-run-loop-and-the-ag-ui-client)
|
|
38
43
|
- [Registering tools](#registering-tools)
|
|
39
|
-
- [
|
|
44
|
+
- [Inline confirmation (`x-destructive` / `x-confirm` / `confirmPredicate`)](#inline-confirmation-x-destructive--x-confirm--confirmpredicate)
|
|
40
45
|
- [DOM-driver and animation primitives](#dom-driver-and-animation-primitives)
|
|
46
|
+
- [New chat and collapse](#new-chat-and-collapse)
|
|
47
|
+
- [Tool-call display modes](#tool-call-display-modes)
|
|
48
|
+
- [Markdown rendering](#markdown-rendering)
|
|
49
|
+
- [Skills: prompt chips and slash palette](#skills-prompt-chips-and-slash-palette)
|
|
41
50
|
- [MPA durability: surviving full page reloads](#mpa-durability-surviving-full-page-reloads)
|
|
42
51
|
- [Host seams: the SPA story](#host-seams-the-spa-story)
|
|
43
52
|
- [Public API surface](#public-api-surface)
|
|
44
|
-
- [Theming](#theming)
|
|
53
|
+
- [Theming, density, and placement](#theming-density-and-placement)
|
|
45
54
|
- [Building the bundle](#building-the-bundle)
|
|
46
55
|
- [Compatibility](#compatibility)
|
|
47
56
|
|
|
@@ -110,7 +119,7 @@ Drop the element into your page and register the tools the agent may call:
|
|
|
110
119
|
});
|
|
111
120
|
|
|
112
121
|
// A destructive tool: x-destructive at the JSON-Schema root gates it behind
|
|
113
|
-
// the confirmation
|
|
122
|
+
// the inline confirmation card before the handler runs.
|
|
114
123
|
chat.registerTool({
|
|
115
124
|
name: "save_article",
|
|
116
125
|
description: "Save the article. Destructive — asks for confirmation.",
|
|
@@ -130,14 +139,32 @@ That's the whole integration: an `endpoint` attribute pointing at your AG-UI ser
|
|
|
130
139
|
|
|
131
140
|
### Attributes and properties
|
|
132
141
|
|
|
142
|
+
**Attributes** (set in HTML; the CSS-only ones are styling presets with no JS API):
|
|
143
|
+
|
|
133
144
|
| Attribute | Property | Notes |
|
|
134
145
|
| --- | --- | --- |
|
|
135
|
-
| `endpoint` | `endpoint`
|
|
136
|
-
| `title-text` | — | Header label; defaults to `"Assistant"`. |
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
|
|
140
|
-
|
|
146
|
+
| `endpoint` | `endpoint` | The AG-UI endpoint URL. Required to send. Reflecting getter + setter. |
|
|
147
|
+
| `title-text` | — | Header label; defaults to `"Assistant"`. The only **observed** attribute (live-updates the header). |
|
|
148
|
+
| `data-tool-display` | `toolDisplay` | Tool-call card detail: `minimal` / `compact` / `full` (default `full`). |
|
|
149
|
+
| `data-text-animation` | — | Incoming-text reveal: `none` (default) / `fade` / `word`. |
|
|
150
|
+
| `data-prompt-chips` | — | `"true"` to surface skills as chips. |
|
|
151
|
+
| `data-slash-commands` | — | `"true"` to enable the `/`-command palette. |
|
|
152
|
+
| `data-skills` | — | Inline JSON skill catalog. |
|
|
153
|
+
| `data-skills-url` | — | URL of a JSON skill catalog (fetched with `headers`). |
|
|
154
|
+
| `collapsed` | `collapsed` | Reflected boolean; collapses the widget. Persisted per-tab in `sessionStorage`. |
|
|
155
|
+
| `theme` | — | CSS-only: `light` (default) / `dark` / `auto` / `code`. |
|
|
156
|
+
| `density` | — | CSS-only: `comfortable` (default) / `compact`. |
|
|
157
|
+
| `placement` | — | CSS-only: `floating` (default) / `bottom-left` / `side` / `full` / `embedded`. |
|
|
158
|
+
|
|
159
|
+
**Properties** (JS only, not attributes): `headers`, `autoConfirm`, `confirmPredicate`,
|
|
160
|
+
`agentFactory`, `getTools`, `getContext`, `routeMap`, `navigate`, `getPageMap`,
|
|
161
|
+
`autoInjectPageMap`, `conversationStore`, `navigationResult`, `skillContext`, plus the mirrors
|
|
162
|
+
`endpoint` / `toolDisplay` / `collapsed`.
|
|
163
|
+
|
|
164
|
+
**Methods**: `registerTool`, `registerStateHook`, `setSkills`, `appendMessage`, `newChat`,
|
|
165
|
+
`setCollapsed`, `toggleCollapsed`.
|
|
166
|
+
|
|
167
|
+
A self-contained live playground lives in [`demo/`](demo/) — run `make demo` to serve it against a
|
|
141
168
|
mock AG-UI server.
|
|
142
169
|
|
|
143
170
|
---
|
|
@@ -146,9 +173,9 @@ mock AG-UI server.
|
|
|
146
173
|
|
|
147
174
|
### The run loop and the AG-UI client
|
|
148
175
|
|
|
149
|
-
`<ag-ui-chat>` is the view; [`AgUiClient`](src/agui_client.ts) is the orchestration layer over
|
|
150
|
-
AG-UI `AbstractAgent`. On the first send the element builds a client (via the overridable
|
|
151
|
-
`agentFactory`, which defaults to [`createHttpAgent`](src/create_http_agent.ts)). Each turn:
|
|
176
|
+
`<ag-ui-chat>` is the view; [`AgUiClient`](src/core/agui_client.ts) is the orchestration layer over
|
|
177
|
+
an AG-UI `AbstractAgent`. On the first send the element builds a client (via the overridable
|
|
178
|
+
`agentFactory`, which defaults to [`createHttpAgent`](src/core/create_http_agent.ts)). Each turn:
|
|
152
179
|
|
|
153
180
|
1. The user message is appended and the agent runs once.
|
|
154
181
|
2. AG-UI subscriber events are translated into the element's handlers — streaming text deltas
|
|
@@ -158,8 +185,10 @@ AG-UI `AbstractAgent`. On the first send the element builds a client (via the ov
|
|
|
158
185
|
4. This repeats until the agent stops calling frontend tools, bounded by `MAX_TOOL_ROUNDS`.
|
|
159
186
|
|
|
160
187
|
Tool calls the client doesn't own (server-side tools the server already executed) are left alone —
|
|
161
|
-
the loop doesn't re-run them
|
|
162
|
-
(
|
|
188
|
+
the loop doesn't re-run them, but their streamed `TOOL_CALL_RESULT` is rendered into the tool-call
|
|
189
|
+
card (honouring `data-tool-display`), so server-side output is visible too. The current tool catalog
|
|
190
|
+
and context are read **fresh on every run** (`getTools()` / `getContext()`), so they always reflect
|
|
191
|
+
the current page state.
|
|
163
192
|
|
|
164
193
|
### Registering tools
|
|
165
194
|
|
|
@@ -184,48 +213,181 @@ Names must be unique (registering a duplicate throws). Each `<ag-ui-chat>` eleme
|
|
|
184
213
|
registry, AG-UI client, and Shadow DOM, so **multiple instances on one page never interfere** —
|
|
185
214
|
there is no module-level shared state anywhere in the package.
|
|
186
215
|
|
|
187
|
-
###
|
|
216
|
+
### Inline confirmation (`x-destructive` / `x-confirm` / `confirmPredicate`)
|
|
217
|
+
|
|
218
|
+
When a tool call needs confirmation, the element appends an **inline confirmation card** (a
|
|
219
|
+
`<div class="confirm">`) to the transcript via
|
|
220
|
+
[`requestConfirmation`](src/ui/confirmation_card.ts) — it is not a modal overlay. The card reads
|
|
221
|
+
naturally after the assistant's explanation, never steals focus from the page, and stays in the
|
|
222
|
+
transcript as a resolved record after the decision:
|
|
223
|
+
|
|
224
|
+
- **Confirm** → the handler runs and the result is posted back.
|
|
225
|
+
- **Cancel** → a `"User declined the action."` result is posted; the agent acknowledges on its
|
|
226
|
+
next turn.
|
|
227
|
+
|
|
228
|
+
Whether a call is gated is decided in this order:
|
|
229
|
+
|
|
230
|
+
1. If `chat.autoConfirm === true`, the call **never** prompts (an "autopilot" toggle).
|
|
231
|
+
2. Else if `chat.confirmPredicate` is set, its boolean return is authoritative — given the tool
|
|
232
|
+
name + parsed args it decides per-call (so one tool can be instant for some args and confirmed
|
|
233
|
+
for others, which a static flag can't express).
|
|
234
|
+
3. Else the element falls back to [`isDestructive(parameters)`](src/tools/is_destructive.ts),
|
|
235
|
+
which reads the `x-destructive` JSON-Schema flag.
|
|
188
236
|
|
|
189
237
|
AG-UI has no built-in risk flag, so destructiveness is carried as a JSON-Schema extension at the
|
|
190
238
|
**schema root**: `parameters["x-destructive"] = true` (use the exported `X_DESTRUCTIVE_KEY`
|
|
191
|
-
constant). There is no parallel metadata channel
|
|
192
|
-
|
|
193
|
-
|
|
239
|
+
constant). There is no parallel metadata channel and no name heuristic — destructiveness is exactly
|
|
240
|
+
the `x-destructive` flag (or `confirmPredicate`). The registry forwards the flag verbatim to
|
|
241
|
+
`RunAgentInput.tools`.
|
|
194
242
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
dispatching to the handler:
|
|
243
|
+
If the schema carries an `x-confirm` string (use `X_CONFIRM_KEY`), the card shows it as the prompt;
|
|
244
|
+
otherwise it falls back to a generic `Run "<tool>"?`.
|
|
198
245
|
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
|
|
246
|
+
```js
|
|
247
|
+
// Per-call: confirm a delete only when it would remove more than one row.
|
|
248
|
+
chat.confirmPredicate = (name, args) =>
|
|
249
|
+
name === "delete_rows" && Array.isArray(args.ids) && args.ids.length > 1;
|
|
202
250
|
|
|
203
|
-
|
|
251
|
+
// Prompt text via x-confirm:
|
|
252
|
+
chat.registerTool({
|
|
253
|
+
name: "activate_project",
|
|
254
|
+
description: "Activate the current project.",
|
|
255
|
+
parameters: { type: "object", properties: {}, [X_DESTRUCTIVE_KEY]: true, [X_CONFIRM_KEY]: "Activate this project?" },
|
|
256
|
+
handler: async () => await api.activate(),
|
|
257
|
+
});
|
|
258
|
+
```
|
|
204
259
|
|
|
205
260
|
### DOM-driver and animation primitives
|
|
206
261
|
|
|
207
262
|
So the agent can visibly drive the host page, the package ships generic, framework-free
|
|
208
|
-
primitives. The **animation** primitives ([`animations.ts`](src/animations.ts)) operate at
|
|
263
|
+
primitives. The **animation** primitives ([`animations.ts`](src/dom/animations.ts)) operate at
|
|
209
264
|
human-readable speed (configurable; pass small/zero durations in tests):
|
|
210
265
|
|
|
211
266
|
- `typeInto(el, value, { charDelayMs })` — clears and types a value character by character,
|
|
212
267
|
firing `input`/`change` events as a real user would.
|
|
213
|
-
- `highlightThenClick(el, { highlightMs })`
|
|
268
|
+
- `highlightThenClick(el, { highlightMs })` / `pressThenClick(el, options)` — outline/press an
|
|
269
|
+
element, pause, then click.
|
|
270
|
+
- `selectOption(el, value)` / `toggleControl(el, checked)` — animate a `<select>` / checkbox.
|
|
214
271
|
- `scrollIntoCenterView(el)` / `focusWithFlash(el, { flashMs })`.
|
|
272
|
+
- `prefersReducedMotion()` — honoured throughout so animations collapse to instant when the user
|
|
273
|
+
asks for reduced motion.
|
|
215
274
|
|
|
216
|
-
The **DOM-driver** primitives ([`dom_driver.ts`](src/dom_driver.ts)) compose those into the
|
|
275
|
+
The **DOM-driver** primitives ([`dom_driver.ts`](src/dom/dom_driver.ts)) compose those into the
|
|
217
276
|
operations a tool handler typically wants:
|
|
218
277
|
|
|
219
278
|
- `fillField(el, value, options)` — scroll to, focus-flash, and type into a text field.
|
|
220
|
-
- `clickElement(el, options)` — scroll to, highlight, and click.
|
|
279
|
+
- `clickElement(el, options)` / `pressButton(el, options)` — scroll to, highlight/press, and click.
|
|
280
|
+
- `selectControl(el, value)` / `toggleCheckbox(el, checked)` — animate a `<select>` / checkbox.
|
|
221
281
|
- `setControlValue(el, value)` — set a `<select>` or checkbox without animation, dispatching
|
|
222
282
|
`input`/`change`.
|
|
223
283
|
|
|
284
|
+
The native-setter helpers ([`native_setter.ts`](src/dom/native_setter.ts)) — `setNativeValue` /
|
|
285
|
+
`setNativeChecked` — set a control through its native prototype setter so React-controlled inputs
|
|
286
|
+
register the change.
|
|
287
|
+
|
|
224
288
|
Each takes an element the caller has already located; host packages wrap them with
|
|
225
289
|
environment-aware lookups (e.g. "find `#id_<name>`, then `fillField`").
|
|
226
290
|
|
|
227
291
|
---
|
|
228
292
|
|
|
293
|
+
## New chat and collapse
|
|
294
|
+
|
|
295
|
+
The header carries two built-in buttons: a new-chat (✚) button and a collapse (—) toggle. The
|
|
296
|
+
matching JS API:
|
|
297
|
+
|
|
298
|
+
- `newChat()` — clears the transcript and the persisted history, drops the in-memory run state,
|
|
299
|
+
and mints a new thread id.
|
|
300
|
+
- `setCollapsed(collapsed)` / `toggleCollapsed()` — collapse or expand the widget. The state is
|
|
301
|
+
reflected as the boolean `collapsed` attribute/property and persisted per-tab in
|
|
302
|
+
`sessionStorage`, so it survives a reload.
|
|
303
|
+
|
|
304
|
+
Each change emits an `ag-ui-toggle` event (the `TOGGLE_EVENT` constant) with
|
|
305
|
+
`detail: { collapsed: boolean }` (typed `ToggleDetail`), so a host can mirror the state in its own
|
|
306
|
+
chrome — or hide the built-in toggle and drive the `collapsed` attribute itself.
|
|
307
|
+
|
|
308
|
+
```js
|
|
309
|
+
chat.newChat();
|
|
310
|
+
chat.toggleCollapsed();
|
|
311
|
+
chat.addEventListener("ag-ui-toggle", (e) => console.log(e.detail.collapsed));
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Tool-call display modes
|
|
317
|
+
|
|
318
|
+
How much a tool-call card shows is set via the `data-tool-display` attribute (or `toolDisplay`
|
|
319
|
+
property), one of `minimal` / `compact` / `full` (default `full`):
|
|
320
|
+
|
|
321
|
+
- `minimal` — tool name + status pill only.
|
|
322
|
+
- `compact` — name + status, with args *and* result behind a single collapsed "Details" toggle.
|
|
323
|
+
- `full` — args inline, result behind its own toggle (the original behaviour).
|
|
324
|
+
|
|
325
|
+
If a tool's schema carries an `x-summary` string (use `X_SUMMARY_KEY`), the card shows it on the
|
|
326
|
+
label instead of the raw tool name.
|
|
327
|
+
|
|
328
|
+
```html
|
|
329
|
+
<ag-ui-chat endpoint="/agent/" data-tool-display="compact"></ag-ui-chat>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Markdown rendering
|
|
335
|
+
|
|
336
|
+
Assistant bubbles render sanitized markdown/HTML via [`marked`](https://www.npmjs.com/package/marked)
|
|
337
|
+
(GitHub-flavoured, single-newline line breaks) piped through
|
|
338
|
+
[DOMPurify](https://www.npmjs.com/package/dompurify). User messages stay literal text. The
|
|
339
|
+
allowlist permits emphasis, code, lists, quotes, headings, links, tables, and images (`img`); links
|
|
340
|
+
are hardened with `target="_blank" rel="noopener noreferrer"`; `iframe`/`style`/scripting are
|
|
341
|
+
excluded. The exported helper `renderMarkdown(text)` does this standalone. `marked` and `dompurify`
|
|
342
|
+
are runtime dependencies.
|
|
343
|
+
|
|
344
|
+
An animated 3-dot "thinking" indicator (`role="status"`, with an aria-label) appears before the
|
|
345
|
+
first token and between tool rounds, honouring `prefers-reduced-motion`. It has no public API.
|
|
346
|
+
|
|
347
|
+
### Incoming-text animations
|
|
348
|
+
|
|
349
|
+
The `data-text-animation` attribute controls how a fully-received assistant message reveals:
|
|
350
|
+
`none` (default) / `fade` (a CSS fade) / `word` (JS word-by-word via the internal `wrapWords`
|
|
351
|
+
reveal). It honours `prefers-reduced-motion` (collapsing to instant).
|
|
352
|
+
|
|
353
|
+
```html
|
|
354
|
+
<ag-ui-chat endpoint="/agent/" data-text-animation="word"></ag-ui-chat>
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Skills: prompt chips and slash palette
|
|
360
|
+
|
|
361
|
+
Skills are pre-defined prompts the user can launch from a chip or the `/`-command palette. They are
|
|
362
|
+
opt-in via two attributes:
|
|
363
|
+
|
|
364
|
+
```html
|
|
365
|
+
<ag-ui-chat endpoint="/agent/" data-prompt-chips="true" data-slash-commands="true"></ag-ui-chat>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
A `Skill` is `{ name, title, description?, prompt, sendImmediately?, chip? }`. Skills are merged
|
|
369
|
+
from three sources — **backend → embed → client** (later wins by `name`):
|
|
370
|
+
|
|
371
|
+
- `data-skills-url` — a JSON endpoint, fetched with the element's `headers`.
|
|
372
|
+
- `data-skills` — an inline JSON catalog.
|
|
373
|
+
- `setSkills(skills)` — set the client catalog from JS.
|
|
374
|
+
|
|
375
|
+
```js
|
|
376
|
+
chat.setSkills([
|
|
377
|
+
{ name: "summarize", title: "Summarize page", prompt: "Summarize {title}.", chip: true },
|
|
378
|
+
]);
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
A skill `prompt` may contain `{placeholder}` tokens; the `skillContext` property
|
|
382
|
+
(`() => Record<string, unknown>`) supplies the values, filled in before send. A missing placeholder
|
|
383
|
+
blocks the send and shows a hint instead.
|
|
384
|
+
|
|
385
|
+
```js
|
|
386
|
+
chat.skillContext = () => ({ title: document.title });
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
229
391
|
## MPA durability: surviving full page reloads
|
|
230
392
|
|
|
231
393
|
In a multi-page app, a tool that navigates reloads the whole page and destroys the in-memory run
|
|
@@ -234,10 +396,10 @@ mechanisms.
|
|
|
234
396
|
|
|
235
397
|
**1. Thread identity.** AG-UI's `thread_id` is the conversation key. It is generated once and
|
|
236
398
|
persisted (so the element reattaches after a reload) by the
|
|
237
|
-
[`ClientConversationStore`](src/conversation_store.ts).
|
|
399
|
+
[`ClientConversationStore`](src/core/conversation_store.ts).
|
|
238
400
|
|
|
239
401
|
**2. Durable conversation.** A pluggable `ClientConversationStore` holds the message list. The
|
|
240
|
-
default [`SessionStorageStore`](src/conversation_store.ts) keeps everything per-tab in
|
|
402
|
+
default [`SessionStorageStore`](src/core/conversation_store.ts) keeps everything per-tab in
|
|
241
403
|
`sessionStorage`, so the chat survives full page reloads and clears on tab close. `loadMessages`
|
|
242
404
|
is async-friendly, so a host can inject a server-backed store (e.g. one that rehydrates from a
|
|
243
405
|
history endpoint) for cross-tab/device durability:
|
|
@@ -246,10 +408,12 @@ history endpoint) for cross-tab/device durability:
|
|
|
246
408
|
chat.conversationStore = new MyServerBackedStore();
|
|
247
409
|
```
|
|
248
410
|
|
|
249
|
-
On mount the element rehydrates the transcript from the store, so the chat looks continuous
|
|
411
|
+
On mount the element rehydrates the transcript from the store, so the chat looks continuous —
|
|
412
|
+
including tool-call cards and their results (reconstructed from the persisted `toolCalls` and `tool`
|
|
413
|
+
messages), not just the text turns.
|
|
250
414
|
|
|
251
415
|
**3. Resumable loop (`x-navigates` + `navigationResult`).** A tool whose schema carries
|
|
252
|
-
`x-navigates: true` (use `X_NAVIGATES_KEY`; read back by [`isNavigates`](src/is_navigates.ts))
|
|
416
|
+
`x-navigates: true` (use `X_NAVIGATES_KEY`; read back by [`isNavigates`](src/tools/is_navigates.ts))
|
|
253
417
|
triggers a full reload. Before the handler navigates, the element writes a checkpoint
|
|
254
418
|
(`{ toolCallId }`) to the store. On the next page mount it:
|
|
255
419
|
|
|
@@ -276,10 +440,16 @@ rather than by exploring:
|
|
|
276
440
|
- `list_routes` — read-only; lists the routes.
|
|
277
441
|
- `navigate_to_route(route_id, params?)` — resolves the id to a path and navigates.
|
|
278
442
|
|
|
443
|
+
A route `path` may contain `:param` segments — e.g. `/projects/:id/users/:userId/`.
|
|
444
|
+
`navigate_to_route` substitutes the path params (URL-encoded) and sends any leftover params as a
|
|
445
|
+
query string; a missing or empty required path param throws. The resolved shape is the exported
|
|
446
|
+
`RouteWithParams` type.
|
|
447
|
+
|
|
279
448
|
```js
|
|
280
449
|
chat.routeMap = [
|
|
281
450
|
{ id: "users", path: "/users", title: "Users", description: "Manage user accounts" },
|
|
282
451
|
{ id: "billing", path: "/billing", title: "Billing" },
|
|
452
|
+
{ id: "user-detail", path: "/projects/:id/users/:userId/", title: "User detail" },
|
|
283
453
|
];
|
|
284
454
|
```
|
|
285
455
|
|
|
@@ -333,6 +503,7 @@ re-export point. Internal modules import from leaf paths.
|
|
|
333
503
|
| `defineAgUiChat()` | function | Idempotently register the element. |
|
|
334
504
|
| `MessageRole` | type | Role of a rendered chat message. |
|
|
335
505
|
| `SubmitDetail` | type | `detail` shape of the submit event. |
|
|
506
|
+
| `ToggleDetail` | type | `detail` shape of the `ag-ui-toggle` event (`{ collapsed }`). |
|
|
336
507
|
|
|
337
508
|
### AG-UI client & agent
|
|
338
509
|
|
|
@@ -360,10 +531,12 @@ re-export point. Internal modules import from leaf paths.
|
|
|
360
531
|
| --- | --- | --- |
|
|
361
532
|
| `createRouteTools(...)` | function | Build the built-in `route.*` tools. |
|
|
362
533
|
| `Route` / `RouteMap` | type | Navigable-route shapes. |
|
|
534
|
+
| `RouteWithParams` | type | A route resolved with `:param` path segments + leftover query params. |
|
|
363
535
|
| `createPageMapContext(...)` | function | Build the per-run `page_map` context entry. |
|
|
364
536
|
| `PageMap` | type | The compact page-surface shape. |
|
|
365
537
|
| `createStateHookTools(hook)` | function | Build `read_<name>` / `set_<name>` tools. |
|
|
366
538
|
| `StateHook` | type | A state-binding declaration. |
|
|
539
|
+
| `Skill` | type | A launchable prompt (chip / `/`-command). |
|
|
367
540
|
|
|
368
541
|
### Durability
|
|
369
542
|
|
|
@@ -378,12 +551,14 @@ re-export point. Internal modules import from leaf paths.
|
|
|
378
551
|
| Export | Kind | Summary |
|
|
379
552
|
| --- | --- | --- |
|
|
380
553
|
| `ToolCallCard` | class | A live tool-call card for the transcript. |
|
|
381
|
-
| `ToolCallStatus` / `SettledStatus` | type | Card lifecycle states. |
|
|
382
|
-
| `requestConfirmation(host, request)` | function |
|
|
383
|
-
| `ConfirmationRequest` | type | What the
|
|
384
|
-
| `
|
|
385
|
-
| `
|
|
386
|
-
| `
|
|
554
|
+
| `ToolCallStatus` / `SettledStatus` / `ToolDisplayMode` | type | Card lifecycle states + display mode. |
|
|
555
|
+
| `requestConfirmation(host, request)` | function | Append the inline confirmation card to the transcript. |
|
|
556
|
+
| `ConfirmationRequest` | type | What the card displays. |
|
|
557
|
+
| `renderMarkdown(text)` | function | Render sanitized markdown/HTML (marked + DOMPurify). |
|
|
558
|
+
| `typeInto` / `highlightThenClick` / `pressThenClick` / `selectOption` / `toggleControl` / `scrollIntoCenterView` / `focusWithFlash` / `prefersReducedMotion` | function | Animation primitives. |
|
|
559
|
+
| `fillField` / `clickElement` / `pressButton` / `selectControl` / `setControlValue` / `toggleCheckbox` | function | DOM-driver primitives. |
|
|
560
|
+
| `setNativeValue` / `setNativeChecked` | function | Set a control via its native prototype setter (React-controlled inputs). |
|
|
561
|
+
| `TypeOptions` / `HighlightClickOptions` / `PressOptions` / `SelectOptions` / `ToggleOptions` / `FlashOptions` / `FillFieldOptions` / `TextLikeElement` | type | Primitive option shapes. |
|
|
387
562
|
|
|
388
563
|
### Constants
|
|
389
564
|
|
|
@@ -391,17 +566,22 @@ re-export point. Internal modules import from leaf paths.
|
|
|
391
566
|
| --- | --- |
|
|
392
567
|
| `ELEMENT_TAG` | The registered tag name (`ag-ui-chat`). |
|
|
393
568
|
| `SUBMIT_EVENT` | The submit CustomEvent name. |
|
|
569
|
+
| `TOGGLE_EVENT` | The collapse-toggle CustomEvent name (`ag-ui-toggle`). |
|
|
394
570
|
| `MESSAGE_ROLE` | Message role constants. |
|
|
395
571
|
| `TOOL_CALL_STATUS` | Tool-call card status constants. |
|
|
572
|
+
| `TOOL_DISPLAY` | Tool-call display-mode constants (`minimal` / `compact` / `full`). |
|
|
573
|
+
| `X_CONFIRM_KEY` | JSON-Schema key carrying a confirmation prompt. |
|
|
574
|
+
| `X_SUMMARY_KEY` | JSON-Schema key carrying a short tool-card label. |
|
|
396
575
|
| `MAX_TOOL_ROUNDS` | Upper bound on tool-call → re-run rounds per send. |
|
|
397
576
|
| `VERSION` | The package version string. |
|
|
398
577
|
|
|
399
578
|
---
|
|
400
579
|
|
|
401
|
-
## Theming
|
|
580
|
+
## Theming, density, and placement
|
|
402
581
|
|
|
403
|
-
The chat shell is styled inside its Shadow DOM and exposes
|
|
404
|
-
|
|
582
|
+
The chat shell is styled inside its Shadow DOM and exposes a large set of `--ag-ui-*` CSS custom
|
|
583
|
+
properties on `:host` (colors, status, surface, spacing, layout), so you theme it from outside
|
|
584
|
+
without piercing the shadow boundary. A few of the knobs:
|
|
405
585
|
|
|
406
586
|
```css
|
|
407
587
|
ag-ui-chat {
|
|
@@ -410,8 +590,7 @@ ag-ui-chat {
|
|
|
410
590
|
--ag-ui-fg: #1a1a2e;
|
|
411
591
|
--ag-ui-radius: 12px;
|
|
412
592
|
|
|
413
|
-
/* Layout
|
|
414
|
-
--ag-ui-position: fixed;
|
|
593
|
+
/* Layout */
|
|
415
594
|
--ag-ui-width: 380px;
|
|
416
595
|
--ag-ui-height: 560px;
|
|
417
596
|
--ag-ui-inset: auto 24px 24px auto;
|
|
@@ -419,8 +598,21 @@ ag-ui-chat {
|
|
|
419
598
|
}
|
|
420
599
|
```
|
|
421
600
|
|
|
422
|
-
|
|
423
|
-
|
|
601
|
+
For the common cases there are three CSS-reactive **preset attributes** (no JS API), so you don't
|
|
602
|
+
have to hand-tune the variables:
|
|
603
|
+
|
|
604
|
+
- `theme` — `light` (default) / `dark` / `auto` (follow the OS) / `code`.
|
|
605
|
+
- `density` — `comfortable` (default) / `compact`.
|
|
606
|
+
- `placement` — `floating` (default) / `bottom-left` / `side` / `full` / `embedded`. `embedded`
|
|
607
|
+
drops the fixed positioning and z-index so the widget sits in normal document flow.
|
|
608
|
+
|
|
609
|
+
```html
|
|
610
|
+
<ag-ui-chat endpoint="/agent/" theme="dark" density="compact" placement="side"></ag-ui-chat>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
See [`src/ui/styles.ts`](src/ui/styles.ts) for the full variable + preset list. The
|
|
614
|
+
[`demo/`](demo/) live playground (`node demo/mock-server.mjs`) flips theme, density, placement,
|
|
615
|
+
text-animation, and tool-display live from a single page.
|
|
424
616
|
|
|
425
617
|
---
|
|
426
618
|
|
|
@@ -449,7 +641,7 @@ Other workflow targets (all identical in name to the sibling Python packages):
|
|
|
449
641
|
| `make test` | Vitest with a 100% line + branch + function + statement coverage gate. |
|
|
450
642
|
| `make lint` | `biome check .` + `tsc --noEmit`. |
|
|
451
643
|
| `make format` | `biome format --write .`. |
|
|
452
|
-
| `make demo` | Build, then serve `demo
|
|
644
|
+
| `make demo` | Build, then serve the live playground (`demo/themes/index.html`) on port 5173 via `demo/mock-server.mjs`. |
|
|
453
645
|
|
|
454
646
|
---
|
|
455
647
|
|
|
@@ -457,7 +649,7 @@ Other workflow targets (all identical in name to the sibling Python packages):
|
|
|
457
649
|
|
|
458
650
|
| Component | Floor | Tested |
|
|
459
651
|
| --- | --- | --- |
|
|
460
|
-
| Node (tooling/tests only) |
|
|
652
|
+
| Node (tooling/tests only) | 22 | 22, 24 |
|
|
461
653
|
| Browsers (runtime target) | ES2022 / evergreen | Chrome / Firefox / Safari 17+ |
|
|
462
654
|
| `@ag-ui/client` | latest 0.x | — |
|
|
463
655
|
|