@assistant-ui/mcp-docs-server 0.2.0 → 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 +12 -13
- package/.docs/organized/code-examples/with-a2a.md +16 -11
- package/.docs/organized/code-examples/with-ag-ui.md +14 -12
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +13 -12
- package/.docs/organized/code-examples/with-artifacts.md +13 -12
- package/.docs/organized/code-examples/with-assistant-transport.md +19 -27
- package/.docs/organized/code-examples/with-browser-extension.md +17 -10
- package/.docs/organized/code-examples/with-chain-of-thought.md +16 -14
- package/.docs/organized/code-examples/with-cloud-standalone.md +9 -10
- package/.docs/organized/code-examples/with-cloud.md +18 -13
- package/.docs/organized/code-examples/with-custom-thread-list.md +13 -12
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +13 -13
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +17 -15
- package/.docs/organized/code-examples/with-eve.md +65 -11
- package/.docs/organized/code-examples/with-expo.md +20 -19
- package/.docs/organized/code-examples/with-external-store.md +16 -11
- package/.docs/organized/code-examples/with-ffmpeg.md +20 -14
- package/.docs/organized/code-examples/with-generative-ui.md +16 -17
- package/.docs/organized/code-examples/with-google-adk.md +17 -12
- package/.docs/organized/code-examples/with-heat-graph.md +6 -7
- package/.docs/organized/code-examples/with-image-generation.md +9 -10
- package/.docs/organized/code-examples/with-interactables.md +13 -12
- package/.docs/organized/code-examples/with-langchain.md +7 -8
- package/.docs/organized/code-examples/with-langgraph.md +17 -11
- package/.docs/organized/code-examples/with-livekit.md +12 -12
- package/.docs/organized/code-examples/with-mcp.md +13 -14
- package/.docs/organized/code-examples/with-nuxt.md +2492 -0
- package/.docs/organized/code-examples/with-opencode.md +23 -14
- package/.docs/organized/code-examples/with-pi.md +59 -57
- package/.docs/organized/code-examples/with-react-hook-form.md +14 -13
- package/.docs/organized/code-examples/with-react-ink-web.md +7 -8
- package/.docs/organized/code-examples/with-react-ink.md +5 -5
- package/.docs/organized/code-examples/with-react-router.md +15 -9
- package/.docs/organized/code-examples/with-resumable-stream.md +11 -12
- package/.docs/organized/code-examples/with-store.md +27 -16
- package/.docs/organized/code-examples/with-tanstack.md +18 -12
- package/.docs/organized/code-examples/with-tap-runtime.md +15 -15
- package/.docs/organized/code-examples/with-virtualized-thread.md +8 -9
- package/.docs/organized/code-examples/with-vue.md +408 -0
- package/.docs/raw/docs/(docs)/cli.mdx +1 -1
- 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/integrations/eve.mdx +8 -0
- 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/copilots/model-context.mdx +4 -3
- package/.docs/raw/docs/copilots/motivation.mdx +4 -4
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/electron.mdx +1 -1
- 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 +9 -4
- package/.docs/raw/docs/ink/primitives.mdx +4 -3
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +16 -0
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/clerk.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +1 -1
- 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 +2 -2
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +15 -13
- package/.docs/raw/docs/migrations/v0-15.mdx +84 -4
- package/.docs/raw/docs/primitives/attachment.mdx +2 -2
- package/.docs/raw/docs/primitives/composer.mdx +2 -2
- package/.docs/raw/docs/primitives/message.mdx +33 -1
- package/.docs/raw/docs/primitives/suggestion.mdx +1 -1
- package/.docs/raw/docs/react-native/hooks.mdx +14 -4
- package/.docs/raw/docs/react-native/index.mdx +1 -1
- package/.docs/raw/docs/react-native/primitives.mdx +2 -2
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v6-legacy.mdx +9 -10
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +9 -10
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +40 -1
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +18 -0
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +30 -1
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +36 -9
- 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/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 +1 -0
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +10 -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 +24 -11
- package/.docs/raw/docs/tools/interactables.mdx +24 -13
- package/.docs/raw/docs/tools/mcp-apps.mdx +35 -6
- 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 +12 -7
- package/.docs/raw/docs/ui/file.mdx +6 -1
- package/.docs/raw/docs/ui/mcp-config.mdx +8 -3
- package/.docs/raw/docs/ui/model-selector.mdx +8 -8
- package/.docs/raw/docs/ui/part-grouping.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.js.map +1 -1
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/tools/docs.js +4 -2
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.js +2 -1
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.js +2 -1
- package/dist/tools/resources.js.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.js +4 -2
- package/dist/tools/xulux-templates.js.map +1 -1
- package/dist/utils/mdx.js +2 -1
- package/dist/utils/mdx.js.map +1 -1
- package/dist/xulux/catalog-client.js +1 -1
- package/dist/xulux/catalog-client.js.map +1 -1
- package/package.json +4 -4
- package/src/tools/tests/docs.test.ts +2 -2
package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx
CHANGED
|
@@ -48,15 +48,35 @@ primitives built on it. Components rendered outside an `AuiProvider`
|
|
|
48
48
|
receive a default client whose scope accessors throw on use, so
|
|
49
49
|
missing-provider mistakes surface at the point of use.
|
|
50
50
|
|
|
51
|
+
`config` is required and must be built with [AuiConfig](/docs/api-reference/utilities/miscellaneous#auiconfig). At the top
|
|
52
|
+
level, `config` alone creates this subtree's own client. Under a parent
|
|
53
|
+
provider, `extends` is mandatory: pass `extends={aui}` to extend the parent
|
|
54
|
+
client or `extends={null}` to isolate from it (enforced with a dev error).
|
|
55
|
+
Configs are identity-insensitive — a fresh object per render is safe.
|
|
56
|
+
A config whose scopes are all Derived keeps its scope set fixed
|
|
57
|
+
at mount (dev-enforced); configs with a root scope, and empty configs,
|
|
58
|
+
may grow and shrink scopes across renders. `ref` receives the resulting
|
|
59
|
+
client after mount.
|
|
60
|
+
|
|
51
61
|
When mounting a runtime built with one of the runtime hooks, use
|
|
52
62
|
[AssistantRuntimeProvider](/docs/api-reference/context-providers/assistant-runtime-provider#assistantruntimeprovider) — it installs an `AuiProvider`
|
|
53
63
|
internally — rather than wiring `AuiProvider` yourself.
|
|
54
64
|
|
|
55
65
|
```tsx
|
|
56
|
-
function
|
|
57
|
-
const aui = useAui(
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
function MessageScope({ index, children }) {
|
|
67
|
+
const aui = useAui();
|
|
68
|
+
const config = AuiConfig({
|
|
69
|
+
message: Derived({
|
|
70
|
+
source: "thread",
|
|
71
|
+
query: { index },
|
|
72
|
+
get: (aui) => aui.thread.message({ index }),
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
return (
|
|
76
|
+
<AuiProvider extends={aui} config={config}>
|
|
77
|
+
{children}
|
|
78
|
+
</AuiProvider>
|
|
79
|
+
);
|
|
60
80
|
}
|
|
61
81
|
```
|
|
62
82
|
|
|
@@ -39,6 +39,14 @@ Eve's `send` API.
|
|
|
39
39
|
const getEveMessageContent: (message: AppendMessage) => NonNullable<SendTurnPayload["message"]>;
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
### toEveInputResponse
|
|
43
|
+
|
|
44
|
+
Converts an assistant-ui tool approval response into an Eve input response.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const toEveInputResponse: (response: RespondToToolApprovalOptions) => InputResponse;
|
|
48
|
+
```
|
|
49
|
+
|
|
42
50
|
### useEveAgentRuntime
|
|
43
51
|
|
|
44
52
|
Connects Eve's `useEveAgent` hook to assistant-ui's runtime contract.
|
|
@@ -3,7 +3,7 @@ title: Utilities
|
|
|
3
3
|
description: Miscellaneous @assistant-ui/react utilities for custom rendering, composition, and advanced assistant UI behavior.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
import { AssistantCloud, ChainOfThoughtClient, DevToolsHooks, InMemoryThreadList, SingleThreadList, Suggestions, useSmooth } from "@/generated/typeDocs";
|
|
6
|
+
import { AssistantCloud, AuiConfig, ChainOfThoughtClient, DevToolsHooks, InMemoryThreadList, SingleThreadList, Suggestions, useSmooth } from "@/generated/typeDocs";
|
|
7
7
|
|
|
8
8
|
{/* AUTO-GENERATED PAGE by scripts/generate-api-reference.mts */}
|
|
9
9
|
{/* Do not edit manually. */}
|
|
@@ -18,6 +18,29 @@ import { AssistantCloud, ChainOfThoughtClient, DevToolsHooks, InMemoryThreadList
|
|
|
18
18
|
|
|
19
19
|
<ParametersTable {...AssistantCloud} />
|
|
20
20
|
|
|
21
|
+
### AuiConfig
|
|
22
|
+
|
|
23
|
+
Builds a config for [AuiProvider](/docs/api-reference/context-providers/assistant-runtime-provider#auiprovider); the `config` prop only accepts
|
|
24
|
+
configs built with this helper.
|
|
25
|
+
|
|
26
|
+
A config is plain data: it can be hoisted to module scope, created inline
|
|
27
|
+
per render, or memoized — the provider never relies on config identity.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
const aui = useAui();
|
|
31
|
+
const config = AuiConfig({
|
|
32
|
+
message: Derived({
|
|
33
|
+
source: "thread",
|
|
34
|
+
query: { index: 0 },
|
|
35
|
+
get: (aui) => aui.thread.message({ index: 0 }),
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
<AuiProvider extends={aui} config={config}>{children}</AuiProvider>;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
<ParametersTable {...AuiConfig} />
|
|
43
|
+
|
|
21
44
|
### ChainOfThoughtClient
|
|
22
45
|
|
|
23
46
|
<ParametersTable {...ChainOfThoughtClient} />
|
|
@@ -391,7 +391,7 @@ export async function POST(req: Request) {
|
|
|
391
391
|
const { messages } = await req.json();
|
|
392
392
|
|
|
393
393
|
const result = streamText({
|
|
394
|
-
model: openai("gpt-5.
|
|
394
|
+
model: openai("gpt-5.6-luna"),
|
|
395
395
|
messages,
|
|
396
396
|
});
|
|
397
397
|
|
|
@@ -459,7 +459,7 @@ export async function POST(req: Request) {
|
|
|
459
459
|
const samplingCalls: Record<string, SamplingCallData[]> = {};
|
|
460
460
|
|
|
461
461
|
const result = streamText({
|
|
462
|
-
model: openai("gpt-5.
|
|
462
|
+
model: openai("gpt-5.6-luna"),
|
|
463
463
|
messages,
|
|
464
464
|
tools: {
|
|
465
465
|
delegate_to_gemini: tool({
|
|
@@ -63,6 +63,7 @@ export default defineToolkit({
|
|
|
63
63
|
|
|
64
64
|
```tsx title="app/Form.tsx"
|
|
65
65
|
import {
|
|
66
|
+
AuiConfig,
|
|
66
67
|
AuiProvider,
|
|
67
68
|
makeAssistantVisible,
|
|
68
69
|
Tools,
|
|
@@ -77,10 +78,10 @@ const ClickableButton = makeAssistantVisible(Button, {
|
|
|
77
78
|
|
|
78
79
|
// Use in your component
|
|
79
80
|
function Form() {
|
|
80
|
-
const aui = useAui(
|
|
81
|
-
|
|
81
|
+
const aui = useAui();
|
|
82
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
82
83
|
return (
|
|
83
|
-
<AuiProvider
|
|
84
|
+
<AuiProvider extends={aui} config={config}>
|
|
84
85
|
<form>{/* form fields */}</form>
|
|
85
86
|
</AuiProvider>
|
|
86
87
|
);
|
|
@@ -131,15 +131,15 @@ export default defineToolkit({
|
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
```tsx title="app/SmartTransactionHistory.tsx"
|
|
134
|
-
import { AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
134
|
+
import { AuiConfig, AuiProvider, Tools, useAui } from "@assistant-ui/react";
|
|
135
135
|
import toolkit from "./transaction-toolkit";
|
|
136
136
|
|
|
137
137
|
function SmartTransactionHistory() {
|
|
138
|
-
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
139
|
-
|
|
140
138
|
// Previous instructions...
|
|
139
|
+
const aui = useAui();
|
|
140
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
141
141
|
return (
|
|
142
|
-
<AuiProvider
|
|
142
|
+
<AuiProvider extends={aui} config={config}>
|
|
143
143
|
<TransactionHistory transactions={transactions} />
|
|
144
144
|
</AuiProvider>
|
|
145
145
|
);
|
|
@@ -109,7 +109,7 @@ export async function POST(req: Request) {
|
|
|
109
109
|
const { messages } = await req.json();
|
|
110
110
|
|
|
111
111
|
const result = streamText({
|
|
112
|
-
model: openai("gpt-5.
|
|
112
|
+
model: openai("gpt-5.6-luna"),
|
|
113
113
|
messages: await convertToModelMessages(messages),
|
|
114
114
|
});
|
|
115
115
|
|
|
@@ -214,7 +214,7 @@ export function registerAssistantIpc(mainWindow: BrowserWindow) {
|
|
|
214
214
|
void (async () => {
|
|
215
215
|
try {
|
|
216
216
|
const result = streamText({
|
|
217
|
-
model: openai("gpt-5.
|
|
217
|
+
model: openai("gpt-5.6-luna"),
|
|
218
218
|
messages: request.messages,
|
|
219
219
|
...(request.system ? { system: request.system } : {}),
|
|
220
220
|
abortSignal: abortController.signal,
|
|
@@ -84,7 +84,7 @@ The context exposes two more verbs: `ctx.status(streamId)` returns `"streaming"
|
|
|
84
84
|
|
|
85
85
|
## Client side: native integration
|
|
86
86
|
|
|
87
|
-
`@assistant-ui/react-ai-sdk` ships a `resumable` option on `AssistantChatTransport`. It captures the stream id from the response header, redirects `chat.resumeStream()` reconnects to your resume route, and clears the stored id when the response finishes naturally. Pair it with `useChatRuntime`, which fires `chat.resumeStream()`
|
|
87
|
+
`@assistant-ui/react-ai-sdk` ships a `resumable` option on `AssistantChatTransport`. It captures the stream id from the response header, redirects `chat.resumeStream()` reconnects to your resume route, and clears the stored id when the response finishes naturally. Pair it with `useChatRuntime`, which fires `chat.resumeStream()` whenever its resumable storage reports a pending id, including ids discovered after mount.
|
|
88
88
|
|
|
89
89
|
```tsx title="/app/page.tsx"
|
|
90
90
|
"use client";
|
|
@@ -127,12 +127,83 @@ export default function Page() {
|
|
|
127
127
|
}
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
`onResumeError` runs when the client finds a stored stream id but the reconnect attempt fails. Use it to show a toast, report telemetry, or mark the thread as needing retry
|
|
130
|
+
`onResumeError` runs when the client finds a stored stream id but the reconnect attempt fails. Use it to show a toast, report telemetry, or mark the thread as needing retry. Assistant-ui clears the failed stream id after the callback unless a newer id has replaced it.
|
|
131
131
|
|
|
132
|
-
`createResumableSessionStorage` returns a `ResumableClientStorage` backed by `window.sessionStorage`. Pass `{ key }` to namespace per route or
|
|
132
|
+
`createResumableSessionStorage` returns a `ResumableClientStorage` backed by `window.sessionStorage`. Pass `{ key }` to namespace per route or chat surface; `key` also accepts a getter that is read lazily on every access, so you can derive it from the active thread's identity (see [Multiple threads](#multiple-threads)). While the getter returns `undefined`, reads report no pending stream and writes are dropped. Reuse one storage instance per key, because separate instances do not synchronize their in-memory caches. The persisted entry survives reloads, while in-memory ownership prevents one mounted thread from attaching to another thread's pending stream. An idle follower that learns a stream id from its backend can call `storage.setStreamId(streamId, threadId)` after the corresponding message exists in local history; the runtime attaches when that thread is current, without requiring a remount. The built-in storage holds one pending stream id per key; the [Multiple threads](#multiple-threads) pattern gives each thread its own key, so several threads stay resumable at once. A custom `ResumableClientStorage` can instead key its records by the optional `threadId` arguments and implement `subscribe(listener, threadId)` for post-mount updates, or replace the storage methods entirely. If you are running on a transport that already wraps `fetch` or `prepareReconnectToStreamRequest`, the `resumable` option composes with your existing handlers.
|
|
133
133
|
|
|
134
134
|
The default finish detector scans the SSE body for the AI SDK `"type":"finish"` marker. Override `isFinishEvent` on the `resumable` option when you ship a custom encoder.
|
|
135
135
|
|
|
136
|
+
### Multiple threads
|
|
137
|
+
|
|
138
|
+
The snippet above stores the pending stream id under one `sessionStorage` key, which is correct for a single chat surface. Under a thread list runtime (`useRemoteThreadListRuntime`, which `useChatRuntime` wraps) with more than one alive thread, a single shared key is written and cleared by whichever thread acts last: switch threads while a response is in flight and the response header writes its stream id to the shared key, which the thread you switched to reads on mount and resumes — replaying the other conversation's stream into this one. An unscoped clear when a stream finishes can also drop another thread's pending id. And after a reload, a pending id under the shared key is claimed by whichever thread is main at mount, which with a thread list is a fresh empty thread rather than the one that started the stream.
|
|
139
|
+
|
|
140
|
+
Scope the key to the thread, and construct the transport and storage per thread inside the per-thread runtime hook rather than once at module level. Derive the key from the thread's identity with a getter so it is read lazily on every access:
|
|
141
|
+
|
|
142
|
+
```tsx title="/app/page.tsx"
|
|
143
|
+
"use client";
|
|
144
|
+
|
|
145
|
+
import {
|
|
146
|
+
AssistantCloud,
|
|
147
|
+
AssistantRuntimeProvider,
|
|
148
|
+
useAui,
|
|
149
|
+
useCloudThreadListAdapter,
|
|
150
|
+
useRemoteThreadListRuntime,
|
|
151
|
+
} from "@assistant-ui/react";
|
|
152
|
+
import {
|
|
153
|
+
AssistantChatTransport,
|
|
154
|
+
createResumableSessionStorage,
|
|
155
|
+
useChatRuntime,
|
|
156
|
+
} from "@assistant-ui/react-ai-sdk";
|
|
157
|
+
import { useMemo } from "react";
|
|
158
|
+
import { Thread } from "@/components/assistant-ui/thread";
|
|
159
|
+
import { ThreadList } from "@/components/assistant-ui/thread-list";
|
|
160
|
+
|
|
161
|
+
const cloud = new AssistantCloud({
|
|
162
|
+
baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
|
|
163
|
+
anonymous: true,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
function ResumableThreadRuntime() {
|
|
167
|
+
const aui = useAui();
|
|
168
|
+
const transport = useMemo(
|
|
169
|
+
() =>
|
|
170
|
+
new AssistantChatTransport({
|
|
171
|
+
api: "/api/chat",
|
|
172
|
+
resumable: {
|
|
173
|
+
storage: createResumableSessionStorage({
|
|
174
|
+
key: () => {
|
|
175
|
+
const item = aui.threadListItem.getState();
|
|
176
|
+
return `aui-resumable-stream-id:${item.remoteId ?? item.id}`;
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
resumeApi: (streamId) => `/api/chat/resume/${streamId}`,
|
|
180
|
+
},
|
|
181
|
+
}),
|
|
182
|
+
[aui],
|
|
183
|
+
);
|
|
184
|
+
return useChatRuntime({ transport });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export default function Page() {
|
|
188
|
+
const adapter = useCloudThreadListAdapter({ cloud });
|
|
189
|
+
const runtime = useRemoteThreadListRuntime({
|
|
190
|
+
adapter,
|
|
191
|
+
runtimeHook: ResumableThreadRuntime,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
196
|
+
<ThreadList />
|
|
197
|
+
<Thread />
|
|
198
|
+
</AssistantRuntimeProvider>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`useCloudThreadListAdapter` is the same adapter `useChatRuntime({ cloud })` builds internally, so cloud thread history and attachments keep working; to bring your own backend, pass a custom `RemoteThreadListAdapter` instead. Each thread's runtime hook constructs its own transport and storage, keyed by that thread's identity, so one conversation's stream id can never be read or cleared by another. `useChatRuntime` is a no-op thread list when nested as a `runtimeHook`, so it only runs the per-thread chat runtime against the per-thread transport; the real thread list is the outer `useRemoteThreadListRuntime`.
|
|
204
|
+
|
|
205
|
+
Key by `remoteId ?? id` under a recognizable prefix, read lazily. A brand-new thread has no `remoteId` yet, but the transport initializes the thread before the request goes out, so by the time the response header delivers the stream id the getter resolves to the `remoteId`. After a reload the same conversation comes back with that `remoteId` as its id, so the stored entry is found again and the pending stream resumes. The local-id fallback covers a thread that has never sent, whose key nothing else reads or writes. Keying by the local id alone would break resume across reloads for threads created in the current session, because their local `__LOCALID_` id is replaced by the `remoteId` when the list reloads.
|
|
206
|
+
|
|
136
207
|
## Storage choices
|
|
137
208
|
|
|
138
209
|
The core package ships `createInMemoryResumableStreamStore` for development and tests. State lives in a process-local `Map`, so it does not survive a server restart. Useful options include `defaultTtlMs`, `maxChunkBytes`, `maxEntriesPerStream`, `maxStreams`, and `gcIntervalMs` for periodic eviction.
|
|
@@ -15,13 +15,13 @@ The Suggestions API allows you to configure a list of suggested prompts that are
|
|
|
15
15
|
Configure suggestions using the `Suggestions()` API in your runtime provider:
|
|
16
16
|
|
|
17
17
|
```tsx
|
|
18
|
-
import {
|
|
18
|
+
import { AuiConfig, Tools, Suggestions } from "@assistant-ui/react";
|
|
19
19
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
20
20
|
|
|
21
21
|
function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
22
22
|
const runtime = useChatRuntime();
|
|
23
23
|
|
|
24
|
-
const
|
|
24
|
+
const config = AuiConfig({
|
|
25
25
|
tools: Tools({ toolkit: myToolkit }),
|
|
26
26
|
suggestions: Suggestions([
|
|
27
27
|
"What can you help me with?",
|
|
@@ -31,7 +31,7 @@ function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
return (
|
|
34
|
-
<AssistantRuntimeProvider
|
|
34
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
35
35
|
{children}
|
|
36
36
|
</AssistantRuntimeProvider>
|
|
37
37
|
);
|
|
@@ -45,7 +45,7 @@ Suggestions can be provided as either strings or objects with title, label, and
|
|
|
45
45
|
### Simple Strings
|
|
46
46
|
|
|
47
47
|
```tsx
|
|
48
|
-
|
|
48
|
+
AuiConfig({
|
|
49
49
|
suggestions: Suggestions([
|
|
50
50
|
"What's the weather today?",
|
|
51
51
|
"Help me write an email",
|
|
@@ -59,7 +59,7 @@ const aui = useAui({
|
|
|
59
59
|
For more detailed suggestions with separate display text and prompts:
|
|
60
60
|
|
|
61
61
|
```tsx
|
|
62
|
-
|
|
62
|
+
AuiConfig({
|
|
63
63
|
suggestions: Suggestions([
|
|
64
64
|
{
|
|
65
65
|
title: "Weather",
|
|
@@ -315,13 +315,13 @@ function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
|
315
315
|
];
|
|
316
316
|
}, [user.isPremium]);
|
|
317
317
|
|
|
318
|
-
const
|
|
318
|
+
const config = AuiConfig({
|
|
319
319
|
tools: Tools({ toolkit: myToolkit }),
|
|
320
320
|
suggestions: Suggestions(suggestions),
|
|
321
321
|
});
|
|
322
322
|
|
|
323
323
|
return (
|
|
324
|
-
<AssistantRuntimeProvider
|
|
324
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
325
325
|
{children}
|
|
326
326
|
</AssistantRuntimeProvider>
|
|
327
327
|
);
|
|
@@ -352,10 +352,10 @@ If your codebase uses the inline `ThreadPrimitive.Suggestion` component (which r
|
|
|
352
352
|
|
|
353
353
|
### Runtime-driven form
|
|
354
354
|
|
|
355
|
-
1. Configure suggestions in your runtime provider
|
|
355
|
+
1. Configure suggestions in your runtime provider's `config`:
|
|
356
356
|
|
|
357
357
|
```tsx
|
|
358
|
-
|
|
358
|
+
AuiConfig({
|
|
359
359
|
suggestions: Suggestions(["What's the weather?"]),
|
|
360
360
|
});
|
|
361
361
|
```
|
|
@@ -187,12 +187,17 @@ export default defineToolkit({
|
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
```tsx title="ToolProvider.tsx"
|
|
190
|
-
import { AuiProvider, Tools, useAui } from "@assistant-ui/react-ink";
|
|
190
|
+
import { AuiConfig, AuiProvider, Tools, useAui } from "@assistant-ui/react-ink";
|
|
191
191
|
import toolkit from "./weather-toolkit";
|
|
192
192
|
|
|
193
193
|
function ToolProvider({ children }: { children: React.ReactNode }) {
|
|
194
|
-
const aui = useAui(
|
|
195
|
-
|
|
194
|
+
const aui = useAui();
|
|
195
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
196
|
+
return (
|
|
197
|
+
<AuiProvider extends={aui} config={config}>
|
|
198
|
+
{children}
|
|
199
|
+
</AuiProvider>
|
|
200
|
+
);
|
|
196
201
|
}
|
|
197
202
|
```
|
|
198
203
|
|
|
@@ -271,7 +276,7 @@ export function useWeatherToolkit() {
|
|
|
271
276
|
}
|
|
272
277
|
```
|
|
273
278
|
|
|
274
|
-
Import the toolkit hook
|
|
279
|
+
Import the toolkit hook and mount it with `<AuiProvider extends={aui} config={config}>` where `const aui = useAui()` and `const config = AuiConfig({ tools: Tools({ toolkit }) })`, as shown in the [Tools](#tools) section above.
|
|
275
280
|
|
|
276
281
|
## Runtime Providers
|
|
277
282
|
|
|
@@ -666,10 +666,11 @@ Container `Box` for an attachment. Forwards all `Box` props.
|
|
|
666
666
|
|
|
667
667
|
### Thumb
|
|
668
668
|
|
|
669
|
-
`Text` component displaying a short identifier for the attachment. Renders the file extension (`.pdf`, `.png`, …) when the name has one. Falls back to the attachment `type` (e.g. `image`, `document`) otherwise, and finally to `file`.
|
|
669
|
+
`Text` component displaying a short identifier for the attachment. Renders the file extension (`.pdf`, `.png`, …) when the name has one. Falls back to the attachment `type` (e.g. `image`, `document`) otherwise, and finally to `file`. Passing `children` overrides the automatic label.
|
|
670
670
|
|
|
671
671
|
| Prop | Type | Description |
|
|
672
672
|
|------|------|-------------|
|
|
673
|
+
| `children` | `ReactNode` | Overrides the automatic extension/type label |
|
|
673
674
|
| `...rest` | `ComponentProps<typeof Text>` | Forwarded to the underlying Ink `Text` |
|
|
674
675
|
|
|
675
676
|
### Status
|
|
@@ -712,7 +713,7 @@ Primitives for rendering individual queued composer items. Use inside a `Compose
|
|
|
712
713
|
|
|
713
714
|
### Text
|
|
714
715
|
|
|
715
|
-
Renders the queue item's
|
|
716
|
+
Renders the queue item's text with Ink `<Text>`. Pass `children` to override the displayed value.
|
|
716
717
|
|
|
717
718
|
```tsx
|
|
718
719
|
<QueueItemPrimitive.Text color="gray" />
|
|
@@ -720,7 +721,7 @@ Renders the queue item's prompt with Ink `<Text>`. Pass `children` to override t
|
|
|
720
721
|
|
|
721
722
|
| Prop | Type | Description |
|
|
722
723
|
|------|------|-------------|
|
|
723
|
-
| `children` | `ReactNode` | Override content; defaults to `s.queueItem.
|
|
724
|
+
| `children` | `ReactNode` | Override content; defaults to the text parts of `s.queueItem.parts` |
|
|
724
725
|
| `...rest` | `TextProps` | Standard Ink Text props |
|
|
725
726
|
|
|
726
727
|
### Remove
|
|
@@ -489,6 +489,22 @@ In the adapter's `add`, call Uploadthing's client upload and read `url` from the
|
|
|
489
489
|
</Tab>
|
|
490
490
|
</Tabs>
|
|
491
491
|
|
|
492
|
+
### Opaque file references (LangGraph / LangChain)
|
|
493
|
+
|
|
494
|
+
When the backend resolves stored files itself and the browser never holds a usable URL, send the storage id instead: set `sourceType: "id"` on the file part in `send()`, and the LangChain-family runtimes emit a `source_type: "id"` block with the value in the `id` key. `sourceType: "url"` similarly forces a url reference for non-http data and is honored by the LangChain-family, A2A, AG-UI, and Google ADK runtimes. `sourceType: "id"` is LangChain-family only; runtimes without the concept ignore the field.
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
const content = [
|
|
498
|
+
{
|
|
499
|
+
type: "file" as const,
|
|
500
|
+
filename: name,
|
|
501
|
+
mimeType: contentType ?? "application/octet-stream",
|
|
502
|
+
data: fileId,
|
|
503
|
+
sourceType: "id" as const,
|
|
504
|
+
},
|
|
505
|
+
];
|
|
506
|
+
```
|
|
507
|
+
|
|
492
508
|
## Notes
|
|
493
509
|
|
|
494
510
|
- **Persistence.** A URL the model sees on Monday must still resolve next week if the thread is reloaded. Either use storage with no expiry on the public URL, or have your [history adapter](/docs/integrations/persistence/custom-adapter) regenerate signed URLs on `load`. Don't store presigned URLs in the message row.
|
|
@@ -66,7 +66,7 @@ export async function POST(req: Request) {
|
|
|
66
66
|
|
|
67
67
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
68
68
|
const result = streamText({
|
|
69
|
-
model: openai("gpt-5.
|
|
69
|
+
model: openai("gpt-5.6-luna"),
|
|
70
70
|
messages: await convertToModelMessages(messages),
|
|
71
71
|
});
|
|
72
72
|
return result.toUIMessageStreamResponse();
|
|
@@ -45,7 +45,7 @@ export async function POST(req: Request) {
|
|
|
45
45
|
|
|
46
46
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
47
47
|
const result = streamText({
|
|
48
|
-
model: openai("gpt-5.
|
|
48
|
+
model: openai("gpt-5.6-luna"),
|
|
49
49
|
messages: await convertToModelMessages(messages),
|
|
50
50
|
});
|
|
51
51
|
return result.toUIMessageStreamResponse();
|
|
@@ -72,7 +72,7 @@ export async function POST(req: Request) {
|
|
|
72
72
|
|
|
73
73
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
74
74
|
const result = streamText({
|
|
75
|
-
model: openai("gpt-5.
|
|
75
|
+
model: openai("gpt-5.6-luna"),
|
|
76
76
|
messages: await convertToModelMessages(messages),
|
|
77
77
|
});
|
|
78
78
|
return result.toUIMessageStreamResponse();
|
|
@@ -68,7 +68,7 @@ export type Env = {
|
|
|
68
68
|
export class Chat extends AIChatAgent<Env> {
|
|
69
69
|
async onChatMessage(onFinish: Parameters<typeof streamText>[0]["onFinish"]) {
|
|
70
70
|
return streamText({
|
|
71
|
-
model: openai("gpt-5.
|
|
71
|
+
model: openai("gpt-5.6-luna"),
|
|
72
72
|
messages: await convertToModelMessages(this.messages),
|
|
73
73
|
onFinish,
|
|
74
74
|
});
|
|
@@ -81,11 +81,11 @@ export const chefAgent = new Agent({
|
|
|
81
81
|
instructions:
|
|
82
82
|
"You are Michel, a practical and experienced home chef. " +
|
|
83
83
|
"You help people cook with whatever ingredients they have available.",
|
|
84
|
-
model: "openai/gpt-5.
|
|
84
|
+
model: "openai/gpt-5.6-luna",
|
|
85
85
|
});
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
`model: "openai/gpt-5.
|
|
88
|
+
`model: "openai/gpt-5.6-luna"` uses Mastra's model router. Set the provider key in `.env.local` so Next.js auto-loads it:
|
|
89
89
|
|
|
90
90
|
```sh title=".env.local"
|
|
91
91
|
OPENAI_API_KEY=sk-...
|
|
@@ -50,7 +50,7 @@ export const chefAgent = new Agent({
|
|
|
50
50
|
instructions:
|
|
51
51
|
"You are Michel, a practical and experienced home chef. " +
|
|
52
52
|
"You help people cook with whatever ingredients they have available.",
|
|
53
|
-
model: "openai/gpt-5.
|
|
53
|
+
model: "openai/gpt-5.6-luna",
|
|
54
54
|
});
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -48,7 +48,7 @@ The rest of this page is what to put in `baseURL`, `headers`, and `model(...)` f
|
|
|
48
48
|
|
|
49
49
|
## OpenRouter
|
|
50
50
|
|
|
51
|
-
[OpenRouter](https://openrouter.ai/) aggregates 100+ models behind one OpenAI-compatible endpoint. The model ID is `provider/model` (e.g., `anthropic/claude-sonnet-4.6`, `openai/gpt-5.
|
|
51
|
+
[OpenRouter](https://openrouter.ai/) aggregates 100+ models behind one OpenAI-compatible endpoint. The model ID is `provider/model` (e.g., `anthropic/claude-sonnet-4.6`, `openai/gpt-5.6-luna`, `meta-llama/llama-3.3-70b-instruct`).
|
|
52
52
|
|
|
53
53
|
```sh title=".env.local"
|
|
54
54
|
OPENROUTER_API_KEY=sk-or-...
|
|
@@ -129,7 +129,7 @@ const litellm = createOpenAI({
|
|
|
129
129
|
});
|
|
130
130
|
|
|
131
131
|
const result = streamText({
|
|
132
|
-
model: litellm("gpt-5.
|
|
132
|
+
model: litellm("gpt-5.6-luna"),
|
|
133
133
|
messages: await convertToModelMessages(messages),
|
|
134
134
|
});
|
|
135
135
|
```
|
|
@@ -57,7 +57,7 @@ const openai = createOpenAI({
|
|
|
57
57
|
export async function POST(req: Request) {
|
|
58
58
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
59
59
|
const result = streamText({
|
|
60
|
-
model: openai("gpt-5.
|
|
60
|
+
model: openai("gpt-5.6-luna"),
|
|
61
61
|
messages: await convertToModelMessages(messages),
|
|
62
62
|
});
|
|
63
63
|
return result.toUIMessageStreamResponse();
|
|
@@ -80,7 +80,7 @@ const openai = new OpenAI({
|
|
|
80
80
|
export async function POST(req: Request) {
|
|
81
81
|
const { messages } = await req.json();
|
|
82
82
|
const stream = await openai.chat.completions.create({
|
|
83
|
-
model: "gpt-5.
|
|
83
|
+
model: "gpt-5.6-luna",
|
|
84
84
|
messages,
|
|
85
85
|
stream: true,
|
|
86
86
|
});
|
|
@@ -101,7 +101,7 @@ export async function POST(req: Request) {
|
|
|
101
101
|
{ traceName: "chat-completion", userId, sessionId },
|
|
102
102
|
async () =>
|
|
103
103
|
streamText({
|
|
104
|
-
model: openai("gpt-5.
|
|
104
|
+
model: openai("gpt-5.6-luna"),
|
|
105
105
|
messages: await convertToModelMessages(messages),
|
|
106
106
|
experimental_telemetry: { isEnabled: true },
|
|
107
107
|
}),
|
|
@@ -63,7 +63,7 @@ export async function POST(req: Request) {
|
|
|
63
63
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
64
64
|
|
|
65
65
|
const result = streamText({
|
|
66
|
-
model: openai("gpt-5.
|
|
66
|
+
model: openai("gpt-5.6-luna"),
|
|
67
67
|
messages: await ai.convertToModelMessages(messages),
|
|
68
68
|
});
|
|
69
69
|
|
|
@@ -84,7 +84,7 @@ Pass a `langsmith` provider option to tag traces with user, session, or run iden
|
|
|
84
84
|
import { createLangSmithProviderOptions } from "langsmith/experimental/vercel";
|
|
85
85
|
|
|
86
86
|
const result = streamText({
|
|
87
|
-
model: openai("gpt-5.
|
|
87
|
+
model: openai("gpt-5.6-luna"),
|
|
88
88
|
messages: await ai.convertToModelMessages(messages),
|
|
89
89
|
providerOptions: {
|
|
90
90
|
langsmith: createLangSmithProviderOptions({
|
|
@@ -73,20 +73,18 @@ export default defineToolkit({
|
|
|
73
73
|
|
|
74
74
|
import {
|
|
75
75
|
AssistantRuntimeProvider,
|
|
76
|
+
AuiConfig,
|
|
76
77
|
Tools,
|
|
77
|
-
useAui,
|
|
78
78
|
} from "@assistant-ui/react";
|
|
79
79
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
80
80
|
import toolkit from "./toolkit";
|
|
81
81
|
|
|
82
82
|
export function App() {
|
|
83
83
|
const runtime = useChatRuntime();
|
|
84
|
-
const
|
|
85
|
-
tools: Tools({ toolkit }),
|
|
86
|
-
});
|
|
84
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
87
85
|
|
|
88
86
|
return (
|
|
89
|
-
<AssistantRuntimeProvider
|
|
87
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
90
88
|
<Thread />
|
|
91
89
|
</AssistantRuntimeProvider>
|
|
92
90
|
);
|
|
@@ -100,7 +98,7 @@ export function App() {
|
|
|
100
98
|
1. Create a `Toolkit` object.
|
|
101
99
|
2. Move each `toolName` into the toolkit key.
|
|
102
100
|
3. Move `description`, `parameters`, `execute`, `providerOptions`, `render`, `renderText`, and `display` onto the toolkit entry.
|
|
103
|
-
4. Register the toolkit once with `
|
|
101
|
+
4. Register the toolkit once with `config={config}` on your runtime provider, where `const config = AuiConfig({ tools: Tools({ toolkit }) })`.
|
|
104
102
|
5. Remove `<Tool />`, `<ToolUI />`, `useAssistantTool(...)`, and `useAssistantToolUI(...)` registrations.
|
|
105
103
|
|
|
106
104
|
## UI-Only Tool Renderers
|
|
@@ -126,7 +124,7 @@ export default defineToolkit({
|
|
|
126
124
|
});
|
|
127
125
|
```
|
|
128
126
|
|
|
129
|
-
Register it like any toolkit: `
|
|
127
|
+
Register it like any toolkit: `config={config}` where `const config = AuiConfig({ tools: Tools({ toolkit }) })`.
|
|
130
128
|
Render-only entries upload no schema and run no browser code — they only attach
|
|
131
129
|
UI for matching tool-call message parts. For MCP server catalogs, spread
|
|
132
130
|
`defineMcpToolkit({ ... })` in the same generative toolkit.
|
|
@@ -163,20 +161,24 @@ export default defineToolkit({
|
|
|
163
161
|
```
|
|
164
162
|
|
|
165
163
|
```tsx title="TaskBoard.tsx"
|
|
166
|
-
import {
|
|
164
|
+
import {
|
|
165
|
+
AuiConfig,
|
|
166
|
+
AuiProvider,
|
|
167
|
+
Tools,
|
|
168
|
+
useAui,
|
|
169
|
+
useAuiToolOverrides,
|
|
170
|
+
} from "@assistant-ui/react";
|
|
167
171
|
import { useState, type Dispatch, type SetStateAction } from "react";
|
|
168
172
|
import type { Task } from "./task-board-toolkit";
|
|
169
173
|
import toolkit from "./task-board-toolkit";
|
|
170
174
|
|
|
171
175
|
function TaskBoard() {
|
|
172
176
|
const [tasks, setTasks] = useState<Task[]>([]);
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
tools: Tools({ toolkit }),
|
|
176
|
-
});
|
|
177
|
+
const aui = useAui();
|
|
178
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
177
179
|
|
|
178
180
|
return (
|
|
179
|
-
<AuiProvider
|
|
181
|
+
<AuiProvider extends={aui} config={config}>
|
|
180
182
|
<TaskBoardToolOverrides setTasks={setTasks} />
|
|
181
183
|
<TaskList tasks={tasks} />
|
|
182
184
|
</AuiProvider>
|