@assistant-ui/mcp-docs-server 0.1.19 → 0.1.21

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 (108) hide show
  1. package/.docs/organized/code-examples/with-ag-ui.md +172 -1633
  2. package/.docs/organized/code-examples/with-ai-sdk-v6.md +42 -1640
  3. package/.docs/organized/code-examples/with-assistant-transport.md +40 -1743
  4. package/.docs/organized/code-examples/with-cloud.md +71 -1745
  5. package/.docs/organized/code-examples/with-custom-thread-list.md +87 -1723
  6. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +70 -1637
  7. package/.docs/organized/code-examples/with-external-store.md +67 -1624
  8. package/.docs/organized/code-examples/with-ffmpeg.md +71 -1629
  9. package/.docs/organized/code-examples/with-langgraph.md +95 -1893
  10. package/.docs/organized/code-examples/with-parent-id-grouping.md +57 -1654
  11. package/.docs/organized/code-examples/with-react-hook-form.md +220 -2163
  12. package/.docs/organized/code-examples/with-react-router.md +66 -1318
  13. package/.docs/organized/code-examples/with-store.md +31 -31
  14. package/.docs/organized/code-examples/with-tanstack.md +77 -861
  15. package/.docs/organized/code-examples/with-tap-runtime.md +812 -0
  16. package/.docs/raw/docs/(docs)/cli.mdx +66 -0
  17. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -1
  18. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -1
  19. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +4 -4
  20. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +3 -3
  21. package/.docs/raw/docs/(docs)/devtools.mdx +0 -1
  22. package/.docs/raw/docs/(docs)/guides/attachments.mdx +2 -3
  23. package/.docs/raw/docs/(docs)/guides/context-api.mdx +117 -117
  24. package/.docs/raw/docs/(docs)/guides/suggestions.mdx +296 -0
  25. package/.docs/raw/docs/(docs)/guides/tools.mdx +336 -513
  26. package/.docs/raw/docs/(docs)/index.mdx +33 -410
  27. package/.docs/raw/docs/(docs)/installation.mdx +450 -0
  28. package/.docs/raw/docs/(docs)/llm.mdx +209 -0
  29. package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +0 -1
  30. package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +0 -1
  31. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +48 -3
  32. package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +0 -1
  33. package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +0 -1
  34. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +9 -3
  35. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +20 -52
  36. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +16 -39
  37. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +49 -50
  38. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +3 -11
  39. package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +0 -3
  40. package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +0 -1
  41. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +5 -16
  42. package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +0 -1
  43. package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +0 -1
  44. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +1 -2
  45. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +0 -1
  46. package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +152 -0
  47. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +0 -1
  48. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +1 -2
  49. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +1 -2
  50. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +28 -40
  51. package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +0 -1
  52. package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +1 -2
  53. package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +2 -3
  54. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +1 -2
  55. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +1 -2
  56. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +0 -1
  57. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +0 -1
  58. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +1 -2
  59. package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +0 -1
  60. package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +5 -5
  61. package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +0 -1
  62. package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +0 -1
  63. package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +207 -33
  64. package/.docs/raw/docs/(reference)/react-compatibility.mdx +0 -1
  65. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +0 -1
  66. package/.docs/raw/docs/cloud/persistence/langgraph.mdx +0 -1
  67. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +0 -1
  68. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +118 -0
  69. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +198 -0
  70. package/.docs/raw/docs/runtimes/assistant-transport.mdx +3 -3
  71. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +5 -6
  72. package/.docs/raw/docs/runtimes/custom/external-store.mdx +9 -11
  73. package/.docs/raw/docs/runtimes/custom/local.mdx +43 -36
  74. package/.docs/raw/docs/runtimes/data-stream.mdx +35 -3
  75. package/.docs/raw/docs/runtimes/langgraph/index.mdx +1 -2
  76. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +0 -1
  77. package/.docs/raw/docs/runtimes/langserve.mdx +0 -1
  78. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +0 -1
  79. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +0 -1
  80. package/.docs/raw/docs/ui/accordion.mdx +259 -0
  81. package/.docs/raw/docs/ui/assistant-modal.mdx +1 -3
  82. package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -3
  83. package/.docs/raw/docs/ui/attachment.mdx +0 -2
  84. package/.docs/raw/docs/ui/badge.mdx +138 -0
  85. package/.docs/raw/docs/ui/diff-viewer.mdx +279 -0
  86. package/.docs/raw/docs/ui/file.mdx +152 -0
  87. package/.docs/raw/docs/ui/image.mdx +100 -0
  88. package/.docs/raw/docs/ui/markdown.mdx +0 -1
  89. package/.docs/raw/docs/ui/mermaid.mdx +0 -1
  90. package/.docs/raw/docs/ui/model-selector.mdx +224 -0
  91. package/.docs/raw/docs/ui/part-grouping.mdx +4 -5
  92. package/.docs/raw/docs/ui/reasoning.mdx +6 -5
  93. package/.docs/raw/docs/ui/scrollbar.mdx +26 -9
  94. package/.docs/raw/docs/ui/select.mdx +245 -0
  95. package/.docs/raw/docs/ui/sources.mdx +6 -5
  96. package/.docs/raw/docs/ui/streamdown.mdx +348 -0
  97. package/.docs/raw/docs/ui/syntax-highlighting.mdx +8 -63
  98. package/.docs/raw/docs/ui/tabs.mdx +259 -0
  99. package/.docs/raw/docs/ui/thread-list.mdx +98 -16
  100. package/.docs/raw/docs/ui/thread.mdx +57 -73
  101. package/.docs/raw/docs/ui/tool-fallback.mdx +0 -1
  102. package/.docs/raw/docs/ui/tool-group.mdx +1 -3
  103. package/README.md +3 -3
  104. package/package.json +4 -4
  105. package/src/tools/tests/examples.test.ts +1 -1
  106. package/.docs/raw/docs/(docs)/about-assistantui.mdx +0 -54
  107. package/.docs/raw/docs/(docs)/mcp-docs-server.mdx +0 -321
  108. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +0 -219
