@artooi/ag-ui-web-component 0.40.0 → 0.41.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,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.41.0] — 2026-09-22
11
+
12
+ ### Changed
13
+
14
+ - **Requires `@ag-ui/client` and `@ag-ui/core` 1.0.** Both ranges are now
15
+ `>=1.0.0 <2`. A host that bundles the package itself resolves 1.0 beside it;
16
+ the vendored bundle carries its own copy.
17
+
18
+ - **A tool result whose content arrives as parts shows its text.** Since 1.0 a
19
+ tool may return an ordered list of parts rather than a string, so a result can
20
+ carry an image beside its text. The card shows the text parts joined, both
21
+ while the run streams and when a reload replays it, and the saved conversation
22
+ keeps the message whole, parts included.
23
+
24
+ - **A tool call's outcome and a message's attachment refs travel in
25
+ `metadata`.** `@ag-ui/client` 1.0 strips every key its schemas do not declare,
26
+ from an inbound event before any subscriber sees it and from the outgoing run
27
+ input before it is sent, and `metadata` is the one field on events and
28
+ messages it declares open by key. The element now reads a `TOOL_CALL_RESULT`'s
29
+ outcome from `metadata.outcome` only, which is also what
30
+ `AgUiClientHandlers.onToolResult` receives, and `sendMessage` puts a user
31
+ message's refs at `metadata.attachments`.
32
+
33
+ The client folds a result's metadata onto the tool message it keeps, so a
34
+ server's outcome is now saved on the message itself, and the element writes
35
+ the outcomes it decides on its own -- a declined confirmation, a frontend tool
36
+ that threw, a call the run left unfinished -- in the same place. The outcome
37
+ therefore goes back to the server with the rest of the history on every run,
38
+ which it never did before. `metadata` is a declared field, and a server that
39
+ does not read the key ignores it.
40
+
41
+ - **Needs django-ag-ui 0.63.0 or later for outcomes and attachments.** An older
42
+ server writes the outcome, and reads the refs, at the top level, where 1.0
43
+ strips them. The chat still runs against one, but the agent is never told a
44
+ file was attached, and a failed or declined server-side tool call settles as
45
+ done.
46
+
47
+ - **Conversations stored by an earlier release keep both.** Their tool messages
48
+ carry `outcome`, and their user messages `attachments`, at the top level. The
49
+ replay reads `metadata` first and falls back to the top-level key, so a
50
+ declined card stays declined after the upgrade and a bubble keeps its chips.
51
+ A client seeded from such a conversation moves both keys into `metadata`
52
+ before its first request, so the server is still told about every file
53
+ attached before the upgrade, and the next save writes the new shape.
54
+
55
+ ### Deprecated
56
+
57
+ - **`AgUiClient.annotatedMessages` is the same list as `messages`.** It returned
58
+ a copy with each tool call's outcome added for the store, which the outcome
59
+ being on the message has made unnecessary. It is kept so code written against
60
+ it compiles and gets the same history.
61
+
10
62
  ## [0.40.0] — 2026-09-17
11
63
 
12
64
  ### Changed
@@ -4126,7 +4178,8 @@ hosts that both arrange the page the way it expects.
4126
4178
  ### Notes
4127
4179
  - First release — exercising the automated npm OIDC publish pipeline end-to-end.
4128
4180
 
