@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/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.23.1] — 2026-08-13
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **A reloaded conversation lost every turn after the first plain answer.**
|
|
15
|
+
Restoring stored history iterated `message.toolCalls` behind an
|
|
16
|
+
`!== undefined` check, and an assistant turn that called no tool can arrive
|
|
17
|
+
carrying `null`: the protocol's Python models declare
|
|
18
|
+
`tool_calls: list[ToolCall] | None`, so a server dumping them without
|
|
19
|
+
`exclude_none` sends exactly that, while `@ag-ui/core` types the field
|
|
20
|
+
optional-and-not-nullable — TypeScript therefore offered no hint that the value
|
|
21
|
+
was reachable. Iterating it threw `TypeError: toolCalls is not iterable`
|
|
22
|
+
*inside* the replay, which aborted at that message and left every later turn
|
|
23
|
+
out of the transcript. Nothing surfaced: no error state, no partial-history
|
|
24
|
+
notice, just a short conversation. Measured against a server-backed store, a
|
|
25
|
+
54-message thread restored as two bubbles and one tool card.
|
|
26
|
+
|
|
27
|
+
Two things follow from where the throw happened, and both are now closed.
|
|
28
|
+
Tool calls are **narrowed rather than trusted** — the same stance
|
|
29
|
+
`messageAttachments` already takes for the neighbouring field on the same
|
|
30
|
+
message, and for the same reason. And a **shapeless entry is skipped instead of
|
|
31
|
+
ending the replay**: a stored call with no `id`, no `function.name`, or a
|
|
32
|
+
`null` where an object belongs no longer costs the rest of the conversation.
|
|
33
|
+
A call whose `arguments` are missing or not a string still renders, with empty
|
|
34
|
+
arguments, because its name is the part worth showing.
|
|
35
|
+
|
|
36
|
+
Only a **server-backed** history reaches this: the default
|
|
37
|
+
`SessionStorageStore` round-trips client-shaped objects through JSON, where an
|
|
38
|
+
absent field stays absent, so the `null` never appears. Anything reading a
|
|
39
|
+
thread index — `data-threads-url` — did, including every Django admin
|
|
40
|
+
configured with a conversation store. There the cost was worse than a short
|
|
41
|
+
transcript: each navigating tool reloads the page and the run continues only
|
|
42
|
+
because the component rehydrates and completes the pending call, so a thread
|
|
43
|
+
that had answered once abandoned its next multi-step task at the first
|
|
44
|
+
navigation.
|
|
45
|
+
|
|
46
|
+
## [0.23.0] — 2026-08-12
|
|
47
|
+
|
|
48
|
+
Attachment chips, which turned out to be the least finished corner of 0.22.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **A filename on a sent attachment chip was invisible on the stock light
|
|
53
|
+
theme.** `.attachment-chip` set the assistant surface as its background but no
|
|
54
|
+
colour, so on a user bubble it inherited `--ag-ui-user-fg` — white on
|
|
55
|
+
`#f1f1f6`, a contrast ratio of 1.13:1 where WCAG AA wants 4.5:1. Only the size
|
|
56
|
+
stayed legible, because it sets its own muted colour, which is exactly how the
|
|
57
|
+
bug read to a user: an icon, a blank gap, and a size. The chip now takes
|
|
58
|
+
`--ag-ui-text`, the same consumer-overridable token the rest of the body text
|
|
59
|
+
uses, so a page that themes its text themes the chip with it. The dark and
|
|
60
|
+
code themes were never affected, which is why this shipped.
|
|
61
|
+
|
|
62
|
+
- **The composer's attachment tray never collapsed.** The tray sets `hidden`
|
|
63
|
+
while it holds no chips, but its rule declared `display: flex` with no
|
|
64
|
+
`[hidden]` guard, and an author `display` beats the UA stylesheet's
|
|
65
|
+
`[hidden] { display: none }`. Every embed that wired uploads therefore carried
|
|
66
|
+
8px of dead space above the composer at all times. With the tray genuinely
|
|
67
|
+
collapsing, its padding is also symmetric again (`8px 12px`), so a chip clears
|
|
68
|
+
the composer's top edge instead of sitting flush against it.
|
|
69
|
+
|
|
70
|
+
- **Filenames truncated far short of the space available.**
|
|
71
|
+
`.attachment-chip-name` capped itself at `14ch`, so
|
|
72
|
+
`LQ27552-7006-EXHIBIT-A.pdf` rendered as `LQ27552-7006 …` inside a chip with
|
|
73
|
+
room to spare. The cap is gone: the chip is already `max-width: 100%` with the
|
|
74
|
+
name ellipsising, so its container bounds it, and a genuinely long name now
|
|
75
|
+
ellipsises at the edge it actually reaches. The chip is `box-sizing:
|
|
76
|
+
border-box` with it, which stops that `100%` from overflowing its container by
|
|
77
|
+
the chip's own padding and border.
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
|
|
81
|
+
- **Attachment chip icons are inline SVG.** 0.22 moved the chrome's glyphs to
|
|
82
|
+
inline SVG and stopped at the chips, leaving emoji sitting beside SVG send,
|
|
83
|
+
attach and mic buttons — a different optical weight, varying by platform, and
|
|
84
|
+
taking neither `currentColor` nor a size from CSS. Four marks (image, PDF,
|
|
85
|
+
text, generic) now follow the same contract as the rest, painted from the
|
|
86
|
+
chip's own colour so an errored chip turns red glyph and all. Both the sent
|
|
87
|
+
bubble's chips and the composer tray's change together.
|
|
88
|
+
|
|
89
|
+
### Removed
|
|
90
|
+
|
|
91
|
+
- **The client-side attachment manifest in `RunAgentInput.context`.**
|
|
92
|
+
`getContext()` appended a one-line summary of the message's attachments; the
|
|
93
|
+
server now derives that from the refs riding the messages, so the client's
|
|
94
|
+
copy only duplicated it on the turn a file was attached. Attachments still
|
|
95
|
+
reach the agent — through the message, which is where they already were. The
|
|
96
|
+
page-map half of `getContext()` is unchanged.
|
|
97
|
+
|
|
98
|
+
**This needs a server that derives the manifest itself.** `django-ag-ui`
|
|
99
|
+
does so from 0.42.0. Against an older server nothing replaces the client's
|
|
100
|
+
copy, so the agent stops being told which attachment ids exist and answers a
|
|
101
|
+
question about an attached file by asking for the file — which is the defect
|
|
102
|
+
the server-side derivation was written to fix. Upgrade the server first, or
|
|
103
|
+
together. A host that read the manifest out of the run context itself is
|
|
104
|
+
likewise affected.
|
|
105
|
+
|
|
10
106
|
## [0.22.0] — 2026-08-11
|
|
11
107
|
|
|
12
108
|
Two complaints about how the widget *feels*, and both turned out to be structural
|
|
@@ -146,7 +242,7 @@ hosts that both arrange the page the way it expects.
|
|
|
146
242
|
`overflow: hidden` ancestor sharing the element's box — a card, a table cell —
|
|
147
243
|
clipped it entirely while the tool reported success. And 200 ms is below the
|
|
148
244
|
threshold at which someone who does not know where to look notices anything.
|
|
149
|
-
|
|
245
|
+
Neither our tests nor the consumer's could have found the second one:
|
|
150
246
|
headless Chromium hides the scroll race, and no automated check has an opinion
|
|
151
247
|
about whether a human sees a 200 ms ring.
|
|
152
248
|
|
|
@@ -162,7 +258,7 @@ hosts that both arrange the page the way it expects.
|
|
|
162
258
|
explicit-duration contract, and the docs now say so instead of overclaiming.
|
|
163
259
|
|
|
164
260
|
- **The tool and skill catalog fetches are deferred by one microtask**, so a React
|
|
165
|
-
`ref` assigned in the same commit as insertion is honoured.
|
|
261
|
+
`ref` assigned in the same commit as insertion is honoured. The thread-history
|
|
166
262
|
request is deliberately **not** deferred: a deferred replay can land after a
|
|
167
263
|
`sendMessage()` and duplicate the transcript. Configure before you insert, or
|
|
168
264
|
call `reload()`; the new React recipe in the README shows both.
|
|
@@ -174,7 +270,7 @@ hosts that both arrange the page the way it expects.
|
|
|
174
270
|
`data-resize-anchor="<y>-<x>"`, but the rules meant to read it were written as
|
|
175
271
|
`[data-resize-anchor~="left"]` — and `~=` matches whitespace-separated words
|
|
176
272
|
while the stamped value is a single hyphenated token, so they could never
|
|
177
|
-
match.
|
|
273
|
+
match. **The cursor rules used `=` and did match**, so the pointer followed
|
|
178
274
|
the measurement while the grip stayed where `placement` had guessed: for any
|
|
179
275
|
host that aligns the panel the other way, the cursor promised a diagonal the
|
|
180
276
|
grip was not on, and the grip sat on the corner that stays put.
|
|
@@ -200,14 +296,14 @@ hosts that both arrange the page the way it expects.
|
|
|
200
296
|
|
|
201
297
|
### Fixed
|
|
202
298
|
|
|
203
|
-
-
|
|
299
|
+
- **`placement="side"` (and `sidebar`) stopped being full height once the
|
|
204
300
|
panel had been resized.** A dragged size is written as a custom property on
|
|
205
301
|
the host, and an inline custom property **outranks a `:host([placement=…])`
|
|
206
302
|
rule setting the same property** — so a height dragged while floating capped a
|
|
207
303
|
docked sidebar that had asked for `100vh`. Since the size persists per tab,
|
|
208
304
|
one drag broke every later visit.
|
|
209
305
|
|
|
210
|
-
|
|
306
|
+
**The previous release claimed this was already handled, and the reasoning
|
|
211
307
|
was wrong.** Writing `--ag-ui-height` rather than inline `height` was supposed
|
|
212
308
|
to leave placement with the final say; it does not, because the indirection
|
|
213
309
|
changes nothing about the cascade. The fix is explicit rather than
|
|
@@ -231,12 +327,12 @@ hosts that both arrange the page the way it expects.
|
|
|
231
327
|
handle at all (a `100vw`/`100vh` layout has nothing to drag), `sidebar` /
|
|
232
328
|
`side` get width only, everything else gets both.
|
|
233
329
|
|
|
234
|
-
|
|
330
|
+
**It writes the custom properties, not inline `width` / `height`.** The
|
|
235
331
|
placement rules set those same properties, so an inline dimension would
|
|
236
332
|
outrank them — a panel dragged while floating would keep that width after
|
|
237
333
|
switching to fullscreen.
|
|
238
334
|
|
|
239
|
-
|
|
335
|
+
**Which corner the grip sits on is measured, not assumed.** A resize is
|
|
240
336
|
computed from the edge that stays still, and which edge that is belongs to the
|
|
241
337
|
*host's* layout rather than to `placement` — a floating panel is pinned
|
|
242
338
|
bottom-right, an embedded one goes wherever the page's CSS puts it. Deriving
|
|
@@ -260,7 +356,7 @@ hosts that both arrange the page the way it expects.
|
|
|
260
356
|
palette — a lone `/` — was left in the composer, which said nothing about what
|
|
261
357
|
the skill wanted or how to supply it. The hint now says what to do, too.
|
|
262
358
|
|
|
263
|
-
-
|
|
359
|
+
- **Picking a skill now sends it.** It used to write the text into the
|
|
264
360
|
composer and wait for a second click unless the skill set
|
|
265
361
|
`sendImmediately: true` — so the default behaviour of a shortcut was to not
|
|
266
362
|
take the shortcut. Set `sendImmediately: false` to keep pre-filling, which is
|
|
@@ -271,7 +367,7 @@ hosts that both arrange the page the way it expects.
|
|
|
271
367
|
sends the bare `/name` token and the agent expands it, from the harness
|
|
272
368
|
`Skills` capability or the server's own instructions.
|
|
273
369
|
|
|
274
|
-
|
|
370
|
+
**The prompt was the leak.** A catalog is either a fetched `GET` or an
|
|
275
371
|
inline `data-skills` attribute sitting in the page source, and a skill is
|
|
276
372
|
often where a project's internal workflow is written down most plainly — so
|
|
277
373
|
the client-side catalog published it to anyone who opened the page. Sending a
|
|
@@ -295,10 +391,10 @@ hosts that both arrange the page the way it expects.
|
|
|
295
391
|
`part` (`tool-card-args` / `tool-card-result`, headings via
|
|
296
392
|
`tool-card-section-label`, body via `tool-card-body`), and are pretty-printed.
|
|
297
393
|
|
|
298
|
-
|
|
394
|
+
Breaking for anyone styling `tool-card-result` as a single combined block.
|
|
299
395
|
A call with no arguments no longer renders an empty `{}` in a box of its own.
|
|
300
396
|
|
|
301
|
-
-
|
|
397
|
+
- **`data-tool-display` is now live.** Changing it restyles every card already
|
|
302
398
|
in the transcript, the way `data-answer-well` always has. The modes are pure
|
|
303
399
|
visibility over **one DOM shape**, selected by the shadow CSS from the host
|
|
304
400
|
attribute; previously each card baked its structure at construction from the
|
|
@@ -313,7 +409,7 @@ hosts that both arrange the page the way it expects.
|
|
|
313
409
|
different objects: the record is the tool card it gates, which settles to the
|
|
314
410
|
outcome and scrolls with the rest of the transcript.
|
|
315
411
|
|
|
316
|
-
-
|
|
412
|
+
- **The confirmation card was appended to the wrong parent**, and it is the
|
|
317
413
|
reason it drifted to the foot of a turn. Every other inline card — tool,
|
|
318
414
|
approval, `ask_user`, run notices — goes into the turn's answer group; this
|
|
319
415
|
one went into the message list, so it became a sibling *after* the group and
|
|
@@ -330,7 +426,7 @@ hosts that both arrange the page the way it expects.
|
|
|
330
426
|
gated, and the server-side gate left nothing at all even though it is the one
|
|
331
427
|
guarding tools that run on the backend.
|
|
332
428
|
|
|
333
|
-
|
|
429
|
+
**Session-scoped, like the "run interrupted" notice.** AG-UI carries no
|
|
334
430
|
approval message — the answer rides `resume[]` as transient run input — so a
|
|
335
431
|
reload restores the call and its result but not the note. Durable "who
|
|
336
432
|
approved what" is an audit concern, not a transcript one.
|
|
@@ -355,7 +451,7 @@ hosts that both arrange the page the way it expects.
|
|
|
355
451
|
entry is what gets persisted. The protocol has no rule to enforce and refusing
|
|
356
452
|
the event would be worse than the merge, so this warns and continues.
|
|
357
453
|
|
|
358
|
-
|
|
454
|
+
Found because the demo harness was doing exactly this, which is the
|
|
359
455
|
argument for the harness in miniature: the bug was the consumer's, the
|
|
360
456
|
invisibility was ours.
|
|
361
457
|
|
|
@@ -365,7 +461,7 @@ hosts that both arrange the page the way it expects.
|
|
|
365
461
|
of replaying one script for everything, and the page gained header-icon,
|
|
366
462
|
German-strings and reset-size controls plus a short "what to try" guide.
|
|
367
463
|
|
|
368
|
-
|
|
464
|
+
Two harness defects were making the component look broken. Its follow-up
|
|
369
465
|
detection matched **any** tool message in the thread, so once a conversation
|
|
370
466
|
had run a single tool every later turn answered "Done" to everything. And the
|
|
371
467
|
page forced `flex: 1` on the element, which silently outranks the width a
|
|
@@ -394,7 +490,7 @@ hosts that both arrange the page the way it expects.
|
|
|
394
490
|
keyboard user), styleable via the `code-copy` part, with `copyCode` /
|
|
395
491
|
`copied` / `copyFailed` in `UiStrings`.
|
|
396
492
|
|
|
397
|
-
|
|
493
|
+
**It reports failure rather than always claiming success.** The Clipboard
|
|
398
494
|
API needs a secure context and is simply absent in some embeddings; a button
|
|
399
495
|
that always says "Copied" sends the reader off to paste stale clipboard
|
|
400
496
|
content and find out somewhere else entirely.
|
|
@@ -413,7 +509,7 @@ hosts that both arrange the page the way it expects.
|
|
|
413
509
|
drawer had done this correctly all along. Focus now moves in on open, is
|
|
414
510
|
restored on close, and Tab is trapped while it is open.
|
|
415
511
|
|
|
416
|
-
|
|
512
|
+
**With no continuable runs the panel holds no controls**, so the panel
|
|
417
513
|
itself is focusable as the fallback — otherwise "move focus to the first
|
|
418
514
|
control" silently does nothing in exactly the case where the user has least to
|
|
419
515
|
go on.
|
|
@@ -435,7 +531,7 @@ hosts that both arrange the page the way it expects.
|
|
|
435
531
|
the composer, clears it, and calls this, so the two paths cannot drift.
|
|
436
532
|
|
|
437
533
|
It no-ops while a run is in flight — a second concurrent run would orphan the
|
|
438
|
-
first — and for an entirely empty message.
|
|
534
|
+
first — and for an entirely empty message. Unlike the built-in Send it does
|
|
439
535
|
**not** consult the attachment tray: what you pass is what is sent, so a host
|
|
440
536
|
composer stays in charge of its own state.
|
|
441
537
|
|
|
@@ -451,7 +547,7 @@ hosts that both arrange the page the way it expects.
|
|
|
451
547
|
a send. `detail` carries `{ attachments, pending }`: the durable refs of
|
|
452
548
|
everything settled, and how many are still in flight.
|
|
453
549
|
|
|
454
|
-
|
|
550
|
+
**This is what makes `sendMessage` usable with files at all.** The tray only
|
|
455
551
|
ever spoke to the built-in Send button, so a host composer had no way to tell a
|
|
456
552
|
settled upload from one still uploading — the same information the built-in
|
|
457
553
|
Send needs, which was simply not exposed. The tray's `onChange` hook already
|
|
@@ -467,13 +563,13 @@ hosts that both arrange the page the way it expects.
|
|
|
467
563
|
`data-strings`, `data-icon-url`.
|
|
468
564
|
|
|
469
565
|
Each is read once while connecting, to decide what chrome exists at all, and
|
|
470
|
-
no later read revisits the decision.
|
|
566
|
+
no later read revisits the decision. **The symptom is an affordance that
|
|
471
567
|
simply never appears** — which reads as a broken component rather than a
|
|
472
568
|
mis-timed assignment, and it is the common React/Vue shape: the element mounts
|
|
473
569
|
on the first render pass and the framework patches attributes in on the next.
|
|
474
570
|
|
|
475
571
|
Set them before the element enters the DOM, or remove and re-insert it to
|
|
476
|
-
apply a new value.
|
|
572
|
+
apply a new value. The attributes that genuinely *are* re-read per use —
|
|
477
573
|
`data-runs-url`, `data-page-actions`, `data-text-animation`,
|
|
478
574
|
`data-tool-display`, `endpoint`, and CSS-reactive `theme` / `collapsed` — are
|
|
479
575
|
deliberately excluded, since a late change works there and a warning would be
|
|
@@ -487,7 +583,7 @@ hosts that both arrange the page the way it expects.
|
|
|
487
583
|
So the panel ignored `theme="dark"` entirely and rendered light-on-dark unless
|
|
488
584
|
a host happened to set three variables documented nowhere. Now derived from the
|
|
489
585
|
real theme tokens, with a new theme-aware `--ag-ui-hover` defined in every
|
|
490
|
-
theme block.
|
|
586
|
+
theme block. The fallbacks are what hid it: they made an unthemed panel look
|
|
491
587
|
deliberate.
|
|
492
588
|
|
|
493
589
|
`checkpoints-title` and `checkpoint-label` also gain `part` attributes — they
|
|
@@ -532,11 +628,11 @@ hosts that both arrange the page the way it expects.
|
|
|
532
628
|
building both and diffing; only the source maps move), so consumers see no
|
|
533
629
|
change.
|
|
534
630
|
|
|
535
|
-
|
|
631
|
+
**Vitest 4 takes a provider *instance*, not the string `"playwright"`.**
|
|
536
632
|
The provider moved to its own package (`@vitest/browser-playwright`) and, with
|
|
537
633
|
v8 coverage, the old string form is a hard error rather than a deprecation.
|
|
538
634
|
|
|
539
|
-
|
|
635
|
+
**TypeScript 7 requires `rootDir` explicitly** (TS5011) instead of
|
|
540
636
|
inferring it from the common source directory. Set to the value 5.x inferred,
|
|
541
637
|
so the published layout is unchanged.
|
|
542
638
|
|
|
@@ -569,7 +665,7 @@ hosts that both arrange the page the way it expects.
|
|
|
569
665
|
transcription error body, and a restored history message with an unrecognised
|
|
570
666
|
role.
|
|
571
667
|
|
|
572
|
-
|
|
668
|
+
**One was a flaw in the test harness, not a missing test.** `makeFakeAgent`
|
|
573
669
|
ended a clean run by calling `onRunFinalized` alone, so the client's
|
|
574
670
|
`RUN_FINISHED` path could only ever be reached through `emit.interrupt()` —
|
|
575
671
|
the ordinary success outcome every real run carries was never exercised. The
|
|
@@ -588,13 +684,13 @@ hosts that both arrange the page the way it expects.
|
|
|
588
684
|
(Playwright) for the tests whose subject is sanitisation. Coverage stays
|
|
589
685
|
unified at 100% across both.
|
|
590
686
|
|
|
591
|
-
|
|
687
|
+
**A correctness requirement, not an optimisation.** DOMPurify 3.4.8+
|
|
592
688
|
silently stops sanitising under happy-dom — `<script>` and `<img>` pass
|
|
593
689
|
straight through, and ordinary markdown loses its `<p>` wrapper. A
|
|
594
690
|
happy-dom-only suite can therefore go green while this component ships no
|
|
595
691
|
sanitisation at all, which is the one failure it must never ship.
|
|
596
692
|
|
|
597
|
-
|
|
693
|
+
**The experiment settles what the pin never could**: dompurify 3.4.13
|
|
598
694
|
sanitises correctly in Chromium. The defect is happy-dom's DOM emulation, not
|
|
599
695
|
a DOMPurify regression — so **consumers were never exposed**, and the risk was
|
|
600
696
|
confined to the test environment the whole time.
|
|
@@ -620,13 +716,13 @@ hosts that both arrange the page the way it expects.
|
|
|
620
716
|
are transitive, so they are pinned through `overrides` — there is no direct
|
|
621
717
|
dependency to bump.
|
|
622
718
|
|
|
623
|
-
|
|
719
|
+
**`overrides` now live in `pnpm-workspace.yaml`**, not the `pnpm` field in
|
|
624
720
|
`package.json`; pnpm 11 ignores the latter and only warns. And an override
|
|
625
721
|
must be scoped to its major — an unbounded `brace-expansion: ">=2.1.2"`
|
|
626
722
|
resolves to 5.x, whose export shape `minimatch` cannot call, breaking `glob`
|
|
627
723
|
at runtime.
|
|
628
724
|
|
|
629
|
-
-
|
|
725
|
+
- **Four `dompurify` advisories are knowingly left open** (three LOW, one
|
|
630
726
|
MEDIUM), and the dependency is now pinned to **exactly `3.4.7`** rather than
|
|
631
727
|
`^3.4.7`.
|
|
632
728
|
|
|
@@ -635,7 +731,7 @@ hosts that both arrange the page the way it expects.
|
|
|
635
731
|
again against dompurify 3.4.13 with happy-dom 20.11.1 — moving the test DOM
|
|
636
732
|
forward does not fix it.
|
|
637
733
|
|
|
638
|
-
|
|
734
|
+
**The pin was previously a caret range**, so the hold existed only in the
|
|
639
735
|
lockfile and nowhere in the manifest, undocumented — a `pnpm update` would
|
|
640
736
|
have silently disabled sanitisation. It is now exact, explained at the import
|
|
641
737
|
site in `src/ui/render_markdown.ts`, and recorded in `CLAUDE.md`.
|
|
@@ -662,7 +758,7 @@ hosts that both arrange the page the way it expects.
|
|
|
662
758
|
client. It now renders as `Using skill <id>` **instead of** the raw tool
|
|
663
759
|
card it would otherwise produce.
|
|
664
760
|
|
|
665
|
-
|
|
761
|
+
Not to be confused with the existing `Skill` catalog — that is a *human*
|
|
666
762
|
affordance (a prompt the user launches from the chip row or `/`-palette).
|
|
667
763
|
An agent skill is chosen by the model mid-run. Only the latter emits a
|
|
668
764
|
notice.
|
|
@@ -869,7 +965,7 @@ hosts that both arrange the page the way it expects.
|
|
|
869
965
|
/ `onReasoningEnd`, wired from `@ag-ui/client`'s `REASONING_*` subscriber
|
|
870
966
|
callbacks (which also cover the deprecated `THINKING_*` family).
|
|
871
967
|
- **Voice input.** Set `data-transcribe-url` (django-ag-ui's
|
|
872
|
-
`TranscribeView`) to reveal a
|
|
968
|
+
`TranscribeView`) to reveal a mic button in the composer (part
|
|
873
969
|
`voice-button`): it records via `MediaRecorder`, POSTs the clip, and drops the
|
|
874
970
|
returned transcript into the textarea. A pluggable `transcribeHandler` —
|
|
875
971
|
`(audio: Blob) => Promise<string>` — swaps the transport (a different STT
|
|
@@ -914,7 +1010,7 @@ hosts that both arrange the page the way it expects.
|
|
|
914
1010
|
+ summary, no box chrome) with the result behind its own toggle. Every
|
|
915
1011
|
tool-call card now leads with a CSS-drawn **status icon** (part
|
|
916
1012
|
`tool-card-icon`): a spinning ring while running, then a check / cross / slash
|
|
917
|
-
on success / error / decline, replacing the hardcoded
|
|
1013
|
+
on success / error / decline, replacing the hardcoded `` glyph. Re-theme via
|
|
918
1014
|
`--ag-ui-tool-icon-done` / `--ag-ui-tool-icon-error` / `--ag-ui-tool-icon-declined`
|
|
919
1015
|
and `--ag-ui-tool-spin-duration`; the spin respects `prefers-reduced-motion`.
|
|
920
1016
|
|
|
@@ -965,7 +1061,7 @@ hosts that both arrange the page the way it expects.
|
|
|
965
1061
|
### Added
|
|
966
1062
|
|
|
967
1063
|
- **File uploads.** Set `data-attachments-url` (django-ag-ui's `AttachmentsView`)
|
|
968
|
-
to reveal a
|
|
1064
|
+
to reveal a picker + drag-and-drop on the composer. Each file uploads
|
|
969
1065
|
out-of-band (multipart, with the element's `headers`) into a pending tray —
|
|
970
1066
|
one chip per file with a progress bar, settling to `ready` or `error` (with
|
|
971
1067
|
retry / remove). On send, the ready files' refs render as read-only chips on
|
|
@@ -981,7 +1077,7 @@ hosts that both arrange the page the way it expects.
|
|
|
981
1077
|
`(file, onProgress) => Promise<AttachmentRef>` — swaps the built-in multipart
|
|
982
1078
|
upload for a custom one (a resumable `tus-js-client` adapter, direct-to-S3
|
|
983
1079
|
multipart, …) without touching the tray, chips, or AG-UI wire. When set, the
|
|
984
|
-
|
|
1080
|
+
affordance appears even with no `data-attachments-url`. Defaults to the
|
|
985
1081
|
built-in `uploadAttachment`.
|
|
986
1082
|
- **New exports:** `uploadAttachment` + `UploadOptions` + `UploadHandler`, the
|
|
987
1083
|
`AttachmentRef` type, and `messageAttachments`. `AgUiClient.send` gains an
|
|
@@ -1250,7 +1346,9 @@ hosts that both arrange the page the way it expects.
|
|
|
1250
1346
|
### Notes
|
|
1251
1347
|
- First release — exercising the automated npm OIDC publish pipeline end-to-end.
|
|
1252
1348
|
|
|
1253
|
-
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.
|
|
1349
|
+
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.23.1...HEAD
|
|
1350
|
+
[0.23.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.23.0...v0.23.1
|
|
1351
|
+
[0.23.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.22.0...v0.23.0
|
|
1254
1352
|
[0.22.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.21.0...v0.22.0
|
|
1255
1353
|
[0.21.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.20.1...v0.21.0
|
|
1256
1354
|
[0.20.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.20.0...v0.20.1
|
package/README.md
CHANGED
|
@@ -420,7 +420,7 @@ AG-UI has no server-side cancel route: cancelling **aborts the streaming request
|
|
|
420
420
|
|
|
421
421
|
- Partial assistant text already streamed **stays in the transcript** and is persisted via
|
|
422
422
|
`onPersist`, so a reload shows the truncated exchange. A muted **"⏹ Stopped"** note is appended
|
|
423
|
-
(`.stopped-note`) — a deliberate stop is not an error, so no
|
|
423
|
+
(`.stopped-note`) — a deliberate stop is not an error, so no bubble.
|
|
424
424
|
- The run loop stops: tool calls collected before the abort are **not executed**, and no further
|
|
425
425
|
round starts. A frontend tool handler already running completes, but its result doesn't trigger
|
|
426
426
|
a re-run.
|
|
@@ -784,7 +784,7 @@ A gated call carries the decision (`approved by you` / `declined by you`, part
|
|
|
784
784
|
from the server-side approval interrupt alike. The prompt itself disappears once answered: a
|
|
785
785
|
prompt and a record are different objects, and the record is the card.
|
|
786
786
|
|
|
787
|
-
|
|
787
|
+
**The annotation is session-scoped**, like the "run interrupted" notice. AG-UI carries no
|
|
788
788
|
approval message — the answer rides `resume[]` as transient run input — so a reload restores the
|
|
789
789
|
tool call and its result but not the note that a human waved it through. If you need "who
|
|
790
790
|
approved what" durably, that is an audit concern rather than a transcript one; record it
|
|
@@ -827,14 +827,14 @@ is what positions the grip.
|
|
|
827
827
|
A drag writes `--ag-ui-width` / `--ag-ui-height` on the host as custom
|
|
828
828
|
properties.
|
|
829
829
|
|
|
830
|
-
|
|
830
|
+
**That alone does not leave placement in charge** — an inline custom property
|
|
831
831
|
still outranks a `:host([placement=…])` rule setting the same property. So the
|
|
832
832
|
component enforces the split directly: **a placement owns the axes it fixes**,
|
|
833
833
|
and a dragged or persisted size is only ever applied to the ones it leaves free.
|
|
834
834
|
Switching placement hands the owned axes back. Without that, a height dragged
|
|
835
835
|
while floating capped a docked sidebar that had asked for `100vh`.
|
|
836
836
|
|
|
837
|
-
|
|
837
|
+
**A host rule that sizes the element wins over both.** `ag-ui-chat { flex: 1 }`
|
|
838
838
|
stretches the panel to its container and the dragged width has no visible
|
|
839
839
|
effect — which reads as a broken control rather than as your stylesheet winning.
|
|
840
840
|
Give the element `flex: 0 1 auto` (plus `max-width: 100%`) if it lives in a flex
|
|
@@ -1149,7 +1149,7 @@ error — a history affordance that fails is empty, not broken.
|
|
|
1149
1149
|
## File uploads
|
|
1150
1150
|
|
|
1151
1151
|
Set **`data-attachments-url`** (django-ag-ui's `AttachmentsView`) to let the user attach files
|
|
1152
|
-
to a message. A
|
|
1152
|
+
to a message. A button and drag-and-drop appear on the composer; each picked file uploads
|
|
1153
1153
|
out-of-band (multipart, with the element's `headers`) and shows a chip in a pending tray —
|
|
1154
1154
|
`uploading` (with a progress bar) → `ready`, or `error` with a retry. On send, the ready files'
|
|
1155
1155
|
**refs** ride on the user bubble as read-only chips and the agent reads their contents
|
|
@@ -1178,7 +1178,7 @@ See [Authenticating requests](#authenticating-requests).
|
|
|
1178
1178
|
`uploadHandler`. Set your own to use a different transport — a resumable
|
|
1179
1179
|
[`tus-js-client`](https://github.com/tus/tus-js-client) adapter, direct-to-S3 multipart, etc.
|
|
1180
1180
|
— without touching the tray, the chips, or the AG-UI wire (refs are transport-agnostic). The
|
|
1181
|
-
handler is `(file, onProgress) => Promise<AttachmentRef>`; when set, the
|
|
1181
|
+
handler is `(file, onProgress) => Promise<AttachmentRef>`; when set, the affordance appears
|
|
1182
1182
|
even with no `data-attachments-url`, and your handler owns its own endpoint and headers:
|
|
1183
1183
|
|
|
1184
1184
|
```js
|
|
@@ -1409,7 +1409,7 @@ have to hand-tune the variables:
|
|
|
1409
1409
|
See [`src/ui/styles.ts`](src/ui/styles.ts) for the full variable + preset list. The
|
|
1410
1410
|
[`demo/`](demo/) live playground (`node demo/mock-server.mjs`) flips theme, density, placement,
|
|
1411
1411
|
text-animation, tool-display, and the answer well live from a single page, and demos the
|
|
1412
|
-
streamed thoughts region, the
|
|
1412
|
+
streamed thoughts region, the mic, and the header theme toggle.
|
|
1413
1413
|
|
|
1414
1414
|
### Parts and slots
|
|
1415
1415
|
|