@artooi/ag-ui-web-component 0.15.0 → 0.17.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 +158 -1
- package/README.md +42 -4
- package/dist/ag-ui-web-component.bundle.js +91 -58
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +21 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts +41 -2
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/agui_client.d.ts.map +1 -1
- package/dist/core/conversation_store.d.ts.map +1 -1
- package/dist/core/remote_conversation_store.d.ts.map +1 -1
- package/dist/core/run_index.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +534 -325
- package/dist/index.js.map +4 -4
- package/dist/tools/client_tool_registry.d.ts.map +1 -1
- package/dist/tools/page_action_tools.d.ts.map +1 -1
- package/dist/tools/route_map.d.ts.map +1 -1
- package/dist/ui/attachment_tray.d.ts +2 -0
- package/dist/ui/attachment_tray.d.ts.map +1 -1
- package/dist/ui/checkpoint_menu.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/ui/thread_drawer.d.ts.map +1 -1
- package/dist/ui/tool_call_card.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +6 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/dist/ui/voice_input.d.ts.map +1 -1
- package/package.json +9 -8
- package/src/constants.ts +23 -0
- package/src/core/ag_ui_chat.ts +243 -15
- package/src/core/remote_conversation_store.ts +2 -2
- package/src/index.ts +2 -0
- package/src/tools/route_map.ts +5 -8
- package/src/ui/attachment_tray.ts +5 -0
- package/src/ui/checkpoint_menu.ts +2 -0
- package/src/ui/styles.ts +38 -6
- package/src/ui/ui_strings.ts +11 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,161 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.17.0] — 2026-08-10
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`sendMessage(content, attachments?)`** — send as if the user had typed it:
|
|
15
|
+
user bubble, `ag-ui-submit`, run started. The programmatic half of the
|
|
16
|
+
composer, for an "Ask about this order" button, a command palette, or a
|
|
17
|
+
composer of your own replacing the built-in one. The built-in Send now reads
|
|
18
|
+
the composer, clears it, and calls this, so the two paths cannot drift.
|
|
19
|
+
|
|
20
|
+
It no-ops while a run is in flight — a second concurrent run would orphan the
|
|
21
|
+
first — and for an entirely empty message. ⚠ Unlike the built-in Send it does
|
|
22
|
+
**not** consult the attachment tray: what you pass is what is sent, so a host
|
|
23
|
+
composer stays in charge of its own state.
|
|
24
|
+
|
|
25
|
+
- **`attachFile(file)`** — queue a file into the tray exactly as the picker and
|
|
26
|
+
drag-and-drop do, with the same validation and progress chip. Returns `false`
|
|
27
|
+
when uploads are not configured (no `data-attachments-url`, no
|
|
28
|
+
`uploadHandler`), which is the only way for a host to tell: with no tray there
|
|
29
|
+
is nothing to report through, and silence would read as a queued file that
|
|
30
|
+
never uploads.
|
|
31
|
+
|
|
32
|
+
- **`ag-ui-attachments` event**, dispatched whenever the tray changes — a file
|
|
33
|
+
queued, an upload finishing or failing, a chip removed, the tray cleared after
|
|
34
|
+
a send. `detail` carries `{ attachments, pending }`: the durable refs of
|
|
35
|
+
everything settled, and how many are still in flight.
|
|
36
|
+
|
|
37
|
+
⭐ **This is what makes `sendMessage` usable with files at all.** The tray only
|
|
38
|
+
ever spoke to the built-in Send button, so a host composer had no way to tell a
|
|
39
|
+
settled upload from one still uploading — the same information the built-in
|
|
40
|
+
Send needs, which was simply not exposed. The tray's `onChange` hook already
|
|
41
|
+
existed and nothing was wired to it.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **Assigning a connect-time-only attribute after the element has connected now
|
|
46
|
+
warns**, instead of being silently ignored: `data-attachments-url`,
|
|
47
|
+
`data-attachment-accept`, `data-attachment-max-bytes`, `data-transcribe-url`,
|
|
48
|
+
`data-threads-url`, `data-tools-url`, `data-skills-url`, `data-skills`,
|
|
49
|
+
`data-prompt-chips`, `data-slash-commands`, `data-theme-toggle`,
|
|
50
|
+
`data-strings`, `data-icon-url`.
|
|
51
|
+
|
|
52
|
+
Each is read once while connecting, to decide what chrome exists at all, and
|
|
53
|
+
no later read revisits the decision. ⚠ **The symptom is an affordance that
|
|
54
|
+
simply never appears** — which reads as a broken component rather than a
|
|
55
|
+
mis-timed assignment, and it is the common React/Vue shape: the element mounts
|
|
56
|
+
on the first render pass and the framework patches attributes in on the next.
|
|
57
|
+
|
|
58
|
+
Set them before the element enters the DOM, or remove and re-insert it to
|
|
59
|
+
apply a new value. ⭐ The attributes that genuinely *are* re-read per use —
|
|
60
|
+
`data-runs-url`, `data-page-actions`, `data-text-animation`,
|
|
61
|
+
`data-tool-display`, `endpoint`, and CSS-reactive `theme` / `collapsed` — are
|
|
62
|
+
deliberately excluded, since a late change works there and a warning would be
|
|
63
|
+
wrong.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- **The checkpoint panel now follows the theme.** Its rules read `--agui-surface`
|
|
68
|
+
/ `--agui-border` / `--agui-hover` — note `--agui-`, not the `--ag-ui-`
|
|
69
|
+
namespace every other rule uses — each with a hardcoded light-mode fallback.
|
|
70
|
+
So the panel ignored `theme="dark"` entirely and rendered light-on-dark unless
|
|
71
|
+
a host happened to set three variables documented nowhere. Now derived from the
|
|
72
|
+
real theme tokens, with a new theme-aware `--ag-ui-hover` defined in every
|
|
73
|
+
theme block. ⭐ The fallbacks are what hid it: they made an unthemed panel look
|
|
74
|
+
deliberate.
|
|
75
|
+
|
|
76
|
+
`checkpoints-title` and `checkpoint-label` also gain `part` attributes — they
|
|
77
|
+
carried classes only, so neither could be styled from outside the shadow root.
|
|
78
|
+
|
|
79
|
+
- **Markdown tables are styled.** `table` / `thead` / `tbody` / `tr` / `th` /
|
|
80
|
+
`td` are all in the sanitizer's `ALLOWED_TAGS`, so an agent emitting a table
|
|
81
|
+
rendered it — completely unstyled, overflowing its bubble. Wide tables now
|
|
82
|
+
scroll inside their own box rather than pushing the layout sideways.
|
|
83
|
+
|
|
84
|
+
- **Sending while a file is still uploading now says so.** `readyRefs()` returns
|
|
85
|
+
only settled uploads and `clearReady()` deliberately keeps the rest for a
|
|
86
|
+
follow-up message — so the file was never lost, but the message went without
|
|
87
|
+
it and nothing indicated that. Attachments are frequently the entire point of
|
|
88
|
+
the message, which is what made the silence the defect. An inline notice now
|
|
89
|
+
names how many are still uploading and that they remain attached.
|
|
90
|
+
|
|
91
|
+
Send is deliberately **not** disabled while uploads are pending: that would
|
|
92
|
+
fight the tray's documented "keep for a follow-up" behaviour and could wedge
|
|
93
|
+
on an upload that never settles.
|
|
94
|
+
|
|
95
|
+
## [0.16.0] — 2026-08-09
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- **A stale-page guard on frontend tool calls.** A round's context records the
|
|
100
|
+
page it describes; if the page moves before the agent's tool call arrives, the
|
|
101
|
+
call is refused with a result telling the agent to call `read_page` and retry,
|
|
102
|
+
instead of running the handler. Most stale calls would simply miss and report
|
|
103
|
+
a failure — the case this prevents is the other one, where a same-named
|
|
104
|
+
control on the *new* page matches and the agent silently acts on the wrong
|
|
105
|
+
page. `read_page` itself and tools marked `x-navigates` are exempt, and the
|
|
106
|
+
guard is inert unless a `getPageMap` provider is set.
|
|
107
|
+
- **New `UiStrings` keys `runInterrupted` and `pageMoved`**, both overridable
|
|
108
|
+
like every other string.
|
|
109
|
+
|
|
110
|
+
### Changed
|
|
111
|
+
|
|
112
|
+
- **Toolchain majors: Vitest 3 → 4 and TypeScript 5.9 → 7**, plus `marked`
|
|
113
|
+
18.0.9, Biome 2.5.7, `@types/node` 26.1.2. All development dependencies — the
|
|
114
|
+
emitted `.d.ts` files are **byte-identical** to the 5.9 output (verified by
|
|
115
|
+
building both and diffing; only the source maps move), so consumers see no
|
|
116
|
+
change.
|
|
117
|
+
|
|
118
|
+
⚠ **Vitest 4 takes a provider *instance*, not the string `"playwright"`.**
|
|
119
|
+
The provider moved to its own package (`@vitest/browser-playwright`) and, with
|
|
120
|
+
v8 coverage, the old string form is a hard error rather than a deprecation.
|
|
121
|
+
|
|
122
|
+
⚠ **TypeScript 7 requires `rootDir` explicitly** (TS5011) instead of
|
|
123
|
+
inferring it from the common source directory. Set to the value 5.x inferred,
|
|
124
|
+
so the published layout is unchanged.
|
|
125
|
+
|
|
126
|
+
### Fixed
|
|
127
|
+
|
|
128
|
+
- **A run interrupted by navigation no longer vanishes silently.** If the page
|
|
129
|
+
navigates or reloads while a run is in flight — routine in an MPA — the
|
|
130
|
+
element is destroyed with it, and on the next mount the transcript replayed
|
|
131
|
+
with the answer simply missing and no indication anything had gone wrong. The
|
|
132
|
+
element now reports it as an inline notice. Detected from the shape of the
|
|
133
|
+
transcript (`send()` persists the user turn *before* starting the run, so a
|
|
134
|
+
history ending on that turn means nothing came back), which is why it needs no
|
|
135
|
+
`ClientConversationStore` change and no `pagehide` listener — neither of which
|
|
136
|
+
would fire on a crash or a force-quit anyway.
|
|
137
|
+
|
|
138
|
+
It is deliberately **a notice, not a resume**: AG-UI has no
|
|
139
|
+
resume-an-aborted-run primitive, so re-sending the accumulated messages is
|
|
140
|
+
semantically a new run and would re-execute any server-side tool the agent had
|
|
141
|
+
already performed. The agent-initiated case is unaffected — a navigating tool
|
|
142
|
+
still checkpoints and resumes exactly as before.
|
|
143
|
+
|
|
144
|
+
- **Six branches that were never actually covered.** Vitest 4's v8 provider
|
|
145
|
+
remaps coverage more precisely, and the 100% gate stopped being satisfiable —
|
|
146
|
+
not because anything regressed, but because v3 had been crediting six
|
|
147
|
+
branches and three callbacks that no test reached. Each is now genuinely
|
|
148
|
+
tested: the paperclip button opening the file picker, the built-in
|
|
149
|
+
transcription handler (every prior voice test supplied its own), a page-action
|
|
150
|
+
tool resolving through `resolvePageTarget`, a non-`Enter` keystroke in a
|
|
151
|
+
question card, a submit click with no answer, a non-string `error` in a
|
|
152
|
+
transcription error body, and a restored history message with an unrecognised
|
|
153
|
+
role.
|
|
154
|
+
|
|
155
|
+
⭐ **One was a flaw in the test harness, not a missing test.** `makeFakeAgent`
|
|
156
|
+
ended a clean run by calling `onRunFinalized` alone, so the client's
|
|
157
|
+
`RUN_FINISHED` path could only ever be reached through `emit.interrupt()` —
|
|
158
|
+
the ordinary success outcome every real run carries was never exercised. The
|
|
159
|
+
fake now emits both events, in the order a real agent does.
|
|
160
|
+
|
|
161
|
+
`route_map`'s unreachable guard was restructured away rather than tested: its
|
|
162
|
+
regex capture group is mandatory, so the `undefined` case existed only to
|
|
163
|
+
satisfy `noUncheckedIndexedAccess` and no test could ever have reached it.
|
|
164
|
+
|
|
10
165
|
## [0.15.0] — 2026-08-08
|
|
11
166
|
|
|
12
167
|
### Changed
|
|
@@ -678,7 +833,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
678
833
|
### Notes
|
|
679
834
|
- First release — exercising the automated npm OIDC publish pipeline end-to-end.
|
|
680
835
|
|
|
681
|
-
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.
|
|
836
|
+
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.17.0...HEAD
|
|
837
|
+
[0.17.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.16.0...v0.17.0
|
|
838
|
+
[0.16.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.15.0...v0.16.0
|
|
682
839
|
[0.15.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.14.1...v0.15.0
|
|
683
840
|
[0.14.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.14.0...v0.14.1
|
|
684
841
|
[0.14.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.13.0...v0.14.0
|
package/README.md
CHANGED
|
@@ -194,8 +194,35 @@ labels are fetched automatically — per card, `x-summary` → an explicit
|
|
|
194
194
|
|
|
195
195
|
**Properties** (selected): `sharedState` — AG-UI shared state (documented under Tools & state).
|
|
196
196
|
|
|
197
|
-
**Methods**: `registerTool`, `registerPageState`, `setSkills`, `
|
|
198
|
-
`setCollapsed`, `toggleCollapsed`.
|
|
197
|
+
**Methods**: `registerTool`, `registerPageState`, `setSkills`, `sendMessage`, `attachFile`,
|
|
198
|
+
`appendMessage`, `newChat`, `setCollapsed`, `toggleCollapsed`.
|
|
199
|
+
|
|
200
|
+
### Sending from your own UI
|
|
201
|
+
|
|
202
|
+
`sendMessage(content, attachments?)` sends as if the user had typed it — user bubble,
|
|
203
|
+
`ag-ui-submit` event, run started. Use it for an "Ask about this order" button, a command
|
|
204
|
+
palette, or a composer of your own replacing the built-in one. It no-ops while a run is in
|
|
205
|
+
flight and for an entirely empty message, and unlike the built-in Send it does **not** consult
|
|
206
|
+
the attachment tray: what you pass is what is sent, so your composer stays in charge of its
|
|
207
|
+
own state.
|
|
208
|
+
|
|
209
|
+
`attachFile(file)` queues a file into the tray exactly as the picker and drag-and-drop do, with
|
|
210
|
+
the same validation and progress chip. It returns `false` when uploads are not configured
|
|
211
|
+
(no `data-attachments-url` and no `uploadHandler`) — the only way to tell, since with no tray
|
|
212
|
+
there is nothing to report through.
|
|
213
|
+
|
|
214
|
+
Uploading is asynchronous, so watch `ag-ui-attachments` for the result. Its `detail` carries
|
|
215
|
+
`{ attachments, pending }`: the durable refs of everything that has finished, and how many are
|
|
216
|
+
still in flight. Send once `pending` is `0`, or you will leave files behind.
|
|
217
|
+
|
|
218
|
+
```js
|
|
219
|
+
chat.addEventListener("ag-ui-attachments", (e) => {
|
|
220
|
+
const { attachments, pending } = e.detail;
|
|
221
|
+
sendButton.disabled = pending > 0;
|
|
222
|
+
sendButton.onclick = () => chat.sendMessage(input.value, attachments);
|
|
223
|
+
});
|
|
224
|
+
chat.attachFile(fileInput.files[0]);
|
|
225
|
+
```
|
|
199
226
|
|
|
200
227
|
A self-contained live playground lives in [`demo/`](demo/) — run `make demo` to serve it against a
|
|
201
228
|
mock AG-UI server.
|
|
@@ -648,13 +675,24 @@ chat.routeMap = [
|
|
|
648
675
|
|
|
649
676
|
**`getPageMap(): PageMap`** — a per-run provider returning the current page's compact actionable
|
|
650
677
|
surface (field names/types/labels, button labels+handles — *not* values). It is auto-injected into
|
|
651
|
-
each run's `context` as a `page_map` entry (toggle with `autoInjectPageMap`)
|
|
652
|
-
so it reflects the page the agent is currently looking at:
|
|
678
|
+
each run's `context` as a `page_map` entry (toggle with `autoInjectPageMap`):
|
|
653
679
|
|
|
654
680
|
```js
|
|
655
681
|
chat.getPageMap = () => ({ fields: introspectForm(), buttons: visibleButtons() });
|
|
656
682
|
```
|
|
657
683
|
|
|
684
|
+
It is recomputed at the top of **every tool round**, not once per `send()` — so after the agent
|
|
685
|
+
acts, the next round already sees the resulting page. Within a round the agent can pull a fresh
|
|
686
|
+
view at any time with the built-in `read_page` tool, which is registered whenever this provider is
|
|
687
|
+
set.
|
|
688
|
+
|
|
689
|
+
That leaves one window: the page can move *after* a round's context was built but *before* the
|
|
690
|
+
agent's tool call arrives — the user clicks a link, or presses back. Calls landing in that window
|
|
691
|
+
are **refused** with a result telling the agent to call `read_page` and retry. Most would have
|
|
692
|
+
missed anyway; the guard exists for the case where a same-named control on the new page matches and
|
|
693
|
+
the agent would otherwise act on the wrong page without either side noticing. `read_page` and tools
|
|
694
|
+
marked `x-navigates` are exempt, and the guard is inert when no `getPageMap` is set.
|
|
695
|
+
|
|
658
696
|
**`registerPageState({ name, read, write?, schema? })`** — ergonomic sugar over `registerTool` for
|
|
659
697
|
SPA app state (Redux/Zustand/signals). It auto-generates a `read_<name>` (read-only) tool and, when
|
|
660
698
|
`write` is supplied, a `set_<name>` tool stamped `x-destructive`:
|