@artooi/ag-ui-web-component 0.12.0 → 0.14.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,91 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.14.0] — 2026-07-28
11
+
12
+ ### Added
13
+
14
+ - **Run notices — a muted inline annotation for things the *run* did**, as
15
+ opposed to work the user asked for. Styleable via the `run-notice`,
16
+ `run-notice-icon` and `run-notice-text` parts; announced with `role="status"`
17
+ so a screen reader hears it politely rather than mid-sentence.
18
+ - **Compaction.** A standard AG-UI `ACTIVITY_SNAPSHOT` with
19
+ `activityType: "compaction"` (emitted by django-ag-ui 0.26+ when a
20
+ compaction capability trimmed the history) renders as "earlier turns
21
+ condensed", with the count. Activity events of any other type pass through
22
+ untouched, so another producer on that channel isn't mistaken for one.
23
+ - **Agent skills.** There is no dedicated event: loading a deferred capability
24
+ *is* an ordinary `load_capability` tool call, which is what reaches the
25
+ client. It now renders as `Using skill <id>` **instead of** the raw tool
26
+ card it would otherwise produce.
27
+
28
+ ⚠ Not to be confused with the existing `Skill` catalog — that is a *human*
29
+ affordance (a prompt the user launches from the chip row or `/`-palette).
30
+ An agent skill is chosen by the model mid-run. Only the latter emits a
31
+ notice.
32
+ - **Suppression covers all three paths a card can come from** — the live
33
+ stream, the client's tool-execution loop, and **restored history** — so a
34
+ reload shows the same transcript rather than resurrecting the raw
35
+ `load_capability` card.
36
+ - A `load_capability` call with **no usable id** falls back to a normal tool
37
+ card rather than being dropped: a malformed call is still real activity, and
38
+ hiding it would be worse than showing it plainly.
39
+ - **`onActivity(activityType, content)`** on `AgUiClientHandlers`, forwarding
40
+ AG-UI activity events to the host element. `COMPACTION_ACTIVITY_TYPE` and
41
+ `LOAD_CAPABILITY_TOOL` are exported from `constants`.
42
+ - **Two new overridable strings**: `historyCompacted` (token `{count}`) and
43
+ `usingSkill` (token `{name}`).
44
+
45
+ ## [0.13.0] — 2026-07-27
46
+
47
+ ### Added
48
+
49
+ - **AG-UI shared state.** `<ag-ui-chat>` now speaks the protocol's own state
50
+ channel: assign `chat.sharedState = {...}` to seed it, listen for the
51
+ `ag-ui-state` event (`detail.state`) to react when the agent changes it.
52
+ State rides `RunAgentInput.state` on every run and is replaced in place when
53
+ the server streams `STATE_SNAPSHOT` / `STATE_DELTA`.
54
+ - **Adoption, not implementation.** `@ag-ui/client` already applies both
55
+ events to `agent.state` and exposes an `onStateChanged` subscriber hook;
56
+ what was missing was seeding it (`initialState`) and surfacing it to the
57
+ host. Deriving state from the raw event stream ourselves would have
58
+ duplicated — and eventually contradicted — the client's own handling,
59
+ including its JSON-Patch delta application.
60
+ - Assigning **after** the conversation has started pushes through to the live
61
+ agent rather than waiting for a new one, so a host that seeds state late
62
+ isn't silently stranded.
63
+ - The event is `composed: true`, so a host listening on `document` receives it
64
+ through the shadow boundary.
65
+ - **Distinct from `registerPageState`**, which exposes host state to the agent
66
+ as ordinary *tools*. Use shared state when agent and page edit the same
67
+ object; use page-state tools when the agent should *ask* — a tool call is
68
+ visible in the transcript and can be gated by a confirmation card, which
69
+ state events cannot.
70
+
71
+ ### Changed
72
+
73
+ - **`registerStateHook` is now `registerPageState`** (and `createStateHookTools` /
74
+ `StateHook` are `createPageStateTools` / `PageState`). **The old names implied a
75
+ feature that does not exist**: they read as AG-UI shared-state sync —
76
+ `STATE_SNAPSHOT` / `STATE_DELTA`, the protocol events that carry a state object
77
+ between agent and client — which neither this component nor `django-ag-ui`
78
+ implements. What the method actually does is generate two ordinary client tools
79
+ (`read_<name>` / `set_<name>`) over host page state, which the agent calls like
80
+ any other tool. `page` matches the vocabulary already used throughout the
81
+ component (`page_map`, `page_action_tools`, `route_map`, the DOM driver).
82
+ - **Not a hard break.** The old spellings are kept as deprecated aliases and
83
+ behave identically; they will be removed in a future major. A rename is only
84
+ ever cheaper the earlier it happens, which is why this ships now rather than
85
+ waiting for state support to exist.
86
+
87
+ ### Documentation
88
+
89
+ - **The README now distinguishes the two state mechanisms**, which the old
90
+ method name conflated. `sharedState` is the protocol's state channel;
91
+ `registerPageState` generates ordinary client tools. The rename and the
92
+ feature landed together, so the docs answer "which one" rather than leaving
93
+ two similar names side by side.
94
+
10
95
  ## [0.12.0] — 2026-07-27
