@assistant-ui/mcp-docs-server 0.1.9 → 0.1.11

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 (35) hide show
  1. package/.docs/organized/code-examples/with-ai-sdk-v5.md +26 -26
  2. package/.docs/organized/code-examples/with-assistant-transport.md +29 -29
  3. package/.docs/organized/code-examples/with-cloud.md +21 -21
  4. package/.docs/organized/code-examples/with-external-store.md +18 -18
  5. package/.docs/organized/code-examples/with-ffmpeg.md +22 -22
  6. package/.docs/organized/code-examples/with-langgraph.md +35 -120
  7. package/.docs/organized/code-examples/with-parent-id-grouping.md +18 -18
  8. package/.docs/organized/code-examples/with-react-hook-form.md +27 -27
  9. package/.docs/raw/docs/api-reference/primitives/Thread.mdx +40 -8
  10. package/.docs/raw/docs/cloud/persistence/langgraph.mdx +64 -68
  11. package/.docs/raw/docs/getting-started.mdx +541 -152
  12. package/.docs/raw/docs/guides/Attachments.mdx +21 -0
  13. package/.docs/raw/docs/guides/ToolUI.mdx +112 -37
  14. package/.docs/raw/docs/guides/Tools.mdx +170 -6
  15. package/.docs/raw/docs/migrations/react-langgraph-v0-7.mdx +324 -0
  16. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +2 -2
  17. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +218 -0
  18. package/.docs/raw/docs/runtimes/custom/external-store.mdx +31 -24
  19. package/.docs/raw/docs/runtimes/langgraph/index.mdx +55 -20
  20. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +8 -3
  21. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +1 -1
  22. package/.docs/raw/docs/ui/AssistantModal.mdx +21 -0
  23. package/.docs/raw/docs/ui/AssistantSidebar.mdx +21 -0
  24. package/.docs/raw/docs/ui/Attachment.mdx +21 -0
  25. package/.docs/raw/docs/ui/Markdown.mdx +22 -1
  26. package/.docs/raw/docs/ui/Mermaid.mdx +22 -1
  27. package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +43 -2
  28. package/.docs/raw/docs/ui/Thread.mdx +374 -5
  29. package/.docs/raw/docs/ui/ThreadList.mdx +48 -2
  30. package/.docs/raw/docs/ui/ToolFallback.mdx +21 -0
  31. package/package.json +7 -7
  32. package/.docs/raw/docs/migrations/v0-7.mdx +0 -188
  33. package/.docs/raw/docs/migrations/v0-8.mdx +0 -160
  34. package/.docs/raw/docs/migrations/v0-9.mdx +0 -75
  35. package/.docs/raw/docs/ui/primitives/Thread.mdx +0 -197