@@ -0,0 +1,812 @@
1
+ # Example: with-tap-runtime
2
+
3
+ ## app/globals.css
4
+
5
+ ```css
6
+ @import "tailwindcss";
7
+ @import "tw-animate-css";
8
+
9
+ @source "../../../packages/ui/src";
10
+
11
+ @custom-variant dark (&:is(.dark *));
12
+
13
+ @theme inline {
14
+ --radius-sm: calc(var(--radius) - 4px);
15
+ --radius-md: calc(var(--radius) - 2px);
16
+ --radius-lg: var(--radius);
17
+ --radius-xl: calc(var(--radius) + 4px);
18
+ --color-background: var(--background);
19
+ --color-foreground: var(--foreground);
20
+ --color-card: var(--card);
21
+ --color-card-foreground: var(--card-foreground);
22
+ --color-popover: var(--popover);
23
+ --color-popover-foreground: var(--popover-foreground);
24
+ --color-primary: var(--primary);
25
+ --color-primary-foreground: var(--primary-foreground);
26
+ --color-secondary: var(--secondary);
27
+ --color-secondary-foreground: var(--secondary-foreground);
28
+ --color-muted: var(--muted);
29
+ --color-muted-foreground: var(--muted-foreground);
30
+ --color-accent: var(--accent);
31
+ --color-accent-foreground: var(--accent-foreground);
32
+ --color-destructive: var(--destructive);
33
+ --color-border: var(--border);
34
+ --color-input: var(--input);
35
+ --color-ring: var(--ring);
36
+ --color-chart-1: var(--chart-1);
37
+ --color-chart-2: var(--chart-2);
38
+ --color-chart-3: var(--chart-3);
39
+ --color-chart-4: var(--chart-4);
40
+ --color-chart-5: var(--chart-5);
41
+ --color-sidebar: var(--sidebar);
42
+ --color-sidebar-foreground: var(--sidebar-foreground);
43
+ --color-sidebar-primary: var(--sidebar-primary);
44
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
45
+ --color-sidebar-accent: var(--sidebar-accent);
46
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
47
+ --color-sidebar-border: var(--sidebar-border);
48
+ --color-sidebar-ring: var(--sidebar-ring);
49
+ }
50
+
51
+ :root {
52
+ --radius: 0.625rem;
53
+ --background: oklch(1 0 0);
54
+ --foreground: oklch(0.141 0.005 285.823);
55
+ --card: oklch(1 0 0);
56
+ --card-foreground: oklch(0.141 0.005 285.823);
57
+ --popover: oklch(1 0 0);
58
+ --popover-foreground: oklch(0.141 0.005 285.823);
59
+ --primary: oklch(0.21 0.006 285.885);
60
+ --primary-foreground: oklch(0.985 0 0);
61
+ --secondary: oklch(0.967 0.001 286.375);
62
+ --secondary-foreground: oklch(0.21 0.006 285.885);
63
+ --muted: oklch(0.967 0.001 286.375);
64
+ --muted-foreground: oklch(0.552 0.016 285.938);
65
+ --accent: oklch(0.967 0.001 286.375);
66
+ --accent-foreground: oklch(0.21 0.006 285.885);
67
+ --destructive: oklch(0.577 0.245 27.325);
68
+ --border: oklch(0.92 0.004 286.32);
69
+ --input: oklch(0.92 0.004 286.32);
70
+ --ring: oklch(0.705 0.015 286.067);
71
+ --chart-1: oklch(0.646 0.222 41.116);
72
+ --chart-2: oklch(0.6 0.118 184.704);
73
+ --chart-3: oklch(0.398 0.07 227.392);
74
+ --chart-4: oklch(0.828 0.189 84.429);
75
+ --chart-5: oklch(0.769 0.188 70.08);
76
+ --sidebar: oklch(0.985 0 0);
77
+ --sidebar-foreground: oklch(0.141 0.005 285.823);
78
+ --sidebar-primary: oklch(0.21 0.006 285.885);
79
+ --sidebar-primary-foreground: oklch(0.985 0 0);
80
+ --sidebar-accent: oklch(0.967 0.001 286.375);
81
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
82
+ --sidebar-border: oklch(0.92 0.004 286.32);
83
+ --sidebar-ring: oklch(0.705 0.015 286.067);
84
+ }
85
+
86
+ .dark {
87
+ --background: oklch(0.141 0.005 285.823);
88
+ --foreground: oklch(0.985 0 0);
89
+ --card: oklch(0.21 0.006 285.885);
90
+ --card-foreground: oklch(0.985 0 0);
91
+ --popover: oklch(0.21 0.006 285.885);
92
+ --popover-foreground: oklch(0.985 0 0);
93
+ --primary: oklch(0.92 0.004 286.32);
94
+ --primary-foreground: oklch(0.21 0.006 285.885);
95
+ --secondary: oklch(0.274 0.006 286.033);
96
+ --secondary-foreground: oklch(0.985 0 0);
97
+ --muted: oklch(0.274 0.006 286.033);
98
+ --muted-foreground: oklch(0.705 0.015 286.067);
99
+ --accent: oklch(0.274 0.006 286.033);
100
+ --accent-foreground: oklch(0.985 0 0);
101
+ --destructive: oklch(0.704 0.191 22.216);
102
+ --border: oklch(1 0 0 / 10%);
103
+ --input: oklch(1 0 0 / 15%);
104
+ --ring: oklch(0.552 0.016 285.938);
105
+ --chart-1: oklch(0.488 0.243 264.376);
106
+ --chart-2: oklch(0.696 0.17 162.48);
107
+ --chart-3: oklch(0.769 0.188 70.08);
108
+ --chart-4: oklch(0.627 0.265 303.9);
109
+ --chart-5: oklch(0.645 0.246 16.439);
110
+ --sidebar: oklch(0.21 0.006 285.885);
111
+ --sidebar-foreground: oklch(0.985 0 0);
112
+ --sidebar-primary: oklch(0.488 0.243 264.376);
113
+ --sidebar-primary-foreground: oklch(0.985 0 0);
114
+ --sidebar-accent: oklch(0.274 0.006 286.033);
115
+ --sidebar-accent-foreground: oklch(0.985 0 0);
116
+ --sidebar-border: oklch(1 0 0 / 10%);
117
+ --sidebar-ring: oklch(0.552 0.016 285.938);
118
+ }
119
+
120
+ @layer base {
121
+ * {
122
+ @apply border-border outline-ring/50;
123
+ }
124
+ body {
125
+ @apply bg-background text-foreground;
126
+ }
127
+ }
128
+
129
+ ```
130
+
131
+ ## app/layout.tsx
132
+
133
+ ```tsx
134
+ import type { Metadata } from "next";
135
+ import { MyRuntimeProvider } from "./MyRuntimeProvider";
136
+
137
+ import "./globals.css";
138
+
139
+ export const metadata: Metadata = {
140
+ title: "Tap-Native Runtime Example",
141
+ description:
142
+ "Example of tap-native runtime with ExternalThread and InMemoryThreadList",
143
+ };
144
+
145
+ export default function RootLayout({
146
+ children,
147
+ }: Readonly<{
148
+ children: React.ReactNode;
149
+ }>) {
150
+ return (
151
+ <MyRuntimeProvider>
152
+ <html lang="en" className="h-dvh">
153
+ <body className="h-dvh font-sans">{children}</body>
154
+ </html>
155
+ </MyRuntimeProvider>
156
+ );
157
+ }
158
+
159
+ ```
160
+
161
+ ## app/MyRuntimeProvider.tsx
162
+
163
+ ```tsx
164
+ "use client";
165
+
166
+ import { useState } from "react";
167
+ import {
168
+ useAui,
169
+ AuiProvider,
170
+ useAuiState,
171
+ ExternalThread,
172
+ InMemoryThreadList,
173
+ unstable_createMessageConverter,
174
+ type ExternalThreadMessage,
175
+ ThreadListPrimitive,
176
+ ThreadListItemPrimitive,
177
+ } from "@assistant-ui/react";
178
+
179
+ type SimpleMessage = {
180
+ id: string;
181
+ role: "user" | "assistant" | "system";
182
+ content: string;
183
+ status?: { type: "complete"; reason: "stop" };
184
+ };
185
+
186
+ const converter = unstable_createMessageConverter<SimpleMessage>(
187
+ (message: SimpleMessage) => ({
188
+ role: message.role,
189
+ content: message.content,
190
+ id: message.id,
191
+ status: message.status,
192
+ }),
193
+ );
194
+
195
+ const SIMPLE_MESSAGES: SimpleMessage[] = [
196
+ {
197
+ id: "1",
198
+ role: "user",
199
+ content: "Hello! What is tap-native runtime?",
200
+ },
201
+ {
202
+ id: "2",
203
+ role: "assistant",
204
+ content:
205
+ "Hi! Tap-native runtime is a new way to build assistant-ui runtimes using @assistant-ui/tap and @assistant-ui/store. It provides:\n\n• Reactive state management with hooks-like API\n• Type-safe client definitions\n• Composable resource architecture\n• Minimal implementation for external state\n\nThis example demonstrates ExternalThread and InMemoryThreadList - the first tap-native runtime clients!",
206
+ status: { type: "complete", reason: "stop" },
207
+ },
208
+ {
209
+ id: "3",
210
+ role: "user",
211
+ content: "That sounds great! Can you show me an example?",
212
+ },
213
+ {
214
+ id: "4",
215
+ role: "assistant",
216
+ content:
217
+ 'Sure! Here\'s how to use the tap-native runtime:\n\n```typescript\nconst messages = [\n { id: "1", role: "user", content: [{ type: "text", text: "Hello!" }] }\n];\n\nconst aui = useAui({\n threads: InMemoryThreadList({\n thread: (threadId) => ExternalThread({ messages, isRunning: false })\n }),\n onSwitchToThread: (threadId) => console.log("Switched to", threadId)\n});\n```\n\nTry using the thread list on the left to create and switch between threads!',
218
+ status: { type: "complete", reason: "stop" },
219
+ },
220
+ ];
221
+
222
+ export function MyRuntimeProvider({ children }: { children: React.ReactNode }) {
223
+ const [threadMessages, setThreadMessages] = useState<
224
+ Map<string, SimpleMessage[]>
225
+ >(() => new Map([["main", SIMPLE_MESSAGES]]));
226
+ const [currentThreadId, setCurrentThreadId] = useState("main");
227
+ const [isRunning, setIsRunning] = useState(false);
228
+
229
+ const currentMessages = threadMessages.get(currentThreadId) || [];
230
+
231
+ const handleSwitchToThread = (threadId: string) => {
232
+ setCurrentThreadId(threadId);
233
+ setIsRunning(false);
234
+ };
235
+
236
+ const handleSwitchToNewThread = () => {
237
+ const newId = `thread-${Date.now()}`;
238
+ setThreadMessages((prev) => new Map(prev).set(newId, []));
239
+ setCurrentThreadId(newId);
240
+ setIsRunning(false);
241
+ };
242
+
243
+ const updateCurrentThreadMessages = (
244
+ updater: (prev: SimpleMessage[]) => SimpleMessage[],
245
+ ) => {
246
+ setThreadMessages((prev) => {
247
+ const newMap = new Map(prev);
248
+ newMap.set(currentThreadId, updater(prev.get(currentThreadId) || []));
249
+ return newMap;
250
+ });
251
+ };
252
+
253
+ const messages = converter.useThreadMessages({
254
+ messages: currentMessages,
255
+ isRunning,
256
+ }) as ExternalThreadMessage[];
257
+
258
+ const aui = useAui({
259
+ threads: InMemoryThreadList({
260
+ thread: (threadId) =>
261
+ ExternalThread({
262
+ messages: threadId === currentThreadId ? messages : [],
263
+ isRunning: threadId === currentThreadId ? isRunning : false,
264
+ onNew: (message) => {
265
+ console.log("New message:", message);
266
+ const textContent = message.content
267
+ .filter((part: any) => part.type === "text")
268
+ .map((part: any) => part.text)
269
+ .join("\n\n");
270
+
271
+ updateCurrentThreadMessages((prev) => [
272
+ ...prev,
273
+ {
274
+ id: String(Date.now()),
275
+ role: message.role,
276
+ content: textContent,
277
+ ...(message.role === "assistant" && {
278
+ status: {
279
+ type: "complete" as const,
280
+ reason: "stop" as const,
281
+ },
282
+ }),
283
+ },
284
+ ]);
285
+ },
286
+ onEdit: (message) => {
287
+ console.log("Edit message:", message);
288
+ updateCurrentThreadMessages((prev) => {
289
+ const index = prev.findIndex((m) => m.id === message.sourceId);
290
+ if (index === -1) return prev;
291
+
292
+ const textContent = message.content
293
+ .filter((part: any) => part.type === "text")
294
+ .map((part: any) => part.text)
295
+ .join("\n\n");
296
+
297
+ const newMessages = [...prev];
298
+ newMessages[index] = {
299
+ ...newMessages[index]!,
300
+ content: textContent,
301
+ };
302
+ return newMessages;
303
+ });
304
+ },
305
+ onReload: (parentId) => {
306
+ console.log("Reload from:", parentId);
307
+ updateCurrentThreadMessages((prev) => {
308
+ let cutMessages: SimpleMessage[];
309
+ let sourceRole: "user" | "assistant" | "system" = "assistant";
310
+
311
+ if (parentId === null) {
312
+ cutMessages = [];
313
+ sourceRole = prev[0]?.role || "assistant";
314
+ } else {
315
+ const parentIndex = prev.findIndex((m) => m.id === parentId);
316
+ if (parentIndex === -1) {
317
+ cutMessages = [];
318
+ sourceRole = "assistant";
319
+ } else {
320
+ cutMessages = prev.slice(0, parentIndex + 1);
321
+ const sourceMessage = prev[parentIndex + 1];
322
+ sourceRole = sourceMessage?.role || "assistant";
323
+ }
324
+ }
325
+
326
+ const reloadMessage: SimpleMessage = {
327
+ id: String(Date.now()),
328
+ role: sourceRole,
329
+ content: "This message was reloaded",
330
+ ...(sourceRole === "assistant" && {
331
+ status: {
332
+ type: "complete" as const,
333
+ reason: "stop" as const,
334
+ },
335
+ }),
336
+ };
337
+
338
+ return [...cutMessages, reloadMessage];
339
+ });
340
+ },
341
+ onStartRun: () => {
342
+ console.log("Start run");
343
+ setIsRunning(true);
344
+ },
345
+ onCancel: () => {
346
+ console.log("Cancel run");
347
+ setIsRunning(false);
348
+ },
349
+ }),
350
+ onSwitchToThread: handleSwitchToThread,
351
+ onSwitchToNewThread: handleSwitchToNewThread,
352
+ }),
353
+ });
354
+
355
+ return (
356
+ <AuiProvider value={aui}>
357
+ <div className="flex h-full">
358
+ {/* Thread List Sidebar */}
359
+ <ThreadListSidebar />
360
+
361
+ {/* Main Content */}
362
+ <div className="flex flex-1 flex-col">
363
+ {children}
364
+
365
+ {/* Control panel */}
366
+ <div className="border-t bg-card p-4">
367
+ <div className="mx-auto flex max-w-2xl flex-col gap-2">
368
+ <div className="flex items-center gap-2">
369
+ <span className="text-muted-foreground text-sm">Controls:</span>
370
+ <button
371
+ onClick={() => {
372
+ updateCurrentThreadMessages((prev) => [
373
+ ...prev,
374
+ {
375
+ id: String(Date.now()),
376
+ role: "user",
377
+ content: "New user message",
378
+ },
379
+ ]);
380
+ }}
381
+ className="rounded-md bg-primary px-3 py-1 font-medium text-primary-foreground text-sm hover:bg-primary/90"
382
+ >
383
+ Add User Message
384
+ </button>
385
+ <button
386
+ onClick={() => {
387
+ updateCurrentThreadMessages((prev) => [
388
+ ...prev,
389
+ {
390
+ id: String(Date.now()),
391
+ role: "assistant",
392
+ content:
393
+ "New assistant message with some helpful information!",
394
+ status: { type: "complete", reason: "stop" },
395
+ },
396
+ ]);
397
+ }}
398
+ className="rounded-md bg-secondary px-3 py-1 font-medium text-secondary-foreground text-sm hover:bg-secondary/80"
399
+ >
400
+ Add Assistant Message
401
+ </button>
402
+ <button
403
+ onClick={() => setIsRunning(!isRunning)}
404
+ className="rounded-md bg-accent px-3 py-1 font-medium text-accent-foreground text-sm hover:bg-accent/80"
405
+ >
406
+ {isRunning ? "Stop" : "Start"} Running
407
+ </button>
408
+ <button
409
+ onClick={() => updateCurrentThreadMessages(() => [])}
410
+ className="rounded-md bg-destructive px-3 py-1 font-medium text-sm text-white hover:bg-destructive/90"
411
+ >
412
+ Clear
413
+ </button>
414
+ </div>
415
+ <div className="text-muted-foreground text-xs">
416
+ {currentMessages.length} message
417
+ {currentMessages.length !== 1 ? "s" : ""} •{" "}
418
+ {isRunning ? "Running" : "Idle"}
419
+ </div>
420
+ </div>
421
+ </div>
422
+ </div>
423
+ </div>
424
+ </AuiProvider>
425
+ );
426
+ }
427
+
428
+ function ThreadListSidebar() {
429
+ return (
430
+ <ThreadListPrimitive.Root className="flex w-64 flex-col border-r bg-muted/30">
431
+ <div className="border-b p-4">
432
+ <h2 className="font-semibold text-lg">Threads</h2>
433
+ </div>
434
+
435
+ <div className="flex-1 overflow-y-auto p-2">
436
+ <ThreadListPrimitive.Items components={{ ThreadListItem }} />
437
+ </div>
438
+
439
+ <div className="border-t p-2">
440
+ <ThreadListPrimitive.New className="w-full rounded-md bg-primary px-3 py-2 font-medium text-primary-foreground text-sm hover:bg-primary/90">
441
+ + New Thread
442
+ </ThreadListPrimitive.New>
443
+ </div>
444
+ </ThreadListPrimitive.Root>
445
+ );
446
+ }
447
+
448
+ function ThreadListItem() {
449
+ return (
450
+ <ThreadListItemPrimitive.Root className="mb-1 w-full rounded-md p-3 text-left transition-colors hover:bg-muted data-active:bg-primary data-active:text-primary-foreground">
451
+ <ThreadListItemPrimitive.Trigger className="w-full text-left">
452
+ <div className="font-medium">
453
+ <ThreadListItemPrimitive.Title fallback="New Thread" />
454
+ </div>
455
+ <div className="text-xs opacity-70">
456
+ <ThreadListItemId />
457
+ </div>
458
+ </ThreadListItemPrimitive.Trigger>
459
+ </ThreadListItemPrimitive.Root>
460
+ );
461
+ }
462
+
463
+ function ThreadListItemId() {
464
+ const id = useAuiState(({ threadListItem }) => threadListItem.id);
465
+ return <>{id}</>;
466
+ }
467
+
468
+ ```
469
+
470
+ ## app/page.tsx
471
+
472
+ ```tsx
473
+ "use client";
474
+
475
+ import { Thread } from "@/components/assistant-ui/thread";
476
+ import { useAuiState } from "@assistant-ui/react";
477
+
478
+ export default function Home() {
479
+ const isEmpty = useAuiState((state) => state.threads.main.isEmpty);
480
+
481
+ return (
482
+ <div className="flex h-full flex-col">
483
+ <header className="border-b bg-card px-6 py-4">
484
+ <h1 className="font-bold text-2xl">Tap-Native Runtime Example</h1>
485
+ <p className="text-muted-foreground text-sm">
486
+ Built with ExternalThread and InMemoryThreadList
487
+ </p>
488
+ </header>
489
+
490
+ <main className="flex-1 overflow-hidden p-4">
491
+ {isEmpty ? (
492
+ <div className="flex h-full items-center justify-center">
493
+ <div className="text-center">
494
+ <h2 className="mb-2 font-semibold text-xl">No messages yet</h2>
495
+ <p className="text-muted-foreground text-sm">
496
+ Use the controls below to add messages
497
+ </p>
498
+ </div>
499
+ </div>
500
+ ) : (
501
+ <>
502
+ <Thread />
503
+ <div className="mx-auto mt-4 max-w-2xl space-y-2">
504
+ <div className="rounded-lg border bg-card p-4">
505
+ <h3 className="mb-2 font-semibold text-sm">
506
+ About This Example
507
+ </h3>
508
+ <ul className="space-y-1 text-muted-foreground text-sm">
509
+ <li>
510
+ • Uses{" "}
511
+ <code className="rounded bg-muted px-1">
512
+ ExternalThread
513
+ </code>{" "}
514
+ to display messages
515
+ </li>
516
+ <li>• Messages are stored in React state</li>
517
+ <li>• Fully reactive - updates automatically</li>
518
+ <li>• No backend needed - pure client-side</li>
519
+ </ul>
520
+ </div>
521
+
522
+ <div className="text-center text-muted-foreground text-xs">
523
+ This is a minimal implementation. Features like editing,
524
+ branching, and attachments can be added.
525
+ </div>
526
+ </div>
527
+ </>
528
+ )}
529
+ </main>
530
+ </div>
531
+ );
532
+ }
533
+
534
+ ```
535
+
536
+ ## components.json
537
+
538
+ ```json
539
+ {
540
+ "$schema": "https://ui.shadcn.com/schema.json",
541
+ "style": "new-york",
542
+ "rsc": true,
543
+ "tsx": true,
544
+ "tailwind": {
545
+ "config": "",
546
+ "css": "app/globals.css",
547
+ "baseColor": "zinc",
548
+ "cssVariables": true,
549
+ "prefix": ""
550
+ },
551
+ "aliases": {
552
+ "components": "@/components",
553
+ "utils": "@/lib/utils",
554
+ "ui": "@/components/ui",
555
+ "lib": "@/lib",
556
+ "hooks": "@/hooks"
557
+ },
558
+ "iconLibrary": "lucide",
559
+ "registries": {
560
+ "@assistant-ui": "https://r.assistant-ui.com/{name}.json"
561
+ }
562
+ }
563
+
564
+ ```
565
+
566
+ ## lib/utils.ts
567
+
568
+ ```typescript
569
+ import { type ClassValue, clsx } from "clsx";
570
+ import { twMerge } from "tailwind-merge";
571
+
572
+ export function cn(...inputs: ClassValue[]) {
573
+ return twMerge(clsx(inputs));
574
+ }
575
+
576
+ ```
577
+
578
+ ## next.config.ts
579
+
580
+ ```typescript
581
+ import type { NextConfig } from "next";
582
+
583
+ const nextConfig: NextConfig = {
584
+ /* config options here */
585
+ };
586
+
587
+ export default nextConfig;
588
+
589
+ ```
590
+
591
+ ## package.json
592
+
593
+ ```json
594
+ {
595
+ "name": "with-tap-runtime",
596
+ "version": "0.0.0",
597
+ "private": true,
598
+ "type": "module",
599
+ "scripts": {
600
+ "dev": "next dev",
601
+ "build": "next build",
602
+ "start": "next start"
603
+ },
604
+ "dependencies": {
605
+ "@assistant-ui/react": "workspace:*",
606
+ "@assistant-ui/react-markdown": "workspace:*",
607
+ "@assistant-ui/ui": "workspace:*",
608
+ "@radix-ui/react-avatar": "^1.1.11",
609
+ "@radix-ui/react-slot": "^1.2.4",
610
+ "@radix-ui/react-tooltip": "^1.2.8",
611
+ "class-variance-authority": "^0.7.1",
612
+ "clsx": "^2.1.1",
613
+ "lucide-react": "^0.563.0",
614
+ "next": "^16.1.6",
615
+ "react": "^19.2.4",
616
+ "react-dom": "^19.2.4",
617
+ "tailwind-merge": "^3.4.0"
618
+ },
619
+ "devDependencies": {
620
+ "@assistant-ui/x-buildutils": "workspace:*",
621
+ "@tailwindcss/postcss": "^4.1.18",
622
+ "@types/node": "^25.2.0",
623
+ "@types/react": "^19.2.10",
624
+ "@types/react-dom": "^19.2.3",
625
+ "postcss": "^8.5.6",
626
+ "tailwindcss": "^4.1.18",
627
+ "tw-animate-css": "^1.4.0",
628
+ "typescript": "^5.9.3"
629
+ }
630
+ }
631
+
632
+ ```
633
+
634
+ ## README.md
635
+
636
+ ```markdown
637
+ # Tap-Native Runtime Example
638
+
639
+ This example demonstrates the first tap-native runtime implementation for assistant-ui using `@assistant-ui/tap` and `@assistant-ui/store`.
640
+
641
+ ## Features
642
+
643
+ - ✅ **ExternalThread**: Display messages from external state
644
+ - ✅ **InMemoryThreadList**: Simple thread list management
645
+ - ✅ **Reactive Updates**: State changes automatically update the UI
646
+ - ✅ **Type-Safe**: Full TypeScript support with client registry
647
+ - ✅ **No Backend**: Pure client-side implementation
648
+
649
+ ## Getting Started
650
+
651
+ ```bash
652
+ # From the monorepo root, install dependencies
653
+ pnpm install
654
+
655
+ # Navigate to this example
656
+ cd examples/with-tap-runtime
657
+
658
+ # Run the development server
659
+ pnpm dev
660
+ ```
661
+
662
+ Open [http://localhost:3000](http://localhost:3000) to see the example.
663
+
664
+ ## How It Works
665
+
666
+ ### 1. Define Messages
667
+
668
+ ```typescript
669
+ const messages: ExternalThreadMessage[] = [
670
+ {
671
+ id: "1",
672
+ role: "user",
673
+ content: [{ type: "text", text: "Hello!" }],
674
+ },
675
+ {
676
+ id: "2",
677
+ role: "assistant",
678
+ content: [{ type: "text", text: "Hi there!" }],
679
+ },
680
+ ];
681
+ ```
682
+
683
+ ### 2. Create Runtime
684
+
685
+ ```typescript
686
+ const aui = useAui({
687
+ threads: InMemoryThreadList({
688
+ thread: () => ExternalThread({ messages, isRunning: false }),
689
+ }),
690
+ });
691
+ ```
692
+
693
+ ### 3. Provide to App
694
+
695
+ ```typescript
696
+ <AuiProvider value={aui}>
697
+ <Thread.Root>
698
+ <Thread.Messages />
699
+ </Thread.Root>
700
+ </AuiProvider>
701
+ ```
702
+
703
+ ## Architecture
704
+
705
+ ```
706
+ ┌─────────────────────────────────────┐
707
+ │ React State (messages, isRunning) │
708
+ └──────────────┬──────────────────────┘
709
+
710
+
711
+ ┌─────────────────────────────────────┐
712
+ │ useAui (tap-native runtime) │
713
+ │ ┌───────────────────────────────┐ │
714
+ │ │ InMemoryThreadList │ │
715
+ │ │ └─ ExternalThread │ │
716
+ │ │ └─ MessageClient │ │
717
+ │ │ └─ ComposerClient │ │
718
+ │ └───────────────────────────────┘ │
719
+ └──────────────┬──────────────────────┘
720
+
721
+
722
+ ┌─────────────────────────────────────┐
723
+ │ Assistant UI Components │
724
+ │ <Thread.Messages /> │
725
+ └─────────────────────────────────────┘
726
+ ```
727
+
728
+ ## Key Concepts
729
+
730
+ ### ExternalThread
731
+
732
+ A client that accepts messages from external state:
733
+
734
+ ```typescript
735
+ ExternalThread({
736
+ messages: ExternalThreadMessage[],
737
+ isRunning?: boolean
738
+ })
739
+ ```
740
+
741
+ ### InMemoryThreadList
742
+
743
+ A client that manages thread list state:
744
+
745
+ ```typescript
746
+ InMemoryThreadList({
747
+ thread: () => ResourceElement<ClientOutput<"thread">>
748
+ })
749
+ ```
750
+
751
+ ### Client Registry
752
+
753
+ Type-safe client definitions via module augmentation (defined in `@assistant-ui/react`):
754
+
755
+ ```typescript
756
+ declare module "@assistant-ui/store" {
757
+ interface ClientRegistry {
758
+ threads: ThreadsClientSchema;
759
+ thread: ThreadClientSchema;
760
+ message: MessageClientSchema;
761
+ // ...
762
+ }
763
+ }
764
+ ```
765
+
766
+ ## Extending This Example
767
+
768
+ You can extend this example to:
769
+
770
+ 1. **Add persistence**: Save messages to localStorage or a database
771
+ 2. **Implement streaming**: Update messages as they stream in
772
+ 3. **Add branching**: Allow users to explore different conversation paths
773
+ 4. **Enable editing**: Let users edit messages
774
+ 5. **Add attachments**: Support file uploads and images
775
+ 6. **Connect to AI**: Integrate with OpenAI, Anthropic, or other AI providers
776
+
777
+ ## Learn More
778
+
779
+ - [Tap Documentation](../../packages/tap/README.md)
780
+ - [Store Documentation](../../packages/store/README.md)
781
+ - [Client Implementation](../../packages/react/src/client/README.md)
782
+ - [Assistant UI Docs](https://assistant-ui.com)
783
+
784
+ ```
785
+
786
+ ## tsconfig.json
787
+
788
+ ```json
789
+ {
790
+ "extends": "@assistant-ui/x-buildutils/ts/next",
791
+ "compilerOptions": {
792
+ "paths": {
793
+ "@/*": ["./*"],
794
+ "@/components/assistant-ui/*": [
795
+ "../../packages/ui/src/components/assistant-ui/*"
796
+ ],
797
+ "@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
798
+ "@assistant-ui/ui/*": ["../../packages/ui/src/*"],
799
+ "@assistant-ui/*": ["../../packages/*/src"],
800
+ "@assistant-ui/react/*": ["../../packages/react/src/*"],
801
+ "@assistant-ui/tap": ["../../packages/tap/src"],
802
+ "@assistant-ui/tap/*": ["../../packages/tap/src/*"],
803
+ "@assistant-ui/store": ["../../packages/store/src"],
804
+ "@assistant-ui/store/*": ["../../packages/store/src/*"]
805
+ }
806
+ },
807
+ "include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
808
+ "exclude": ["node_modules"]
809
+ }
810
+
811
+ ```
812
+