@assistant-ui/mcp-docs-server 0.1.32 → 0.1.34

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.
Files changed (134) hide show
  1. package/.docs/organized/code-examples/waterfall.md +20 -22
  2. package/.docs/organized/code-examples/with-a2a.md +24 -24
  3. package/.docs/organized/code-examples/with-ag-ui.md +30 -25
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +11 -9
  5. package/.docs/organized/code-examples/with-artifacts.md +49 -37
  6. package/.docs/organized/code-examples/with-assistant-transport.md +63 -51
  7. package/.docs/organized/code-examples/with-browser-extension.md +22 -10
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +406 -87
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +25 -24
  10. package/.docs/organized/code-examples/with-cloud.md +11 -9
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +14 -12
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +23 -21
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +14 -13
  14. package/.docs/organized/code-examples/with-expo.md +44 -29
  15. package/.docs/organized/code-examples/with-external-store.md +9 -7
  16. package/.docs/organized/code-examples/with-ffmpeg.md +322 -285
  17. package/.docs/organized/code-examples/with-generative-ui.md +1066 -256
  18. package/.docs/organized/code-examples/with-google-adk.md +10 -8
  19. package/.docs/organized/code-examples/with-heat-graph.md +13 -11
  20. package/.docs/organized/code-examples/with-image-generation.md +19 -17
  21. package/.docs/organized/code-examples/with-interactables.md +317 -239
  22. package/.docs/organized/code-examples/with-langchain.md +14 -12
  23. package/.docs/organized/code-examples/with-langgraph.md +91 -83
  24. package/.docs/organized/code-examples/with-livekit.md +24 -22
  25. package/.docs/organized/code-examples/with-mcp.md +18 -12
  26. package/.docs/organized/code-examples/with-opencode.md +66 -66
  27. package/.docs/organized/code-examples/with-react-hook-form.md +19 -17
  28. package/.docs/organized/code-examples/with-react-ink.md +297 -102
  29. package/.docs/organized/code-examples/with-react-router.md +17 -15
  30. package/.docs/organized/code-examples/with-resumable-stream.md +15 -14
  31. package/.docs/organized/code-examples/with-store.md +78 -76
  32. package/.docs/organized/code-examples/with-tanstack.md +13 -14
  33. package/.docs/organized/code-examples/with-tap-runtime.md +26 -24
  34. package/.docs/raw/docs/(docs)/architecture.mdx +94 -42
  35. package/.docs/raw/docs/(docs)/cli.mdx +1 -2
  36. package/.docs/raw/docs/(docs)/installation.mdx +1 -1
  37. package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +5 -1
  38. package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +15 -15
  39. package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +14 -1
  40. package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +18 -0
  41. package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +33 -0
  42. package/.docs/raw/docs/(reference)/api-reference/generative-ui/spec.mdx +45 -0
  43. package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +41 -41
  44. package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +19 -1
  45. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +122 -122
  46. package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +43 -2
  47. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +6 -0
  48. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +4 -6
  49. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +30 -0
  50. package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +20 -3
  51. package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +8 -8
  52. package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +52 -4
  53. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +100 -10
  54. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +7 -59
  55. package/.docs/raw/docs/cloud/ai-sdk.mdx +0 -2
  56. package/.docs/raw/docs/{(docs)/copilots → copilots}/model-context.mdx +34 -26
  57. package/.docs/raw/docs/{(docs)/copilots → copilots}/motivation.mdx +32 -26
  58. package/.docs/raw/docs/guides/chain-of-thought.mdx +7 -9
  59. package/.docs/raw/docs/guides/context-api.mdx +2 -1
  60. package/.docs/raw/docs/guides/index.mdx +3 -12
  61. package/.docs/raw/docs/guides/mentions.mdx +4 -4
  62. package/.docs/raw/docs/guides/slash-commands.mdx +1 -1
  63. package/.docs/raw/docs/guides/suggestions.mdx +1 -1
  64. package/.docs/raw/docs/ink/adapters.mdx +23 -1
  65. package/.docs/raw/docs/ink/hooks.mdx +101 -85
  66. package/.docs/raw/docs/ink/migration.mdx +1 -1
  67. package/.docs/raw/docs/ink/primitives.mdx +2 -2
  68. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +1 -1
  69. package/.docs/raw/docs/integrations/index.mdx +2 -2
  70. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +17 -2
  71. package/.docs/raw/docs/migrations/toolkit-tools.mdx +232 -0
  72. package/.docs/raw/docs/primitives/chain-of-thought.mdx +10 -16
  73. package/.docs/raw/docs/primitives/message.mdx +9 -10
  74. package/.docs/raw/docs/react-native/hooks.mdx +62 -79
  75. package/.docs/raw/docs/react-native/migration.mdx +1 -1
  76. package/.docs/raw/docs/react-native/primitives.mdx +2 -2
  77. package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +3 -0
  78. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +41 -0
  79. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +122 -1
  80. package/.docs/raw/docs/runtimes/concepts/architecture.mdx +46 -4
  81. package/.docs/raw/docs/runtimes/concepts/threads.mdx +7 -1
  82. package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +54 -12
  83. package/.docs/raw/docs/runtimes/custom/external-store.mdx +62 -4
  84. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +30 -7
  85. package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +108 -38
  86. package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +2 -2
  87. package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +14 -1
  88. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +64 -50
  89. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +98 -86
  90. package/.docs/raw/docs/tools/backend.mdx +144 -0
  91. package/.docs/raw/docs/tools/defining-tools.mdx +538 -0
  92. package/.docs/raw/docs/tools/dynamic-tools.mdx +110 -0
  93. package/.docs/raw/docs/tools/generative-ui.mdx +214 -0
  94. package/.docs/raw/docs/tools/index.mdx +71 -0
  95. package/.docs/raw/docs/{guides → tools}/interactables.mdx +1 -1
  96. package/.docs/raw/docs/{integrations/tools → tools}/mcp.mdx +145 -50
  97. package/.docs/raw/docs/{guides → tools}/multi-agent.mdx +15 -17
  98. package/.docs/raw/docs/tools/tool-ui.mdx +967 -0
  99. package/.docs/raw/docs/{integrations/tools/react-mcp.mdx → tools/user-managed-mcp.mdx} +7 -7
  100. package/.docs/raw/docs/ui/directive-text.mdx +3 -3
  101. package/.docs/raw/docs/ui/mcp-config.mdx +4 -4
  102. package/.docs/raw/docs/ui/mermaid.mdx +16 -9
  103. package/.docs/raw/docs/ui/part-grouping.mdx +84 -50
  104. package/.docs/raw/docs/ui/reasoning.mdx +4 -5
  105. package/.docs/raw/docs/ui/tool-fallback.mdx +16 -0
  106. package/.docs/raw/docs/ui/tool-group.mdx +5 -6
  107. package/.docs/raw/docs/utilities/heat-graph.mdx +1 -1
  108. package/.docs/raw/docs/utilities/react-o11y.mdx +2 -2
  109. package/dist/constants.js.map +1 -1
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js.map +1 -1
  112. package/dist/prepare-docs/code-examples.d.ts.map +1 -1
  113. package/dist/prepare-docs/code-examples.js.map +1 -1
  114. package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
  115. package/dist/prepare-docs/copy-raw.js.map +1 -1
  116. package/dist/prepare-docs/prepare.js.map +1 -1
  117. package/dist/stdio.js.map +1 -1
  118. package/dist/tools/docs.js.map +1 -1
  119. package/dist/tools/examples.js.map +1 -1
  120. package/dist/tools/tests/test-setup.js.map +1 -1
  121. package/dist/utils/mdx.js.map +1 -1
  122. package/dist/utils/paths.d.ts.map +1 -1
  123. package/dist/utils/paths.js.map +1 -1
  124. package/package.json +5 -5
  125. package/.docs/organized/code-examples/with-parent-id-grouping.md +0 -596
  126. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -151
  127. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -230
  128. package/.docs/raw/docs/guides/generative-ui.mdx +0 -142
  129. package/.docs/raw/docs/guides/tool-ui.mdx +0 -858
  130. package/.docs/raw/docs/guides/tools.mdx +0 -736
  131. /package/.docs/raw/docs/{(docs)/copilots → copilots}/assistant-frame.mdx +0 -0
  132. /package/.docs/raw/docs/{(docs)/copilots → copilots}/make-assistant-visible.mdx +0 -0
  133. /package/.docs/raw/docs/{(docs)/copilots → copilots}/use-assistant-instructions.mdx +0 -0
  134. /package/.docs/raw/docs/{guides → tools}/mcp-apps.mdx +0 -0