11
96
 
12
97
  ### Added
@@ -528,7 +613,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
528
613
  ### Notes
529
614
  - First release — exercising the automated npm OIDC publish pipeline end-to-end.
530
615
 
531
- [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.12.0...HEAD
616
+ [Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.14.0...HEAD
617
+ [0.14.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.13.0...v0.14.0
618
+ [0.13.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.12.0...v0.13.0
532
619
  [0.12.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.11.0...v0.12.0
533
620
  [0.11.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.10.0...v0.11.0
534
621
  [0.10.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.9.0...v0.10.0
package/README.md CHANGED
@@ -48,6 +48,7 @@ No framework, no Django, no admin specifics live here. Downstream consumers (e.g
48
48
  - [New chat and collapse](#new-chat-and-collapse)
49
49
  - [Tool-call display modes](#tool-call-display-modes)
50
50
  - [Markdown rendering](#markdown-rendering)
51
+ - [Run notices: compaction and agent skills](#run-notices-compaction-and-agent-skills)
51
52
  - [Skills: prompt chips and slash palette](#skills-prompt-chips-and-slash-palette)
52
53
  - [MPA durability: surviving full page reloads](#mpa-durability-surviving-full-page-reloads)
53
54
  - [Host seams: the SPA story](#host-seams-the-spa-story)
@@ -191,7 +192,9 @@ the django-ag-ui `@tool` registry), whose schema never reaches the browser — e
191
192
  labels are fetched automatically — per card, `x-summary` → an explicit
192
193
  `toolSummaries` entry → the fetched catalog → the raw name.
193
194
 
194
- **Methods**: `registerTool`, `registerStateHook`, `setSkills`, `appendMessage`, `newChat`,
195
+ **Properties** (selected): `sharedState` AG-UI shared state (documented under Tools & state).
196
+
197
+ **Methods**: `registerTool`, `registerPageState`, `setSkills`, `appendMessage`, `newChat`,
195
198
  `setCollapsed`, `toggleCollapsed`.
196
199
 
197
200
  A self-contained live playground lives in [`demo/`](demo/) — run `make demo` to serve it against a
@@ -515,6 +518,37 @@ reveal). It honours `prefers-reduced-motion` (collapsing to instant).
515
518
 
516
519
  ---
517
520
 
521
+ ## Run notices: compaction and agent skills
522
+
523
+ Some things a run does are neither text nor a tool the user asked for — the server condensed
524
+ earlier turns to fit the context window, or the model pulled in an agent skill. Those render as
525
+ **run notices**: a muted one-line annotation inline in the transcript, styleable via the
526
+ `run-notice`, `run-notice-icon` and `run-notice-text` `part`s.
527
+
528
+ > **Two different things are called "skills".**
529
+ > The [prompt chips and slash palette](#skills-prompt-chips-and-slash-palette) below are a
530
+ > **human** affordance — prompts *the user* launches. An **agent skill** is a folder of
531
+ > instructions *the model* chooses to load mid-run. Only the second produces a run notice.
532
+
533
+ Neither notice needs configuration here — both appear when the server is set up to produce them.
534
+
535
+ **Compaction.** `django-ag-ui` emits a standard AG-UI `ACTIVITY_SNAPSHOT` with
536
+ `activityType: "compaction"` when a compaction capability trimmed the history; the notice reports
537
+ how many messages went. Server side, that means wrapping the capability in `CompactionObserver` —
538
+ see [django-ag-ui's compaction guide](https://artui.github.io/django-ag-ui/compaction/). Activity
539
+ events of any other type pass through untouched, so another producer on that channel is not
540
+ mistaken for a compaction.
541
+
542
+ **Agent skills.** There is no dedicated event for these: loading a deferred capability *is* an
543
+ ordinary `load_capability` tool call, which is what reaches the client. The component recognises
544
+ it, renders `Using skill <id>`, and suppresses the raw tool card that would otherwise appear
545
+ beside it — on the live stream and on restored history alike, so a reload shows the same
546
+ transcript. A `load_capability` call with no usable id falls back to a normal tool card rather
547
+ than being dropped, since it is still real activity.
548
+
549
+ Both strings are overridable like every other — `historyCompacted` (token `{count}`) and
550
+ `usingSkill` (token `{name}`).
551
+
518
552
  ## Skills: prompt chips and slash palette
519
553
 
520
554
  Skills are pre-defined prompts the user can launch from a chip or the `/`-command palette. They are
@@ -621,12 +655,12 @@ so it reflects the page the agent is currently looking at:
621
655
  chat.getPageMap = () => ({ fields: introspectForm(), buttons: visibleButtons() });
622
656
  ```
623
657
 
624
- **`registerStateHook({ name, read, write?, schema? })`** — ergonomic sugar over `registerTool` for
658
+ **`registerPageState({ name, read, write?, schema? })`** — ergonomic sugar over `registerTool` for
625
659
  SPA app state (Redux/Zustand/signals). It auto-generates a `read_<name>` (read-only) tool and, when
626
660
  `write` is supplied, a `set_<name>` tool stamped `x-destructive`:
627
661
 
628
662
  ```js
629
- chat.registerStateHook({
663
+ chat.registerPageState({
630
664
  name: "cart",
631
665
  read: () => store.getState().cart,
632
666
  write: ({ items }) => store.dispatch(setCart(items)),
@@ -634,6 +668,42 @@ chat.registerStateHook({
634
668
  });
635
669
  ```
636
670
 
671
+ **This is not AG-UI shared state** — that is `sharedState`, below. `registerPageState` generates two
672
+ ordinary client tools; the agent reads or writes your store by *calling a tool*. The method was
673
+ called `registerStateHook` through 0.12, a name that read as protocol state sync; the old spelling
674
+ still works and is deprecated.
675
+
676
+ **`sharedState`** *(property)* — AG-UI **shared state**: the protocol's own state channel, sent as
677
+ `RunAgentInput.state` on every run and replaced in place when the server streams `STATE_SNAPSHOT` /
678
+ `STATE_DELTA`. Assign to seed it, listen for `ag-ui-state` to react:
679
+
680
+ ```js
681
+ chat.sharedState = { document: "" };
682
+
683
+ chat.addEventListener("ag-ui-state", (e) => {
684
+ editor.value = e.detail.state.document; // the agent rewrote it
685
+ });
686
+ ```
687
+
688
+ Server-side, a tool mutates `ctx.deps.state` and returns the snapshot as `ToolReturn` metadata —
689
+ pydantic-ai does not emit deltas for you:
690
+
691
+ ```python
692
+ @tool(registry)
693
+ async def write_document(ctx: RunContext[AgentDeps], body: str) -> ToolReturn:
694
+ """Replace the shared document."""
695
+ ctx.deps.state = {**(ctx.deps.state or {}), "document": body}
696
+ return ToolReturn(
697
+ return_value="written",
698
+ metadata=[StateSnapshotEvent(type=EventType.STATE_SNAPSHOT, snapshot=ctx.deps.state)],
699
+ )
700
+ ```
701
+
702
+ Use this when the agent and the page are editing **the same object** (a document, a form, a
703
+ canvas). Use `registerPageState` when the agent should *ask* for a value or *request* a change —
704
+ the tool call is visible in the transcript and can be gated by a confirmation card, which state
705
+ events cannot.
706
+
637
707
  **`navigate(path): void`** *(optional)* — a host routing callback. **This single seam is what
638
708
  distinguishes an SPA from an MPA.** When set, `navigate_to_route` routes client-side (no reload) and
639
709
  the in-memory run loop simply continues — the whole resumable-loop / checkpoint machinery is
@@ -798,8 +868,8 @@ re-export point. Internal modules import from leaf paths.
798
868
  | `RouteWithParams` | type | A route resolved with `:param` path segments + leftover query params. |
799
869
  | `createPageMapContext(...)` | function | Build the per-run `page_map` context entry. |
800
870
  | `PageMap` | type | The compact page-surface shape. |
801
- | `createStateHookTools(hook)` | function | Build `read_<name>` / `set_<name>` tools. |
802
- | `StateHook` | type | A state-binding declaration. |
871
+ | `createPageStateTools(binding)` | function | Build `read_<name>` / `set_<name>` tools. |
872
+ | `PageState` | type | A page-state binding declaration. |
803
873
  | `Skill` | type | A launchable prompt (chip / `/`-command). |
804
874
 
805
875
  ### Durability