@artooi/ag-ui-web-component 0.35.1 → 0.36.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,68 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.36.0] — 2026-09-05
11
+
12
+ ### Added
13
+
14
+ - **A tool call that failed can now say so.** `TOOL_CALL_RESULT` may carry an
15
+ optional `outcome` field -- `success`, `failed` or `denied`, read off the new
16
+ `TOOL_OUTCOME` constant -- and the card settles to *done*, *error* or
17
+ *declined* accordingly. **Absent is a success**, so every server written before
18
+ the field existed renders exactly as it did, and so does any value this release
19
+ does not recognise: a card is a claim about what happened, and not knowing a
20
+ word is not grounds for claiming failure.
21
+
22
+ Nothing in `@ag-ui/core` declares the field. AG-UI's event schemas extend a
23
+ `passthrough` base, so an unknown key survives parsing and reaches the
24
+ subscriber -- asserted in `tests/ag_ui_event_contract.test.ts`, because if that
25
+ ever stops being true every card silently goes back to claiming success.
26
+
27
+ `AgUiClientHandlers.onToolResult` gains a third parameter for it, typed
28
+ `unknown` because the protocol does not validate it; `toolStatusFromOutcome`
29
+ does the narrowing. A handler written against the two-parameter form still
30
+ satisfies the interface and still behaves as before. A **frontend** tool states
31
+ its own outcome on the `ToolExecution` it returns, since no server ran it.
32
+
33
+ ### Fixed
34
+
35
+ - **A refused tool call rendered as a successful one.** Every `TOOL_CALL_RESULT`
36
+ settled its card as *done*, whatever the server said, so a refusal arrived
37
+ green with the reason folded into its result body -- in a sibling demo, a
38
+ booking the server had declined read at a glance as a booking that was made.
39
+ `ERROR` and `DECLINED` existed and the card rendered all three distinctly; they
40
+ were simply unreachable from the server's side.
41
+
42
+ - **A reload turned every tool card green**, which was the same bug reached by a
43
+ second path and needed no server involvement at all: restoring a conversation
44
+ settled *every* historical `tool` message as *done*, so a confirmation the user
45
+ had cancelled came back as an action that went through. The outcome is now
46
+ persisted beside the tool message and read back through the same mapping the
47
+ live path uses.
48
+
49
+ It is written onto the copy handed to the store, never onto `agent.messages` --
50
+ so it does not travel back to the server on the next run -- and a store that
51
+ drops fields it does not know loses only the distinction, falling back to
52
+ *done*. `Message` does not declare the field, exactly as it does not declare
53
+ the `attachments` an upload rides on a user message.
54
+
55
+ ## [0.35.2] — 2026-09-05
56
+
57
+ ### Fixed
58
+
59
+ - **The README's two callouts rendered as code blocks.** This file is the
60
+ documentation -- there is no docs site, so it is what GitHub shows and what npm
61
+ puts on the package page -- and `!!! note` is MkDocs syntax that neither
62
+ understands. The line rendered literally and its indented body became a *code
63
+ block*, so a warning was displayed as something to copy. Both are now GitHub
64
+ callouts.
65
+
66
+ One of the two was 0.35.1's own note about forgetting `defineAgUiChat()`,
67
+ written because that failure is silent. A reader hit the same failure after it
68
+ shipped, which is how the rendering was found: the note was there, was
69
+ correct, and reached nobody. `tests/readme_renders.test.ts` now fails on any
70
+ admonition, and on the registration callout going missing.
71
+
10
72
  ## [0.35.1] — 2026-09-05
11
73
 
12
74
  ### Documentation
@@ -3415,7 +3477,9 @@ hosts that both arrange the page the way it expects.
3415
3477
  ### Notes
3416
3478
  - First release — exercising the automated npm OIDC publish pipeline end-to-end.
3417
3479
 
