@assistant-ui/mcp-docs-server 0.1.33 → 0.1.35
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 +7 -7
- package/.docs/organized/code-examples/with-a2a.md +8 -8
- package/.docs/organized/code-examples/with-ag-ui.md +12 -12
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +10 -10
- package/.docs/organized/code-examples/with-artifacts.md +40 -34
- package/.docs/organized/code-examples/with-assistant-transport.md +11 -11
- package/.docs/organized/code-examples/with-browser-extension.md +9 -9
- package/.docs/organized/code-examples/with-chain-of-thought.md +72 -51
- package/.docs/organized/code-examples/with-cloud-standalone.md +10 -10
- package/.docs/organized/code-examples/with-cloud.md +10 -10
- package/.docs/organized/code-examples/with-custom-thread-list.md +10 -10
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +12 -12
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +12 -12
- package/.docs/organized/code-examples/with-expo.md +66 -31
- package/.docs/organized/code-examples/with-external-store.md +8 -8
- package/.docs/organized/code-examples/with-ffmpeg.md +13 -13
- package/.docs/organized/code-examples/with-generative-ui.md +98 -368
- package/.docs/organized/code-examples/with-google-adk.md +9 -9
- package/.docs/organized/code-examples/with-heat-graph.md +7 -7
- package/.docs/organized/code-examples/with-image-generation.md +10 -10
- package/.docs/organized/code-examples/with-interactables.md +10 -10
- package/.docs/organized/code-examples/with-langchain.md +10 -10
- package/.docs/organized/code-examples/with-langgraph.md +33 -29
- package/.docs/organized/code-examples/with-livekit.md +12 -12
- package/.docs/organized/code-examples/with-mcp.md +11 -11
- package/.docs/organized/code-examples/with-opencode.md +109 -583
- package/.docs/organized/code-examples/with-pi.md +2044 -0
- package/.docs/organized/code-examples/with-react-hook-form.md +11 -11
- package/.docs/organized/code-examples/with-react-ink-web.md +691 -0
- package/.docs/organized/code-examples/with-react-ink.md +309 -102
- package/.docs/organized/code-examples/with-react-router.md +14 -14
- package/.docs/organized/code-examples/with-resumable-stream.md +11 -11
- package/.docs/organized/code-examples/with-store.md +70 -66
- package/.docs/organized/code-examples/with-tanstack.md +25 -11
- package/.docs/organized/code-examples/with-tap-runtime.md +8 -8
- package/.docs/organized/code-examples/with-virtualized-thread.md +656 -0
- package/.docs/raw/docs/(docs)/architecture.mdx +65 -53
- package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +3 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +44 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +14 -3
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +2 -23
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +22 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +93 -9
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +21 -86
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/index.mdx +3 -0
- package/.docs/raw/docs/guides/input-history.mdx +55 -0
- package/.docs/raw/docs/guides/virtualization.mdx +63 -0
- package/.docs/raw/docs/ink/adapters.mdx +23 -1
- package/.docs/raw/docs/ink/hooks.mdx +22 -19
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +14 -8
- package/.docs/raw/docs/react-native/hooks.mdx +26 -18
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +39 -0
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +3 -3
- package/.docs/raw/docs/runtimes/concepts/architecture.mdx +46 -4
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +54 -12
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +62 -4
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +120 -4
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +9 -9
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +13 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +5 -5
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +3 -3
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +6 -6
- package/.docs/raw/docs/tools/backend.mdx +19 -11
- package/.docs/raw/docs/tools/defining-tools.mdx +177 -52
- package/.docs/raw/docs/tools/index.mdx +7 -12
- package/.docs/raw/docs/tools/mcp.mdx +83 -15
- package/.docs/raw/docs/tools/multi-agent.mdx +5 -5
- package/.docs/raw/docs/tools/tool-ui.mdx +64 -28
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +4 -4
- package/.docs/raw/docs/ui/dot-matrix.mdx +133 -0
- package/.docs/raw/docs/ui/mermaid.mdx +16 -9
- package/.docs/raw/docs/ui/model-selector.mdx +219 -52
- package/.docs/raw/docs/ui/number-roll.mdx +154 -0
- package/.docs/raw/docs/ui/part-grouping.mdx +2 -2
- package/.docs/raw/docs/ui/reasoning.mdx +3 -3
- package/.docs/raw/docs/ui/streamdown.mdx +2 -0
- package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -1
- package/.docs/raw/docs/ui/thread.mdx +52 -0
- package/.docs/raw/docs/ui/tool-fallback.mdx +16 -0
- package/.docs/raw/docs/utilities/react-o11y.mdx +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/copy-raw.js.map +1 -1
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/stdio.js.map +1 -1
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/utils/mdx.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/package.json +4 -4
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/assistant-frame.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/make-assistant-visible.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/model-context.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/motivation.mdx +0 -0
- /package/.docs/raw/docs/{(docs)/copilots → copilots}/use-assistant-instructions.mdx +0 -0
|
@@ -17,14 +17,44 @@ If you do not have an existing store, use [`LocalRuntime`](/docs/runtimes/custom
|
|
|
17
17
|
|
|
18
18
|
## Architecture
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
graph TD
|
|
20
|
+
<Flow.Root
|
|
21
|
+
llm={`graph TD
|
|
22
22
|
A[Your state] -->|messages| B[ExternalStoreAdapter]
|
|
23
23
|
B --> C[ExternalStoreRuntime]
|
|
24
24
|
C --> D[assistant-ui components]
|
|
25
25
|
D -->|user actions| B
|
|
26
|
-
B -->|state updates| A
|
|
27
|
-
|
|
26
|
+
B -->|state updates| A`}
|
|
27
|
+
>
|
|
28
|
+
<Flow.Canvas
|
|
29
|
+
className="pr-44"
|
|
30
|
+
edges={[
|
|
31
|
+
{
|
|
32
|
+
from: "components",
|
|
33
|
+
to: "adapter",
|
|
34
|
+
route: "loop-right",
|
|
35
|
+
label: "user actions",
|
|
36
|
+
laneOffset: 40,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
from: "adapter",
|
|
40
|
+
to: "state",
|
|
41
|
+
route: "loop-right",
|
|
42
|
+
label: "state updates",
|
|
43
|
+
laneOffset: 88,
|
|
44
|
+
},
|
|
45
|
+
]}
|
|
46
|
+
>
|
|
47
|
+
<Flow.Column>
|
|
48
|
+
<Flow.Node flowId="state">Your state</Flow.Node>
|
|
49
|
+
<Flow.Arrow direction="down" label="messages" length={36} />
|
|
50
|
+
<Flow.Node flowId="adapter">ExternalStoreAdapter</Flow.Node>
|
|
51
|
+
<Flow.Arrow direction="down" length={36} />
|
|
52
|
+
<Flow.Node>ExternalStoreRuntime</Flow.Node>
|
|
53
|
+
<Flow.Arrow direction="down" length={36} />
|
|
54
|
+
<Flow.Node flowId="components">assistant-ui components</Flow.Node>
|
|
55
|
+
</Flow.Column>
|
|
56
|
+
</Flow.Canvas>
|
|
57
|
+
</Flow.Root>
|
|
28
58
|
|
|
29
59
|
Key idea: you own the state, the adapter translates between your format and assistant-ui's. UI features are capability-based; if you provide `setMessages`, branching turns on; if you provide `onEdit`, editing turns on; etc.
|
|
30
60
|
|
|
@@ -178,6 +208,7 @@ Each handler enables a specific UI feature.
|
|
|
178
208
|
| `onReload` | Regenerate button |
|
|
179
209
|
| `onCancel` | Cancel button while generating |
|
|
180
210
|
| `onAddToolResult` | Client-side tool result handoff |
|
|
211
|
+
| `queue` | Queueing messages sent while a run is in progress |
|
|
181
212
|
|
|
182
213
|
## Streaming responses
|
|
183
214
|
|
|
@@ -312,6 +343,33 @@ const runtime = useExternalStoreRuntime({
|
|
|
312
343
|
});
|
|
313
344
|
```
|
|
314
345
|
|
|
346
|
+
## Queueing messages during a run
|
|
347
|
+
|
|
348
|
+
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).
|
|
349
|
+
|
|
350
|
+
The `createMessageQueue` helper owns the FIFO ordering and the in-flight guard. 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()`).
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
import { useEffect, useRef, useState } from "react";
|
|
354
|
+
import { createMessageQueue, useExternalStoreRuntime } from "@assistant-ui/react";
|
|
355
|
+
|
|
356
|
+
const [queue] = useState(() => createMessageQueue({ run: onNew }));
|
|
357
|
+
|
|
358
|
+
const runtime = useExternalStoreRuntime({
|
|
359
|
+
messages,
|
|
360
|
+
isRunning,
|
|
361
|
+
onNew,
|
|
362
|
+
queue: queue.adapter,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const wasRunning = useRef(isRunning);
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
if (!wasRunning.current && isRunning) queue.notifyBusy();
|
|
368
|
+
if (wasRunning.current && !isRunning) queue.notifyIdle();
|
|
369
|
+
wasRunning.current = isRunning;
|
|
370
|
+
}, [isRunning, queue]);
|
|
371
|
+
```
|
|
372
|
+
|
|
315
373
|
## Multi-thread
|
|
316
374
|
|
|
317
375
|
`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.
|
|
@@ -457,18 +457,122 @@ function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
|
|
|
457
457
|
|
|
458
458
|
See the [tools guide](/docs/tools/defining-tools) for advanced patterns.
|
|
459
459
|
|
|
460
|
-
### Human-in-the-loop
|
|
460
|
+
### Human-in-the-loop tools
|
|
461
461
|
|
|
462
|
-
|
|
462
|
+
Tools listed in `unstable_humanToolNames` are not executed by code. The run pauses on the tool call and the user supplies the result through the tool UI:
|
|
463
463
|
|
|
464
464
|
```ts
|
|
465
465
|
const runtime = useLocalRuntime(MyModelAdapter, {
|
|
466
|
-
unstable_humanToolNames: ["
|
|
466
|
+
unstable_humanToolNames: ["send_email"],
|
|
467
|
+
});
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
The pause is driven by the message status your adapter returns; `LocalRuntime` never sets it for you. When the model requests a human tool call, end the run with `status: { type: "requires-action", reason: "tool-calls" }`. Without that status, the runtime marks the message complete and nothing waits. Only return it while a listed tool call is missing its result: unresolved tool calls that are not listed do not hold the run, so the runtime would invoke your adapter again immediately.
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
const MyModelAdapter: ChatModelAdapter = {
|
|
474
|
+
async run({ messages, abortSignal, unstable_getMessage }) {
|
|
475
|
+
const toolResults = unstable_getMessage().content.flatMap((part) =>
|
|
476
|
+
part.type === "tool-call" && part.result !== undefined
|
|
477
|
+
? [{ toolCallId: part.toolCallId, result: part.result }]
|
|
478
|
+
: [],
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
const result = await fetch("<YOUR_API_ENDPOINT>", {
|
|
482
|
+
method: "POST",
|
|
483
|
+
headers: { "Content-Type": "application/json" },
|
|
484
|
+
body: JSON.stringify({ messages, toolResults }),
|
|
485
|
+
signal: abortSignal,
|
|
486
|
+
});
|
|
487
|
+
const data = await result.json();
|
|
488
|
+
|
|
489
|
+
if (data.toolCall) {
|
|
490
|
+
return {
|
|
491
|
+
content: [
|
|
492
|
+
{
|
|
493
|
+
type: "tool-call",
|
|
494
|
+
toolCallId: data.toolCall.id,
|
|
495
|
+
toolName: data.toolCall.name,
|
|
496
|
+
args: data.toolCall.args,
|
|
497
|
+
argsText: JSON.stringify(data.toolCall.args),
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
status: { type: "requires-action", reason: "tool-calls" },
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return { content: [{ type: "text", text: data.text }] };
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
The full loop:
|
|
510
|
+
|
|
511
|
+
1. **The run pauses.** While a listed tool call has no result, the runtime stops invoking your adapter. The unresolved tool call part reports `status.type === "requires-action"` to its renderer.
|
|
512
|
+
2. **The user responds.** The tool UI completes the call with `addResult(...)`. The stock [`ToolFallback`](/docs/ui/tool-fallback) component handles this out of the box: in the requires-action state it shows Allow and Deny buttons that record the decision as the tool result.
|
|
513
|
+
3. **The run resumes.** Once every listed tool call has a result, the runtime invokes your adapter again. The resumed call receives the same `messages` array as before (it ends at the user message; the in-progress assistant message is not part of it), so read the recorded results from `unstable_getMessage().content` as shown above. Content returned by the resumed call is appended to the same assistant message.
|
|
514
|
+
|
|
515
|
+
For a custom confirmation UI, register a human tool whose `render` completes the call with `addResult`. The shape of the result payload is yours to define; the adapter receives it verbatim and translates it for your backend:
|
|
516
|
+
|
|
517
|
+
```tsx
|
|
518
|
+
const toolkit = defineToolkit({
|
|
519
|
+
send_email: {
|
|
520
|
+
type: "human",
|
|
521
|
+
description: "Send an email after the user confirms",
|
|
522
|
+
parameters: z.object({ to: z.string(), subject: z.string() }),
|
|
523
|
+
render: ({ args, result, addResult }) => {
|
|
524
|
+
if (result) {
|
|
525
|
+
return <p>{result.approved ? "Sent" : `Cancelled: ${result.reason}`}</p>;
|
|
526
|
+
}
|
|
527
|
+
return (
|
|
528
|
+
<div>
|
|
529
|
+
<p>
|
|
530
|
+
Send "{args.subject}" to {args.to}?
|
|
531
|
+
</p>
|
|
532
|
+
<button onClick={() => addResult({ approved: true })}>Allow</button>
|
|
533
|
+
<button
|
|
534
|
+
onClick={() =>
|
|
535
|
+
addResult({ approved: false, reason: "User declined" })
|
|
536
|
+
}
|
|
537
|
+
>
|
|
538
|
+
Deny
|
|
539
|
+
</button>
|
|
540
|
+
</div>
|
|
541
|
+
);
|
|
542
|
+
},
|
|
543
|
+
},
|
|
467
544
|
});
|
|
468
545
|
```
|
|
469
546
|
|
|
470
547
|
`unstable_humanToolNames` is unstable; see [stability](/docs/runtimes/concepts/stability).
|
|
471
548
|
|
|
549
|
+
### Approval gates
|
|
550
|
+
|
|
551
|
+
The [server-side approval gate](/docs/tools/tool-ui#server-side-approval-gates) is also supported on `LocalRuntime`, for actions your backend executes after the user authorizes them. Where a human tool asks the user to supply the tool result, an approval gate asks the user to allow or block an action the adapter performs. Emit `approval: { id }` on the tool call part and end the run with the same `requires-action` status:
|
|
552
|
+
|
|
553
|
+
```tsx
|
|
554
|
+
return {
|
|
555
|
+
content: [
|
|
556
|
+
{
|
|
557
|
+
type: "tool-call",
|
|
558
|
+
toolCallId: data.toolCall.id,
|
|
559
|
+
toolName: data.toolCall.name,
|
|
560
|
+
args: data.toolCall.args,
|
|
561
|
+
argsText: JSON.stringify(data.toolCall.args),
|
|
562
|
+
approval: { id: data.toolCall.id },
|
|
563
|
+
},
|
|
564
|
+
],
|
|
565
|
+
status: { type: "requires-action", reason: "tool-calls" },
|
|
566
|
+
};
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
A tool call with a pending approval pauses the run, whether or not the tool is listed in `unstable_humanToolNames`. Always emit gates in the pending state (`approval: { id }` with no `approved` field); a part that arrives already decided is treated as resolved and the runtime invokes the adapter again immediately. The stock [`ToolFallback`](/docs/ui/tool-fallback) Allow and Deny buttons, or a custom renderer calling `respondToApproval({ approved, reason? })`, record the decision:
|
|
570
|
+
|
|
571
|
+
- **Deny** sets `approval.approved: false` and synthesizes an error result (`{ error: reason || "Tool approval denied" }` with `isError: true`), so the model sees the denial.
|
|
572
|
+
- **Allow** sets `approval.approved: true` and leaves the result empty; performing the action is your adapter's job.
|
|
573
|
+
|
|
574
|
+
Once every pending approval on the message is decided and every listed human tool has a result, the runtime invokes your adapter again. Read the decisions from `unstable_getMessage().content`, perform the approved actions, and return the follow-up response. A tool call that carries an approval is owned by the gate: it does not additionally require a result, even when its name is listed in `unstable_humanToolNames`.
|
|
575
|
+
|
|
472
576
|
## Resuming a run
|
|
473
577
|
|
|
474
578
|
`resumeRun` reconnects to an in-progress assistant run. Useful for page refresh, network reconnect, tab backgrounding, or thread switching when the backend is still generating.
|
|
@@ -521,6 +625,18 @@ function useStreamReconnect(threadId: string) {
|
|
|
521
625
|
}
|
|
522
626
|
```
|
|
523
627
|
|
|
628
|
+
## Queueing messages during a run
|
|
629
|
+
|
|
630
|
+
Set `unstable_enableMessageQueue` to keep the composer usable while a run is in progress. A message sent during a run is held in `composer.queue` and sent once the run settles; steering a queued message runs it next.
|
|
631
|
+
|
|
632
|
+
```tsx
|
|
633
|
+
const runtime = useLocalRuntime(MyModelAdapter, {
|
|
634
|
+
unstable_enableMessageQueue: true,
|
|
635
|
+
});
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
Render the pending messages with [`ComposerPrimitive.Queue`](/docs/api-reference/primitives/composer) and [`QueueItemPrimitive`](/docs/api-reference/primitives/queue-item).
|
|
639
|
+
|
|
524
640
|
## Adapters
|
|
525
641
|
|
|
526
642
|
Attachments, speech, feedback, history, and suggestions are wired through the standard adapter contracts, see [adapters](/docs/runtimes/concepts/adapters):
|
|
@@ -731,7 +847,7 @@ const CustomAPIAdapter: ChatModelAdapter = {
|
|
|
731
847
|
name: "unstable_humanToolNames",
|
|
732
848
|
type: "string[]",
|
|
733
849
|
description:
|
|
734
|
-
"Tool names that
|
|
850
|
+
"Tool names that pause the run until the user supplies a result via addResult (unstable).",
|
|
735
851
|
},
|
|
736
852
|
]}
|
|
737
853
|
/>
|
|
@@ -389,8 +389,8 @@ Register the renderer with a backend toolkit entry inside `AssistantRuntimeProvi
|
|
|
389
389
|
```tsx
|
|
390
390
|
import {
|
|
391
391
|
AssistantRuntimeProvider,
|
|
392
|
+
defineToolkit,
|
|
392
393
|
Tools,
|
|
393
|
-
type Toolkit,
|
|
394
394
|
useAui,
|
|
395
395
|
} from "@assistant-ui/react";
|
|
396
396
|
import {
|
|
@@ -399,12 +399,12 @@ import {
|
|
|
399
399
|
} from "@assistant-ui/react-google-adk";
|
|
400
400
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
401
401
|
|
|
402
|
-
const toolkit = {
|
|
402
|
+
const toolkit = defineToolkit({
|
|
403
403
|
adk_request_input: {
|
|
404
404
|
type: "backend",
|
|
405
405
|
render: RequestInputToolUI,
|
|
406
406
|
},
|
|
407
|
-
}
|
|
407
|
+
});
|
|
408
408
|
|
|
409
409
|
function App() {
|
|
410
410
|
const runtime = useAdkRuntime({
|
|
@@ -426,8 +426,8 @@ function App() {
|
|
|
426
426
|
```tsx
|
|
427
427
|
import {
|
|
428
428
|
AssistantRuntimeProvider,
|
|
429
|
+
defineToolkit,
|
|
429
430
|
Tools,
|
|
430
|
-
type Toolkit,
|
|
431
431
|
useAui,
|
|
432
432
|
} from "@assistant-ui/react-native";
|
|
433
433
|
import {
|
|
@@ -439,12 +439,12 @@ import { Thread } from "@/components/assistant-ui/thread";
|
|
|
439
439
|
|
|
440
440
|
const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3000";
|
|
441
441
|
|
|
442
|
-
const toolkit = {
|
|
442
|
+
const toolkit = defineToolkit({
|
|
443
443
|
adk_request_input: {
|
|
444
444
|
type: "backend",
|
|
445
445
|
render: RequestInputToolUI,
|
|
446
446
|
},
|
|
447
|
-
}
|
|
447
|
+
});
|
|
448
448
|
|
|
449
449
|
function App() {
|
|
450
450
|
const runtime = useAdkRuntime({
|
|
@@ -468,8 +468,8 @@ function App() {
|
|
|
468
468
|
```tsx
|
|
469
469
|
import {
|
|
470
470
|
AssistantRuntimeProvider,
|
|
471
|
+
defineToolkit,
|
|
471
472
|
Tools,
|
|
472
|
-
type Toolkit,
|
|
473
473
|
useAui,
|
|
474
474
|
} from "@assistant-ui/react-ink";
|
|
475
475
|
import {
|
|
@@ -479,12 +479,12 @@ import {
|
|
|
479
479
|
import { Box } from "ink";
|
|
480
480
|
import { Thread } from "./components/thread.js";
|
|
481
481
|
|
|
482
|
-
const toolkit = {
|
|
482
|
+
const toolkit = defineToolkit({
|
|
483
483
|
adk_request_input: {
|
|
484
484
|
type: "backend",
|
|
485
485
|
render: RequestInputToolUI,
|
|
486
486
|
},
|
|
487
|
-
}
|
|
487
|
+
});
|
|
488
488
|
|
|
489
489
|
function App() {
|
|
490
490
|
const runtime = useAdkRuntime({
|
|
@@ -106,6 +106,19 @@ LangGraph can emit structured UI components alongside assistant messages via `pu
|
|
|
106
106
|
|
|
107
107
|
See [Generative UI](/docs/runtimes/langgraph/generative-ui) for full setup: enabling the `custom` stream channel, emitting UI messages, registering renderers, dynamic loading, and persisting UI state across thread switches.
|
|
108
108
|
|
|
109
|
+
## Queueing messages during a run
|
|
110
|
+
|
|
111
|
+
Set `unstable_enableMessageQueue` to keep the composer usable while a run is streaming. A message sent during a run is held in `composer.queue` and sent once the run settles; steering a queued message runs it next.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
const runtime = useLangGraphRuntime({
|
|
115
|
+
stream,
|
|
116
|
+
unstable_enableMessageQueue: true,
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Render the pending messages with [`ComposerPrimitive.Queue`](/docs/api-reference/primitives/composer) and [`QueueItemPrimitive`](/docs/api-reference/primitives/queue-item).
|
|
121
|
+
|
|
109
122
|
## Next
|
|
110
123
|
|
|
111
124
|
<Cards>
|
|
@@ -94,14 +94,14 @@ 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,
|
|
97
|
+
import { AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
98
98
|
|
|
99
|
-
const toolkit = {
|
|
99
|
+
const toolkit = defineToolkit({
|
|
100
100
|
price_snapshot: {
|
|
101
101
|
type: "backend",
|
|
102
102
|
render: PriceSnapshotToolUI,
|
|
103
103
|
},
|
|
104
|
-
}
|
|
104
|
+
});
|
|
105
105
|
|
|
106
106
|
export default function Home() {
|
|
107
107
|
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
@@ -326,12 +326,12 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
|
326
326
|
### Bind fallback UI
|
|
327
327
|
|
|
328
328
|
```tsx title="@/app/page.tsx"
|
|
329
|
-
const toolkit = {
|
|
329
|
+
const toolkit = defineToolkit({
|
|
330
330
|
price_snapshot: {
|
|
331
331
|
type: "backend",
|
|
332
332
|
render: PriceSnapshotToolUI,
|
|
333
333
|
},
|
|
334
|
-
}
|
|
334
|
+
});
|
|
335
335
|
|
|
336
336
|
export default function Home() {
|
|
337
337
|
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
@@ -212,9 +212,9 @@ 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,
|
|
215
|
+
import { AuiProvider, defineToolkit, Tools, useAui } from "@assistant-ui/react";
|
|
216
216
|
|
|
217
|
-
const toolkit = {
|
|
217
|
+
const toolkit = defineToolkit({
|
|
218
218
|
price_snapshot: {
|
|
219
219
|
type: "backend",
|
|
220
220
|
render: PriceSnapshotToolUI,
|
|
@@ -223,7 +223,7 @@ const toolkit = {
|
|
|
223
223
|
type: "backend",
|
|
224
224
|
render: PurchaseStockToolUI,
|
|
225
225
|
},
|
|
226
|
-
}
|
|
226
|
+
});
|
|
227
227
|
|
|
228
228
|
export default function Home() {
|
|
229
229
|
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
@@ -28,13 +28,13 @@ assistant-ui ships React adapter packages for these. Pick the matching card and
|
|
|
28
28
|
icon={<VercelIcon width={20} height={20} />}
|
|
29
29
|
title="Vercel AI SDK"
|
|
30
30
|
description="useChat hook, streaming, tools, attachments, multi-step. v6 current; v5 / v4 legacy."
|
|
31
|
-
href="/docs/runtimes/ai-sdk"
|
|
31
|
+
href="/docs/runtimes/ai-sdk/overview"
|
|
32
32
|
/>
|
|
33
33
|
<Card
|
|
34
34
|
icon={<LangGraphIcon width={20} height={20} className="text-[#1C3C3C] dark:text-[#5b9595]" />}
|
|
35
35
|
title="LangGraph"
|
|
36
36
|
description="Direct integration with @langchain/langgraph-sdk. Subgraph events, UI messages, message metadata."
|
|
37
|
-
href="/docs/runtimes/langgraph"
|
|
37
|
+
href="/docs/runtimes/langgraph/overview"
|
|
38
38
|
/>
|
|
39
39
|
<Card
|
|
40
40
|
icon={<LangChainIcon width={20} height={20} className="text-[#7FC8FF]" />}
|
|
@@ -46,7 +46,7 @@ assistant-ui ships React adapter packages for these. Pick the matching card and
|
|
|
46
46
|
icon={<AdkIcon width={20} height={20} />}
|
|
47
47
|
title="Google ADK"
|
|
48
48
|
description="ADK JS or Python agents. Tool confirmations, auth flows, multi-agent, code execution."
|
|
49
|
-
href="/docs/runtimes/google-adk"
|
|
49
|
+
href="/docs/runtimes/google-adk/overview"
|
|
50
50
|
/>
|
|
51
51
|
<Card
|
|
52
52
|
icon={<A2AIcon width={20} height={20} />}
|
|
@@ -58,14 +58,14 @@ assistant-ui ships React adapter packages for these. Pick the matching card and
|
|
|
58
58
|
icon={<AguiIcon width={20} height={20} />}
|
|
59
59
|
title="AG-UI Protocol"
|
|
60
60
|
description="AG-UI agents (CopilotKit, custom servers). Streaming text, thinking, tool calls, state snapshots."
|
|
61
|
-
href="/docs/runtimes/ag-ui"
|
|
61
|
+
href="/docs/runtimes/ag-ui/overview"
|
|
62
62
|
/>
|
|
63
63
|
<PlatformOnly platforms={["react"]}>
|
|
64
64
|
<Card
|
|
65
65
|
icon={<OpenCodeIcon width={20} height={20} />}
|
|
66
66
|
title="OpenCode"
|
|
67
67
|
description="OpenCode coding-agent server. Permission flows, questions, fork / revert. Experimental."
|
|
68
|
-
href="/docs/runtimes/opencode"
|
|
68
|
+
href="/docs/runtimes/opencode/overview"
|
|
69
69
|
/>
|
|
70
70
|
</PlatformOnly>
|
|
71
71
|
</Cards>
|
|
@@ -104,7 +104,7 @@ If you do not know your framework yet, or your backend is custom, pick by what y
|
|
|
104
104
|
| Backend that already speaks the data stream protocol | [DataStream](/docs/runtimes/custom/data-stream) |
|
|
105
105
|
| Stream full agent state snapshots (not just messages) | [AssistantTransport](/docs/runtimes/custom/assistant-transport) |
|
|
106
106
|
|
|
107
|
-
If none of the framework adapters fits, start at [custom backend](/docs/runtimes/custom).
|
|
107
|
+
If none of the framework adapters fits, start at [custom backend](/docs/runtimes/custom/overview).
|
|
108
108
|
|
|
109
109
|
## Shared concepts
|
|
110
110
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Backend Tools
|
|
3
|
-
description: Wire assistant-ui toolkits into your server with the AI SDK —
|
|
3
|
+
description: Wire assistant-ui toolkits into your server with the AI SDK — AISDKToolkit, frontendTools, mixing client and server tools, and multi-modal results.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -24,16 +24,18 @@ const {
|
|
|
24
24
|
} = await req.json();
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
## Generative toolkits: `
|
|
27
|
+
## Generative toolkits: `AISDKToolkit`
|
|
28
28
|
|
|
29
|
-
When you author tools in a [`"use generative"` file](/docs/tools/defining-tools#quick-start-use-generative), the same import resolves to the **server build** inside a route handler — schema plus any backend `execute`, with renderers stripped.
|
|
29
|
+
When you author tools in a [`"use generative"` file](/docs/tools/defining-tools#quick-start-use-generative), the same import resolves to the **server build** inside a route handler — schema plus any backend `execute`, with renderers stripped. Wrap it in an `AISDKToolkit` and call `.tools()` with the uploaded `tools`:
|
|
30
30
|
|
|
31
31
|
```ts title="app/api/chat/route.ts"
|
|
32
|
-
import {
|
|
32
|
+
import { AISDKToolkit } from "@assistant-ui/react-ai-sdk";
|
|
33
33
|
import { streamText, convertToModelMessages, type UIMessage } from "ai";
|
|
34
34
|
import { openai } from "@ai-sdk/openai";
|
|
35
35
|
import toolkit from "../../toolkit";
|
|
36
36
|
|
|
37
|
+
const aiToolkit = new AISDKToolkit({ toolkit });
|
|
38
|
+
|
|
37
39
|
export async function POST(req: Request) {
|
|
38
40
|
const { messages, system, tools } = await req.json();
|
|
39
41
|
|
|
@@ -41,24 +43,29 @@ export async function POST(req: Request) {
|
|
|
41
43
|
model: openai("gpt-5.4-nano"),
|
|
42
44
|
system,
|
|
43
45
|
messages: await convertToModelMessages(messages),
|
|
44
|
-
tools:
|
|
46
|
+
tools: await aiToolkit.tools({ frontend: tools }),
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
return result.toUIMessageStreamResponse();
|
|
48
50
|
}
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
`
|
|
53
|
+
`AISDKToolkit.tools()` registers every toolkit tool with the model using its schema, wires the backend `execute` where the server build carries one, and merges in the uploaded frontend tools. A server `execute` wins over an uploaded entry of the same name. Frontend and human tools (no server `execute`) are exposed schema-only and left for the client and the user to fulfill.
|
|
52
54
|
|
|
53
55
|
<Callout type="info">
|
|
54
|
-
If your toolkit spreads in MCP server tools (`defineMcpToolkit`),
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
If your toolkit spreads in MCP server tools (`defineMcpToolkit`), `.tools()`
|
|
57
|
+
also opens those connections. A module-scope `aiToolkit` pools them across
|
|
58
|
+
requests; see [MCP](/docs/tools/mcp) for the connection lifecycle and when to
|
|
59
|
+
call `aiToolkit.close()`. The older
|
|
60
|
+
`generativeTools({ toolkit, frontendTools })` is deprecated, MCP-less, and
|
|
61
|
+
superseded by `AISDKToolkit`.
|
|
57
62
|
</Callout>
|
|
58
63
|
|
|
59
64
|
## Client-defined tools: `frontendTools`
|
|
60
65
|
|
|
61
|
-
If
|
|
66
|
+
If a toolkit cannot go through the generative compiler, the AI SDK adapter still
|
|
67
|
+
serializes browser-executed tools into the request `tools`. Convert them to the
|
|
68
|
+
AI SDK shape with `frontendTools` and spread your own server tools alongside:
|
|
62
69
|
|
|
63
70
|
```ts title="app/api/chat/route.ts"
|
|
64
71
|
import { frontendTools } from "@assistant-ui/react-ai-sdk";
|
|
@@ -86,7 +93,8 @@ export async function POST(req: Request) {
|
|
|
86
93
|
}
|
|
87
94
|
```
|
|
88
95
|
|
|
89
|
-
`
|
|
96
|
+
`AISDKToolkit.tools()` calls `frontendTools` for you under the hood; reach for
|
|
97
|
+
`frontendTools` directly when you're not on the generative build.
|
|
90
98
|
|
|
91
99
|
<Callout type="tip">
|
|
92
100
|
`toToolsJSONSchema` emits the uploaded tools in alphabetical order, so two
|