4129
- [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.40.0...HEAD
4181
+ [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.41.0...HEAD
4182
+ [0.41.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.40.0...v0.41.0
4130
4183
  [0.40.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.39.0...v0.40.0
4131
4184
  [0.39.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.38.0...v0.39.0
4132
4185
  [0.38.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.37.0...v0.38.0
package/README.md CHANGED
@@ -569,8 +569,9 @@ the current page state.
569
569
 
570
570
  #### A tool call that failed
571
571
 
572
- A `TOOL_CALL_RESULT` may carry an optional **`outcome`** field saying how the call ended. It takes
573
- pydantic-ai's own `ToolReturnPart` vocabulary — read the values off `TOOL_OUTCOME`:
572
+ A `TOOL_CALL_RESULT` may say how the call ended, as an optional **`outcome`** key in the event's
573
+ `metadata` (`"metadata": { "outcome": "failed" }`). It takes pydantic-ai's own `ToolReturnPart`
574
+ vocabulary — read the values off `TOOL_OUTCOME`:
574
575
 
575
576
  | `outcome` | Card | Means |
576
577
  | --- | --- | --- |
@@ -586,18 +587,23 @@ recognise a word is not grounds for claiming failure. So no server has to change
586
587
  rendering it has today, and a server that adds the field gets the truth on screen instead of a
587
588
  green card with a refusal folded inside it.
588
589
 
589
- Nothing in `@ag-ui/core` needs to declare the field: AG-UI's event schemas are zod `passthrough`, so
590
- an unknown key survives parsing and reaches the subscriber. It arrives on
591
- `AgUiClientHandlers.onToolResult` as an optional third argument, typed `unknown` because the
592
- protocol does not validate it; `toolStatusFromOutcome` does the narrowing.
590
+ It has to be in `metadata`. `@ag-ui/client` 1.0 strips every key its schemas do not declare from an
591
+ event before any subscriber sees it, with a `[ag-ui][enforce]` console warning, and `metadata` is
592
+ the one place on an event it declares open by key. An `outcome` at the top level of the event —
593
+ where a server wrote it for the 0.x client, and where a django-ag-ui older than 0.63.0 still does —
594
+ never arrives, so the card settles as done. The key arrives on `AgUiClientHandlers.onToolResult` as
595
+ an optional third argument, typed `unknown` because the protocol validates nothing inside
596
+ `metadata`; `toolStatusFromOutcome` does the narrowing.
593
597
 
594
598
  A **frontend** tool never streams this event — the client posts its own result — so its outcome is
595
599
  recorded on the `ToolExecution` the executor returns (`{ content, outcome: "denied" }`). That covers
596
600
  the two refusals the component makes itself: a confirmation card the user declined, and a call
597
601
  blocked because the page moved under the round.
598
602
 
599
- Either way the outcome is **persisted beside the tool message**, so a reload replays the card as it
600
- settled rather than as a plain result. See
603
+ Either way the outcome is **persisted on the tool message, in its `metadata`**, so a reload replays
604
+ the card as it settled rather than as a plain result. For a server's result `@ag-ui/client` puts it
605
+ there itself, folding the event's metadata onto the tool message it appends; for its own results the
606
+ client writes it in the same place. See
601
607
  [MPA durability](#mpa-durability-surviving-full-page-reloads).
602
608
 
603
609
  **Every request carries a result for every tool call in it.** Several model providers reject a
@@ -2019,16 +2025,23 @@ On mount the element rehydrates the transcript from the store, so the chat looks
2019
2025
  including tool-call cards and their results (reconstructed from the persisted `toolCalls` and `tool`
2020
2026
  messages), not just the text turns.
2021
2027
 
2022
- A tool message is saved with an extra **`outcome`** field when the call did not simply succeed, in
2023
- the same vocabulary the wire uses (see [A tool call that failed](#a-tool-call-that-failed)), so a
2024
- failed or declined card replays as failed or declined instead of turning green on reload. `Message`
2025
- does not declare the field, exactly as it does not declare the `attachments` an upload rides on a
2026
- user message; the default store round-trips both through `JSON.stringify`. **A store that drops
2027
- unknown fields loses only the distinction** — the card falls back to *done*, which is what it did
2028
- before. It is written onto the copy handed to the store and never onto `agent.messages`, so it is
2029
- not sent back to the server on the next run. That holds after a restore too: the client seeded from
2030
- a stored conversation takes the field off every message it is seeded with and writes it back on the
2031
- next save.
2028
+ A tool message is saved with an **`outcome`** in its `metadata` when the call did not simply
2029
+ succeed, in the same vocabulary the wire uses (see [A tool call that failed](#a-tool-call-that-failed)),
2030
+ so a failed or declined card replays as failed or declined instead of turning green on reload. A user
2031
+ message keeps the refs of its uploads the same way, under `attachments` in its `metadata`. Both
2032
+ round-trip through `JSON.stringify` in the default store. **A store that drops `metadata` loses only
2033
+ the distinction** — the card falls back to *done*, which is what it did before, and the bubble loses
2034
+ its chips.
2035
+
2036
+ What is saved is exactly what the next request sends, so both go back to the server on every run.
2037
+ That is the protocol's own behaviour for a declared field rather than a client-side addition: a server
2038
+ validates `metadata` as an open object, and one that does not read a key ignores it — django-ag-ui
2039
+ reads `attachments` and ignores `outcome`.
2040
+
2041
+ A conversation stored by an earlier release has both keys at the top level of the message instead.
2042
+ The history replay reads them from there when the metadata has none, and a client seeded from such a
2043
+ conversation moves them into `metadata` before its first request, because `@ag-ui/client` 1.0 would
2044
+ strip them from the request as it stands. The next save writes them in the new shape.
2032
2045
 
2033
2046
  **3. Resumable loop (`x-navigates` + `navigationResult`).** A tool whose schema carries
2034
2047
  `x-navigates: true` (use `X_NAVIGATES_KEY`; read back by [`isNavigates`](src/tools/is_navigates.ts))
@@ -2455,7 +2468,10 @@ out-of-band (multipart, with the element's `headers`) and shows a chip in a pend
2455
2468
  `uploading` (with a progress bar) → `ready`, or `error` with a retry. On send, the ready files'
2456
2469
  **refs** ride on the user bubble as read-only chips and the agent reads their contents
2457
2470
  server-side via the `read_attachment` tool. The wire stays vanilla AG-UI: only lightweight refs
2458
- (`{ id, name, mime, size }`) travel, never the bytes.
2471
+ (`{ id, name, mime, size }`) travel, never the bytes, in the user message's `metadata` under
2472
+ `attachments` — the one place on a message `@ag-ui/client` 1.0 does not strip an unknown key from.
2473
+ django-ag-ui reads them from there as of 0.63.0; an older one reads only the top-level key 1.0
2474
+ removes, so against it the agent is never told a file was attached.
2459
2475
 
2460
2476
  ### Pasting
2461
2477
 
@@ -2626,7 +2642,7 @@ re-export point. Internal modules import from leaf paths.
2626
2642
  | `UploadOptions` | type | `{ url, headers?, credentials?, onProgress?, signal? }`. `credentials` is spelled as a fetch mode but carried by `XMLHttpRequest.withCredentials`, so only `"include"` is distinguishable. |
2627
2643
  | `UploadHandler` | type | `(file, onProgress, signal?) => Promise<AttachmentRef>` — the `uploadHandler` swap seam (tus / S3). The signal fires when the tray removes a chip or the element is torn down; a handler that honours it aborts its own transport, so a cancelled upload leaves no orphaned file on the server. |
2628
2644
  | `AttachmentRef` | type | The durable upload ref (`{ id, name, mime, size, url? }`). |
2629
- | `messageAttachments(message)` | function | Read the refs a restored user message carries. |
2645
+ | `messageAttachments(message)` | function | Read the refs a restored user message carries: from its `metadata`, or from the top level where an earlier release stored them. |
2630
2646
 
2631
2647
  ### Voice input
2632
2648
 
@@ -3165,9 +3181,9 @@ When a reasoning model streams its chain-of-thought (django-ag-ui forwards it as
3165
3181
  events — enable a thinking budget via `MODEL_SETTINGS`, see its docs), the element renders a muted,
3166
3182
  collapsible **thoughts region** (part `thoughts`) at the top of the current answer group. It opens
3167
3183
  while the model reasons and folds away on the answer's first token; the reader can reopen it. The
3168
- web component handles the `REASONING_*` event family (and the deprecated `THINKING_*`, which
3169
- `@ag-ui/client` maps onto it), so no client config is needed — the thoughts appear whenever the
3170
- server forwards reasoning.
3184
+ web component handles the `REASONING_*` event family (and the retired `THINKING_*`, which
3185
+ `@ag-ui/client` still converts onto it, with a console warning, during its deprecation window), so
3186
+ no client config is needed — the thoughts appear whenever the server forwards reasoning.
3171
3187
 
3172
3188
  ### The composer
3173
3189
 
@@ -3298,11 +3314,17 @@ Other workflow targets (all identical in name to the sibling Python packages):
3298
3314
  | --- | --- | --- |
3299
3315
  | Node (tooling/tests only) | 22 | 22, 24 |
3300
3316
  | Browsers (runtime target) | ES2022 / evergreen | Chrome / Firefox / Safari 17+ |
3301
- | `@ag-ui/client` | latest 0.x | — |
3317
+ | `@ag-ui/client`, `@ag-ui/core` | 1.0 | 1.0 |
3318
+ | django-ag-ui (server) | 0.63.0 | — |
3302
3319
 
3303
3320
  The shipped artefact targets evergreen browsers (Shadow DOM, Custom Elements v1, ES2022). Node is
3304
3321
  only the build/test runtime, not a runtime target.
3305
3322
 
3323
+ The server floor is a wire contract rather than a dependency. A tool call's outcome and a user
3324
+ message's attachment refs travel in `metadata`, since `@ag-ui/client` 1.0 strips every key its
3325
+ schemas do not declare. Against an older django-ag-ui the chat still runs, but the agent is never
3326
+ told about an attached file and a failed or declined server-side tool call settles as done.
3327
+
3306
3328
  ---
3307
3329
 
3308
3330
  ## License