@@ -16,13 +16,13 @@
16
16
  "dependencies": {
17
17
  "@assistant-ui/react-ink": "workspace:*",
18
18
  "@assistant-ui/react-ink-markdown": "workspace:*",
19
- "ink": "^7.0.3",
20
- "react": "^19.2.6"
19
+ "ink": "^7.0.5",
20
+ "react": "^19.2.7"
21
21
  },
22
22
  "devDependencies": {
23
- "@types/react": "^19.2.15",
23
+ "@types/react": "^19.2.17",
24
24
  "esbuild": "^0.28.0",
25
- "tsx": "^4.22.3",
25
+ "tsx": "^4.22.4",
26
26
  "typescript": "^6.0.3"
27
27
  }
28
28
  }
@@ -37,74 +37,36 @@ import { Box, Text } from "ink";
37
37
  import {
38
38
  AssistantRuntimeProvider,
39
39
  useLocalRuntime,
40
- type ChatModelAdapter,
40
+ StatusBarPrimitive,
41
41
  } from "@assistant-ui/react-ink";
42
42
  import { Thread } from "./components/thread.js";
43
-
44
- const createDemoAdapter = (): ChatModelAdapter => ({
45
- async *run({ messages }) {
46
- const lastUserMessage = messages.filter((m) => m.role === "user").at(-1);
47
-
48
- const userText =
49
- lastUserMessage?.content
50
- .filter((p) => p.type === "text")
51
- .map((p) => ("text" in p ? p.text : ""))
52
- .join("") ?? "";
53
-
54
- // Simulate streaming with a markdown-rich response
55
- const response = `## Response to your question
56
-
57
- You asked: **"${userText}"**
58
-
59
- Here's a quick example in JavaScript:
60
-
61
- \`\`\`js
62
- const promise = new Promise((resolve, reject) => {
63
- setTimeout(() => resolve("done!"), 1000);
64
- });
65
-
66
- promise.then(result => console.log(result));
67
- \`\`\`
68
-
69
- ### Key points
70
-
71
- - A \`Promise\` represents an **async operation**
72
- - It can be *pending*, *fulfilled*, or *rejected*
73
- - Use \`.then()\` and \`.catch()\` to handle results
74
-
75
- > Promises are the foundation of modern async JavaScript.
76
-
77
- | Method | Purpose |
78
- |--------|---------|
79
- | \`.then()\` | Handle success |
80
- | \`.catch()\` | Handle errors |
81
- | \`.finally()\` | Run cleanup |
82
-
83
- Learn more at [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).`;
84
- const words = response.split(" ");
85
-
86
- let accumulated = "";
87
- for (const word of words) {
88
- accumulated += (accumulated ? " " : "") + word;
89
- yield { content: [{ type: "text" as const, text: accumulated }] };
90
- await new Promise((r) => setTimeout(r, 50));
91
- }
92
- },
93
- });
43
+ import { createScriptedAdapter, MODEL_NAME } from "./scripted-adapter.js";
44
+ import { ApplyPatchToolUI } from "./tools.js";
45
+
46
+ const StatusBar = () => (
47
+ <StatusBarPrimitive.Root>
48
+ <Text dimColor>
49
+ model: <StatusBarPrimitive.ModelName name={MODEL_NAME} /> ·{" "}
50
+ <StatusBarPrimitive.MessageCount /> · <StatusBarPrimitive.Status />
51
+ </Text>
52
+ </StatusBarPrimitive.Root>
53
+ );
94
54
 
