@assistant-ui/mcp-docs-server 0.1.39 → 0.2.1
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/.docs/organized/code-examples/waterfall.md +17 -18
- package/.docs/organized/code-examples/with-a2a.md +20 -15
- package/.docs/organized/code-examples/with-ag-ui.md +19 -17
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +17 -16
- package/.docs/organized/code-examples/with-artifacts.md +471 -145
- package/.docs/organized/code-examples/with-assistant-transport.md +23 -31
- package/.docs/organized/code-examples/with-browser-extension.md +21 -14
- package/.docs/organized/code-examples/with-chain-of-thought.md +22 -20
- package/.docs/organized/code-examples/with-cloud-standalone.md +13 -14
- package/.docs/organized/code-examples/with-cloud.md +22 -17
- package/.docs/organized/code-examples/with-custom-thread-list.md +17 -16
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +17 -17
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +21 -19
- package/.docs/organized/code-examples/with-eve.md +70 -16
- package/.docs/organized/code-examples/with-expo.md +32 -51
- package/.docs/organized/code-examples/with-external-store.md +20 -15
- package/.docs/organized/code-examples/with-ffmpeg.md +24 -18
- package/.docs/organized/code-examples/with-generative-ui.md +20 -21
- package/.docs/organized/code-examples/with-google-adk.md +21 -16
- package/.docs/organized/code-examples/with-heat-graph.md +10 -11
- package/.docs/organized/code-examples/with-image-generation.md +13 -14
- package/.docs/organized/code-examples/with-interactables.md +17 -16
- package/.docs/organized/code-examples/with-langchain.md +13 -14
- package/.docs/organized/code-examples/with-langgraph.md +23 -17
- package/.docs/organized/code-examples/with-livekit.md +17 -17
- package/.docs/organized/code-examples/with-mcp.md +36 -32
- package/.docs/organized/code-examples/with-nuxt.md +2492 -0
- package/.docs/organized/code-examples/with-opencode.md +27 -21
- package/.docs/organized/code-examples/with-pi.md +69 -67
- package/.docs/organized/code-examples/with-react-hook-form.md +18 -17
- package/.docs/organized/code-examples/with-react-ink-web.md +10 -11
- package/.docs/organized/code-examples/with-react-ink.md +7 -7
- package/.docs/organized/code-examples/with-react-router.md +23 -17
- package/.docs/organized/code-examples/with-resumable-stream.md +15 -16
- package/.docs/organized/code-examples/with-store.md +31 -20
- package/.docs/organized/code-examples/with-tanstack.md +22 -16
- package/.docs/organized/code-examples/with-tap-runtime.md +19 -19
- package/.docs/organized/code-examples/with-virtualized-thread.md +12 -13
- package/.docs/organized/code-examples/with-vue.md +408 -0
- package/.docs/raw/docs/(docs)/cli.mdx +3 -1
- package/.docs/raw/docs/(docs)/devtools.mdx +7 -2
- package/.docs/raw/docs/(docs)/index.mdx +9 -76
- package/.docs/raw/docs/(docs)/installation.mdx +4 -18
- package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +24 -4
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/a2ui.mdx +40 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +3 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +19 -420
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +8 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +21 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -9
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +1 -18
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +24 -1
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +1 -1
- package/.docs/raw/docs/cloud/ai-sdk.mdx +2 -2
- package/.docs/raw/docs/cloud/langgraph.mdx +1 -1
- package/.docs/raw/docs/copilots/model-context.mdx +5 -4
- package/.docs/raw/docs/copilots/motivation.mdx +5 -5
- package/.docs/raw/docs/guides/attachments.mdx +3 -3
- package/.docs/raw/docs/guides/branching.mdx +2 -2
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/context-api.mdx +89 -111
- package/.docs/raw/docs/guides/editing.mdx +5 -5
- package/.docs/raw/docs/guides/electron.mdx +369 -0
- package/.docs/raw/docs/guides/index.mdx +10 -0
- package/.docs/raw/docs/guides/quoting.mdx +3 -3
- package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +2 -2
- package/.docs/raw/docs/guides/resumable-streams.mdx +74 -3
- package/.docs/raw/docs/guides/suggestions.mdx +9 -9
- package/.docs/raw/docs/ink/hooks.mdx +12 -7
- package/.docs/raw/docs/ink/primitives.mdx +18 -10
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +16 -0
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +3 -3
- package/.docs/raw/docs/integrations/auth/clerk.mdx +3 -3
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +4 -4
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +2 -2
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
- package/.docs/raw/docs/integrations/gateways/index.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/helicone.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +3 -3
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +36 -9
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +15 -13
- package/.docs/raw/docs/migrations/v0-15.mdx +236 -0
- package/.docs/raw/docs/primitives/attachment.mdx +2 -2
- package/.docs/raw/docs/primitives/composer.mdx +3 -3
- package/.docs/raw/docs/primitives/message.mdx +33 -1
- package/.docs/raw/docs/primitives/suggestion.mdx +1 -1
- package/.docs/raw/docs/primitives/thread-list.mdx +2 -2
- package/.docs/raw/docs/react-native/hooks.mdx +17 -7
- package/.docs/raw/docs/react-native/index.mdx +3 -3
- package/.docs/raw/docs/react-native/primitives.mdx +41 -7
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +3 -3
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +5 -5
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +5 -5
- package/.docs/raw/docs/runtimes/ai-sdk/v6-legacy.mdx +13 -14
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +11 -12
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +50 -11
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +20 -2
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +31 -2
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +39 -12
- package/.docs/raw/docs/runtimes/eve/overview.mdx +51 -0
- package/.docs/raw/docs/runtimes/eve/quickstart.mdx +51 -2
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +9 -12
- package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +7 -7
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +4 -4
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +4 -1
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +10 -0
- package/.docs/raw/docs/tools/a2ui.mdx +107 -0
- package/.docs/raw/docs/tools/backend.mdx +2 -2
- package/.docs/raw/docs/tools/defining-tools.mdx +9 -7
- package/.docs/raw/docs/tools/dynamic-tools.mdx +6 -4
- package/.docs/raw/docs/tools/interactables-legacy.mdx +28 -15
- package/.docs/raw/docs/tools/interactables.mdx +27 -16
- package/.docs/raw/docs/tools/mcp-apps.mdx +96 -8
- package/.docs/raw/docs/tools/mcp.mdx +9 -7
- package/.docs/raw/docs/tools/tool-ui.mdx +26 -22
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +64 -14
- package/.docs/raw/docs/ui/file.mdx +6 -1
- package/.docs/raw/docs/ui/follow-up-suggestions.mdx +2 -0
- package/.docs/raw/docs/ui/mcp-config.mdx +8 -3
- package/.docs/raw/docs/ui/model-selector.mdx +9 -9
- package/.docs/raw/docs/ui/part-grouping.mdx +1 -5
- package/.docs/raw/docs/ui/reasoning.mdx +1 -1
- package/.docs/raw/docs/ui/thread.mdx +24 -5
- package/.docs/raw/docs/utilities/react-o11y.mdx +7 -9
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/prepare.d.ts +1 -1
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/stdio.d.ts +1 -1
- package/dist/tools/docs.d.ts +6 -10
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +6 -4
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +4 -8
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +4 -3
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.d.ts +1 -1
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +3 -2
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/search.d.ts +4 -10
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +2 -2
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/tests/mcp-test-client.d.ts +15 -0
- package/dist/tools/tests/mcp-test-client.d.ts.map +1 -0
- package/dist/tools/tests/mcp-test-client.js +68 -0
- package/dist/tools/tests/mcp-test-client.js.map +1 -0
- package/dist/tools/tests/test-setup.d.ts.map +1 -1
- package/dist/tools/tests/test-setup.js +2 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/tools/xulux-templates.d.ts +9 -23
- package/dist/tools/xulux-templates.d.ts.map +1 -1
- package/dist/tools/xulux-templates.js +8 -6
- package/dist/tools/xulux-templates.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/mdx.js +2 -1
- package/dist/utils/mdx.js.map +1 -1
- package/dist/utils/security.js.map +1 -1
- package/dist/xulux/catalog-client.js +1 -1
- package/dist/xulux/catalog-client.js.map +1 -1
- package/package.json +6 -5
- package/src/index.ts +2 -2
- package/src/tools/docs.ts +2 -2
- package/src/tools/examples.ts +2 -2
- package/src/tools/resources.ts +1 -4
- package/src/tools/search.ts +2 -2
- package/src/tools/tests/completions.test.ts +40 -26
- package/src/tools/tests/docs.test.ts +2 -2
- package/src/tools/tests/integration.test.ts +3 -4
- package/src/tools/tests/mcp-protocol.test.ts +160 -175
- package/src/tools/tests/mcp-test-client.ts +111 -0
- package/src/tools/tests/resources.test.ts +97 -66
- package/src/tools/xulux-templates.ts +4 -4
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Quickstart
|
|
3
|
-
description:
|
|
3
|
+
description: Template, Eve CLI, and manual setup paths to a working Eve agent chat in assistant-ui.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Three paths to a running Eve-powered assistant-ui app. The template is fastest, `eve add` drops assistant-ui into an Eve app you already have, and the manual path is what you adapt when integrating into an existing Next.js project.
|
|
7
7
|
|
|
8
8
|
## From the template
|
|
9
9
|
|
|
@@ -45,6 +45,55 @@ Use Eve's terminal UI directly for command-line agent sessions.
|
|
|
45
45
|
</Tab>
|
|
46
46
|
</PlatformTabs>
|
|
47
47
|
|
|
48
|
+
## With the Eve CLI
|
|
49
|
+
|
|
50
|
+
For an Eve app that already exists, register the assistant-ui registry once and install the chat page from it:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
eve registry add @assistant-ui=https://r.assistant-ui.com/{name}.json
|
|
54
|
+
eve add @assistant-ui/eve-chat --overwrite
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`eve registry add` records the namespace in your `package.json`. `eve add` then installs `@assistant-ui/react` and `@assistant-ui/eve`, writes `app/page.tsx`, and writes the thread component together with everything it imports into `components/assistant-ui` and `components/ui`. It expects an Eve app that carries the Next.js Web Chat scaffold, because the installed files import `@/lib/utils` through the `@/*` alias that `eve init --channel-web-nextjs` sets up.
|
|
58
|
+
|
|
59
|
+
`--overwrite` is global rather than per file. It is what lets the item replace the scaffold's own `app/page.tsx`, and it also replaces any `components/assistant-ui` or `components/ui` file already in the project, including `avatar`, `button`, `collapsible`, `dialog`, and `tooltip`, so install on a clean tree and read the diff before keeping it. A plain `eve add` skips every pre-existing file instead, which leaves `app/page.tsx` untouched. Inspect an item before installing it with `eve registry view @assistant-ui/eve-chat`, and browse the rest of the registry with `eve registry list --registry @assistant-ui`.
|
|
60
|
+
|
|
61
|
+
That namespace serves the Radix flavor, which matches the shadcn components in Eve's Next.js scaffold. Point it at `https://r.assistant-ui.com/base/{name}.json` instead for a Base UI project.
|
|
62
|
+
|
|
63
|
+
The Eve CLI writes registry files without editing CSS, so add the styles the reasoning and tool components animate with to `app/globals.css` yourself:
|
|
64
|
+
|
|
65
|
+
```css title="app/globals.css"
|
|
66
|
+
@import "tw-shimmer";
|
|
67
|
+
|
|
68
|
+
@custom-variant data-open (&:where([data-state="open"], [data-open]:not([data-open="false"])));
|
|
69
|
+
@custom-variant data-closed (&:where([data-state="closed"], [data-closed]:not([data-closed="false"])));
|
|
70
|
+
|
|
71
|
+
@theme inline {
|
|
72
|
+
@keyframes collapsible-down {
|
|
73
|
+
from {
|
|
74
|
+
height: 0;
|
|
75
|
+
}
|
|
76
|
+
to {
|
|
77
|
+
height: var(
|
|
78
|
+
--radix-collapsible-content-height,
|
|
79
|
+
var(--collapsible-panel-height, auto)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
@keyframes collapsible-up {
|
|
84
|
+
from {
|
|
85
|
+
height: var(
|
|
86
|
+
--radix-collapsible-content-height,
|
|
87
|
+
var(--collapsible-panel-height, auto)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
height: 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
48
97
|
## Manual setup in an existing app
|
|
49
98
|
|
|
50
99
|
<Steps>
|
|
@@ -389,9 +389,9 @@ Register the renderer with a backend toolkit entry inside `AssistantRuntimeProvi
|
|
|
389
389
|
```tsx
|
|
390
390
|
import {
|
|
391
391
|
AssistantRuntimeProvider,
|
|
392
|
+
AuiConfig,
|
|
392
393
|
defineToolkit,
|
|
393
394
|
Tools,
|
|
394
|
-
useAui,
|
|
395
395
|
} from "@assistant-ui/react";
|
|
396
396
|
import {
|
|
397
397
|
createAdkStream,
|
|
@@ -410,10 +410,9 @@ function App() {
|
|
|
410
410
|
const runtime = useAdkRuntime({
|
|
411
411
|
stream: createAdkStream({ api: "/api/chat" }),
|
|
412
412
|
});
|
|
413
|
-
const
|
|
414
|
-
|
|
413
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
415
414
|
return (
|
|
416
|
-
<AssistantRuntimeProvider
|
|
415
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
417
416
|
<Thread />
|
|
418
417
|
</AssistantRuntimeProvider>
|
|
419
418
|
);
|
|
@@ -426,9 +425,9 @@ function App() {
|
|
|
426
425
|
```tsx
|
|
427
426
|
import {
|
|
428
427
|
AssistantRuntimeProvider,
|
|
428
|
+
AuiConfig,
|
|
429
429
|
defineToolkit,
|
|
430
430
|
Tools,
|
|
431
|
-
useAui,
|
|
432
431
|
} from "@assistant-ui/react-native";
|
|
433
432
|
import {
|
|
434
433
|
createAdkStream,
|
|
@@ -450,10 +449,9 @@ function App() {
|
|
|
450
449
|
const runtime = useAdkRuntime({
|
|
451
450
|
stream: createAdkStream({ api: `${API_URL}/api/chat` }),
|
|
452
451
|
});
|
|
453
|
-
const
|
|
454
|
-
|
|
452
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
455
453
|
return (
|
|
456
|
-
<AssistantRuntimeProvider
|
|
454
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
457
455
|
<View style={{ flex: 1 }}>
|
|
458
456
|
<Thread />
|
|
459
457
|
</View>
|
|
@@ -468,9 +466,9 @@ function App() {
|
|
|
468
466
|
```tsx
|
|
469
467
|
import {
|
|
470
468
|
AssistantRuntimeProvider,
|
|
469
|
+
AuiConfig,
|
|
471
470
|
defineToolkit,
|
|
472
471
|
Tools,
|
|
473
|
-
useAui,
|
|
474
472
|
} from "@assistant-ui/react-ink";
|
|
475
473
|
import {
|
|
476
474
|
createAdkStream,
|
|
@@ -490,10 +488,9 @@ function App() {
|
|
|
490
488
|
const runtime = useAdkRuntime({
|
|
491
489
|
stream: createAdkStream({ api: "http://localhost:3000/api/chat" }),
|
|
492
490
|
});
|
|
493
|
-
const
|
|
494
|
-
|
|
491
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
495
492
|
return (
|
|
496
|
-
<AssistantRuntimeProvider
|
|
493
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
497
494
|
<Box flexDirection="column">
|
|
498
495
|
<Thread />
|
|
499
496
|
</Box>
|
|
@@ -5,7 +5,7 @@ description: Use LangChain's useStream hook with a React chat UI through assista
|
|
|
5
5
|
|
|
6
6
|
import { LangGraphIcon } from "@/components/icons/langgraph";
|
|
7
7
|
|
|
8
|
-
`@assistant-ui/react-langchain` wraps [`useStream`](https://
|
|
8
|
+
`@assistant-ui/react-langchain` wraps [`useStream`](https://reference.langchain.com/javascript/langchain-react/use-stream) from `@langchain/react` and exposes it as an assistant-ui runtime. It targets the same backend as [`@assistant-ui/react-langgraph`](/docs/runtimes/langgraph/overview) (LangGraph Cloud) but at a higher level, delegating stream plumbing to the upstream hook.
|
|
9
9
|
|
|
10
10
|
## When to use it
|
|
11
11
|
|
|
@@ -32,7 +32,7 @@ Shared adapters (attachments, speech, feedback) work the same way described in [
|
|
|
32
32
|
|
|
33
33
|
## Requirements
|
|
34
34
|
|
|
35
|
-
- A LangGraph Cloud API server (locally via [LangGraph Studio](https://
|
|
35
|
+
- A LangGraph Cloud API server (locally via [LangGraph Studio](https://docs.langchain.com/langsmith/quick-start-studio) or hosted via [LangSmith](https://www.langchain.com/langsmith)).
|
|
36
36
|
- The graph state must include a `messages` key with LangChain-alike messages, or pass a custom `messagesKey`.
|
|
37
37
|
|
|
38
38
|
## Quickstart
|
|
@@ -13,7 +13,7 @@ description: Build a chat UI for LangGraph agents in React with assistant-ui —
|
|
|
13
13
|
|
|
14
14
|
Pick the LangGraph runtime when:
|
|
15
15
|
|
|
16
|
-
- You have (or want) a LangGraph Cloud server, locally via [LangGraph Studio](https://
|
|
16
|
+
- You have (or want) a LangGraph Cloud server, locally via [LangGraph Studio](https://docs.langchain.com/langsmith/quick-start-studio) or hosted via [LangSmith](https://www.langchain.com/langsmith).
|
|
17
17
|
- Your graph state has a `messages` key with LangChain-alike messages.
|
|
18
18
|
- You want generative UI (`ui_message`), per-message metadata, subgraph events, or checkpoint-based message editing.
|
|
19
19
|
|
|
@@ -108,7 +108,7 @@ See [Generative UI](/docs/runtimes/langgraph/generative-ui) for full setup: enab
|
|
|
108
108
|
|
|
109
109
|
## Queueing messages during a run
|
|
110
110
|
|
|
111
|
-
Set `unstable_enableMessageQueue` to keep the composer usable while a run is streaming. A message sent during a run
|
|
111
|
+
Set `unstable_enableMessageQueue` to keep the composer usable while a run is streaming. A message sent during a queued run steers by default — it lands in the steer lane, ahead of previously queued items; `send({ steer: false })` queues a follow-up behind them instead. Pending items are held in `composer.queue` and drain once the run settles.
|
|
112
112
|
|
|
113
113
|
```tsx
|
|
114
114
|
const runtime = useLangGraphRuntime({
|
|
@@ -94,7 +94,7 @@ This simply displays the tool name and arguments passed to it, but not the resul
|
|
|
94
94
|
|
|
95
95
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
96
96
|
import { PriceSnapshotToolUI } from "@/components/tools/price-snapshot/PriceSnapshotTool";
|
|
97
|
-
import { AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
97
|
+
import { AuiConfig, AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
98
98
|
|
|
99
99
|
const toolkit = defineToolkit({
|
|
100
100
|
price_snapshot: {
|
|
@@ -104,10 +104,10 @@ const toolkit = defineToolkit({
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
export default function Home() {
|
|
107
|
-
const aui = useAui(
|
|
108
|
-
|
|
107
|
+
const aui = useAui();
|
|
108
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
109
109
|
return (
|
|
110
|
-
<AuiProvider
|
|
110
|
+
<AuiProvider extends={aui} config={config}>
|
|
111
111
|
<Thread />
|
|
112
112
|
</AuiProvider>
|
|
113
113
|
);
|
|
@@ -334,10 +334,10 @@ const toolkit = defineToolkit({
|
|
|
334
334
|
});
|
|
335
335
|
|
|
336
336
|
export default function Home() {
|
|
337
|
-
const aui = useAui(
|
|
338
|
-
|
|
337
|
+
const aui = useAui();
|
|
338
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
339
339
|
return (
|
|
340
|
-
<AuiProvider
|
|
340
|
+
<AuiProvider extends={aui} config={config}>
|
|
341
341
|
<Thread />
|
|
342
342
|
</AuiProvider>
|
|
343
343
|
);
|
|
@@ -212,7 +212,7 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
|
|
|
212
212
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
213
213
|
import { PriceSnapshotToolUI } from "@/components/tools/price-snapshot/PriceSnapshotTool";
|
|
214
214
|
import { PurchaseStockToolUI } from "@/components/tools/purchase-stock/PurchaseStockTool";
|
|
215
|
-
import { AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
215
|
+
import { AuiConfig, AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
216
216
|
|
|
217
217
|
const toolkit = defineToolkit({
|
|
218
218
|
price_snapshot: {
|
|
@@ -226,10 +226,10 @@ const toolkit = defineToolkit({
|
|
|
226
226
|
});
|
|
227
227
|
|
|
228
228
|
export default function Home() {
|
|
229
|
-
const aui = useAui(
|
|
230
|
-
|
|
229
|
+
const aui = useAui();
|
|
230
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
231
231
|
return (
|
|
232
|
-
<AuiProvider
|
|
232
|
+
<AuiProvider extends={aui} config={config}>
|
|
233
233
|
<Thread />
|
|
234
234
|
</AuiProvider>
|
|
235
235
|
);
|
|
@@ -9,7 +9,9 @@ OpenCode-specific React hooks for interacting with the running session. All hook
|
|
|
9
9
|
|
|
10
10
|
## Permissions
|
|
11
11
|
|
|
12
|
-
OpenCode pauses tool execution to ask the user for permission (e.g. running shell commands, writing files). `
|
|
12
|
+
OpenCode pauses tool execution to ask the user for permission (e.g. running shell commands, writing files). Permissions linked to a tool call are projected into assistant-ui's standard tool approval contract, so the default `ToolFallback` renders working **Allow**, **Always allow**, and **Deny** actions without a custom permission component. The always option only appears when OpenCode offers patterns to persist.
|
|
13
|
+
|
|
14
|
+
`useOpenCodePermissions` remains available for custom tool renderers and permission requests that are not linked to a tool call. It returns the pending permission requests and a reply function:
|
|
13
15
|
|
|
14
16
|
```tsx
|
|
15
17
|
import { useOpenCodePermissions } from "@assistant-ui/react-opencode";
|
|
@@ -110,6 +112,7 @@ The returned `OpenCodeThreadState` includes:
|
|
|
110
112
|
|
|
111
113
|
- `sessionId`, `session`, `sessionStatus`, `loadState`, `runState`
|
|
112
114
|
- `messageOrder`, `messagesById`, `pendingUserMessages`
|
|
115
|
+
- `childSessionsById` (OpenCode `task` child-session projections keyed by session ID)
|
|
113
116
|
- `interactions.permissions` (pending + resolved), `interactions.questions` (pending + answered + rejected)
|
|
114
117
|
- `unhandledEvents`, `sync` timestamps
|
|
115
118
|
|
|
@@ -28,6 +28,16 @@ If your backend is not OpenCode-based, see [picking a runtime](/docs/runtimes/pi
|
|
|
28
28
|
- A running [OpenCode](https://opencode.ai/) server (defaults to `http://localhost:4096`).
|
|
29
29
|
- React 18 or 19.
|
|
30
30
|
|
|
31
|
+
## Sub-agent conversations
|
|
32
|
+
|
|
33
|
+
OpenCode `task` tool calls expose their child session through tool metadata. The runtime loads those child sessions, keeps them synchronized from the same OpenCode event stream, and projects their transcripts into `ToolCallMessagePart.messages`. Parallel and recursively nested tasks are supported.
|
|
34
|
+
|
|
35
|
+
Loading is eager, not keyed to what a renderer displays. Once a thread is subscribed, every `task` part in its transcript fetches its child session, and each child does the same for its own nested tasks, so a long session with many task calls fetches every sub-agent transcript whether or not any of them is expanded. Each child session is fetched once and then kept current from the event stream, so re-subscribing a thread does not refetch it.
|
|
36
|
+
|
|
37
|
+
A `task` part carries `messages` only once its child session has loaded. While the child is still loading, the part projects as an ordinary tool call, so an empty `messages` array always means the sub-agent produced nothing rather than that its transcript is still in flight.
|
|
38
|
+
|
|
39
|
+
Use assistant-ui's [`MessagePartPrimitive.Messages`](/docs/tools/multi-agent) inside a `task` tool renderer to display the child conversation. Nested conversations are read-only and inherit the parent thread's tool renderers.
|
|
40
|
+
|
|
31
41
|
## Install
|
|
32
42
|
|
|
33
43
|
<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-opencode", "@opencode-ai/sdk"]} />
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: A2UI over AG-UI
|
|
3
|
+
description: Render A2UI surfaces from AG-UI activity snapshots as generative UI, using the community a2ui-surface convention.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[A2UI](https://a2ui.org/) is a declarative generative UI protocol: the agent streams surface operations (create a surface, upsert components, update a data model) and the host renders them from a pre-approved component catalog, with no code over the wire. The AG-UI ecosystem carries A2UI as `ACTIVITY_SNAPSHOT` events with `activityType: "a2ui-surface"` and the operations under `content.a2ui_operations`; this is the convention emitted by [`@ag-ui/a2ui-middleware`](https://github.com/ag-ui-protocol/ag-ui/tree/main/middlewares/a2ui-middleware).
|
|
8
|
+
|
|
9
|
+
`useAgUiRuntime` consumes these snapshots natively. Each surface becomes one tool-call part with `toolCallId` `a2ui:<surfaceId>` and `toolName` `"present"`, whose args are the converted generative UI spec, so surfaces render through the same path as the [`present` frontend tool](/docs/tools/generative-ui). Snapshots with any other `activityType` are ignored, and the MCP Apps activity path is unaffected.
|
|
10
|
+
|
|
11
|
+
## Wire contract
|
|
12
|
+
|
|
13
|
+
A backend paints or updates a surface by emitting an activity snapshot on the AG-UI stream:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"type": "ACTIVITY_SNAPSHOT",
|
|
18
|
+
"messageId": "a2ui-surface-call_1",
|
|
19
|
+
"activityType": "a2ui-surface",
|
|
20
|
+
"replace": true,
|
|
21
|
+
"content": {
|
|
22
|
+
"a2ui_operations": [
|
|
23
|
+
{ "version": "v0.9", "createSurface": { "surfaceId": "s1" } },
|
|
24
|
+
{
|
|
25
|
+
"version": "v0.9",
|
|
26
|
+
"updateComponents": {
|
|
27
|
+
"surfaceId": "s1",
|
|
28
|
+
"components": [
|
|
29
|
+
{ "id": "root", "component": "Card", "title": "Order", "children": ["total"] },
|
|
30
|
+
{ "id": "total", "component": "Text", "text": { "path": "/total" } }
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"version": "v0.9",
|
|
36
|
+
"updateDataModel": { "surfaceId": "s1", "path": "/", "contents": { "total": "$42" } }
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- A snapshot with `replace: true` (the schema default) rebuilds that `messageId`'s surface state from the operations it carries. `replace: false` means the snapshot is ignored when that `messageId` has already been seen, matching the AG-UI event spec. The middleware always emits `replace: true`.
|
|
44
|
+
- Surfaces are keyed by the `surfaceId` inside the operations, not by `messageId`. Multiple snapshots that share a `messageId` update their surfaces in place, and the synthesized part keeps its `toolCallId`, so the rendered surface updates without duplicating parts.
|
|
45
|
+
- Component trees use the A2UI adjacency-list model: nodes reference children by id, the root node has id `root`, and props of shape `{ "path": "/x/y" }` are JSON Pointer bindings resolved against the surface data model. Both v0.9 and v1.0 operation payloads are accepted, including the v1.0 inline `components` and `dataModel` on `createSurface`.
|
|
46
|
+
- Lifecycle snapshots that carry a `status` (such as `"building"`) but no `a2ui_operations` are tolerated and produce no part until operations arrive. A `deleteSurface` operation removes the surface's part.
|
|
47
|
+
- The `a2ui:` tool-call id prefix is reserved for synthesized surface parts: they are client-side render artifacts and are excluded from the history sent back to the agent, so genuine agent tool calls must not use ids starting with `a2ui:`.
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
Register the `present` frontend tool from `@assistant-ui/react-generative-ui`; incoming surfaces then render with the default vocabulary:
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import {
|
|
55
|
+
JSONGenerativeUI,
|
|
56
|
+
defaultGenerativeUILibrary,
|
|
57
|
+
} from "@assistant-ui/react-generative-ui";
|
|
58
|
+
|
|
59
|
+
const generative = new JSONGenerativeUI({
|
|
60
|
+
library: defaultGenerativeUILibrary,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const toolkit = {
|
|
64
|
+
present: generative.present({ display: "standalone" }),
|
|
65
|
+
};
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Pass the toolkit to your assistant as on the [Generative UI](/docs/tools/generative-ui) page; no other configuration is needed on `useAgUiRuntime`.
|
|
69
|
+
|
|
70
|
+
## Actions
|
|
71
|
+
|
|
72
|
+
`Button` nodes dispatch `$action` objects with type `"a2ui:action"` through the action registry. Wire the registry to `useAgUiSendA2uiAction` inside a component; the hook returns a stable function, so the toolkit can be memoized on it:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useMemo } from "react";
|
|
76
|
+
import { useAgUiSendA2uiAction } from "@assistant-ui/react-ag-ui";
|
|
77
|
+
import {
|
|
78
|
+
JSONGenerativeUI,
|
|
79
|
+
createActionRegistry,
|
|
80
|
+
defaultGenerativeUILibrary,
|
|
81
|
+
} from "@assistant-ui/react-generative-ui";
|
|
82
|
+
|
|
83
|
+
function useA2uiToolkit() {
|
|
84
|
+
const sendA2uiAction = useAgUiSendA2uiAction();
|
|
85
|
+
return useMemo(() => {
|
|
86
|
+
const generative = new JSONGenerativeUI({
|
|
87
|
+
library: defaultGenerativeUILibrary,
|
|
88
|
+
actions: createActionRegistry({
|
|
89
|
+
"a2ui:action": ({ payload }) => sendA2uiAction(payload),
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
return { present: generative.present({ display: "standalone" }) };
|
|
93
|
+
}, [sendA2uiAction]);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Sending an action triggers a run with no new user message, and the agent receives it as `forwardedProps.a2uiAction.userAction`, the convention `@ag-ui/a2ui-middleware` consumes. The action rides exactly one run; the `type` field is stripped and a `timestamp` is added when absent.
|
|
98
|
+
|
|
99
|
+
The middleware turns the action into a synthetic `log_a2ui_event` tool-call pair that is never declared in `input.tools`; a backend that validates tool calls against the declared tool list will reject it.
|
|
100
|
+
|
|
101
|
+
## Component mapping
|
|
102
|
+
|
|
103
|
+
The converter maps the A2UI basic catalog onto the default generative UI vocabulary: `Text` becomes `Markdown` (`h1` to `h6` variants become `Header`, `caption` becomes `Caption`), `Column` becomes `Col`, `TextField` becomes `Input` (the control name is derived from the last segment of its binding path), `CheckBox` becomes `Checkbox`, and `Image`, `Row`, `Card`, `Divider`, `Button` map one to one. A node with template children expands into a `ListView` over the bound list. `Button` actions become `$action` objects with type `"a2ui:action"` carrying the action name, `surfaceId`, and `sourceComponentId`, which is how your action registry receives them. Unknown components and operations are skipped with a debug warning, and conversion is bounded (depth 32, 100 template items, 5000 nodes) so a malformed stream cannot hang the client.
|
|
104
|
+
|
|
105
|
+
## Limitations
|
|
106
|
+
|
|
107
|
+
- The upstream middleware currently emits v0.9 operation payloads; the renderer accepts v0.9 and v1.0 shapes.
|
|
@@ -42,7 +42,7 @@ export async function POST(req: Request) {
|
|
|
42
42
|
const { messages, system, tools } = await req.json();
|
|
43
43
|
|
|
44
44
|
const result = streamText({
|
|
45
|
-
model: openai("gpt-5.
|
|
45
|
+
model: openai("gpt-5.6-luna"),
|
|
46
46
|
system,
|
|
47
47
|
messages: await convertToModelMessages(messages),
|
|
48
48
|
tools: await aiToolkit.tools({ frontend: tools }),
|
|
@@ -79,7 +79,7 @@ export async function POST(req: Request) {
|
|
|
79
79
|
const { messages, tools } = await req.json();
|
|
80
80
|
|
|
81
81
|
const result = streamText({
|
|
82
|
-
model: openai("gpt-5.
|
|
82
|
+
model: openai("gpt-5.6-luna"),
|
|
83
83
|
messages: await convertToModelMessages(messages),
|
|
84
84
|
tools: {
|
|
85
85
|
...frontendTools(tools ?? {}),
|
|
@@ -115,21 +115,23 @@ The inner `"use client"` inside `execute` marks this as a **frontend** tool —
|
|
|
115
115
|
|
|
116
116
|
### Register the toolkit
|
|
117
117
|
|
|
118
|
-
Import the toolkit in your runtime provider and pass it to `
|
|
118
|
+
Import the toolkit in your runtime provider and pass it to `config` via `Tools`:
|
|
119
119
|
|
|
120
120
|
```tsx title="app/MyRuntimeProvider.tsx"
|
|
121
121
|
"use client";
|
|
122
122
|
|
|
123
|
-
import { AssistantRuntimeProvider,
|
|
123
|
+
import { AssistantRuntimeProvider, AuiConfig, Tools } from "@assistant-ui/react";
|
|
124
124
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
125
125
|
import toolkit from "./toolkit";
|
|
126
126
|
|
|
127
127
|
export function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
128
128
|
const runtime = useChatRuntime();
|
|
129
|
-
const
|
|
130
|
-
|
|
129
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
131
130
|
return (
|
|
132
|
-
<AssistantRuntimeProvider
|
|
131
|
+
<AssistantRuntimeProvider
|
|
132
|
+
runtime={runtime}
|
|
133
|
+
config={config}
|
|
134
|
+
>
|
|
133
135
|
{children}
|
|
134
136
|
</AssistantRuntimeProvider>
|
|
135
137
|
);
|
|
@@ -157,7 +159,7 @@ export async function POST(req: Request) {
|
|
|
157
159
|
const { messages, tools } = await req.json();
|
|
158
160
|
|
|
159
161
|
const result = streamText({
|
|
160
|
-
model: openai("gpt-5.
|
|
162
|
+
model: openai("gpt-5.6-luna"),
|
|
161
163
|
messages: await convertToModelMessages(messages),
|
|
162
164
|
tools: await aiToolkit.tools({ frontend: tools }),
|
|
163
165
|
});
|
|
@@ -368,7 +370,7 @@ export const toolkit = defineToolkit({
|
|
|
368
370
|
});
|
|
369
371
|
```
|
|
370
372
|
|
|
371
|
-
Register it exactly like a generative toolkit: `
|
|
373
|
+
Register it exactly like a generative toolkit: hoist `const config = AuiConfig({ tools: Tools({ toolkit }) })` in the component body and pass `config={config}`. The key must match the tool name your backend or MCP server publishes. Render-only entries upload no schema and run no browser code — they only attach UI to matching tool-call message parts.
|
|
372
374
|
|
|
373
375
|
<Callout type="warn">
|
|
374
376
|
This `{ type: "backend", render }` shape is **plain-toolkit only**. Inside a
|
|
@@ -43,6 +43,7 @@ The component that owns the state registers the toolkit, then renders a small nu
|
|
|
43
43
|
|
|
44
44
|
```tsx title="app/TaskBoard.tsx"
|
|
45
45
|
import {
|
|
46
|
+
AuiConfig,
|
|
46
47
|
AuiProvider,
|
|
47
48
|
Tools,
|
|
48
49
|
useAui,
|
|
@@ -54,10 +55,10 @@ import toolkit from "./task-board-toolkit";
|
|
|
54
55
|
|
|
55
56
|
function TaskBoard() {
|
|
56
57
|
const [tasks, setTasks] = useState<Task[]>([]);
|
|
57
|
-
const aui = useAui(
|
|
58
|
-
|
|
58
|
+
const aui = useAui();
|
|
59
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
59
60
|
return (
|
|
60
|
-
<AuiProvider
|
|
61
|
+
<AuiProvider extends={aui} config={config}>
|
|
61
62
|
<TaskBoardToolOverrides setTasks={setTasks} />
|
|
62
63
|
<TaskList tasks={tasks} />
|
|
63
64
|
</AuiProvider>
|
|
@@ -102,7 +103,8 @@ The override supplies **only** the `execute`; the description, parameters, and `
|
|
|
102
103
|
<Callout type="info">
|
|
103
104
|
Keep the override keys stable after mount, and let only one mounted provider
|
|
104
105
|
define a given tool name at a time. The null-returning overrides component
|
|
105
|
-
re-binds the executor whenever the setter changes, without
|
|
106
|
+
re-binds the executor whenever the setter changes, without remounting the
|
|
107
|
+
provider.
|
|
106
108
|
</Callout>
|
|
107
109
|
|
|
108
110
|
## When to reach for this vs. Interactables
|
|
@@ -33,18 +33,20 @@ Common use cases:
|
|
|
33
33
|
### 1. Register the Interactables scope
|
|
34
34
|
|
|
35
35
|
```tsx
|
|
36
|
-
import {
|
|
36
|
+
import { AuiConfig, Interactables, AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
37
37
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
38
38
|
|
|
39
39
|
function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
40
40
|
const runtime = useChatRuntime();
|
|
41
|
-
|
|
42
|
-
const aui = useAui({
|
|
41
|
+
const config = AuiConfig({
|
|
43
42
|
interactables: Interactables(), // [!code ++]
|
|
44
43
|
});
|
|
45
44
|
|
|
46
45
|
return (
|
|
47
|
-
<AssistantRuntimeProvider
|
|
46
|
+
<AssistantRuntimeProvider
|
|
47
|
+
runtime={runtime}
|
|
48
|
+
config={config}
|
|
49
|
+
>
|
|
48
50
|
{children}
|
|
49
51
|
</AssistantRuntimeProvider>
|
|
50
52
|
);
|
|
@@ -54,7 +56,7 @@ function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
|
54
56
|
<Callout type="idea">
|
|
55
57
|
The legacy `interactables: Interactables()` scope and the new
|
|
56
58
|
`unstable_interactables: unstable_Interactables()` scope are mutually
|
|
57
|
-
exclusive. Mount only one interactables API in a single
|
|
59
|
+
exclusive. Mount only one interactables API in a single provider config.
|
|
58
60
|
</Callout>
|
|
59
61
|
|
|
60
62
|
### 2. Create an interactable
|
|
@@ -266,10 +268,10 @@ const [state, { setState, setSelected, isPending, error, flush }] = useInteracta
|
|
|
266
268
|
|
|
267
269
|
### `Interactables`
|
|
268
270
|
|
|
269
|
-
The scope resource that manages all interactables. Register it via `
|
|
271
|
+
The scope resource that manages all interactables. Register it via your provider's `config`:
|
|
270
272
|
|
|
271
273
|
```tsx
|
|
272
|
-
|
|
274
|
+
AuiConfig({
|
|
273
275
|
interactables: Interactables(),
|
|
274
276
|
});
|
|
275
277
|
```
|
|
@@ -291,14 +293,25 @@ By default, interactable state is in-memory and lost on page refresh. You can ad
|
|
|
291
293
|
|
|
292
294
|
```tsx
|
|
293
295
|
import { useEffect } from "react";
|
|
294
|
-
import {
|
|
296
|
+
import { AuiConfig, AuiProvider, Interactables, useAui } from "@assistant-ui/react";
|
|
295
297
|
|
|
296
298
|
function MyRuntimeProvider({ children }) {
|
|
297
|
-
const aui = useAui(
|
|
299
|
+
const aui = useAui();
|
|
300
|
+
const config = AuiConfig({ interactables: Interactables() });
|
|
301
|
+
return (
|
|
302
|
+
<AuiProvider extends={aui} config={config}>
|
|
303
|
+
<PersistenceSetup />
|
|
304
|
+
{children}
|
|
305
|
+
</AuiProvider>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function PersistenceSetup() {
|
|
310
|
+
const aui = useAui();
|
|
298
311
|
|
|
299
312
|
useEffect(() => {
|
|
300
313
|
// Set up persistence adapter
|
|
301
|
-
aui.interactables
|
|
314
|
+
aui.interactables.setPersistenceAdapter({
|
|
302
315
|
save: async (state) => {
|
|
303
316
|
localStorage.setItem("interactables", JSON.stringify(state));
|
|
304
317
|
},
|
|
@@ -307,11 +320,11 @@ function MyRuntimeProvider({ children }) {
|
|
|
307
320
|
// Restore saved state on mount
|
|
308
321
|
const saved = localStorage.getItem("interactables");
|
|
309
322
|
if (saved) {
|
|
310
|
-
aui.interactables
|
|
323
|
+
aui.interactables.importState(JSON.parse(saved));
|
|
311
324
|
}
|
|
312
325
|
}, [aui]);
|
|
313
326
|
|
|
314
|
-
return
|
|
327
|
+
return null;
|
|
315
328
|
}
|
|
316
329
|
```
|
|
317
330
|
|
|
@@ -334,10 +347,10 @@ State changes are automatically debounced (500ms) before saving. When a componen
|
|
|
334
347
|
For custom persistence strategies, use `exportState` and `importState` directly:
|
|
335
348
|
|
|
336
349
|
```tsx
|
|
337
|
-
const snapshot = aui.interactables
|
|
350
|
+
const snapshot = aui.interactables.exportState();
|
|
338
351
|
// => { "note-1": { name: "note", state: { title: "Hello" } }, ... }
|
|
339
352
|
|
|
340
|
-
aui.interactables
|
|
353
|
+
aui.interactables.importState(snapshot);
|
|
341
354
|
// Imported state is picked up when components next register
|
|
342
355
|
```
|
|
343
356
|
|
|
@@ -346,7 +359,7 @@ aui.interactables().importState(snapshot);
|
|
|
346
359
|
You can use `Interactables` alongside `Tools`:
|
|
347
360
|
|
|
348
361
|
```tsx
|
|
349
|
-
|
|
362
|
+
AuiConfig({
|
|
350
363
|
tools: Tools({ toolkit: myToolkit }),
|
|
351
364
|
interactables: Interactables(),
|
|
352
365
|
});
|