@assistant-ui/mcp-docs-server 0.2.0 → 0.2.2
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 +15 -13
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +14 -13
- package/.docs/organized/code-examples/with-artifacts.md +14 -13
- package/.docs/organized/code-examples/with-assistant-transport.md +20 -28
- package/.docs/organized/code-examples/with-browser-extension.md +18 -11
- package/.docs/organized/code-examples/with-chain-of-thought.md +17 -15
- package/.docs/organized/code-examples/with-cloud-standalone.md +10 -11
- package/.docs/organized/code-examples/with-cloud.md +19 -14
- package/.docs/organized/code-examples/with-custom-thread-list.md +15 -14
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +14 -14
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +19 -17
- package/.docs/organized/code-examples/with-eve.md +66 -12
- package/.docs/organized/code-examples/with-expo.md +26 -31
- package/.docs/organized/code-examples/with-external-store.md +17 -12
- package/.docs/organized/code-examples/with-ffmpeg.md +21 -15
- package/.docs/organized/code-examples/with-generative-ui.md +271 -36
- 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 +14 -13
- package/.docs/organized/code-examples/with-langchain.md +12 -13
- package/.docs/organized/code-examples/with-langgraph.md +19 -13
- package/.docs/organized/code-examples/with-livekit.md +13 -13
- package/.docs/organized/code-examples/with-mcp.md +14 -15
- package/.docs/organized/code-examples/with-nuxt.md +2428 -0
- package/.docs/organized/code-examples/with-opencode.md +23 -14
- package/.docs/organized/code-examples/with-openui.md +449 -0
- package/.docs/organized/code-examples/with-pi.md +59 -57
- package/.docs/organized/code-examples/with-react-hook-form.md +16 -15
- package/.docs/organized/code-examples/with-react-ink-web.md +7 -8
- package/.docs/organized/code-examples/with-react-ink.md +6 -6
- package/.docs/organized/code-examples/with-react-router.md +17 -11
- package/.docs/organized/code-examples/with-resumable-stream.md +12 -13
- package/.docs/organized/code-examples/with-store.md +27 -16
- package/.docs/organized/code-examples/with-svelte.md +415 -0
- package/.docs/organized/code-examples/with-sveltekit.md +1061 -0
- package/.docs/organized/code-examples/with-tanstack.md +19 -13
- 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 +7 -2
- package/.docs/raw/docs/(docs)/index.mdx +9 -76
- package/.docs/raw/docs/(docs)/installation.mdx +6 -20
- package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +24 -4
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +5 -1
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +9 -2
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +2 -2
- package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +47 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +29 -4
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +52 -1
- package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +1 -1
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +2 -2
- package/.docs/raw/docs/cloud/ai-sdk.mdx +4 -4
- package/.docs/raw/docs/cloud/index.mdx +1 -1
- package/.docs/raw/docs/copilots/model-context.mdx +4 -3
- package/.docs/raw/docs/copilots/motivation.mdx +4 -4
- package/.docs/raw/docs/guides/attachments.mdx +2 -2
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/context-api.mdx +15 -17
- package/.docs/raw/docs/guides/dictation.mdx +1 -1
- package/.docs/raw/docs/guides/electron.mdx +1 -1
- package/.docs/raw/docs/guides/mentions.mdx +2 -0
- package/.docs/raw/docs/guides/resumable-streams.mdx +74 -3
- package/.docs/raw/docs/guides/suggestions.mdx +15 -12
- package/.docs/raw/docs/ink/hooks.mdx +9 -4
- package/.docs/raw/docs/ink/primitives.mdx +5 -4
- 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/integrations/persistence/custom-adapter.mdx +146 -128
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +15 -13
- package/.docs/raw/docs/migrations/v0-15.mdx +118 -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 +4 -2
- package/.docs/raw/docs/primitives/thread.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/ag-ui/runtime-options.mdx +35 -5
- 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/claude-managed-agents.mdx +118 -0
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +2 -1
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +106 -27
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +19 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +34 -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/langchain.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +5 -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/runtimes/pick-a-runtime.mdx +8 -1
- package/.docs/raw/docs/tools/backend.mdx +2 -2
- package/.docs/raw/docs/tools/defining-tools.mdx +28 -7
- package/.docs/raw/docs/tools/dynamic-tools.mdx +6 -4
- package/.docs/raw/docs/tools/generative-ui-primitive.mdx +180 -0
- package/.docs/raw/docs/tools/generative-ui-slack.mdx +167 -0
- package/.docs/raw/docs/tools/generative-ui-teams.mdx +160 -0
- package/.docs/raw/docs/tools/generative-ui.mdx +224 -211
- package/.docs/raw/docs/tools/index.mdx +2 -1
- package/.docs/raw/docs/tools/interactables.mdx +29 -17
- package/.docs/raw/docs/tools/mcp-apps.mdx +35 -6
- package/.docs/raw/docs/tools/mcp.mdx +9 -7
- package/.docs/raw/docs/tools/openui.mdx +175 -0
- package/.docs/raw/docs/tools/tool-ui.mdx +27 -24
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +17 -8
- package/.docs/raw/docs/ui/attachment.mdx +27 -0
- package/.docs/raw/docs/ui/file.mdx +7 -2
- package/.docs/raw/docs/ui/image.mdx +1 -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/tools/interactables-legacy.mdx +0 -410
|
@@ -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>),
|
|
@@ -307,7 +308,7 @@ aui-state:[{"type":"set","path":["status"],"value":"completed"}]
|
|
|
307
308
|
prepareSendCommandsRequest?: (body: SendCommandsRequestBody) => Record<string, unknown> | Promise<Record<string, unknown>>,
|
|
308
309
|
capabilities?: { edit?: boolean },
|
|
309
310
|
adapters?: { attachments?: AttachmentAdapter; history?: ThreadHistoryAdapter },
|
|
310
|
-
onResponse?: (response: Response) => void
|
|
311
|
+
onResponse?: (response: Response) => void | Promise<void>,
|
|
311
312
|
onFinish?: () => void,
|
|
312
313
|
onError?: (error: Error, params: { commands: AssistantTransportCommand[]; updateState: (updater: (state: T) => T) => void }) => void | Promise<void>,
|
|
313
314
|
onCancel?: (params: { commands: AssistantTransportCommand[]; updateState: (updater: (state: T) => T) => void; error?: Error }) => void
|
|
@@ -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,12 +421,36 @@ useEffect(() => {
|
|
|
418
421
|
}, [isRunning, queue]);
|
|
419
422
|
```
|
|
420
423
|
|
|
424
|
+
With a `createMessageQueue` adapter, cancelling pauses the queue for you: the runtime tells the queue before your `onCancel` runs, so the cancelled run's settle keeps the pending items instead of dispatching the next one, and the next send resumes draining. Call `queue.clear()` in `onCancel` instead if you want a cancel to drop them. A hand-rolled adapter has no such channel, so it owns its cancel policy the same way it owns the rest. Edit and reload stay host-owned: 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
|
+
// the runtime already paused the queue; clear() here to drop the 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.
|
|
424
447
|
|
|
425
448
|
## Integration examples
|
|
426
449
|
|
|
450
|
+
<Callout type="info">
|
|
451
|
+
**Real-world example:** the [Claude Managed Agents guide](/docs/runtimes/claude-managed-agents) maps Anthropic-hosted agent sessions onto this runtime, with Anthropic's official [quickstart](https://github.com/anthropics/claude-quickstarts/tree/main/managed-agents/assistant-ui) as the runnable reference.
|
|
452
|
+
</Callout>
|
|
453
|
+
|
|
427
454
|
### Redux
|
|
428
455
|
|
|
429
456
|
```tsx title="app/chatSlice.ts"
|
|
@@ -787,6 +814,12 @@ useExternalStoreRuntime({
|
|
|
787
814
|
type: "() => Promise<void>",
|
|
788
815
|
description: "Handler for cancelling the current generation.",
|
|
789
816
|
},
|
|
817
|
+
{
|
|
818
|
+
name: "onRefetchThread",
|
|
819
|
+
type: "() => Promise<void>",
|
|
820
|
+
description:
|
|
821
|
+
"Handler for re-fetching this thread's state in place, driving threads.reloadMainThread(). Unrelated to onReload, which re-generates an assistant message.",
|
|
822
|
+
},
|
|
790
823
|
{
|
|
791
824
|
name: "onAddToolResult",
|
|
792
825
|
type: "(options: AddToolResultOptions) => Promise<void> | Void",
|
|
@@ -353,7 +353,7 @@ const openai = new OpenAI();
|
|
|
353
353
|
const MyModelAdapter: ChatModelAdapter = {
|
|
354
354
|
async *run({ messages, abortSignal, context }) {
|
|
355
355
|
const stream = await openai.chat.completions.create({
|
|
356
|
-
model: "gpt-5.
|
|
356
|
+
model: "gpt-5.6-luna",
|
|
357
357
|
messages: convertToOpenAIMessages(messages),
|
|
358
358
|
stream: true,
|
|
359
359
|
signal: abortSignal,
|
|
@@ -372,6 +372,34 @@ const MyModelAdapter: ChatModelAdapter = {
|
|
|
372
372
|
|
|
373
373
|
Each yield replaces the previous content. Yield the full state every time, not deltas.
|
|
374
374
|
|
|
375
|
+
### Only the last part streams
|
|
376
|
+
|
|
377
|
+
A text or reasoning part reports `status.type === "running"` only while it is the last part of the message. Every earlier one reads as complete, and the components that react to streaming follow that status: the reasoning disclosure auto-opens and pins its live preview while its part is running, and part status indicators resolve the same way. Tool-call parts are exempt, since their status comes from whether they have a result.
|
|
378
|
+
|
|
379
|
+
That makes an empty trailing part destructive. Yielding `[reasoning, text("")]` to reserve the text slot marks the reasoning part complete the moment the empty text part appears, even though reasoning is still streaming, and nothing in the UI signals why. Add a part on its first token instead of reserving it:
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
let reasoning = "";
|
|
383
|
+
let text = "";
|
|
384
|
+
|
|
385
|
+
for await (const chunk of stream) {
|
|
386
|
+
const delta = chunk.choices[0]?.delta;
|
|
387
|
+
text += delta?.content ?? "";
|
|
388
|
+
// Reasoning deltas are provider-specific; read whichever field yours sends
|
|
389
|
+
reasoning += (delta as { reasoning?: string })?.reasoning ?? "";
|
|
390
|
+
|
|
391
|
+
// Include each part only once it has content
|
|
392
|
+
yield {
|
|
393
|
+
content: [
|
|
394
|
+
...(reasoning ? [{ type: "reasoning" as const, text: reasoning }] : []),
|
|
395
|
+
...(text ? [{ type: "text" as const, text }] : []),
|
|
396
|
+
],
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Guard every text or reasoning part this way, not just the trailing one. An empty part that is never filled also renders as an empty block, and whichever part ends up last is the only one that can report `running`.
|
|
402
|
+
|
|
375
403
|
### Streaming with tool calls
|
|
376
404
|
|
|
377
405
|
Accumulate tool calls in a `Map` outside the streaming loop so they persist across chunks:
|
|
@@ -379,7 +407,7 @@ Accumulate tool calls in a `Map` outside the streaming loop so they persist acro
|
|
|
379
407
|
```tsx
|
|
380
408
|
async *run({ messages, abortSignal, context }) {
|
|
381
409
|
const stream = await openai.chat.completions.create({
|
|
382
|
-
model: "gpt-5.
|
|
410
|
+
model: "gpt-5.6-luna",
|
|
383
411
|
messages: convertToOpenAIMessages(messages),
|
|
384
412
|
tools: context.tools,
|
|
385
413
|
stream: true,
|
|
@@ -415,7 +443,7 @@ If you build the `content` array fresh from the current chunk each iteration, to
|
|
|
415
443
|
|
|
416
444
|
## Tool calling
|
|
417
445
|
|
|
418
|
-
`LocalRuntime` supports OpenAI-compatible function calling. Register tools through `
|
|
446
|
+
`LocalRuntime` supports OpenAI-compatible function calling. Register tools through the provider's `config` so the runtime exposes them to your adapter via `context.tools`:
|
|
419
447
|
|
|
420
448
|
```tsx title="app/toolkit.tsx"
|
|
421
449
|
"use generative";
|
|
@@ -440,15 +468,14 @@ export default defineToolkit({
|
|
|
440
468
|
```
|
|
441
469
|
|
|
442
470
|
```tsx title="app/MyRuntimeProvider.tsx"
|
|
443
|
-
import {
|
|
471
|
+
import { AuiConfig, Tools } from "@assistant-ui/react";
|
|
444
472
|
import toolkit from "./toolkit";
|
|
445
473
|
|
|
446
474
|
function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
447
475
|
const runtime = useLocalRuntime(MyModelAdapter);
|
|
448
|
-
const
|
|
449
|
-
|
|
476
|
+
const config = AuiConfig({ tools: Tools({ toolkit }) });
|
|
450
477
|
return (
|
|
451
|
-
<AssistantRuntimeProvider
|
|
478
|
+
<AssistantRuntimeProvider runtime={runtime} config={config}>
|
|
452
479
|
{children}
|
|
453
480
|
</AssistantRuntimeProvider>
|
|
454
481
|
);
|
|
@@ -627,7 +654,7 @@ function useStreamReconnect(threadId: string) {
|
|
|
627
654
|
|
|
628
655
|
## Queueing messages during a run
|
|
629
656
|
|
|
630
|
-
Set `unstable_enableMessageQueue` to keep the composer usable while a run is in progress. A message sent during a run
|
|
657
|
+
Set `unstable_enableMessageQueue` to keep the composer usable while a run is in progress. 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.
|
|
631
658
|
|
|
632
659
|
```tsx
|
|
633
660
|
const runtime = useLocalRuntime(MyModelAdapter, {
|
|
@@ -674,7 +701,7 @@ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
|
674
701
|
const OpenAIAdapter: ChatModelAdapter = {
|
|
675
702
|
async *run({ messages, abortSignal, context }) {
|
|
676
703
|
const stream = await openai.chat.completions.create({
|
|
677
|
-
model: "gpt-5.
|
|
704
|
+
model: "gpt-5.6-luna",
|
|
678
705
|
messages: messages.map((m) => ({
|
|
679
706
|
role: m.role,
|
|
680
707
|
content: m.content
|
|
@@ -49,6 +49,57 @@ export default function Home() {
|
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
The `custom` bag of a per-turn `runConfig` is forwarded to Eve as
|
|
53
|
+
`clientContext`, so `runConfig: { custom: { page: "/pricing" } }` arrives as
|
|
54
|
+
`clientContext: { page: "/pricing" }`. An empty or absent bag is omitted, and
|
|
55
|
+
every value must be JSON-serializable.
|
|
56
|
+
|
|
57
|
+
Eve turns that object into a model context message, which is why the
|
|
58
|
+
assistant-ui `custom` envelope is unwrapped: the envelope would put a literal
|
|
59
|
+
`custom` key in the prompt. It is page or client context rather than run
|
|
60
|
+
configuration, and it cannot select a model or change how the turn executes.
|
|
61
|
+
Keep secrets, credentials, and personal data out of it, since the model reads
|
|
62
|
+
it as message text.
|
|
63
|
+
|
|
64
|
+
## Connector authorization
|
|
65
|
+
|
|
66
|
+
When Eve pauses for connector authorization, the runtime emits an assistant
|
|
67
|
+
data part named `authorization`. Its data includes `state`, `name`, and the
|
|
68
|
+
available display fields such as `displayName`, `description`, `url`,
|
|
69
|
+
`userCode`, `instructions`, and `expiresAt`. Completed parts may also include
|
|
70
|
+
`outcome` and `reason`. `url` is present only when the connector supplied an
|
|
71
|
+
`http(s)` address; the adapter drops other schemes so a renderer can link to it
|
|
72
|
+
directly.
|
|
73
|
+
|
|
74
|
+
The Eve template ships this renderer as `components/eve-authorization.tsx` and
|
|
75
|
+
mounts it next to `<Thread />`. To add it to an existing app, register a data UI
|
|
76
|
+
for the part and type it with the exported `EveAuthorizationData`:
|
|
77
|
+
|
|
78
|
+
```tsx title="authorization-ui.tsx"
|
|
79
|
+
import type { EveAuthorizationData } from "@assistant-ui/eve";
|
|
80
|
+
import { makeAssistantDataUI } from "@assistant-ui/react";
|
|
81
|
+
|
|
82
|
+
export const AuthorizationUI = makeAssistantDataUI<EveAuthorizationData>({
|
|
83
|
+
name: "authorization",
|
|
84
|
+
render: ({ data }) => (
|
|
85
|
+
<div>
|
|
86
|
+
{data.state === "required" ? (
|
|
87
|
+
<>
|
|
88
|
+
<p>{data.instructions ?? `Sign in to ${data.displayName ?? data.name}`}</p>
|
|
89
|
+
{data.userCode && <code>{data.userCode}</code>}
|
|
90
|
+
{data.url && <a href={data.url}>Continue to sign in</a>}
|
|
91
|
+
</>
|
|
92
|
+
) : (
|
|
93
|
+
<p>{data.outcome ?? "Authorization completed"}</p>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
),
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Mount `<AuthorizationUI />` inside the `AssistantRuntimeProvider` tree. The
|
|
101
|
+
standard thread intentionally leaves unmatched data parts unrendered.
|
|
102
|
+
|
|
52
103
|
## Requirements
|
|
53
104
|
|
|
54
105
|
- Node.js 24 or higher.
|
|
@@ -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>
|
|
@@ -262,7 +262,7 @@ Follow the [Ink setup](/docs/ink).
|
|
|
262
262
|
|
|
263
263
|
### Forwarding per-run config
|
|
264
264
|
|
|
265
|
-
When a message is sent, its `runConfig.custom` (for example a selected mode or model) is forwarded on the underlying `useStream().submit` call as `config.configurable`. Read it in the graph from `config["configurable"]`; on LangGraph v1 the same values are also reachable through the Runtime `context`, which `config.configurable` is aliased to. This lets per-run app config reach the graph without extra wiring.
|
|
265
|
+
When a message is sent, its `runConfig.custom` (for example a selected mode or model) is forwarded on the underlying `useStream().submit` call as `config.configurable`. Automatic tool-result resumes and the interrupt helpers (`useLangChainRespond`, `useLangChainRespondAll`, and `useLangChainSubmit(null, { command })`) reuse that same recorded `configurable` unless the caller passes `config`. Raw `useLangChainSubmit` / `useLangChainSend` calls that start a new run do not inherit it. The recording is session-scoped and does not survive a reload. Read it in the graph from `config["configurable"]`; on LangGraph v1 the same values are also reachable through the Runtime `context`, which `config.configurable` is aliased to. This lets per-run app config reach the graph without extra wiring.
|
|
266
266
|
|
|
267
267
|
## Reading custom state keys
|
|
268
268
|
|
|
@@ -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({
|
|
@@ -119,6 +119,10 @@ const runtime = useLangGraphRuntime({
|
|
|
119
119
|
|
|
120
120
|
Render the pending messages with [`ComposerPrimitive.Queue`](/docs/api-reference/primitives/composer) and [`QueueItemPrimitive`](/docs/api-reference/primitives/queue-item).
|
|
121
121
|
|
|
122
|
+
## Per-run config
|
|
123
|
+
|
|
124
|
+
When a message is sent, its `runConfig` is forwarded to `stream` and, if you use `unstable_createLangGraphStream`, posted as the LangGraph SDK run `config`. Automatic frontend tool-result resumes and `useLangGraphSendCommand` reuse the `runConfig` of the run that produced the pending tool call or interrupt. An explicit `runConfig` on `useLangGraphSend` still wins. A thread refetch that still carries the interrupt keeps that owner. History loaded without local ownership stays unconfigured on resume; the recording is session-scoped and does not survive a reload.
|
|
125
|
+
|
|
122
126
|
## Next
|
|
123
127
|
|
|
124
128
|
<Cards>
|
|
@@ -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
|
);
|
|
@@ -112,6 +112,7 @@ The returned `OpenCodeThreadState` includes:
|
|
|
112
112
|
|
|
113
113
|
- `sessionId`, `session`, `sessionStatus`, `loadState`, `runState`
|
|
114
114
|
- `messageOrder`, `messagesById`, `pendingUserMessages`
|
|
115
|
+
- `childSessionsById` (OpenCode `task` child-session projections keyed by session ID)
|
|
115
116
|
- `interactions.permissions` (pending + resolved), `interactions.questions` (pending + answered + rejected)
|
|
116
117
|
- `unhandledEvents`, `sync` timestamps
|
|
117
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"]} />
|
|
@@ -6,6 +6,7 @@ description: Decision guide for choosing the right runtime, by framework or by f
|
|
|
6
6
|
import { A2AIcon } from "@/components/icons/a2a";
|
|
7
7
|
import { AdkIcon } from "@/components/icons/adk";
|
|
8
8
|
import { AguiIcon } from "@/components/icons/agui";
|
|
9
|
+
import { ClaudeIcon } from "@/components/icons/claude";
|
|
9
10
|
import { CloudflareIcon } from "@/components/icons/cloudflare";
|
|
10
11
|
import { LangChainIcon } from "@/components/icons/langchain";
|
|
11
12
|
import { LangGraphIcon } from "@/components/icons/langgraph";
|
|
@@ -80,7 +81,7 @@ assistant-ui ships React adapter packages for these. Pick the matching card and
|
|
|
80
81
|
|
|
81
82
|
### Integration guides
|
|
82
83
|
|
|
83
|
-
For frameworks without a dedicated adapter, these wiring guides route through one of the
|
|
84
|
+
For frameworks without a dedicated adapter, these wiring guides route through an existing runtime: an adapter above, or one of the core runtimes.
|
|
84
85
|
|
|
85
86
|
<Cards>
|
|
86
87
|
<Card
|
|
@@ -95,6 +96,12 @@ For frameworks without a dedicated adapter, these wiring guides route through on
|
|
|
95
96
|
description="TypeScript agent framework. Wired through the Vercel AI SDK runtime."
|
|
96
97
|
href="/docs/integrations/frameworks/mastra/overview"
|
|
97
98
|
/>
|
|
99
|
+
<Card
|
|
100
|
+
icon={<ClaudeIcon width={20} height={20} className="text-[#D97757]" />}
|
|
101
|
+
title="Claude Managed Agents"
|
|
102
|
+
description="Anthropic-hosted agent sessions. Wired through the external store runtime: event-log replay, approval gates, sessions as threads."
|
|
103
|
+
href="/docs/runtimes/claude-managed-agents"
|
|
104
|
+
/>
|
|
98
105
|
</Cards>
|
|
99
106
|
|
|
100
107
|
</PlatformOnly>
|
|
@@ -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
|
});
|
|
@@ -192,6 +194,25 @@ The compiler also enforces, at build time:
|
|
|
192
194
|
- a **frontend** tool declares a `render` or `renderText`;
|
|
193
195
|
- a **human** tool declares a `render`.
|
|
194
196
|
|
|
197
|
+
### Running without your own backend
|
|
198
|
+
|
|
199
|
+
The client build skips uploading frontend/human schemas because it assumes your backend imported the same file's server build and already knows them. When no server of yours does — for example, cloud-hosted runs — that assumption breaks and the model never learns about those tools. Compile with the `backendless` option so the client keeps every schema uploadable, including the `present`/`prompt_user` schema of a `JSONGenerativeUI` component library:
|
|
200
|
+
|
|
201
|
+
```ts title="next.config.ts"
|
|
202
|
+
export default withAui({ ...yourConfig, aui: { backendless: true } });
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```ts title="vite.config.ts"
|
|
206
|
+
plugins: [aui({ backendless: true })];
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```js title="metro.config.js"
|
|
210
|
+
module.exports = withAui({
|
|
211
|
+
...getDefaultConfig(__dirname),
|
|
212
|
+
aui: { backendless: true },
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
195
216
|
## Tool kinds
|
|
196
217
|
|
|
197
218
|
### Backend tools
|
|
@@ -368,7 +389,7 @@ export const toolkit = defineToolkit({
|
|
|
368
389
|
});
|
|
369
390
|
```
|
|
370
391
|
|
|
371
|
-
Register it exactly like a generative toolkit: `
|
|
392
|
+
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
393
|
|
|
373
394
|
<Callout type="warn">
|
|
374
395
|
This `{ type: "backend", render }` shape is **plain-toolkit only**. Inside a
|