95
55
  export const App = () => {
96
- const adapter = useMemo(() => createDemoAdapter(), []);
56
+ const adapter = useMemo(() => createScriptedAdapter(), []);
97
57
  const runtime = useLocalRuntime(adapter);
98
58
 
99
59
  return (
100
60
  <AssistantRuntimeProvider runtime={runtime}>
61
+ <ApplyPatchToolUI />
101
62
  <Box flexDirection="column" padding={1}>
102
- <Text bold color="cyan">
103
- assistant-ui Terminal Chat
104
- </Text>
105
- <Text dimColor>
106
- Type a message and press Enter to send. Ctrl+C to exit.
107
- </Text>
63
+ <Box>
64
+ <Text bold color="cyan">
65
+ demo-agent
66
+ </Text>
67
+ <Text dimColor>{" ~/acme-app"}</Text>
68
+ </Box>
69
+ <StatusBar />
108
70
  <Box marginTop={1}>
109
71
  <Thread />
110
72
  </Box>
@@ -122,62 +84,68 @@ import { Box, Text } from "ink";
122
84
  import {
123
85
  ThreadPrimitive,
124
86
  ComposerPrimitive,
125
- useAuiState,
87
+ MessagePrimitive,
88
+ ErrorPrimitive,
89
+ LoadingPrimitive,
90
+ LiveChecklist,
126
91
  } from "@assistant-ui/react-ink";
127
92
  import { MarkdownText } from "@assistant-ui/react-ink-markdown";
128
93
 
129
- const UserMessage = () => {
130
- const text = useAuiState((s) =>
131
- s.message.parts
132
- .filter((p) => p.type === "text")
133
- .map((p) => ("text" in p ? p.text : ""))
134
- .join(""),
135
- );
136
-
137
- return (
94
+ const UserMessage = () => (
95
+ <MessagePrimitive.Root>
138
96
  <Box marginBottom={1}>
139
97
  <Text bold color="green">
140
98
  You:{" "}
141
99
  </Text>
142
- <Text wrap="wrap">{text}</Text>
100
+ <MessagePrimitive.Content
101
+ renderText={({ part }) => <Text wrap="wrap">{part.text}</Text>}
102
+ />
143
103
  </Box>
144
- );
145
- };
104
+ </MessagePrimitive.Root>
105
+ );
146
106
 
147
- const AssistantMessage = () => {
148
- const text = useAuiState((s) =>
149
- s.message.parts
150
- .filter((p) => p.type === "text")
151
- .map((p) => ("text" in p ? p.text : ""))
152
- .join(""),
153
- );
154
-
155
- return (
107
+ const AssistantMessage = () => (
108
+ <MessagePrimitive.Root>
156
109
  <Box flexDirection="column" marginBottom={1}>
157
110
  <Text bold color="blue">
158
111
  AI:
159
112
  </Text>
160
- <MarkdownText text={text} />
113
+ <MessagePrimitive.Content
114
+ renderText={({ part }) => <MarkdownText text={part.text} />}
115
+ renderReasoning={({ part }) => (
116
+ <Text dimColor italic>
117
+ {part.text}
118
+ </Text>
119
+ )}
120
+ />
121
+ <LiveChecklist title="Plan" showProgress marginTop={1} />
122
+ <ErrorPrimitive.Root>
123
+ <ErrorPrimitive.Message />
124
+ </ErrorPrimitive.Root>
161
125
  </Box>
162
- );
163
- };
164
-
165
- const StatusIndicator = () => {
166
- const isRunning = useAuiState((s) => s.thread.isRunning);
167
- if (!isRunning) return null;
168
- return (
169
- <Box marginBottom={1}>
170
- <Text color="yellow">Thinking...</Text>
171
- </Box>
172
- );
173
- };
126
+ </MessagePrimitive.Root>
127
+ );
128
+
129
+ const Loading = () => (
130
+ <LoadingPrimitive.Root marginBottom={1}>
131
+ <LoadingPrimitive.Spinner />
132
+ <Text> </Text>
133
+ <LoadingPrimitive.Text>Working</LoadingPrimitive.Text>
134
+ <Text> </Text>
135
+ <LoadingPrimitive.ElapsedTime />
136
+ </LoadingPrimitive.Root>
137
+ );
174
138
 
175
139
  export const Thread = () => {
176
140
  return (
177
141
  <ThreadPrimitive.Root>
178
142
  <ThreadPrimitive.Empty>
179
- <Box marginBottom={1}>
180
- <Text dimColor>No messages yet. Start typing below!</Text>
143
+ <Box flexDirection="column" marginBottom={1}>
144
+ <Text>
145
+ Working in this project. <Text color="yellow">fetchUser()</Text> is
146
+ flaky in prod and has no retry logic.
147
+ </Text>
148
+ <Text dimColor>{' try: "make fetchUser retry on failure"'}</Text>
181
149
  </Box>
182
150
  </ThreadPrimitive.Empty>
183
151
 
@@ -187,13 +155,14 @@ export const Thread = () => {
187
155
  }
188
156
  </ThreadPrimitive.Messages>
189
157
 
190
- <StatusIndicator />
158
+ <Loading />
191
159
 
192
160
  <Box borderStyle="round" borderColor="gray" paddingX={1}>
193
161
  <Text color="gray">{"> "}</Text>
194
162
  <ComposerPrimitive.Input
195
163
  submitOnEnter
196
- placeholder="Type a message..."
164
+ multiLine
165
+ placeholder="Type a message... (Enter to send)"
197
166
  autoFocus
198
167
  />
199
168
  </Box>
@@ -242,6 +211,232 @@ render(<App />);
242
211
 
243
212
  ```
244
213
 
214
+ ## src/scripted-adapter.ts
215
+
216
+ ```typescript
217
+ import type {
218
+ ChatModelAdapter,
219
+ ThreadAssistantMessagePart,
220
+ } from "@assistant-ui/react-ink";
221
+
222
+ export const MODEL_NAME = "demo-agent";
223
+
224
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
225
+
226
+ const RETRY_PATCH = `--- a/src/retry.ts
227
+ +++ b/src/retry.ts
228
+ @@ -1,6 +1,18 @@
229
+ export async function fetchUser(id: string) {
230
+ - const res = await fetch(\`/api/users/\${id}\`);
231
+ - return res.json();
232
+ + return retry(() => fetch(\`/api/users/\${id}\`).then((r) => r.json()));
233
+ +}
234
+ +
235
+ +export async function retry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
236
+ + let lastError: unknown;
237
+ + for (let i = 0; i <= attempts; i++) {
238
+ + try {
239
+ + return await fn();
240
+ + } catch (err) {
241
+ + lastError = err;
242
+ + await new Promise((r) => setTimeout(r, 2 ** i * 100));
243
+ + }
244
+ + }
245
+ + throw lastError;
246
+ }
247
+ `;
248
+
249
+ const RETRY_PATCH_FIX = `--- a/src/retry.ts
250
+ +++ b/src/retry.ts
251
+ @@ -6,7 +6,7 @@ export async function retry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
252
+ let lastError: unknown;
253
+ - for (let i = 0; i <= attempts; i++) {
254
+ + for (let i = 0; i < attempts; i++) {
255
+ try {
256
+ return await fn();
257
+ } catch (err) {
258
+ `;
259
+
260
+ const isTaskRequest = (text: string) =>
261
+ /fetch|retry|resilient|flaky|backoff|robust|network|\byes\b|sure|\bok\b|go ahead|do it|please/i.test(
262
+ text,
263
+ );
264
+
265
+ const lastUserText = (
266
+ messages: readonly { role: string; content: readonly { type: string }[] }[],
267
+ ) => {
268
+ const last = messages.filter((m) => m.role === "user").at(-1);
269
+ return (
270
+ last?.content
271
+ .filter((p): p is { type: "text"; text: string } => p.type === "text")
272
+ .map((p) => p.text)
273
+ .join("") ?? ""
274
+ );
275
+ };
276
+
277
+ async function* streamText(
278
+ parts: ThreadAssistantMessagePart[],
279
+ index: number,
280
+ text: string,
281
+ delay: number,
282
+ ): AsyncGenerator<{ content: ThreadAssistantMessagePart[] }> {
283
+ for (const word of text.split(" ")) {
284
+ const p = parts[index] as Extract<
285
+ ThreadAssistantMessagePart,
286
+ { type: "text" | "reasoning" }
287
+ >;
288
+ parts[index] = { ...p, text: p.text ? `${p.text} ${word}` : word };
289
+ yield { content: [...parts] };
290
+ await sleep(delay);
291
+ }
292
+ }
293
+
294
+ async function* runAgentScript(): AsyncGenerator<{
295
+ content: ThreadAssistantMessagePart[];
296
+ }> {
297
+ const parts: ThreadAssistantMessagePart[] = [];
298
+ const emit = () => ({ content: [...parts] });
299
+ const setResult = (result: unknown, isError = false) => {
300
+ parts[parts.length - 1] = {
301
+ ...parts[parts.length - 1],
302
+ result,
303
+ ...(isError ? { isError: true } : {}),
304
+ } as ThreadAssistantMessagePart;
305
+ };
306
+ const pushToolCall = (
307
+ toolCallId: string,
308
+ toolName: string,
309
+ args: Record<string, string>,
310
+ ) =>
311
+ parts.push({
312
+ type: "tool-call",
313
+ toolCallId,
314
+ toolName,
315
+ args,
316
+ argsText: JSON.stringify(args),
317
+ });
318
+
319
+ const reasoningIdx = parts.push({ type: "reasoning", text: "" }) - 1;
320
+ yield* streamText(
321
+ parts,
322
+ reasoningIdx,
323
+ "Let me look at how fetchUser is implemented, wrap it in retry-with-backoff, and run the tests to make sure it holds up.",
324
+ 20,
325
+ );
326
+
327
+ pushToolCall("read-1", "read_file", { path: "src/retry.ts" });
328
+ yield emit();
329
+ await sleep(500);
330
+ setResult("12 lines read");
331
+ yield emit();
332
+ await sleep(300);
333
+
334
+ pushToolCall("patch-1", "apply_patch", {
335
+ path: "src/retry.ts",
336
+ patch: RETRY_PATCH,
337
+ });
338
+ yield emit();
339
+ await sleep(600);
340
+ setResult({ applied: true });
341
+ yield emit();
342
+ await sleep(300);
343
+
344
+ pushToolCall("test-1", "run_tests", { command: "pnpm test retry" });
345
+ yield emit();
346
+ await sleep(700);
347
+ setResult(
348
+ "FAIL src/retry.test.ts - retry() ran 4 times, expected 3 (off-by-one in loop bound)",
349
+ true,
350
+ );
351
+ yield emit();
352
+ await sleep(400);
353
+
354
+ const noteIdx = parts.push({ type: "text", text: "" }) - 1;
355
+ yield* streamText(
356
+ parts,
357
+ noteIdx,
358
+ "The loop bound was off by one. Tightening it and re-running.",
359
+ 20,
360
+ );
361
+
362
+ pushToolCall("patch-2", "apply_patch", {
363
+ path: "src/retry.ts",
364
+ patch: RETRY_PATCH_FIX,
365
+ });
366
+ yield emit();
367
+ await sleep(500);
368
+ setResult({ applied: true });
369
+ yield emit();
370
+ await sleep(300);
371
+
372
+ pushToolCall("test-2", "run_tests", { command: "pnpm test retry" });
373
+ yield emit();
374
+ await sleep(600);
375
+ setResult("PASS src/retry.test.ts (3 passed)");
376
+ yield emit();
377
+ await sleep(300);
378
+
379
+ const summary = `### Done
380
+
381
+ Added a \`retry()\` helper and routed \`fetchUser\` through it:
382
+
383
+ - exponential backoff (\`100ms\`, \`200ms\`, \`400ms\`)
384
+ - rethrows the **last error** after exhausting attempts
385
+ - fixed an off-by-one that ran one extra attempt
386
+
387
+ Tests are green.`;
388
+ const summaryIdx = parts.push({ type: "text", text: "" }) - 1;
389
+ yield* streamText(parts, summaryIdx, summary, 15);
390
+ }
391
+
392
+ async function* runProposalReply(): AsyncGenerator<{
393
+ content: ThreadAssistantMessagePart[];
394
+ }> {
395
+ const response = `I'm set up to work in this repo. The obvious thing to fix is the flaky \`fetchUser()\` call in \`src/retry.ts\` — it has no retry logic, so a single network blip fails the request.
396
+
397
+ Want me to wrap it in retry-with-backoff? Just say *make fetchUser retry on failure*.`;
398
+ let acc = "";
399
+ for (const word of response.split(" ")) {
400
+ acc += (acc ? " " : "") + word;
401
+ yield { content: [{ type: "text", text: acc }] };
402
+ await sleep(20);
403
+ }
404
+ }
405
+
406
+ export const createScriptedAdapter = (): ChatModelAdapter => ({
407
+ run({ messages }) {
408
+ return isTaskRequest(lastUserText(messages))
409
+ ? runAgentScript()
410
+ : runProposalReply();
411
+ },
412
+ });
413
+
414
+ ```
415
+
416
+ ## src/tools.tsx
417
+
418
+ ```tsx
419
+ import { Box, Text } from "ink";
420
+ import { makeAssistantToolUI, DiffView } from "@assistant-ui/react-ink";
421
+
422
+ export const ApplyPatchToolUI = makeAssistantToolUI<
423
+ { path: string; patch: string },
424
+ unknown
425
+ >({
426
+ toolName: "apply_patch",
427
+ render: ({ args }) => {
428
+ if (!args?.patch) return null;
429
+ return (
430
+ <Box flexDirection="column" marginBottom={1}>
431
+ <Text color="cyan">edit {args.path}</Text>
432
+ <DiffView patch={args.patch} showLineNumbers />
433
+ </Box>
434
+ );
435
+ },
436
+ });
437
+
438
+ ```
439
+
245
440
  ## tsconfig.json
246
441
 
247
442
  ```json
@@ -11,8 +11,9 @@
11
11
  @custom-variant dark (&:is(.dark *));
12
12
 
13
13
  @theme {
14
- --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif,
15
- "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
14
+ --font-sans:
15
+ "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
16
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
16
17
  }
17
18
 
18
19
  html,
@@ -772,30 +773,30 @@ export default function Home() {
772
773
  "dependencies": {
773
774
  "@assistant-ui/react": "workspace:*",
774
775
  "@assistant-ui/react-markdown": "workspace:*",
775
- "@react-router/node": "^7.15.1",
776
- "@react-router/serve": "^7.15.1",
776
+ "@react-router/node": "^7.17.0",
777
+ "@react-router/serve": "^7.17.0",
777
778
  "class-variance-authority": "^0.7.1",
778
779
  "clsx": "^2.1.1",
779
- "eventsource-parser": "^3.0.8",
780
- "isbot": "^5.1.40",
781
- "lucide-react": "^1.16.0",
782
- "openai": "^6.38.0",
783
- "react": "^19.2.6",
784
- "react-dom": "^19.2.6",
785
- "react-router": "^7.15.1",
780
+ "eventsource-parser": "^3.1.0",
781
+ "isbot": "^5.1.41",
782
+ "lucide-react": "^1.17.0",
783
+ "openai": "^6.42.0",
784
+ "react": "^19.2.7",
785
+ "react-dom": "^19.2.7",
786
+ "react-router": "^7.17.0",
786
787
  "remark-gfm": "^4.0.1",
787
788
  "tailwind-merge": "^3.6.0"
788
789
  },
789
790
  "devDependencies": {
790
- "@react-router/dev": "^7.15.1",
791
+ "@react-router/dev": "^7.17.0",
791
792
  "@tailwindcss/vite": "^4.3.0",
792
- "@types/node": "^25.9.1",
793
- "@types/react": "^19.2.15",
793
+ "@types/node": "^25.9.2",
794
+ "@types/react": "^19.2.17",
794
795
  "@types/react-dom": "^19.2.3",
795
796
  "tailwindcss": "^4.3.0",
796
797
  "tw-animate-css": "^1.4.0",
797
798
  "typescript": "^6.0.3",
798
- "vite": "^8.0.14",
799
+ "vite": "^8.0.16",
799
800
  "vite-tsconfig-paths": "^6.1.1"
800
801
  }
801
802
  }
@@ -880,6 +881,7 @@ npm run dev
880
881
  "jsx": "react-jsx",
881
882
  "rootDirs": [".", "./.react-router/types"],
882
883
  "baseUrl": ".",
884
+ "ignoreDeprecations": "6.0",
883
885
  "paths": {
884
886
  "@/*": ["./app/*"],
885
887
  "@/components/assistant-ui/*": [
@@ -476,9 +476,8 @@ async function createStore(): Promise<ResumableStreamStore> {
476
476
  }
477
477
 
478
478
  const { createClient } = await import("redis");
479
- const { createRedisResumableStreamStore } = await import(
480
- "assistant-stream/resumable/redis"
481
- );
479
+ const { createRedisResumableStreamStore } =
480
+ await import("assistant-stream/resumable/redis");
482
481
 
483
482
  const client = createClient({ url });
484
483
  client.on("error", (err) => {
@@ -493,10 +492,11 @@ async function createStore(): Promise<ResumableStreamStore> {
493
492
  ## next.config.js
494
493
 
495
494
  ```javascript
495
+ import { withAui } from "@assistant-ui/next";
496
496
  /** @type {import('next').NextConfig} */
497
497
  const nextConfig = {};
498
498
 
499
- export default nextConfig;
499
+ export default withAui(nextConfig);
500
500
 
501
501
  ```
502
502
 
@@ -514,31 +514,32 @@ export default nextConfig;
514
514
  "start": "next start"
515
515
  },
516
516
  "dependencies": {
517
- "@ai-sdk/openai": "^3.0.64",
518
- "@ai-sdk/react": "^3.0.190",
517
+ "@ai-sdk/openai": "^3.0.68",
518
+ "@ai-sdk/react": "^3.0.199",
519
519
  "@assistant-ui/react": "workspace:*",
520
520
  "@assistant-ui/react-ai-sdk": "workspace:*",
521
521
  "@assistant-ui/react-markdown": "workspace:*",
522
522
  "@assistant-ui/store": "workspace:*",
523
523
  "@assistant-ui/tap": "workspace:*",
524
524
  "@assistant-ui/ui": "workspace:*",
525
- "ai": "^6.0.188",
525
+ "ai": "^6.0.197",
526
526
  "assistant-stream": "workspace:*",
527
527
  "class-variance-authority": "^0.7.1",
528
528
  "clsx": "^2.1.1",
529
- "lucide-react": "^1.16.0",
530
- "next": "^16.2.6",
531
- "react": "^19.2.6",
532
- "react-dom": "^19.2.6",
533
- "redis": "^5.12.1",
529
+ "lucide-react": "^1.17.0",
530
+ "next": "^16.2.7",
531
+ "react": "^19.2.7",
532
+ "react-dom": "^19.2.7",
533
+ "redis": "^6.0.0",
534
534
  "tailwind-merge": "^3.6.0",
535
535
  "zod": "^4.4.3"
536
536
  },
537
537
  "devDependencies": {
538
+ "@assistant-ui/next": "workspace:*",
538
539
  "@assistant-ui/x-buildutils": "workspace:*",
539
540
  "@tailwindcss/postcss": "^4.3.0",
540
- "@types/node": "^25.9.1",
541
- "@types/react": "^19.2.15",
541
+ "@types/node": "^25.9.2",
542
+ "@types/react": "^19.2.17",
542
543
  "@types/react-dom": "^19.2.3",
543
544
  "postcss": "^8.5.15",
544
545
  "tailwindcss": "^4.3.0",