3418
- [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.1...HEAD
3480
+ [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.36.0...HEAD
3481
+ [0.36.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.2...v0.36.0
3482
+ [0.35.2]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.1...v0.35.2
3419
3483
  [0.35.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.0...v0.35.1
3420
3484
  [0.35.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.34.0...v0.35.0
3421
3485
  [0.34.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.33.1...v0.34.0
package/README.md CHANGED
@@ -149,16 +149,18 @@ Drop the element into your page and register the tools the agent may call:
149
149
  <ag-ui-chat endpoint="/agent/" title-text="Assistant"></ag-ui-chat>
150
150
  ```
151
151
 
152
- !!! note "If nothing appears, check `defineAgUiChat()` ran"
153
- Forgetting it looks like nothing. `<ag-ui-chat>` is then an *unknown
154
- element*, which every browser renders as an inline 0x0 box, in flow, with no
155
- console warning and no error so the page looks finished and the chat is
156
- simply absent. A bare `import "@artooi/ag-ui-web-component"` does not
157
- register anything, deliberately: registration is an explicit call so the
158
- package stays tree-shakeable.
159
-
160
- `customElements.get("ag-ui-chat")` in a console answers it in one line
161
- `undefined` means the call did not run.
152
+ > [!IMPORTANT]
153
+ > **If nothing appears, check that `defineAgUiChat()` ran.** Forgetting it looks
154
+ > like nothing at all. `<ag-ui-chat>` is then an *unknown element*, which every
155
+ > browser renders as an inline 0x0 box, in flow, with no console warning and no
156
+ > error so the page looks finished and the chat is simply absent. There is
157
+ > nothing to search for.
158
+ >
159
+ > A bare `import "@artooi/ag-ui-web-component"` registers nothing, deliberately:
160
+ > registration is an explicit call so the package stays tree-shakeable.
161
+ >
162
+ > `customElements.get("ag-ui-chat")` in a console answers it in one line.
163
+ > `undefined` means the call did not run.
162
164
 
163
165
  That's the whole integration: an `endpoint` attribute pointing at your AG-UI server, optional
164
166
  `headers`, and the tools you want the agent to be able to invoke in the browser. If your API is on
@@ -553,6 +555,38 @@ card (honouring `data-tool-display`), so server-side output is visible too. The
553
555
  and context are read **fresh on every run** (`getTools()` / `getContext()`), so they always reflect
554
556
  the current page state.
555
557
 
558
+ #### A tool call that failed
559
+
560
+ A `TOOL_CALL_RESULT` may carry an optional **`outcome`** field saying how the call ended. It takes
561
+ pydantic-ai's own `ToolReturnPart` vocabulary — read the values off `TOOL_OUTCOME`:
562
+
563
+ | `outcome` | Card | Means |
564
+ | --- | --- | --- |
565
+ | *(absent)* | done | A result, said the way every server has always said it. |
566
+ | `success` | done | The same thing, stated. |
567
+ | `failed` | error | The call ran and failed. |
568
+ | `denied` | declined | A person or a guard refused it, so it never ran. |
569
+
570
+ **Absent is a success, and anything unrecognised is too** — including a value from a later protocol
571
+ version, and pydantic-ai's own `interrupted`. A card is a claim about what happened, and refusing to
572
+ recognise a word is not grounds for claiming failure. So no server has to change to keep the
573
+ rendering it has today, and a server that adds the field gets the truth on screen instead of a
574
+ green card with a refusal folded inside it.
575
+
576
+ Nothing in `@ag-ui/core` needs to declare the field: AG-UI's event schemas are zod `passthrough`, so
577
+ an unknown key survives parsing and reaches the subscriber. It arrives on
578
+ `AgUiClientHandlers.onToolResult` as an optional third argument, typed `unknown` because the
579
+ protocol does not validate it; `toolStatusFromOutcome` does the narrowing.
580
+
581
+ A **frontend** tool never streams this event — the client posts its own result — so its outcome is
582
+ recorded on the `ToolExecution` the executor returns (`{ content, outcome: "denied" }`). That covers
583
+ the two refusals the component makes itself: a confirmation card the user declined, and a call
584
+ blocked because the page moved under the round.
585
+
586
+ Either way the outcome is **persisted beside the tool message**, so a reload replays the card as it
587
+ settled rather than as a plain result. See
588
+ [MPA durability](#mpa-durability-surviving-full-page-reloads).
589
+
556
590
  The catalog a run advertises is also the set that run can execute. Override `getTools` to scope
557
591
  what a page offers — say, exposing `delete_record` only where deleting makes sense — and a call
558
592
  naming a tool you withheld is treated exactly as a call naming a tool you never registered: no
@@ -1668,11 +1702,11 @@ Retry sits on the **last** answer only. Re-running an older turn is branching,
1668
1702
  and for a page-driving agent editing a past turn is not neutral — those turns
1669
1703
  clicked buttons, and re-running turn 3 does not un-save what turn 5 saved.
1670
1704
 
1671
- !!! note
1672
- A retried turn **re-runs its tools.** The previous attempt already did what
1673
- it did, and this does not undo it. Confirmation still applies, so a
1674
- destructive tool asks again — unless the user waived it for this session
1675
- with *Always allow*.
1705
+ > [!NOTE]
1706
+ > A retried turn **re-runs its tools.** The previous attempt already did what it
1707
+ > did, and this does not undo it. Confirmation still applies, so a destructive
1708
+ > tool asks again — unless the user waived it for this session with
1709
+ > *Always allow*.
1676
1710
 
1677
1711
  A failed run gets the same row, with Retry and Copy and no rating: error text is
1678
1712
  what people paste into a bug report, but "the connection dropped" is not a
@@ -1921,6 +1955,15 @@ On mount the element rehydrates the transcript from the store, so the chat looks
1921
1955
  including tool-call cards and their results (reconstructed from the persisted `toolCalls` and `tool`
1922
1956
  messages), not just the text turns.
1923
1957
 
1958
+ A tool message is saved with an extra **`outcome`** field when the call did not simply succeed, in
1959
+ the same vocabulary the wire uses (see [A tool call that failed](#a-tool-call-that-failed)), so a
1960
+ failed or declined card replays as failed or declined instead of turning green on reload. `Message`
1961
+ does not declare the field, exactly as it does not declare the `attachments` an upload rides on a
1962
+ user message; the default store round-trips both through `JSON.stringify`. **A store that drops
1963
+ unknown fields loses only the distinction** — the card falls back to *done*, which is what it did
1964
+ before. It is written onto the copy handed to the store and never onto `agent.messages`, so it is
1965
+ not sent back to the server on the next run.
1966
+
1924
1967
  **3. Resumable loop (`x-navigates` + `navigationResult`).** A tool whose schema carries
1925
1968
  `x-navigates: true` (use `X_NAVIGATES_KEY`; read back by [`isNavigates`](src/tools/is_navigates.ts))
1926
1969
  triggers a full reload. Before the handler navigates, the element writes a checkpoint
@@ -2395,6 +2438,8 @@ re-export point. Internal modules import from leaf paths.
2395
2438
  | `AgUiClient` | class | Orchestration layer over an AG-UI `AbstractAgent`. |
2396
2439
  | `AgUiClientConfig` / `AgUiClientHandlers` / `AgUiRunInputs` | type | Client config, lifecycle handlers, per-run input providers. |
2397
2440
  | `AgUiToolCall` / `ToolExecution` / `ExecuteTool` | type | Tool-call shape, execution result, executor signature. |
2441
+ | `ToolOutcome` | type | The `TOOL_OUTCOME` values as a union. |
2442
+ | `toolStatusFromOutcome` | function | Map a wire outcome to the card status it settles into; anything absent or unrecognised is a success. |
2398
2443
  | `ConnectionLostError` | class | Raised (→ `onError`) when a run's stream closes with no terminal AG-UI event. |
2399
2444
  | `createHttpAgent(options)` | function | Default agent factory (wraps `HttpAgent`). |
2400
2445
  | `AgentFactory` / `HttpAgentOptions` | type | Factory signature and its options. |
@@ -2549,6 +2594,7 @@ re-export point. Internal modules import from leaf paths.
2549
2594
  | `MESSAGE_ACTIONS` | The message-action tokens `data-message-actions` selects by (`copy` / `retry` / `feedback`). |
2550
2595
  | `TOOL_CALL_STATUS` | Tool-call card status constants. |
2551
2596
  | `TOOL_DISPLAY` | Tool-call display-mode constants (`inline` / `minimal` / `compact` / `full`). |
2597
+ | `TOOL_OUTCOME` | How a tool call ended, as a server states it on `TOOL_CALL_RESULT` (`success` / `failed` / `denied`). |
2552
2598
  | `X_CONFIRM_KEY` | Confirmation-prompt key: on a tool's JSON Schema for a client-side confirmation, and in an AG-UI interrupt's `metadata` for a server-side approval. |
2553
2599
  | `X_SUMMARY_KEY` | JSON-Schema key carrying a short tool-card label. |
2554
2600
  | `MAX_TOOL_ROUNDS` | Upper bound on tool-call → re-run rounds per send. |