@artooi/ag-ui-web-component 0.35.2 → 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,51 @@ 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
+
10
55
  ## [0.35.2] — 2026-09-05
11
56
 
12
57
  ### Fixed
@@ -3432,7 +3477,8 @@ hosts that both arrange the page the way it expects.
3432
3477
  ### Notes
3433
3478
  - First release — exercising the automated npm OIDC publish pipeline end-to-end.
3434
3479
 
3435
- [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.2...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
3436
3482
  [0.35.2]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.1...v0.35.2
3437
3483
  [0.35.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.35.0...v0.35.1
3438
3484
  [0.35.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.34.0...v0.35.0
package/README.md CHANGED
@@ -555,6 +555,38 @@ card (honouring `data-tool-display`), so server-side output is visible too. The
555
555
  and context are read **fresh on every run** (`getTools()` / `getContext()`), so they always reflect
556
556
  the current page state.
557
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
+
558
590
  The catalog a run advertises is also the set that run can execute. Override `getTools` to scope
559
591
  what a page offers — say, exposing `delete_record` only where deleting makes sense — and a call
560
592
  naming a tool you withheld is treated exactly as a call naming a tool you never registered: no
@@ -1923,6 +1955,15 @@ On mount the element rehydrates the transcript from the store, so the chat looks
1923
1955
  including tool-call cards and their results (reconstructed from the persisted `toolCalls` and `tool`
1924
1956
  messages), not just the text turns.
1925
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
+
1926
1967
  **3. Resumable loop (`x-navigates` + `navigationResult`).** A tool whose schema carries
1927
1968
  `x-navigates: true` (use `X_NAVIGATES_KEY`; read back by [`isNavigates`](src/tools/is_navigates.ts))
1928
1969
  triggers a full reload. Before the handler navigates, the element writes a checkpoint
@@ -2397,6 +2438,8 @@ re-export point. Internal modules import from leaf paths.
2397
2438
  | `AgUiClient` | class | Orchestration layer over an AG-UI `AbstractAgent`. |
2398
2439
  | `AgUiClientConfig` / `AgUiClientHandlers` / `AgUiRunInputs` | type | Client config, lifecycle handlers, per-run input providers. |
2399
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. |
2400
2443
  | `ConnectionLostError` | class | Raised (→ `onError`) when a run's stream closes with no terminal AG-UI event. |
2401
2444
  | `createHttpAgent(options)` | function | Default agent factory (wraps `HttpAgent`). |
2402
2445
  | `AgentFactory` / `HttpAgentOptions` | type | Factory signature and its options. |
@@ -2551,6 +2594,7 @@ re-export point. Internal modules import from leaf paths.
2551
2594
  | `MESSAGE_ACTIONS` | The message-action tokens `data-message-actions` selects by (`copy` / `retry` / `feedback`). |
2552
2595
  | `TOOL_CALL_STATUS` | Tool-call card status constants. |
2553
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`). |
2554
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. |
2555
2599
  | `X_SUMMARY_KEY` | JSON-Schema key carrying a short tool-card label. |
2556
2600
  | `MAX_TOOL_ROUNDS` | Upper bound on tool-call → re-run rounds per send. |