@@ -0,0 +1,324 @@
1
+ ---
2
+ title: Migrating to react-langgraph v0.7
3
+ ---
4
+
5
+ import { Callout } from "fumadocs-ui/components/callout";
6
+ import { Steps, Step } from "fumadocs-ui/components/steps";
7
+
8
+ ## Overview
9
+
10
+ This guide helps you migrate from the previous LangGraph integration pattern to the new simplified API introduced in `@assistant-ui/react-langgraph` v0.7. The new API consolidates thread management directly into `useLangGraphRuntime`, eliminating the need for separate runtime hooks and manual thread state management.
11
+
12
+ ## Key Changes
13
+
14
+ ### 1. Simplified Thread Management
15
+
16
+ The `useLangGraphRuntime` hook now directly handles thread lifecycle:
17
+ - No more `useRemoteThreadListRuntime` wrapper
18
+ - No more separate runtime hook functions
19
+ - Thread management is built into the core runtime
20
+
21
+ ### 2. New `initialize` Parameter
22
+
23
+ The `stream` function now receives an `initialize` parameter that handles thread creation and loading automatically.
24
+
25
+ ### 3. Direct Cloud Integration
26
+
27
+ Cloud persistence can now be configured directly in `useLangGraphRuntime` with the `cloud` parameter.
28
+
29
+ ## Migration Steps
30
+
31
+ <Steps>
32
+
33
+ <Step>
34
+
35
+ ### Update Your Runtime Implementation
36
+
37
+ #### Before (Old Pattern)
38
+
39
+ ```tsx
40
+ import {
41
+ useCloudThreadListRuntime,
42
+ useThreadListItemRuntime,
43
+ } from "@assistant-ui/react";
44
+ import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
45
+
46
+ const useMyLangGraphRuntime = () => {
47
+ const threadListItemRuntime = useThreadListItemRuntime();
48
+
49
+ const runtime = useLangGraphRuntime({
50
+ stream: async function* (messages) {
51
+ const { externalId } = await threadListItemRuntime.initialize();
52
+ if (!externalId) throw new Error("Thread not found");
53
+
54
+ return sendMessage({
55
+ threadId: externalId,
56
+ messages,
57
+ });
58
+ },
59
+ onSwitchToThread: async (externalId) => {
60
+ const state = await getThreadState(externalId);
61
+ return {
62
+ messages: state.values.messages,
63
+ };
64
+ },
65
+ });
66
+
67
+ return runtime;
68
+ };
69
+
70
+ // In your component:
71
+ const runtime = useCloudThreadListRuntime({
72
+ cloud,
73
+ runtimeHook: useMyLangGraphRuntime,
74
+ create: async () => {
75
+ const { thread_id } = await createThread();
76
+ return { externalId: thread_id };
77
+ },
78
+ });
79
+ ```
80
+
81
+ #### After (New Pattern)
82
+
83
+ ```tsx
84
+ import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
85
+
86
+ // Directly in your component:
87
+ const runtime = useLangGraphRuntime({
88
+ cloud, // Optional: for cloud persistence
89
+ stream: async function* (messages, { initialize }) {
90
+ const { externalId } = await initialize();
91
+ if (!externalId) throw new Error("Thread not found");
92
+
93
+ return sendMessage({
94
+ threadId: externalId,
95
+ messages,
96
+ });
97
+ },
98
+ create: async () => {
99
+ const { thread_id } = await createThread();
100
+ return { externalId: thread_id };
101
+ },
102
+ load: async (externalId) => {
103
+ const state = await getThreadState(externalId);
104
+ return {
105
+ messages: state.values.messages,
106
+ };
107
+ },
108
+ });
109
+ ```
110
+
111
+ </Step>
112
+
113
+ <Step>
114
+
115
+ ### Update Import Statements
116
+
117
+ Remove unused imports:
118
+
119
+ ```diff
120
+ - import {
121
+ - useCloudThreadListRuntime,
122
+ - useThreadListItemRuntime,
123
+ - } from "@assistant-ui/react";
124
+ + import { AssistantCloud } from "@assistant-ui/react";
125
+ ```
126
+
127
+ </Step>
128
+
129
+ <Step>
130
+
131
+ ### Simplify Component Structure
132
+
133
+ You no longer need a separate runtime hook function. Everything can be defined directly in your component or provider:
134
+
135
+ ```tsx
136
+ export function MyRuntimeProvider({ children }) {
137
+ const cloud = useMemo(
138
+ () => new AssistantCloud({
139
+ baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL,
140
+ }),
141
+ []
142
+ );
143
+
144
+ const runtime = useLangGraphRuntime({
145
+ cloud,
146
+ // All configuration inline
147
+ stream: async function* (messages, { initialize }) {
148
+ // Your stream implementation
149
+ },
150
+ create: async () => {
151
+ // Your create implementation
152
+ },
153
+ load: async (externalId) => {
154
+ // Your load implementation
155
+ },
156
+ });
157
+
158
+ return (
159
+ <AssistantRuntimeProvider runtime={runtime}>
160
+ {children}
161
+ </AssistantRuntimeProvider>
162
+ );
163
+ }
164
+ ```
165
+
166
+ </Step>
167
+
168
+ <Step>
169
+
170
+ ### Update Method Names
171
+
172
+ Rename methods to match the new API:
173
+
174
+ - `onSwitchToThread` → `load`
175
+ - `onSwitchToNewThread` → handled automatically via `create`
176
+ - Thread ID management is now automatic
177
+
178
+ </Step>
179
+
180
+ </Steps>
181
+
182
+ ## API Reference Changes
183
+
184
+ ### Old API
185
+
186
+ ```typescript
187
+ type OldLangGraphRuntimeOptions = {
188
+ threadId?: string;
189
+ stream: (messages: Message[]) => AsyncGenerator;
190
+ onSwitchToNewThread?: () => Promise<void>;
191
+ onSwitchToThread?: (threadId: string) => Promise<ThreadState>;
192
+ };
193
+ ```
194
+
195
+ ### New API
196
+
197
+ ```typescript
198
+ type NewLangGraphRuntimeOptions = {
199
+ cloud?: AssistantCloud;
200
+ stream: (
201
+ messages: Message[],
202
+ context: {
203
+ initialize: () => Promise<{
204
+ remoteId: string;
205
+ externalId: string | undefined;
206
+ }>
207
+ }
208
+ ) => AsyncGenerator;
209
+ create?: () => Promise<{ externalId: string }>;
210
+ load?: (externalId: string) => Promise<ThreadState>;
211
+ delete?: (externalId: string) => Promise<void>;
212
+ };
213
+ ```
214
+
215
+ ## Benefits of the New API
216
+
217
+ 1. **Simpler Setup**: No need for multiple runtime hooks and wrappers
218
+ 2. **Cleaner Code**: All configuration in one place
219
+ 3. **Better Type Safety**: More explicit types for thread management
220
+ 4. **Automatic Thread Handling**: The runtime manages thread lifecycle internally
221
+ 5. **Optional Cloud Integration**: Add cloud persistence with a single parameter
222
+
223
+ ## Common Migration Issues
224
+
225
+ <Callout type="warning">
226
+ **Breaking Change**: The `threadId` and `onSwitchToNewThread` parameters are no longer supported. Use the new `create` and `load` methods instead.
227
+ </Callout>
228
+
229
+ ### Issue: `threadListItemRuntime` is not defined
230
+
231
+ **Solution**: Remove references to `useThreadListItemRuntime()`. Use the `initialize` parameter in the stream function instead.
232
+
233
+ ### Issue: Thread switching doesn't work
234
+
235
+ **Solution**: Ensure you've implemented both `create` and `load` functions. The runtime needs both to manage thread lifecycle.
236
+
237
+ ### Issue: Cloud persistence not working
238
+
239
+ **Solution**: Pass the `AssistantCloud` instance directly to `useLangGraphRuntime` via the `cloud` parameter.
240
+
241
+ ## Example: Complete Migration
242
+
243
+ Here's a complete before and after example for a typical LangGraph integration:
244
+
245
+ ### Before
246
+
247
+ ```tsx title="runtime-provider.tsx"
248
+ import {
249
+ AssistantCloud,
250
+ AssistantRuntimeProvider,
251
+ useCloudThreadListRuntime,
252
+ useThreadListItemRuntime,
253
+ } from "@assistant-ui/react";
254
+ import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
255
+
256
+ const useMyRuntime = () => {
257
+ const threadListItemRuntime = useThreadListItemRuntime();
258
+
259
+ return useLangGraphRuntime({
260
+ stream: async function* (messages) {
261
+ const { externalId } = await threadListItemRuntime.initialize();
262
+ // ... implementation
263
+ },
264
+ onSwitchToThread: async (externalId) => {
265
+ // ... implementation
266
+ },
267
+ });
268
+ };
269
+
270
+ export function Provider({ children }) {
271
+ const cloud = new AssistantCloud({ /* config */ });
272
+
273
+ const runtime = useCloudThreadListRuntime({
274
+ cloud,
275
+ runtimeHook: useMyRuntime,
276
+ create: async () => { /* ... */ },
277
+ });
278
+
279
+ return (
280
+ <AssistantRuntimeProvider runtime={runtime}>
281
+ {children}
282
+ </AssistantRuntimeProvider>
283
+ );
284
+ }
285
+ ```
286
+
287
+ ### After
288
+
289
+ ```tsx title="runtime-provider.tsx"
290
+ import {
291
+ AssistantCloud,
292
+ AssistantRuntimeProvider,
293
+ } from "@assistant-ui/react";
294
+ import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
295
+
296
+ export function Provider({ children }) {
297
+ const cloud = new AssistantCloud({ /* config */ });
298
+
299
+ const runtime = useLangGraphRuntime({
300
+ cloud,
301
+ stream: async function* (messages, { initialize }) {
302
+ const { externalId } = await initialize();
303
+ // ... implementation
304
+ },
305
+ create: async () => { /* ... */ },
306
+ load: async (externalId) => {
307
+ // ... implementation (formerly onSwitchToThread)
308
+ },
309
+ });
310
+
311
+ return (
312
+ <AssistantRuntimeProvider runtime={runtime}>
313
+ {children}
314
+ </AssistantRuntimeProvider>
315
+ );
316
+ }
317
+ ```
318
+
319
+ ## Need Help?
320
+
321
+ If you encounter issues during migration:
322
+ 1. Check the updated [LangGraph documentation](/docs/runtimes/langgraph)
323
+ 2. Review the [example implementation](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-langgraph)
324
+ 3. Report issues on [GitHub](https://github.com/assistant-ui/assistant-ui/issues)
@@ -41,7 +41,7 @@ npm install @assistant-ui/react @assistant-ui/react-ai-sdk ai @ai-sdk/openai
41
41
  ```tsx
42
42
  import { openai } from "@ai-sdk/openai";
43
43
  import { streamText, UIMessage, convertToModelMessages, tool } from "ai";
44
- import { frontendTools } from "@assistant-ui/assistant-stream/ai-sdk";
44
+ import { frontendTools } from "@assistant-ui/react-ai-sdk";
45
45
  import { z } from "zod";
46
46
 
47
47
  // Allow streaming responses up to 30 seconds
@@ -173,7 +173,7 @@ const runtime = useChatRuntime({
173
173
  When using `AssistantChatTransport`, frontend tools are forwarded to your backend. Use the `frontendTools` helper to properly integrate them:
174
174
 
175
175
  ```tsx
176
- import { frontendTools } from "@assistant-ui/assistant-stream/ai-sdk";
176
+ import { frontendTools } from "@assistant-ui/react-ai-sdk";
177
177
 
178
178
  export async function POST(req: Request) {
179
179
  const { messages, system, tools } = await req.json();
@@ -0,0 +1,218 @@
1
+ ---
2
+ title: Custom Thread List
3
+ ---
4
+
5
+ import { Callout } from "fumadocs-ui/components/callout";
6
+ import { Steps, Step } from "fumadocs-ui/components/steps";
7
+ import { ParametersTable } from "@/components/docs";
8
+
9
+ ## Overview
10
+
11
+ `useRemoteThreadListRuntime` lets you plug a custom thread database into assistant-ui. It keeps the UI and local runtime logic in sync while you provide persistence, archiving, and metadata for every conversation. The hook is exported as `unstable_useRemoteThreadListRuntime`; we refer to it here as **Custom Thread List**.
12
+
13
+ ## When to Use
14
+
15
+ Use a Custom Thread List when you need to:
16
+
17
+ - Persist conversations in your own database or multitenant backend
18
+ - Share threads across devices, teams, or long-lived sessions
19
+ - Control thread metadata (titles, archived state, external identifiers)
20
+ - Layer additional adapters (history, attachments) around each thread runtime
21
+
22
+ ## How It Works
23
+
24
+ Custom Thread List merges two pieces of state:
25
+
26
+ 1. **Per-thread runtime** – powered by any runtime hook (for example `useLocalRuntime` or `useAssistantTransportRuntime`).
27
+ 2. **Thread list adapter** – your adapter that reads and writes thread metadata in a remote store.
28
+
29
+ When the hook mounts it calls `list()` on your adapter, hydrates existing threads, and uses your runtime hook to spawn a runtime whenever a thread is opened. Creating a new conversation calls `initialize(threadId)` so you can create a record server-side and return the canonical `remoteId`.
30
+
31
+ <Callout type="info">
32
+ The built-in Assistant Cloud runtime is implemented with the same API. Inspect
33
+ `useCloudThreadListAdapter` for a production-ready reference adapter.
34
+ </Callout>
35
+
36
+ ## Build a Custom Thread List
37
+
38
+ <Steps>
39
+ <Step>
40
+ ### Provide a runtime per thread
41
+
42
+ Use any runtime hook that returns an `AssistantRuntime`. In most custom setups this is `useLocalRuntime(modelAdapter)` or `useAssistantTransportRuntime(...)`.
43
+
44
+ </Step>
45
+ <Step>
46
+ ### Implement the adapter contract
47
+
48
+ Your adapter decides how threads are stored. Implement the methods in the table below to connect to your database or API.
49
+
50
+ </Step>
51
+ <Step>
52
+ ### Compose the provider
53
+
54
+ Wrap `AssistantRuntimeProvider` with the runtime returned from the Custom Thread List hook.
55
+
56
+ ```tsx twoslash title="app/CustomThreadListProvider.tsx"
57
+ // @filename: app/model-adapter.ts
58
+ export const myModelAdapter = {} as any;
59
+
60
+ // @filename: app/CustomThreadListProvider.tsx
61
+ // ---cut---
62
+ "use client";
63
+
64
+ import type { ReactNode } from "react";
65
+ import {
66
+ AssistantRuntimeProvider,
67
+ useLocalRuntime,
68
+ unstable_useRemoteThreadListRuntime as useRemoteThreadListRuntime,
69
+ type unstable_RemoteThreadListAdapter as RemoteThreadListAdapter,
70
+ } from "@assistant-ui/react";
71
+ import { createAssistantStream } from "assistant-stream";
72
+ import { myModelAdapter } from "./model-adapter"; // your chat model adapter
73
+
74
+ const threadListAdapter: RemoteThreadListAdapter = {
75
+ async list() {
76
+ const response = await fetch("/api/threads");
77
+ const threads = await response.json();
78
+ return {
79
+ threads: threads.map((thread: any) => ({
80
+ remoteId: thread.id,
81
+ externalId: thread.external_id ?? undefined,
82
+ status: thread.is_archived ? "archived" : "regular",
83
+ title: thread.title ?? undefined,
84
+ })),
85
+ };
86
+ },
87
+ async initialize(localId) {
88
+ const response = await fetch("/api/threads", {
89
+ method: "POST",
90
+ headers: { "Content-Type": "application/json" },
91
+ body: JSON.stringify({ localId }),
92
+ });
93
+ const result = await response.json();
94
+ return { remoteId: result.id, externalId: result.external_id };
95
+ },
96
+ async rename(remoteId, title) {
97
+ await fetch(`/api/threads/${remoteId}`, {
98
+ method: "PATCH",
99
+ headers: { "Content-Type": "application/json" },
100
+ body: JSON.stringify({ title }),
101
+ });
102
+ },
103
+ async archive(remoteId) {
104
+ await fetch(`/api/threads/${remoteId}/archive`, { method: "POST" });
105
+ },
106
+ async unarchive(remoteId) {
107
+ await fetch(`/api/threads/${remoteId}/unarchive`, { method: "POST" });
108
+ },
109
+ async delete(remoteId) {
110
+ await fetch(`/api/threads/${remoteId}`, { method: "DELETE" });
111
+ },
112
+ async generateTitle(remoteId, messages) {
113
+ return createAssistantStream(async (controller) => {
114
+ const response = await fetch(`/api/threads/${remoteId}/title`, {
115
+ method: "POST",
116
+ headers: { "Content-Type": "application/json" },
117
+ body: JSON.stringify({ messages }),
118
+ });
119
+ const { title } = await response.json();
120
+ controller.appendText(title);
121
+ });
122
+ },
123
+ };
124
+
125
+ export function CustomThreadListProvider({
126
+ children,
127
+ }: Readonly<{ children: ReactNode }>) {
128
+ const runtime = useRemoteThreadListRuntime({
129
+ runtimeHook: () => useLocalRuntime(myModelAdapter),
130
+ adapter: threadListAdapter,
131
+ });
132
+
133
+ return (
134
+ <AssistantRuntimeProvider runtime={runtime}>
135
+ {children}
136
+ </AssistantRuntimeProvider>
137
+ );
138
+ }
139
+ ```
140
+
141
+ </Step>
142
+ </Steps>
143
+
144
+ ## Adapter Responsibilities
145
+
146
+ <ParametersTable
147
+ type="RemoteThreadListAdapter"
148
+ parameters={[
149
+ {
150
+ name: "list",
151
+ type: "() => Promise<{ threads: RemoteThreadMetadata[] }>",
152
+ description:
153
+ "Return the current threads. Each thread must include status, remoteId, and any metadata you want to show immediately.",
154
+ required: true,
155
+ },
156
+ {
157
+ name: "initialize",
158
+ type: "(localId: string) => Promise<{ remoteId: string; externalId?: string }>",
159
+ description:
160
+ "Create a new remote record when the user starts a conversation. Return the canonical ids so later operations target the right thread.",
161
+ required: true,
162
+ },
163
+ {
164
+ name: "rename",
165
+ type: "(remoteId: string, title: string) => Promise<void>",
166
+ description: "Persist title changes triggered from the UI.",
167
+ required: true,
168
+ },
169
+ {
170
+ name: "archive",
171
+ type: "(remoteId: string) => Promise<void>",
172
+ description: "Mark the thread as archived in your system.",
173
+ required: true,
174
+ },
175
+ {
176
+ name: "unarchive",
177
+ type: "(remoteId: string) => Promise<void>",
178
+ description: "Restore an archived thread to the active list.",
179
+ required: true,
180
+ },
181
+ {
182
+ name: "delete",
183
+ type: "(remoteId: string) => Promise<void>",
184
+ description: "Permanently remove the thread and stop rendering it.",
185
+ required: true,
186
+ },
187
+ {
188
+ name: "generateTitle",
189
+ type: "(remoteId: string, unstable_messages: readonly ThreadMessage[]) => Promise<AssistantStream>",
190
+ description:
191
+ "Return a streaming title generator. You can reuse your model endpoint or queue a background job.",
192
+ required: true,
193
+ },
194
+ {
195
+ name: "unstable_Provider",
196
+ type: "ComponentType<PropsWithChildren>",
197
+ description:
198
+ "Optional wrapper rendered around all thread runtimes. Use it to inject adapters such as history or attachments (see the Cloud adapter).",
199
+ },
200
+ ]}
201
+ />
202
+
203
+ ## Thread Lifecycle Cheatsheet
204
+
205
+ - `list()` hydrates threads on mount and during refreshes.
206
+ - Creating a new conversation calls `initialize()` once the user sends the first message.
207
+ - `archive`, `unarchive`, and `delete` are called optimistically; throw to revert the UI.
208
+ - `generateTitle()` powers the automatic title button and expects an `AssistantStream`.
209
+ - Provide a `runtimeHook` that always returns a fresh runtime instance per active thread.
210
+
211
+ ## Optional Adapters
212
+
213
+ If you need history or attachment support, expose them via `unstable_Provider`. The cloud implementation wraps each thread runtime with `RuntimeAdapterProvider` to inject:
214
+
215
+ - `history` – e.g. `useAssistantCloudThreadHistoryAdapter`
216
+ - `attachments` – e.g. `CloudFileAttachmentAdapter`
217
+
218
+ Reuse that pattern to register any capability your runtime requires.
@@ -164,45 +164,52 @@ graph TD
164
164
  ```tsx title="app/MyRuntimeProvider.tsx"
165
165
  "use client";
166
166
 
167
- import { useState } from "react";
167
+ import { ThreadMessageLike } from "@assistant-ui/react";
168
+ import { AppendMessage } from "@assistant-ui/react";
168
169
  import {
169
- useExternalStoreRuntime,
170
- ThreadMessageLike,
171
- AppendMessage,
172
170
  AssistantRuntimeProvider,
171
+ useExternalStoreRuntime,
173
172
  } from "@assistant-ui/react";
174
-
175
- export function MyRuntimeProvider({ children }) {
176
- const [messages, setMessages] = useState<ThreadMessageLike[]>([]);
177
- const [isRunning, setIsRunning] = useState(false);
178
-
173
+ import { useState } from "react";
174
+
175
+ const convertMessage = (message: ThreadMessageLike) => {
176
+ return message;
177
+ };
178
+
179
+ export function MyRuntimeProvider({
180
+ children,
181
+ }: Readonly<{
182
+ children: React.ReactNode;
183
+ }>) {
184
+ const [messages, setMessages] = useState<readonly ThreadMessageLike[]>([]);
185
+
179
186
  const onNew = async (message: AppendMessage) => {
180
- // Add user message
187
+ if (message.content.length !== 1 || message.content[0]?.type !== "text")
188
+ throw new Error("Only text content is supported");
189
+
181
190
  const userMessage: ThreadMessageLike = {
182
191
  role: "user",
183
- content: message.content,
192
+ content: [{ type: "text", text: message.content[0].text }],
184
193
  };
185
- setMessages(prev => [...prev, userMessage]);
186
-
187
- // Generate response
188
- setIsRunning(true);
189
- const response = await callYourAPI(message);
190
-
194
+ setMessages((currentMessages) => [...currentMessages, userMessage]);
195
+
196
+ // normally you would perform an API call here to get the assistant response
197
+ await new Promise((resolve) => setTimeout(resolve, 1000));
198
+
191
199
  const assistantMessage: ThreadMessageLike = {
192
200
  role: "assistant",
193
- content: response.content,
201
+ content: [{ type: "text", text: "Hello, world!" }],
194
202
  };
195
- setMessages(prev => [...prev, assistantMessage]);
196
- setIsRunning(false);
203
+ setMessages((currentMessages) => [...currentMessages, assistantMessage]);
197
204
  };
198
-
199
- const runtime = useExternalStoreRuntime({
205
+
206
+ const runtime = useExternalStoreRuntime<ThreadMessageLike>({
200
207
  messages,
201
208
  setMessages,
202
- isRunning,
203
209
  onNew,
210
+ convertMessage,
204
211
  });
205
-
212
+
206
213
  return (
207
214
  <AssistantRuntimeProvider runtime={runtime}>
208
215
  {children}