@assistant-ui/mcp-docs-server 0.1.8 → 0.1.10
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/with-ai-sdk-v5.md +24 -17
- package/.docs/organized/code-examples/with-assistant-transport.md +1599 -0
- package/.docs/organized/code-examples/with-cloud.md +11 -11
- package/.docs/organized/code-examples/with-external-store.md +9 -9
- package/.docs/organized/code-examples/with-ffmpeg.md +17 -16
- package/.docs/organized/code-examples/with-langgraph.md +33 -110
- package/.docs/organized/code-examples/with-parent-id-grouping.md +9 -9
- package/.docs/organized/code-examples/with-react-hook-form.md +17 -16
- package/.docs/raw/docs/api-reference/primitives/Thread.mdx +40 -8
- package/.docs/raw/docs/cloud/persistence/langgraph.mdx +42 -66
- package/.docs/raw/docs/copilots/assistant-frame.mdx +18 -16
- package/.docs/raw/docs/devtools.mdx +51 -0
- package/.docs/raw/docs/getting-started.mdx +2 -4
- package/.docs/raw/docs/guides/ToolUI.mdx +112 -37
- package/.docs/raw/docs/guides/Tools.mdx +170 -6
- package/.docs/raw/docs/migrations/react-langgraph-v0-7.mdx +324 -0
- package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +2 -2
- package/.docs/raw/docs/runtimes/custom/local.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +55 -20
- package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +6 -5
- package/.docs/raw/docs/runtimes/mastra/overview.mdx +3 -3
- package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +13 -13
- package/.docs/raw/docs/ui/Thread.mdx +368 -5
- package/package.json +8 -8
- package/.docs/raw/docs/migrations/v0-7.mdx +0 -188
- package/.docs/raw/docs/migrations/v0-8.mdx +0 -160
- package/.docs/raw/docs/migrations/v0-9.mdx +0 -75
- package/.docs/raw/docs/ui/primitives/Thread.mdx +0 -197
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
title: Chat History for LangGraph Cloud
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
import { Steps, Step } from
|
|
6
|
-
import { Callout } from
|
|
7
|
-
import { Tab, Tabs } from
|
|
5
|
+
import { Steps, Step } from "fumadocs-ui/components/steps";
|
|
6
|
+
import { Callout } from "fumadocs-ui/components/callout";
|
|
7
|
+
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
|
8
8
|
|
|
9
9
|
## Overview
|
|
10
10
|
|
|
@@ -13,7 +13,8 @@ assistant-cloud provides thread management and persistent chat history for appli
|
|
|
13
13
|
## Prerequisites
|
|
14
14
|
|
|
15
15
|
<Callout type="info">
|
|
16
|
-
You need an assistant-cloud account to follow this guide. [Sign up
|
|
16
|
+
You need an assistant-cloud account to follow this guide. [Sign up
|
|
17
|
+
here](https://cloud.assistant-ui.com/) to get started.
|
|
17
18
|
</Callout>
|
|
18
19
|
|
|
19
20
|
## Setup Guide
|
|
@@ -75,40 +76,12 @@ Create a runtime provider that integrates LangGraph with assistant-cloud. Choose
|
|
|
75
76
|
import {
|
|
76
77
|
AssistantCloud,
|
|
77
78
|
AssistantRuntimeProvider,
|
|
78
|
-
useCloudThreadListRuntime,
|
|
79
|
-
useThreadListItemRuntime,
|
|
80
79
|
} from "@assistant-ui/react";
|
|
81
80
|
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
|
|
82
81
|
import { createThread, getThreadState, sendMessage } from "@/lib/chatApi";
|
|
83
82
|
import { LangChainMessage } from "@assistant-ui/react-langgraph";
|
|
84
83
|
import { useMemo } from "react";
|
|
85
84
|
|
|
86
|
-
const useMyLangGraphRuntime = () => {
|
|
87
|
-
const threadListItemRuntime = useThreadListItemRuntime();
|
|
88
|
-
|
|
89
|
-
const runtime = useLangGraphRuntime({
|
|
90
|
-
stream: async function* (messages) {
|
|
91
|
-
const { externalId } = await threadListItemRuntime.initialize();
|
|
92
|
-
if (!externalId) throw new Error("Thread not found");
|
|
93
|
-
|
|
94
|
-
return sendMessage({
|
|
95
|
-
threadId: externalId,
|
|
96
|
-
messages,
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
onSwitchToThread: async (externalId) => {
|
|
101
|
-
const state = await getThreadState(externalId);
|
|
102
|
-
return {
|
|
103
|
-
messages:
|
|
104
|
-
(state.values as { messages?: LangChainMessage[] }).messages ?? [],
|
|
105
|
-
};
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
return runtime;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
85
|
export function MyRuntimeProvider({
|
|
113
86
|
children,
|
|
114
87
|
}: Readonly<{
|
|
@@ -123,13 +96,28 @@ export function MyRuntimeProvider({
|
|
|
123
96
|
[],
|
|
124
97
|
);
|
|
125
98
|
|
|
126
|
-
const runtime =
|
|
99
|
+
const runtime = useLangGraphRuntime({
|
|
127
100
|
cloud,
|
|
128
|
-
|
|
101
|
+
stream: async function* (messages, { initialize }) {
|
|
102
|
+
const { externalId } = await initialize();
|
|
103
|
+
if (!externalId) throw new Error("Thread not found");
|
|
104
|
+
|
|
105
|
+
return sendMessage({
|
|
106
|
+
threadId: externalId,
|
|
107
|
+
messages,
|
|
108
|
+
});
|
|
109
|
+
},
|
|
129
110
|
create: async () => {
|
|
130
111
|
const { thread_id } = await createThread();
|
|
131
112
|
return { externalId: thread_id };
|
|
132
113
|
},
|
|
114
|
+
load: async (externalId) => {
|
|
115
|
+
const state = await getThreadState(externalId);
|
|
116
|
+
return {
|
|
117
|
+
messages:
|
|
118
|
+
(state.values as { messages?: LangChainMessage[] }).messages ?? [],
|
|
119
|
+
};
|
|
120
|
+
},
|
|
133
121
|
});
|
|
134
122
|
|
|
135
123
|
return (
|
|
@@ -150,8 +138,6 @@ export function MyRuntimeProvider({
|
|
|
150
138
|
import {
|
|
151
139
|
AssistantCloud,
|
|
152
140
|
AssistantRuntimeProvider,
|
|
153
|
-
useCloudThreadListRuntime,
|
|
154
|
-
useThreadListItemRuntime,
|
|
155
141
|
} from "@assistant-ui/react";
|
|
156
142
|
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
|
|
157
143
|
import { createThread, getThreadState, sendMessage } from "@/lib/chatApi";
|
|
@@ -159,32 +145,6 @@ import { LangChainMessage } from "@assistant-ui/react-langgraph";
|
|
|
159
145
|
import { useAuth } from "@clerk/nextjs";
|
|
160
146
|
import { useMemo } from "react";
|
|
161
147
|
|
|
162
|
-
const useMyLangGraphRuntime = () => {
|
|
163
|
-
const threadListItemRuntime = useThreadListItemRuntime();
|
|
164
|
-
|
|
165
|
-
const runtime = useLangGraphRuntime({
|
|
166
|
-
stream: async function* (messages) {
|
|
167
|
-
const { externalId } = await threadListItemRuntime.initialize();
|
|
168
|
-
if (!externalId) throw new Error("Thread not found");
|
|
169
|
-
|
|
170
|
-
return sendMessage({
|
|
171
|
-
threadId: externalId,
|
|
172
|
-
messages,
|
|
173
|
-
});
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
onSwitchToThread: async (externalId) => {
|
|
177
|
-
const state = await getThreadState(externalId);
|
|
178
|
-
return {
|
|
179
|
-
messages:
|
|
180
|
-
(state.values as { messages?: LangChainMessage[] }).messages ?? []
|
|
181
|
-
};
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
return runtime;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
148
|
export function MyRuntimeProvider({
|
|
189
149
|
children,
|
|
190
150
|
}: Readonly<{
|
|
@@ -201,13 +161,28 @@ export function MyRuntimeProvider({
|
|
|
201
161
|
[getToken],
|
|
202
162
|
);
|
|
203
163
|
|
|
204
|
-
const runtime =
|
|
164
|
+
const runtime = useLangGraphRuntime({
|
|
205
165
|
cloud,
|
|
206
|
-
|
|
166
|
+
stream: async function* (messages, { initialize }) {
|
|
167
|
+
const { externalId } = await initialize();
|
|
168
|
+
if (!externalId) throw new Error("Thread not found");
|
|
169
|
+
|
|
170
|
+
return sendMessage({
|
|
171
|
+
threadId: externalId,
|
|
172
|
+
messages,
|
|
173
|
+
});
|
|
174
|
+
},
|
|
207
175
|
create: async () => {
|
|
208
176
|
const { thread_id } = await createThread();
|
|
209
177
|
return { externalId: thread_id };
|
|
210
178
|
},
|
|
179
|
+
load: async (externalId) => {
|
|
180
|
+
const state = await getThreadState(externalId);
|
|
181
|
+
return {
|
|
182
|
+
messages:
|
|
183
|
+
(state.values as { messages?: LangChainMessage[] }).messages ?? [],
|
|
184
|
+
};
|
|
185
|
+
},
|
|
211
186
|
});
|
|
212
187
|
|
|
213
188
|
return (
|
|
@@ -219,7 +194,8 @@ export function MyRuntimeProvider({
|
|
|
219
194
|
```
|
|
220
195
|
|
|
221
196
|
<Callout type="info">
|
|
222
|
-
For Clerk authentication, configure the `"assistant-ui"` token template in
|
|
197
|
+
For Clerk authentication, configure the `"assistant-ui"` token template in
|
|
198
|
+
your Clerk dashboard.
|
|
223
199
|
</Callout>
|
|
224
200
|
|
|
225
201
|
</Tab>
|
|
@@ -227,7 +203,7 @@ export function MyRuntimeProvider({
|
|
|
227
203
|
</Tabs>
|
|
228
204
|
|
|
229
205
|
<Callout type="info">
|
|
230
|
-
The `
|
|
206
|
+
The `useLangGraphRuntime` hook now directly accepts `cloud`, `create`, and `load` parameters for simplified thread management. The runtime handles thread lifecycle internally.
|
|
231
207
|
</Callout>
|
|
232
208
|
|
|
233
209
|
</Step>
|
|
@@ -74,7 +74,7 @@ function ParentComponent() {
|
|
|
74
74
|
|
|
75
75
|
return (
|
|
76
76
|
<div>
|
|
77
|
-
<Thread /> {/* Your assistant
|
|
77
|
+
<Thread /> {/* Your assistant-ui */}
|
|
78
78
|
<iframe
|
|
79
79
|
ref={iframeRef}
|
|
80
80
|
src="https://trusted-iframe-domain.com/embed"
|
|
@@ -98,10 +98,10 @@ const registry = new ModelContextRegistry();
|
|
|
98
98
|
const toolHandle = registry.addTool({
|
|
99
99
|
toolName: "convertCurrency",
|
|
100
100
|
description: "Convert between currencies",
|
|
101
|
-
parameters: z.object({
|
|
101
|
+
parameters: z.object({
|
|
102
102
|
amount: z.number(),
|
|
103
103
|
from: z.string(),
|
|
104
|
-
to: z.string()
|
|
104
|
+
to: z.string(),
|
|
105
105
|
}),
|
|
106
106
|
execute: async ({ amount, from, to }) => {
|
|
107
107
|
const rate = await fetchExchangeRate(from, to);
|
|
@@ -113,19 +113,19 @@ const toolHandle = registry.addTool({
|
|
|
113
113
|
toolHandle.update({
|
|
114
114
|
toolName: "convertCurrency",
|
|
115
115
|
description: "Convert between currencies with live rates", // Updated description
|
|
116
|
-
parameters: z.object({
|
|
116
|
+
parameters: z.object({
|
|
117
117
|
amount: z.number(),
|
|
118
118
|
from: z.string(),
|
|
119
119
|
to: z.string(),
|
|
120
|
-
includesFees: z.boolean().optional()
|
|
120
|
+
includesFees: z.boolean().optional(),
|
|
121
121
|
}),
|
|
122
122
|
execute: async ({ amount, from, to, includesFees }) => {
|
|
123
123
|
const rate = await fetchExchangeRate(from, to);
|
|
124
124
|
const fee = includesFees ? 0.02 : 0; // 2% fee
|
|
125
|
-
return {
|
|
126
|
-
result: amount * rate * (1 - fee),
|
|
125
|
+
return {
|
|
126
|
+
result: amount * rate * (1 - fee),
|
|
127
127
|
currency: to,
|
|
128
|
-
fee: includesFees ? amount * rate * fee : 0
|
|
128
|
+
fee: includesFees ? amount * rate * fee : 0,
|
|
129
129
|
};
|
|
130
130
|
},
|
|
131
131
|
});
|
|
@@ -377,20 +377,22 @@ Provide data visualization tools in an iframe:
|
|
|
377
377
|
registry.addTool({
|
|
378
378
|
toolName: "createChart",
|
|
379
379
|
description: "Generate a chart from data",
|
|
380
|
-
parameters: z.object({
|
|
381
|
-
data: z.array(
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
parameters: z.object({
|
|
381
|
+
data: z.array(
|
|
382
|
+
z.object({
|
|
383
|
+
label: z.string(),
|
|
384
|
+
value: z.number(),
|
|
385
|
+
}),
|
|
386
|
+
),
|
|
385
387
|
chartType: z.enum(["bar", "line", "pie"]),
|
|
386
|
-
title: z.string().optional()
|
|
388
|
+
title: z.string().optional(),
|
|
387
389
|
}),
|
|
388
390
|
execute: async ({ data, chartType, title }) => {
|
|
389
391
|
// Generate chart using a library like Chart.js or D3
|
|
390
392
|
const chartUrl = await generateChart(data, chartType, title);
|
|
391
|
-
return {
|
|
393
|
+
return {
|
|
392
394
|
chartUrl,
|
|
393
|
-
summary: `Created ${chartType} chart with ${data.length} data points
|
|
395
|
+
summary: `Created ${chartType} chart with ${data.length} data points`,
|
|
394
396
|
};
|
|
395
397
|
},
|
|
396
398
|
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: DevTools
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
import { Step, Steps } from "fumadocs-ui/components/steps";
|
|
6
|
+
|
|
7
|
+
Hey, the assistant-ui DevTools allows you to debug the assistant-ui state and context, and events without resorting to `console.log`. It's an easy way to see how data flows to the assistant-ui's runtime layer.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
<Steps>
|
|
14
|
+
<Step>
|
|
15
|
+
|
|
16
|
+
### Install the DevTools package
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @assistant-ui/react-devtools
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
</Step>
|
|
23
|
+
<Step>
|
|
24
|
+
|
|
25
|
+
### Mount the DevTools modal
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
29
|
+
import { DevToolsModal } from "@assistant-ui/react-devtools";
|
|
30
|
+
|
|
31
|
+
export function AssistantApp() {
|
|
32
|
+
return (
|
|
33
|
+
<AssistantRuntimeProvider>
|
|
34
|
+
<DevToolsModal />
|
|
35
|
+
{/* ...your assistant-ui... */}
|
|
36
|
+
</AssistantRuntimeProvider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
</Step>
|
|
42
|
+
<Step>
|
|
43
|
+
|
|
44
|
+
### Verify the DevTools overlay
|
|
45
|
+
|
|
46
|
+
That's it! In development builds you should now see the DevTools in the lower-right corner of your site.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
</Step>
|
|
51
|
+
</Steps>
|
|
@@ -283,8 +283,7 @@ const ThreadWelcomeSuggestions: FC = () => {
|
|
|
283
283
|
<ThreadPrimitive.Suggestion
|
|
284
284
|
className="aui-thread-welcome-suggestion"
|
|
285
285
|
prompt="What is the weather in Tokyo?"
|
|
286
|
-
|
|
287
|
-
autoSend
|
|
286
|
+
send
|
|
288
287
|
>
|
|
289
288
|
<span className="aui-thread-welcome-suggestion-text">
|
|
290
289
|
What is the weather in Tokyo?
|
|
@@ -293,8 +292,7 @@ const ThreadWelcomeSuggestions: FC = () => {
|
|
|
293
292
|
<ThreadPrimitive.Suggestion
|
|
294
293
|
className="aui-thread-welcome-suggestion"
|
|
295
294
|
prompt="What is assistant-ui?"
|
|
296
|
-
|
|
297
|
-
autoSend
|
|
295
|
+
send
|
|
298
296
|
>
|
|
299
297
|
<span className="aui-thread-welcome-suggestion-text">
|
|
300
298
|
What is assistant-ui?
|
|
@@ -378,17 +378,42 @@ const DatePickerToolUI = makeAssistantToolUI<
|
|
|
378
378
|
|
|
379
379
|
### Multi-Step Interactions
|
|
380
380
|
|
|
381
|
-
Build complex workflows with
|
|
381
|
+
Build complex workflows with human-in-the-loop patterns for multi-step user interactions:
|
|
382
382
|
|
|
383
383
|
```tsx
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
{
|
|
387
|
-
|
|
384
|
+
const DeleteProjectTool = makeAssistantTool({
|
|
385
|
+
toolName: "deleteProject",
|
|
386
|
+
execute: async ({ projectId }, { human }) => {
|
|
387
|
+
const response = await human({ action, details });
|
|
388
|
+
if (!response.approved) throw new Error("Project deletion cancelled");
|
|
389
|
+
|
|
390
|
+
await deleteProject(projectId);
|
|
391
|
+
return { success: true };
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const ApprovalTool = makeAssistantTool({
|
|
396
|
+
...tool({
|
|
397
|
+
description: "Request user approval for an action",
|
|
398
|
+
parameters: z.object({
|
|
399
|
+
action: z.string(),
|
|
400
|
+
details: z.any(),
|
|
401
|
+
}),
|
|
402
|
+
execute: async ({ action, details }, { human }) => {
|
|
403
|
+
// Request approval from user
|
|
404
|
+
const response = await human({ action, details });
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
approved: response.approved,
|
|
408
|
+
reason: response.reason,
|
|
409
|
+
};
|
|
410
|
+
},
|
|
411
|
+
}),
|
|
388
412
|
toolName: "requestApproval",
|
|
389
|
-
render: ({ args, result,
|
|
413
|
+
render: ({ args, result, interrupt, resume }) => {
|
|
390
414
|
const [reason, setReason] = useState("");
|
|
391
415
|
|
|
416
|
+
// Show result after approval/rejection
|
|
392
417
|
if (result) {
|
|
393
418
|
return (
|
|
394
419
|
<div className={result.approved ? "text-green-600" : "text-red-600"}>
|
|
@@ -397,41 +422,53 @@ const ApprovalToolUI = makeAssistantToolUI<
|
|
|
397
422
|
);
|
|
398
423
|
}
|
|
399
424
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
<
|
|
404
|
-
|
|
405
|
-
{
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
425
|
+
// Show approval UI when waiting for user input
|
|
426
|
+
if (interrupt) {
|
|
427
|
+
return (
|
|
428
|
+
<div className="rounded border-2 border-yellow-400 p-4">
|
|
429
|
+
<h4 className="font-bold">Approval Required</h4>
|
|
430
|
+
<p className="my-2">{interrupt.payload.action}</p>
|
|
431
|
+
<pre className="rounded bg-gray-100 p-2 text-sm">
|
|
432
|
+
{JSON.stringify(interrupt.payload.details, null, 2)}
|
|
433
|
+
</pre>
|
|
434
|
+
|
|
435
|
+
<div className="mt-4 flex gap-2">
|
|
436
|
+
<button
|
|
437
|
+
onClick={() => resume({ approved: true })}
|
|
438
|
+
className="rounded bg-green-500 px-4 py-2 text-white"
|
|
439
|
+
>
|
|
440
|
+
Approve
|
|
441
|
+
</button>
|
|
442
|
+
<button
|
|
443
|
+
onClick={() => resume({ approved: false, reason })}
|
|
444
|
+
className="rounded bg-red-500 px-4 py-2 text-white"
|
|
445
|
+
>
|
|
446
|
+
Reject
|
|
447
|
+
</button>
|
|
448
|
+
<input
|
|
449
|
+
type="text"
|
|
450
|
+
placeholder="Rejection reason..."
|
|
451
|
+
value={reason}
|
|
452
|
+
onChange={(e) => setReason(e.target.value)}
|
|
453
|
+
className="flex-1 rounded border px-2"
|
|
454
|
+
/>
|
|
455
|
+
</div>
|
|
428
456
|
</div>
|
|
429
|
-
|
|
430
|
-
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return <div>Processing...</div>;
|
|
431
461
|
},
|
|
432
462
|
});
|
|
433
463
|
```
|
|
434
464
|
|
|
465
|
+
<Callout type="tip">
|
|
466
|
+
Use tool human input (`human()` / `resume()`) for workflows that need to
|
|
467
|
+
pause tool execution and wait for user input. Use `addResult()` for "human
|
|
468
|
+
tools" where the AI requests a tool call but the entire execution happens
|
|
469
|
+
through user interaction.
|
|
470
|
+
</Callout>
|
|
471
|
+
|
|
435
472
|
## Advanced Features
|
|
436
473
|
|
|
437
474
|
### Tool Status Handling
|
|
@@ -589,14 +626,52 @@ type ToolUIRenderProps<TArgs, TResult> = {
|
|
|
589
626
|
toolName: string;
|
|
590
627
|
toolCallId: string;
|
|
591
628
|
|
|
592
|
-
// Interactive
|
|
629
|
+
// Interactive callbacks
|
|
593
630
|
addResult: (result: TResult) => void;
|
|
631
|
+
resume: (payload: unknown) => void;
|
|
632
|
+
|
|
633
|
+
// Interrupt state
|
|
634
|
+
interrupt?: { type: "human"; payload: unknown }; // Payload from context.human()
|
|
594
635
|
|
|
595
636
|
// Optional artifact data
|
|
596
637
|
artifact?: unknown;
|
|
597
638
|
};
|
|
598
639
|
```
|
|
599
640
|
|
|
641
|
+
### Human Input Handling
|
|
642
|
+
|
|
643
|
+
When a tool calls `human()` during execution, the payload becomes available in the render function as `interrupt.payload`:
|
|
644
|
+
|
|
645
|
+
```tsx
|
|
646
|
+
const ConfirmationToolUI = makeAssistantToolUI<
|
|
647
|
+
{ action: string },
|
|
648
|
+
{ confirmed: boolean }
|
|
649
|
+
>({
|
|
650
|
+
toolName: "confirmAction",
|
|
651
|
+
render: ({ args, result, interrupt, resume }) => {
|
|
652
|
+
// Tool is waiting for user input
|
|
653
|
+
if (interrupt) {
|
|
654
|
+
return (
|
|
655
|
+
<div className="confirmation-dialog">
|
|
656
|
+
<p>Confirm: {interrupt.payload.message}</p>
|
|
657
|
+
<button onClick={() => resume(true)}>Yes</button>
|
|
658
|
+
<button onClick={() => resume(false)}>No</button>
|
|
659
|
+
</div>
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// Tool completed
|
|
664
|
+
if (result) {
|
|
665
|
+
return <div>Action {result.confirmed ? "confirmed" : "cancelled"}</div>;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return <div>Processing...</div>;
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Learn more about tool human input in the [Tools Guide](/docs/guides/Tools#tool-human-input).
|
|
674
|
+
|
|
600
675
|
## Best Practices
|
|
601
676
|
|
|
602
677
|
### 1. Handle All Status States
|