@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
|
@@ -133,16 +133,96 @@ const aui = useAui(scopes, { parent });
|
|
|
133
133
|
|
|
134
134
|
// After
|
|
135
135
|
const Scoped = ({ children }) => {
|
|
136
|
-
const aui = useAui(
|
|
137
|
-
|
|
136
|
+
const aui = useAui();
|
|
137
|
+
const config = AuiConfig(scopes);
|
|
138
|
+
return (
|
|
139
|
+
<AuiProvider extends={aui} config={config}>
|
|
140
|
+
{children}
|
|
141
|
+
</AuiProvider>
|
|
142
|
+
);
|
|
138
143
|
};
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
const rootConfig = AuiConfig({});
|
|
146
|
+
|
|
147
|
+
<AuiProvider extends={parent} config={rootConfig}>
|
|
141
148
|
<Scoped />
|
|
142
149
|
</AuiProvider>;
|
|
143
150
|
```
|
|
144
151
|
|
|
145
|
-
Where `{ parent: null }` was used to detach from context, `<AuiProvider
|
|
152
|
+
Where `{ parent: null }` was used to detach from context, `<AuiProvider extends={null} config={config}>` where `const config = AuiConfig({})` now provides an isolated empty root.
|
|
153
|
+
|
|
154
|
+
## `AuiProvider` Grammar
|
|
155
|
+
|
|
156
|
+
`AuiProvider` takes a `config` built with `AuiConfig(...)` — raw object literals are a type error. At the top level, `config` alone creates the subtree's client. Nested under a parent provider, `extends` is mandatory: `extends={aui}` extends the parent, `extends={null}` isolates (dev-enforced). `ref` receives the resulting client after mount.
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
const aui = useAui();
|
|
160
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
161
|
+
|
|
162
|
+
// Top-level root
|
|
163
|
+
<AuiProvider config={config}>
|
|
164
|
+
|
|
165
|
+
// Nested: extend the parent
|
|
166
|
+
<AuiProvider extends={aui} config={config}>
|
|
167
|
+
|
|
168
|
+
// Nested: isolate from the parent
|
|
169
|
+
<AuiProvider extends={null} config={config}>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`AuiConfig` is exported from `@assistant-ui/store` and re-exported from `@assistant-ui/react`, `@assistant-ui/react-native`, and `@assistant-ui/react-ink`.
|
|
173
|
+
|
|
174
|
+
### `value` Prop Deprecated
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
// Before
|
|
178
|
+
<AuiProvider value={client}>
|
|
179
|
+
<AuiProvider value={null}>
|
|
180
|
+
|
|
181
|
+
// After
|
|
182
|
+
const config = AuiConfig({});
|
|
183
|
+
|
|
184
|
+
<AuiProvider extends={client} config={config}>
|
|
185
|
+
<AuiProvider extends={null} config={config}>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The replacement exposes a client extending the given one, not the same instance — `useAui()` beneath it returns the new client, with scope access delegating to `client`. The deprecated `value={client}` form behaves the same way: it also exposes a derived client rather than the exact instance, and the given client must implement `subscribe`.
|
|
189
|
+
|
|
190
|
+
### `useAui({ ... })` Extension Overload Deprecated
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
// Before
|
|
194
|
+
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
195
|
+
return <AuiProvider value={aui}>{children}</AuiProvider>;
|
|
196
|
+
|
|
197
|
+
// After
|
|
198
|
+
const aui = useAui();
|
|
199
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
200
|
+
return (
|
|
201
|
+
<AuiProvider extends={aui} config={config}>
|
|
202
|
+
{children}
|
|
203
|
+
</AuiProvider>
|
|
204
|
+
);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Where the extended client was passed to `<AssistantRuntimeProvider aui={aui}>`, use the new `config` prop instead — the scopes are provided alongside the runtime's threads scope:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
// Before
|
|
211
|
+
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
212
|
+
return (
|
|
213
|
+
<AssistantRuntimeProvider aui={aui} runtime={runtime}>
|
|
214
|
+
{children}
|
|
215
|
+
</AssistantRuntimeProvider>
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// After
|
|
219
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
220
|
+
return (
|
|
221
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
222
|
+
{children}
|
|
223
|
+
</AssistantRuntimeProvider>
|
|
224
|
+
);
|
|
225
|
+
```
|
|
146
226
|
|
|
147
227
|
## Still Deprecated (not removed)
|
|
148
228
|
|
|
@@ -53,7 +53,7 @@ import { AttachmentPrimitive, ComposerPrimitive } from "@assistant-ui/react";
|
|
|
53
53
|
</ComposerPrimitive.Root>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
`Root` renders a `<div>`, `unstable_Thumb` renders a `<div>` showing the file extension with a leading dot (e.g., `.pdf`), `Name` renders plain text, and `Remove` renders a `<button>`.
|
|
56
|
+
`Root` renders a `<div>`, `unstable_Thumb` renders a `<div>` showing the file extension with a leading dot (e.g., `.pdf`), or the attachment type (e.g., `image`) when the filename has no extension (including leading-dot names like `.env`), `Name` renders plain text, and `Remove` renders a `<button>`. If you pass `children` to `unstable_Thumb`, they override that text.
|
|
57
57
|
|
|
58
58
|
<Callout type="info">
|
|
59
59
|
Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRuntimeProvider` with a runtime (for example `useLocalRuntime(...)`). See [Pick a Runtime](/docs/runtimes/pick-a-runtime).
|
|
@@ -124,7 +124,7 @@ Container for a single attachment item. Renders a `<div>` element unless `asChil
|
|
|
124
124
|
|
|
125
125
|
### unstable_Thumb
|
|
126
126
|
|
|
127
|
-
Thumbnail slot for attachment previews. Renders a `<div>` element unless `asChild` is set.
|
|
127
|
+
Thumbnail slot for attachment previews. Renders a `<div>` element unless `asChild` is set. By default it shows the file extension with a leading dot (e.g., `.pdf`); if you pass `children`, they override the automatic text.
|
|
128
128
|
|
|
129
129
|
```tsx
|
|
130
130
|
<AttachmentPrimitive.unstable_Thumb className="flex size-10 items-center justify-center rounded bg-muted text-xs" />
|
|
@@ -258,7 +258,7 @@ Renders a single attachment at a specific index.
|
|
|
258
258
|
|
|
259
259
|
### AttachmentDropzone
|
|
260
260
|
|
|
261
|
-
Drag-and-drop zone for file attachments. Sets `data-dragging` when a file is being dragged over it. Renders a `<div>` element unless `asChild` is set.
|
|
261
|
+
Drag-and-drop zone for file attachments. Sets `data-dragging` when a file is being dragged over it and the runtime supports attachments; without the attachments capability the dropzone accepts no files and shows no highlight. Non-file drags (text, links) are ignored. Renders a `<div>` element unless `asChild` is set.
|
|
262
262
|
|
|
263
263
|
```tsx
|
|
264
264
|
<ComposerPrimitive.AttachmentDropzone className="rounded-xl border-2 border-dashed data-[dragging]:border-primary data-[dragging]:bg-primary/5">
|
|
@@ -507,7 +507,7 @@ Wrap your composer with `AttachmentDropzone` to support dragging files directly
|
|
|
507
507
|
</ComposerPrimitive.AttachmentDropzone>
|
|
508
508
|
```
|
|
509
509
|
|
|
510
|
-
The dropzone sets `data-dragging` when a file is being dragged over it, so you can style the active state with CSS.
|
|
510
|
+
The dropzone sets `data-dragging` when a file is being dragged over it, so you can style the active state with CSS. It requires the runtime's attachments capability (an attachment adapter); without it the dropzone stays inert.
|
|
511
511
|
|
|
512
512
|
### With Voice Input
|
|
513
513
|
|
|
@@ -112,6 +112,37 @@ Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRun
|
|
|
112
112
|
For most new code, prefer `MessagePrimitive.Parts` with a `children` render function. When you need adjacent grouping, use `MessagePrimitive.GroupedParts`.
|
|
113
113
|
</Callout>
|
|
114
114
|
|
|
115
|
+
### Part Types
|
|
116
|
+
|
|
117
|
+
A message part is one of three kinds, and which kind a new capability belongs to is decided by the list below rather than case by case.
|
|
118
|
+
|
|
119
|
+
| Kind | Parts | Grows by |
|
|
120
|
+
|------|-------|----------|
|
|
121
|
+
| Modality | `text`, `image`, `file` | Never. `file` carries every non-image binary modality through its `mimeType`. |
|
|
122
|
+
| Provider channel | `reasoning`, `source`, `tool-call`, `generative-ui` | Never. These mirror channels a model already emits. |
|
|
123
|
+
| Extensibility | `data` | Freely, through `name`. This is the growth path for anything app-level. |
|
|
124
|
+
|
|
125
|
+
`file` is the media carrier. Audio, video, PDFs and everything else are `{ type: "file", mimeType: "audio/mpeg" }` rather than part types of their own, so one renderer and one converter branch handle them all. The payload can be inline base64 or a URL; `sourceType` additionally allows an opaque storage id, which the LangChain-family runtimes honor and other adapters ignore.
|
|
126
|
+
|
|
127
|
+
Anything that is not a modality the model consumes or a channel it emits is a `data` part, routed by `name`:
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<MessagePrimitive.Parts
|
|
131
|
+
components={{
|
|
132
|
+
data: {
|
|
133
|
+
by_name: { citation: MyCitation },
|
|
134
|
+
Fallback: MyDataFallback,
|
|
135
|
+
},
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
<Callout type="warn">
|
|
141
|
+
`Unstable_AudioMessagePart` and the `Unstable_Audio` slot are deprecated. The audio part cannot carry a filename, has no way to declare how its payload goes on the wire (no `sourceType`, so no storage id), and exists only on user messages, so a model that returns audio has no way to express it. Send audio as a `file` part with an `audio/*` mime type instead, and give it a filename.
|
|
142
|
+
|
|
143
|
+
Adapter coverage for the file path is still uneven, so check your adapter's converter before relying on file parts. Known so far: `react-pi` and the assistant-transport runtime have no file part on their user-content surface at all, so one is dropped; `react-data-stream` carries the payload but not the filename. Existing audio parts keep working; they will not gain fields.
|
|
144
|
+
</Callout>
|
|
145
|
+
|
|
115
146
|
### Tool Resolution
|
|
116
147
|
|
|
117
148
|
Tool call parts resolve in this order:
|
|
@@ -149,7 +180,8 @@ Returning `null` still allows registered tool UIs and data renderer UIs to rende
|
|
|
149
180
|
- `components.ChainOfThought` takes over all reasoning and tool-call rendering (mutually exclusive with `ToolGroup`, `ReasoningGroup`, `tools`, and `Reasoning`). This legacy path is deprecated; use `MessagePrimitive.GroupedParts` for grouped Chain of Thought in new code.
|
|
150
181
|
- `data.by_name` and `data.Fallback` let you route custom data part types
|
|
151
182
|
- `Quote` renders quoted message references from metadata
|
|
152
|
-
- `Empty`
|
|
183
|
+
- `Empty` is available for edge rendering paths
|
|
184
|
+
- `Unstable_Audio` is deprecated; render `audio/*` from the `File` slot instead
|
|
153
185
|
|
|
154
186
|
```tsx
|
|
155
187
|
<MessagePrimitive.Parts
|
|
@@ -106,7 +106,7 @@ Both render a `<span>` and accept `children` to override the value from state:
|
|
|
106
106
|
|
|
107
107
|
`Trigger`'s `send` prop controls what happens on click:
|
|
108
108
|
|
|
109
|
-
- **`send={true}`**: immediately sends the suggestion as a new message.
|
|
109
|
+
- **`send={true}`**: immediately sends the suggestion as a new message. While a run is in progress, the suggestion is queued on runtimes that support queueing (leaving the composer draft untouched); otherwise the trigger is disabled.
|
|
110
110
|
- **`send={false}`** (default): populates the composer text so the user can edit before sending
|
|
111
111
|
|
|
112
112
|
```tsx
|
|
@@ -155,12 +155,22 @@ export default defineToolkit({
|
|
|
155
155
|
```
|
|
156
156
|
|
|
157
157
|
```tsx title="ToolProvider.tsx"
|
|
158
|
-
import {
|
|
158
|
+
import {
|
|
159
|
+
AuiConfig,
|
|
160
|
+
AuiProvider,
|
|
161
|
+
Tools,
|
|
162
|
+
useAui,
|
|
163
|
+
} from "@assistant-ui/react-native";
|
|
159
164
|
import toolkit from "./weather-toolkit";
|
|
160
165
|
|
|
161
166
|
function ToolProvider({ children }: { children: React.ReactNode }) {
|
|
162
|
-
const aui = useAui(
|
|
163
|
-
|
|
167
|
+
const aui = useAui();
|
|
168
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
169
|
+
return (
|
|
170
|
+
<AuiProvider extends={aui} config={config}>
|
|
171
|
+
{children}
|
|
172
|
+
</AuiProvider>
|
|
173
|
+
);
|
|
164
174
|
}
|
|
165
175
|
```
|
|
166
176
|
|
|
@@ -218,7 +228,7 @@ export function useMyToolToolkit(someOuterProp: string) {
|
|
|
218
228
|
}
|
|
219
229
|
```
|
|
220
230
|
|
|
221
|
-
Import the toolkit hook,
|
|
231
|
+
Import the toolkit hook, hoist `const aui = useAui()` and `const config = AuiConfig({ tools: Tools({ toolkit }) })` in the component body, and mount it with `<AuiProvider extends={aui} config={config}>`, as shown in the [Tools](#tools) section above.
|
|
222
232
|
|
|
223
233
|
### makeAssistantDataUI
|
|
224
234
|
|
|
@@ -69,7 +69,7 @@ export const maxDuration = 30;
|
|
|
69
69
|
export async function POST(req: Request) {
|
|
70
70
|
const { messages } = await req.json();
|
|
71
71
|
const result = streamText({
|
|
72
|
-
model: openai("gpt-5.
|
|
72
|
+
model: openai("gpt-5.6-luna"),
|
|
73
73
|
messages: await convertToModelMessages(messages),
|
|
74
74
|
});
|
|
75
75
|
return result.toUIMessageStreamResponse();
|
|
@@ -437,7 +437,7 @@ Renders message content parts via a `components` prop. Tool call and data parts
|
|
|
437
437
|
| `Reasoning` | `ReasoningMessagePartComponent` | Reasoning part renderer |
|
|
438
438
|
| `Source` | `SourceMessagePartComponent` | Source part renderer |
|
|
439
439
|
| `File` | `FileMessagePartComponent` | File part renderer |
|
|
440
|
-
| `Unstable_Audio` | `
|
|
440
|
+
| `Unstable_Audio` | `Unstable_AudioMessagePartComponent` | Audio part renderer (deprecated, render `audio/*` from `File`) |
|
|
441
441
|
| `tools` | `{ by_name?, Fallback? }` or `{ Override }` | Tool call rendering config — use `by_name` to map tool names to components, `Fallback` for unregistered tools, or `Override` to handle all tool calls |
|
|
442
442
|
| `data` | `{ by_name?, Fallback? }` | Data part rendering config — use `by_name` to map data event names, `Fallback` for unmatched events |
|
|
443
443
|
| `Empty` | `EmptyMessagePartComponent` | Component shown for empty messages |
|
|
@@ -541,7 +541,7 @@ Container `View` for an attachment.
|
|
|
541
541
|
|
|
542
542
|
### AttachmentPrimitive.Thumb
|
|
543
543
|
|
|
544
|
-
`Text` component displaying the file extension (e.g. `.pdf`).
|
|
544
|
+
`Text` component displaying the file extension (e.g. `.pdf`), or the attachment type (e.g. `image`) when the filename has no extension (including leading-dot names like `.env`). If you pass `children`, they override that text.
|
|
545
545
|
|
|
546
546
|
```tsx
|
|
547
547
|
<AttachmentPrimitive.Thumb style={styles.extension} />
|
|
@@ -35,7 +35,7 @@ import { openai } from "@ai-sdk/openai";
|
|
|
35
35
|
|
|
36
36
|
export async function POST(req: Request) {
|
|
37
37
|
const { messages } = await req.json();
|
|
38
|
-
const result = streamText({ model: openai("gpt-5.
|
|
38
|
+
const result = streamText({ model: openai("gpt-5.6-luna"), messages });
|
|
39
39
|
return result.toDataStreamResponse();
|
|
40
40
|
}
|
|
41
41
|
```
|
|
@@ -40,7 +40,7 @@ export const maxDuration = 30;
|
|
|
40
40
|
export async function POST(req: Request) {
|
|
41
41
|
const { messages }: { messages: Message[] } = await req.json();
|
|
42
42
|
const result = streamText({
|
|
43
|
-
model: openai("gpt-5.
|
|
43
|
+
model: openai("gpt-5.6-luna"),
|
|
44
44
|
messages,
|
|
45
45
|
tools: {
|
|
46
46
|
get_current_weather: tool({
|
|
@@ -92,7 +92,7 @@ export async function POST(req: Request) {
|
|
|
92
92
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
93
93
|
|
|
94
94
|
const result = streamText({
|
|
95
|
-
model: openai("gpt-5.
|
|
95
|
+
model: openai("gpt-5.6-luna"),
|
|
96
96
|
messages: await convertToModelMessages(messages), // async in v6
|
|
97
97
|
tools: {
|
|
98
98
|
get_current_weather: tool({
|
|
@@ -245,7 +245,7 @@ export async function POST(req: Request) {
|
|
|
245
245
|
} = await req.json();
|
|
246
246
|
|
|
247
247
|
const result = streamText({
|
|
248
|
-
model: openai("gpt-5.
|
|
248
|
+
model: openai("gpt-5.6-luna"),
|
|
249
249
|
system,
|
|
250
250
|
messages: await convertToModelMessages(messages),
|
|
251
251
|
tools: {
|
|
@@ -258,7 +258,7 @@ export async function POST(req: Request) {
|
|
|
258
258
|
}
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
-
Frontend tools are registered through `
|
|
261
|
+
Frontend tools are registered through the provider's `config` (see the [tools guide](/docs/tools/defining-tools)) and serialized for the backend via `frontendTools`.
|
|
262
262
|
|
|
263
263
|
## Multi-step tool calls
|
|
264
264
|
|
|
@@ -276,7 +276,7 @@ export async function POST(req: Request) {
|
|
|
276
276
|
const { messages } = await req.json();
|
|
277
277
|
|
|
278
278
|
const result = streamText({
|
|
279
|
-
model: openai("gpt-5.
|
|
279
|
+
model: openai("gpt-5.6-luna"),
|
|
280
280
|
messages: await convertToModelMessages(messages),
|
|
281
281
|
tools: {
|
|
282
282
|
/* ... */
|
|
@@ -305,7 +305,7 @@ export async function POST(req: Request) {
|
|
|
305
305
|
const { messages } = await req.json();
|
|
306
306
|
|
|
307
307
|
const result = streamText({
|
|
308
|
-
model: openai("gpt-5.
|
|
308
|
+
model: openai("gpt-5.6-luna"),
|
|
309
309
|
messages: await convertToModelMessages(messages),
|
|
310
310
|
tools: {
|
|
311
311
|
deploy: tool({
|
|
@@ -356,9 +356,9 @@ Render the gate with a toolkit entry. The `approval` field carries the gate stat
|
|
|
356
356
|
import { useChat } from "@ai-sdk/react";
|
|
357
357
|
import {
|
|
358
358
|
AssistantRuntimeProvider,
|
|
359
|
+
AuiConfig,
|
|
359
360
|
defineToolkit,
|
|
360
361
|
Tools,
|
|
361
|
-
useAui,
|
|
362
362
|
} from "@assistant-ui/react";
|
|
363
363
|
import { useAISDKRuntime } from "@assistant-ui/react-ai-sdk";
|
|
364
364
|
import { lastAssistantMessageIsCompleteWithApprovalResponses } from "ai";
|
|
@@ -397,10 +397,9 @@ export default function Page() {
|
|
|
397
397
|
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
|
|
398
398
|
});
|
|
399
399
|
const runtime = useAISDKRuntime(chat);
|
|
400
|
-
const
|
|
401
|
-
|
|
400
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
402
401
|
return (
|
|
403
|
-
<AssistantRuntimeProvider
|
|
402
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
404
403
|
<Thread />
|
|
405
404
|
</AssistantRuntimeProvider>
|
|
406
405
|
);
|
|
@@ -424,7 +423,7 @@ import { openai } from "@ai-sdk/openai";
|
|
|
424
423
|
export async function POST(req: Request) {
|
|
425
424
|
const { messages } = await req.json();
|
|
426
425
|
const result = streamText({
|
|
427
|
-
model: openai("gpt-5.
|
|
426
|
+
model: openai("gpt-5.6-luna"),
|
|
428
427
|
messages: await convertToModelMessages(injectQuoteContext(messages)),
|
|
429
428
|
});
|
|
430
429
|
return result.toUIMessageStreamResponse();
|
|
@@ -90,7 +90,7 @@ export async function POST(req: Request) {
|
|
|
90
90
|
const { messages }: { messages: UIMessage[] } = await req.json();
|
|
91
91
|
|
|
92
92
|
const result = streamText({
|
|
93
|
-
model: openai("gpt-5.
|
|
93
|
+
model: openai("gpt-5.6-luna"),
|
|
94
94
|
messages: await convertToModelMessages(messages), // async in v7
|
|
95
95
|
tools: {
|
|
96
96
|
get_current_weather: tool({
|
|
@@ -245,7 +245,7 @@ export async function POST(req: Request) {
|
|
|
245
245
|
} = await req.json();
|
|
246
246
|
|
|
247
247
|
const result = streamText({
|
|
248
|
-
model: openai("gpt-5.
|
|
248
|
+
model: openai("gpt-5.6-luna"),
|
|
249
249
|
system,
|
|
250
250
|
messages: await convertToModelMessages(messages),
|
|
251
251
|
tools: {
|
|
@@ -260,7 +260,7 @@ export async function POST(req: Request) {
|
|
|
260
260
|
}
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
Frontend tools are registered through `
|
|
263
|
+
Frontend tools are registered through the provider's `config` (see the [tools guide](/docs/tools/defining-tools)) and serialized for the backend via `frontendTools`.
|
|
264
264
|
|
|
265
265
|
## Multi-step tool calls
|
|
266
266
|
|
|
@@ -280,7 +280,7 @@ export async function POST(req: Request) {
|
|
|
280
280
|
const { messages } = await req.json();
|
|
281
281
|
|
|
282
282
|
const result = streamText({
|
|
283
|
-
model: openai("gpt-5.
|
|
283
|
+
model: openai("gpt-5.6-luna"),
|
|
284
284
|
messages: await convertToModelMessages(messages),
|
|
285
285
|
tools: {
|
|
286
286
|
/* ... */
|
|
@@ -311,7 +311,7 @@ export async function POST(req: Request) {
|
|
|
311
311
|
const { messages } = await req.json();
|
|
312
312
|
|
|
313
313
|
const result = streamText({
|
|
314
|
-
model: openai("gpt-5.
|
|
314
|
+
model: openai("gpt-5.6-luna"),
|
|
315
315
|
messages: await convertToModelMessages(messages),
|
|
316
316
|
tools: {
|
|
317
317
|
deploy: tool({
|
|
@@ -368,9 +368,9 @@ Render the gate with a toolkit entry. The `approval` field carries the gate stat
|
|
|
368
368
|
import { useChat } from "@ai-sdk/react";
|
|
369
369
|
import {
|
|
370
370
|
AssistantRuntimeProvider,
|
|
371
|
+
AuiConfig,
|
|
371
372
|
defineToolkit,
|
|
372
373
|
Tools,
|
|
373
|
-
useAui,
|
|
374
374
|
} from "@assistant-ui/react";
|
|
375
375
|
import { useAISDKRuntime } from "@assistant-ui/react-ai-sdk";
|
|
376
376
|
import { lastAssistantMessageIsCompleteWithApprovalResponses } from "ai";
|
|
@@ -410,10 +410,9 @@ export default function Page() {
|
|
|
410
410
|
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
|
|
411
411
|
});
|
|
412
412
|
const runtime = useAISDKRuntime(chat);
|
|
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
|
);
|
|
@@ -439,7 +438,7 @@ import { openai } from "@ai-sdk/openai";
|
|
|
439
438
|
export async function POST(req: Request) {
|
|
440
439
|
const { messages } = await req.json();
|
|
441
440
|
const result = streamText({
|
|
442
|
-
model: openai("gpt-5.
|
|
441
|
+
model: openai("gpt-5.6-luna"),
|
|
443
442
|
messages: await convertToModelMessages(injectQuoteContext(messages)),
|
|
444
443
|
});
|
|
445
444
|
return createUIMessageStreamResponse({
|
|
@@ -209,6 +209,45 @@ function ReloadOnAuth() {
|
|
|
209
209
|
|
|
210
210
|
`reload()` discards in-flight responses from superseded calls, so it is safe to invoke on every auth transition.
|
|
211
211
|
|
|
212
|
+
### Refetching the open thread
|
|
213
|
+
|
|
214
|
+
`reload()` re-runs `list()`, which refreshes thread list metadata only. It does not touch the messages of the thread the user is looking at. When the open thread's server state changes out of band, so that nothing arrives over the stream (a human-in-the-loop interrupt raised by another process, a stalled stream, a status change picked up by polling), call `aui.threads.reloadMainThread()`:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
function RefetchOnInterrupt({ status }: { status: string }) {
|
|
218
|
+
const aui = useAui();
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
if (status !== "interrupted") return;
|
|
221
|
+
aui.threads.reloadMainThread().catch(reportError);
|
|
222
|
+
}, [status]);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
What the promise means depends on the path. On the remount path, it resolves as soon as the replacement runtime attaches, which happens before that runtime's `load()` has started, so awaiting it does not mean the thread is fresh and a failed load cannot reach the caller. On the in-place path, it settles with the refetch itself and rejects when it fails, which is why the example above still handles the rejection.
|
|
228
|
+
|
|
229
|
+
A thread that has not been sent yet is left alone because it holds no remote state.
|
|
230
|
+
|
|
231
|
+
What happens to a run in progress depends on the path. The remount path drops the runtime that was rendering the run; whether the run itself stops is up to that hook's unmount cleanup, which core cannot enforce. On the in-place path the runtime that declared the capability decides, since core does not stop the run for it. Either way this belongs on an event rather than a short timer: drive it from a state change like the one above, or skip the call while `useAuiState((s) => s.thread.isRunning)` is true.
|
|
232
|
+
|
|
233
|
+
How the refetch happens depends on the runtime, in one of three ways. When it declares the capability, the thread runtime is reused: composer drafts survive, existing messages stay rendered while the fresh state loads, and the returned promise settles with the refetch, rejecting if it fails. A remote thread list without the capability remounts the runtime hook instead, which re-runs `load()` at the cost of discarding unsent composer input, and resolves once the new runtime attaches. The single and in-memory thread lists hold no remote state and have no hook to remount, so there it resolves without doing anything.
|
|
234
|
+
|
|
235
|
+
`useAuiState((s) => s.thread.capabilities.refetchThread)` reports which of those you would get, in place or not. It is not a signal for whether to offer a refresh at all: it is false on the remount path, where the call still does the work, and false again where the call does nothing.
|
|
236
|
+
|
|
237
|
+
Both the LangGraph and Google ADK adapters register the in-place refetch capability when their runtime hook receives a `load` function; without one they fall back to the remount path. Other remote adapters take the remount path unless they provide the capability themselves.
|
|
238
|
+
|
|
239
|
+
For an external store runtime, declare it with `onRefetchThread`, which is unrelated to `onReload` (that one re-generates an assistant message):
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
useExternalStoreRuntime({
|
|
243
|
+
messages,
|
|
244
|
+
onNew,
|
|
245
|
+
onRefetchThread: async () => {
|
|
246
|
+
setMessages(await fetchMessages(threadId));
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
212
251
|
### Paginating the thread list
|
|
213
252
|
|
|
214
253
|
If your backend returns thread pages, return a `nextCursor` from `list()` and consume `aui.threads.hasMore` plus `aui.threads.loadMore()` in the UI. The runtime threads `params.after` back through `list()` on every `loadMore()`; the initial call passes no `params`, so treat a missing `after` as "first page". `reload()` resets the cursor so the next load starts from page 1 again.
|
|
@@ -326,7 +365,7 @@ A few invariants worth knowing when wiring a custom UI on top of `loadMore()`:
|
|
|
326
365
|
},
|
|
327
366
|
{
|
|
328
367
|
name: "unstable_Provider",
|
|
329
|
-
type: "
|
|
368
|
+
type: "RemoteThreadListProviderComponent",
|
|
330
369
|
description:
|
|
331
370
|
"Optional wrapper rendered around each active thread. Inject thread-scoped adapters (history, attachments) here.",
|
|
332
371
|
},
|
|
@@ -300,6 +300,7 @@ aui-state:[{"type":"set","path":["status"],"value":"completed"}]
|
|
|
300
300
|
initialState: T,
|
|
301
301
|
api: string,
|
|
302
302
|
resumeApi?: string,
|
|
303
|
+
resumeStateApi?: string,
|
|
303
304
|
protocol?: "data-stream" | "assistant-transport",
|
|
304
305
|
converter: (state: T, connectionMetadata: ConnectionMetadata) => AssistantTransportState,
|
|
305
306
|
headers?: Record<string, string> | Headers | (() => Promise<Record<string, string> | Headers>),
|
|
@@ -519,6 +520,23 @@ const runtime = useAssistantTransportRuntime({
|
|
|
519
520
|
});
|
|
520
521
|
```
|
|
521
522
|
|
|
523
|
+
Setting `resumeStateApi` additionally hydrates resumed runs from the server-retained starting state. It requires a sync server that serves the initial-state route; do not configure it against a server without one, since a failing preflight fails the resume closed:
|
|
524
|
+
|
|
525
|
+
```tsx
|
|
526
|
+
const runtime = useAssistantTransportRuntime({
|
|
527
|
+
// ...
|
|
528
|
+
resumeStateApi: "http://localhost:8010/initial-state",
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
Before resuming, the runtime posts `{ threadId }` to `resumeStateApi`. The endpoint must return the state that started the active run together with its identity:
|
|
533
|
+
|
|
534
|
+
```json
|
|
535
|
+
{ "runId": "8b3a...", "state": { "messages": [] } }
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
The runtime replaces its local base with this snapshot and includes `runId` in the resume request; the request carries no `state`, since the server replays from the snapshot it retained. A sync server should reject the resume when that ID no longer identifies the same run, preventing replay operations from being applied to a drifted or replaced base state. When no run is active, the endpoint responds `204 No Content` and the runtime skips the resume without raising an error. On a resume, `runId` takes precedence over fields supplied through `body` and survives `prepareSendCommandsRequest`; any `state` either of them supplies is stripped.
|
|
539
|
+
|
|
522
540
|
```tsx
|
|
523
541
|
import { useAui } from "@assistant-ui/react";
|
|
524
542
|
import { useEffect, useRef } from "react";
|
|
@@ -207,6 +207,7 @@ Each handler enables a specific UI feature.
|
|
|
207
207
|
| `onEdit` | Message edit button |
|
|
208
208
|
| `onReload` | Regenerate button |
|
|
209
209
|
| `onCancel` | Cancel button while generating |
|
|
210
|
+
| `onRefetchThread` | `threads.reloadMainThread()` refetching the open thread in place |
|
|
210
211
|
| `onAddToolResult` | Client-side tool result handoff |
|
|
211
212
|
| `queue` | Queueing messages sent while a run is in progress |
|
|
212
213
|
|
|
@@ -395,7 +396,9 @@ const runtime = useExternalStoreRuntime({
|
|
|
395
396
|
|
|
396
397
|
By default, sending while the thread is running is disabled. Provide a `queue` adapter to buffer a message sent during a run and process it once the run settles. The pending message is exposed on `composer.queue` and renders through [`ComposerPrimitive.Queue`](/docs/api-reference/primitives/composer).
|
|
397
398
|
|
|
398
|
-
The `createMessageQueue` helper owns the
|
|
399
|
+
The `createMessageQueue` helper owns the two-lane ordering and the in-flight guard: `steerItems` drain before `items`, and within each lane items drain in order. Supply a driver that runs a message, pass its `adapter` to the runtime, and tell the queue when a run starts (`notifyBusy()`, so concurrent sends buffer) and ends (`notifyIdle()`).
|
|
400
|
+
|
|
401
|
+
A hand-rolled adapter must implement the same contract: `items` and `steerItems` expose the lanes (each item carries a required `parts` projection of its content), `enqueue`/`steer` add to a lane, and `move(queueItemId, placement)` repositions with fail-fast anchors — unknown ids or anchors throw rather than being coerced. Individual items are addressable through `composer.queueItem({ id })` (or by index).
|
|
399
402
|
|
|
400
403
|
```tsx
|
|
401
404
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -418,6 +421,26 @@ useEffect(() => {
|
|
|
418
421
|
}, [isRunning, queue]);
|
|
419
422
|
```
|
|
420
423
|
|
|
424
|
+
Queue policy on cancel, edit, and reload is host-owned. Call `queue.notifyCancelled()` in your `onCancel` handler before aborting so the cancelled run's settle pauses draining instead of dispatching the next item (the next send or run start resumes it), or call `queue.clear()` to drop the pending items. Call `queue.clear()` in your `onEdit` and `onReload` handlers so stale items do not drain onto the new branch.
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
const runtime = useExternalStoreRuntime({
|
|
428
|
+
// ...
|
|
429
|
+
onCancel: async () => {
|
|
430
|
+
queue.notifyCancelled(); // or queue.clear() to drop pending items
|
|
431
|
+
await cancelRun();
|
|
432
|
+
},
|
|
433
|
+
onEdit: async (message) => {
|
|
434
|
+
queue.clear();
|
|
435
|
+
// ...
|
|
436
|
+
},
|
|
437
|
+
onReload: async (parentId) => {
|
|
438
|
+
queue.clear();
|
|
439
|
+
// ...
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
421
444
|
## Multi-thread
|
|
422
445
|
|
|
423
446
|
`ExternalStoreRuntime` uses `ExternalStoreThreadListAdapter` (synchronous, inline). See [threads](/docs/runtimes/concepts/threads#externalstorethreadlistadapter) for the contract and best practices on keeping `currentThreadId` in sync with your store.
|
|
@@ -787,6 +810,12 @@ useExternalStoreRuntime({
|
|
|
787
810
|
type: "() => Promise<void>",
|
|
788
811
|
description: "Handler for cancelling the current generation.",
|
|
789
812
|
},
|
|
813
|
+
{
|
|
814
|
+
name: "onRefetchThread",
|
|
815
|
+
type: "() => Promise<void>",
|
|
816
|
+
description:
|
|
817
|
+
"Handler for re-fetching this thread's state in place, driving threads.reloadMainThread(). Unrelated to onReload, which re-generates an assistant message.",
|
|
818
|
+
},
|
|
790
819
|
{
|
|
791
820
|
name: "onAddToolResult",
|
|
792
821
|
type: "(options: AddToolResultOptions) => Promise<void> | Void",
|