@assistant-ui/mcp-docs-server 0.1.23 → 0.1.25

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 (137) hide show
  1. package/.docs/organized/code-examples/waterfall.md +5 -3
  2. package/.docs/organized/code-examples/with-a2a.md +676 -0
  3. package/.docs/organized/code-examples/with-ag-ui.md +7 -8
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +28 -16
  5. package/.docs/organized/code-examples/with-artifacts.md +5 -5
  6. package/.docs/organized/code-examples/with-assistant-transport.md +3 -3
  7. package/.docs/organized/code-examples/with-chain-of-thought.md +34 -26
  8. package/.docs/organized/code-examples/with-cloud-standalone.md +10 -8
  9. package/.docs/organized/code-examples/with-cloud.md +5 -5
  10. package/.docs/organized/code-examples/with-custom-thread-list.md +7 -7
  11. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +8 -8
  12. package/.docs/organized/code-examples/with-expo.md +571 -539
  13. package/.docs/organized/code-examples/with-external-store.md +3 -4
  14. package/.docs/organized/code-examples/with-ffmpeg.md +5 -5
  15. package/.docs/organized/code-examples/with-google-adk.md +353 -0
  16. package/.docs/organized/code-examples/with-heat-graph.md +304 -0
  17. package/.docs/organized/code-examples/with-langgraph.md +25 -23
  18. package/.docs/organized/code-examples/with-parent-id-grouping.md +4 -4
  19. package/.docs/organized/code-examples/with-react-hook-form.md +6 -9
  20. package/.docs/organized/code-examples/with-react-ink.md +265 -0
  21. package/.docs/organized/code-examples/with-react-router.md +10 -11
  22. package/.docs/organized/code-examples/with-store.md +29 -18
  23. package/.docs/organized/code-examples/with-tanstack.md +7 -7
  24. package/.docs/organized/code-examples/with-tap-runtime.md +6 -4
  25. package/.docs/raw/blog/2025-01-31-changelog/index.mdx +1 -1
  26. package/.docs/raw/blog/2026-03-launch-week/index.mdx +227 -0
  27. package/.docs/raw/docs/(docs)/architecture.mdx +1 -1
  28. package/.docs/raw/docs/(docs)/cli.mdx +14 -9
  29. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +8 -3
  30. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +5 -1
  31. package/.docs/raw/docs/(docs)/copilots/{make-assistant-readable.mdx → make-assistant-visible.mdx} +14 -5
  32. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +11 -11
  33. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +2 -2
  34. package/.docs/raw/docs/(docs)/devtools.mdx +3 -2
  35. package/.docs/raw/docs/(docs)/guides/attachments.mdx +9 -11
  36. package/.docs/raw/docs/(docs)/guides/branching.mdx +11 -6
  37. package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +18 -16
  38. package/.docs/raw/docs/(docs)/guides/context-api.mdx +81 -43
  39. package/.docs/raw/docs/(docs)/guides/dictation.mdx +5 -5
  40. package/.docs/raw/docs/(docs)/guides/editing.mdx +16 -7
  41. package/.docs/raw/docs/(docs)/guides/latex.mdx +3 -0
  42. package/.docs/raw/docs/(docs)/guides/message-timing.mdx +2 -1
  43. package/.docs/raw/docs/(docs)/guides/multi-agent.mdx +173 -0
  44. package/.docs/raw/docs/(docs)/guides/quoting.mdx +55 -206
  45. package/.docs/raw/docs/(docs)/guides/speech.mdx +1 -4
  46. package/.docs/raw/docs/(docs)/guides/suggestions.mdx +9 -15
  47. package/.docs/raw/docs/(docs)/guides/tool-ui.mdx +17 -7
  48. package/.docs/raw/docs/(docs)/guides/tools.mdx +24 -9
  49. package/.docs/raw/docs/(docs)/index.mdx +3 -3
  50. package/.docs/raw/docs/(docs)/installation.mdx +69 -46
  51. package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +20 -6
  52. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +24 -4
  53. package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +1 -1
  54. package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +20 -19
  55. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +28 -53
  56. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +4 -4
  57. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +7 -1
  58. package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +20 -14
  59. package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +1 -1
  60. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +99 -45
  61. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +52 -40
  62. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +343 -23
  63. package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +4 -6
  64. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +4 -2
  65. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +3 -5
  66. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +169 -22
  67. package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +14 -4
  68. package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +15 -26
  69. package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +39 -21
  70. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +33 -9
  71. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +48 -21
  72. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +36 -7
  73. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +30 -10
  74. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +12 -10
  75. package/.docs/raw/docs/(reference)/migrations/deprecation-policy.mdx +1 -1
  76. package/.docs/raw/docs/(reference)/migrations/react-langgraph-v0-7.mdx +9 -4
  77. package/.docs/raw/docs/(reference)/migrations/v0-11.mdx +7 -5
  78. package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +9 -7
  79. package/.docs/raw/docs/(reference)/migrations/v0-14.mdx +159 -0
  80. package/.docs/raw/docs/(reference)/react-compatibility.mdx +5 -134
  81. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +89 -7
  82. package/.docs/raw/docs/cloud/ai-sdk.mdx +19 -5
  83. package/.docs/raw/docs/cloud/langgraph.mdx +13 -3
  84. package/.docs/raw/docs/ink/adapters.mdx +41 -0
  85. package/.docs/raw/docs/ink/custom-backend.mdx +203 -0
  86. package/.docs/raw/docs/ink/hooks.mdx +448 -0
  87. package/.docs/raw/docs/ink/index.mdx +239 -0
  88. package/.docs/raw/docs/ink/migration.mdx +140 -0
  89. package/.docs/raw/docs/ink/primitives.mdx +699 -0
  90. package/.docs/raw/docs/react-native/adapters.mdx +63 -87
  91. package/.docs/raw/docs/react-native/custom-backend.mdx +11 -14
  92. package/.docs/raw/docs/react-native/hooks.mdx +214 -232
  93. package/.docs/raw/docs/react-native/index.mdx +118 -159
  94. package/.docs/raw/docs/react-native/migration.mdx +144 -0
  95. package/.docs/raw/docs/react-native/primitives.mdx +431 -302
  96. package/.docs/raw/docs/runtimes/a2a/index.mdx +294 -0
  97. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +9 -9
  98. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +14 -3
  99. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +53 -0
  100. package/.docs/raw/docs/runtimes/assistant-transport.mdx +59 -25
  101. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +13 -6
  102. package/.docs/raw/docs/runtimes/custom/external-store.mdx +138 -38
  103. package/.docs/raw/docs/runtimes/custom/local.mdx +184 -42
  104. package/.docs/raw/docs/runtimes/data-stream.mdx +92 -19
  105. package/.docs/raw/docs/runtimes/google-adk/index.mdx +624 -0
  106. package/.docs/raw/docs/runtimes/helicone.mdx +6 -6
  107. package/.docs/raw/docs/runtimes/langgraph/index.mdx +38 -27
  108. package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +1 -1
  109. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +15 -20
  110. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +7 -11
  111. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +8 -11
  112. package/.docs/raw/docs/runtimes/langserve.mdx +6 -7
  113. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +18 -3
  114. package/.docs/raw/docs/ui/context-display.mdx +147 -0
  115. package/.docs/raw/docs/ui/file.mdx +5 -4
  116. package/.docs/raw/docs/ui/image.mdx +5 -4
  117. package/.docs/raw/docs/ui/markdown.mdx +3 -1
  118. package/.docs/raw/docs/ui/model-selector.mdx +8 -8
  119. package/.docs/raw/docs/ui/part-grouping.mdx +7 -10
  120. package/.docs/raw/docs/ui/quote.mdx +210 -0
  121. package/.docs/raw/docs/ui/reasoning.mdx +12 -11
  122. package/.docs/raw/docs/ui/sources.mdx +88 -17
  123. package/.docs/raw/docs/ui/streamdown.mdx +16 -7
  124. package/.docs/raw/docs/ui/thread-list.mdx +11 -13
  125. package/.docs/raw/docs/ui/thread.mdx +28 -33
  126. package/.docs/raw/docs/ui/tool-fallback.mdx +5 -6
  127. package/.docs/raw/docs/ui/tool-group.mdx +9 -8
  128. package/.docs/raw/docs/utilities/heat-graph.mdx +236 -0
  129. package/.docs/raw/docs/utilities/tw-shimmer.mdx +211 -0
  130. package/package.json +4 -4
  131. package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +0 -77
  132. package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +0 -635
  133. package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +0 -77
  134. package/.docs/raw/docs/(reference)/legacy/styled/scrollbar.mdx +0 -72
  135. package/.docs/raw/docs/(reference)/legacy/styled/thread-width.mdx +0 -22
  136. package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +0 -77
  137. /package/.docs/raw/docs/cloud/{overview.mdx → index.mdx} +0 -0
@@ -26,7 +26,7 @@ The `useChatRuntime` hook from `@assistant-ui/react-ai-sdk` wraps AI SDK's `useC
26
26
  3. Generates a conversation title after the assistant's first response
27
27
  4. Loads historical messages when switching threads via `<ThreadList />`
28
28
 
29
- You provide the AI SDK endpoint (`api: "/api/chat"`) and the cloud configuration—everything else is handled.
29
+ You provide the cloud configuration—everything else is handled. The default `AssistantChatTransport` automatically sends requests to `/api/chat`.
30
30
 
31
31
  ## Prerequisites
32
32
 
@@ -84,16 +84,21 @@ Create a client-side AssistantCloud instance and integrate it with your AI SDK r
84
84
  ```tsx title="app/chat/page.tsx"
85
85
  "use client";
86
86
 
87
+ import { useMemo } from "react";
87
88
  import { AssistantCloud, AssistantRuntimeProvider } from "@assistant-ui/react";
88
89
  import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
89
90
  import { ThreadList } from "@/components/assistant-ui/thread-list";
90
91
  import { Thread } from "@/components/assistant-ui/thread";
91
92
 
92
93
  export default function ChatPage() {
93
- const cloud = new AssistantCloud({
94
- baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
95
- anonymous: true, // Creates browser-session based user ID
96
- });
94
+ const cloud = useMemo(
95
+ () =>
96
+ new AssistantCloud({
97
+ baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
98
+ anonymous: true, // Creates browser-session based user ID
99
+ }),
100
+ [],
101
+ );
97
102
 
98
103
  const runtime = useChatRuntime({
99
104
  cloud,
@@ -114,6 +119,74 @@ export default function ChatPage() {
114
119
 
115
120
  </Steps>
116
121
 
122
+ ## `useChatRuntime` Options
123
+
124
+ <ParametersTable
125
+ parameters={[
126
+ {
127
+ name: "cloud",
128
+ type: "AssistantCloud",
129
+ description:
130
+ "Optional AssistantCloud instance for chat persistence and thread management.",
131
+ },
132
+ {
133
+ name: "adapters",
134
+ type: "RuntimeAdapters",
135
+ description:
136
+ "Optional runtime adapters to extend or override built-in functionality.",
137
+ children: [
138
+ {
139
+ type: "RuntimeAdapters",
140
+ parameters: [
141
+ {
142
+ name: "attachments",
143
+ type: "AttachmentAdapter",
144
+ description:
145
+ "Custom attachment adapter for file uploads. Defaults to the Vercel AI SDK attachment adapter.",
146
+ },
147
+ {
148
+ name: "speech",
149
+ type: "SpeechSynthesisAdapter",
150
+ description:
151
+ "Adapter for text-to-speech functionality.",
152
+ },
153
+ {
154
+ name: "dictation",
155
+ type: "DictationAdapter",
156
+ description:
157
+ "Adapter for speech-to-text dictation input.",
158
+ },
159
+ {
160
+ name: "feedback",
161
+ type: "FeedbackAdapter",
162
+ description:
163
+ "Adapter for collecting user feedback on messages.",
164
+ },
165
+ {
166
+ name: "history",
167
+ type: "ThreadHistoryAdapter",
168
+ description:
169
+ "Adapter for loading and saving thread history. Used to restore previous messages when switching threads.",
170
+ },
171
+ ],
172
+ },
173
+ ],
174
+ },
175
+ {
176
+ name: "toCreateMessage",
177
+ type: "(message: AppendMessage) => CreateUIMessage",
178
+ description:
179
+ "Optional custom function to convert an assistant-ui AppendMessage into an AI SDK CreateUIMessage before sending. Use this to customize how outgoing messages are formatted, for example to add custom metadata or transform content parts.",
180
+ },
181
+ {
182
+ name: "transport",
183
+ type: "ChatTransport",
184
+ description:
185
+ "Custom transport implementation. Defaults to AssistantChatTransport which sends requests to '/api/chat'.",
186
+ },
187
+ ]}
188
+ />
189
+
117
190
  ## Telemetry
118
191
 
119
192
  The `useChatRuntime` hook captures full run telemetry including timing data. This integrates with the assistant-ui runtime to provide:
@@ -134,19 +207,26 @@ To capture model and usage data, add the `messageMetadata` callback to your AI S
134
207
 
135
208
  ```tsx title="app/api/chat/route.ts"
136
209
  import { streamText } from "ai";
210
+ import { openai } from "@ai-sdk/openai";
137
211
 
138
212
  export async function POST(req: Request) {
213
+ const { messages } = await req.json();
214
+
139
215
  const result = streamText({
140
- model: openai("gpt-5-mini"),
216
+ model: openai("gpt-4o-mini"),
141
217
  messages,
142
218
  });
143
219
 
144
220
  return result.toUIMessageStreamResponse({
145
221
  messageMetadata: ({ part }) => {
222
+ if (part.type === "finish") {
223
+ return {
224
+ usage: part.totalUsage,
225
+ };
226
+ }
146
227
  if (part.type === "finish-step") {
147
228
  return {
148
229
  modelId: part.response.modelId,
149
- usage: part.usage,
150
230
  };
151
231
  }
152
232
  return undefined;
@@ -164,6 +244,7 @@ Use the `beforeReport` hook to add custom metadata or filter reports:
164
244
  ```tsx
165
245
  const cloud = new AssistantCloud({
166
246
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
247
+ anonymous: true,
167
248
  telemetry: {
168
249
  beforeReport: (report) => ({
169
250
  ...report,
@@ -180,6 +261,7 @@ Return `null` from `beforeReport` to skip reporting a specific run. To disable t
180
261
  The example above uses anonymous mode (browser session-based user ID) via the env var. For production apps with user accounts, pass an explicit cloud instance:
181
262
 
182
263
  ```tsx
264
+ import { useMemo } from "react";
183
265
  import { useAuth } from "@clerk/nextjs";
184
266
  import { AssistantCloud } from "@assistant-ui/react";
185
267
  import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
@@ -49,7 +49,7 @@ NEXT_PUBLIC_ASSISTANT_BASE_URL=https://proj-[YOUR-ID].assistant-api.com
49
49
 
50
50
  ### Install Dependencies
51
51
 
52
- <InstallCommand npm={["@assistant-ui/cloud-ai-sdk", "assistant-cloud", "@ai-sdk/react", "ai"]} />
52
+ <InstallCommand npm={["@assistant-ui/cloud-ai-sdk", "@ai-sdk/react", "ai"]} />
53
53
 
54
54
  </Step>
55
55
 
@@ -151,7 +151,7 @@ const chat = useCloudChat({ threads: myThreads });
151
151
  | `options.threads` | `UseThreadsResult` | External thread management from `useThreads()`. Use when you need thread operations in a separate component or custom thread options like `includeArchived` |
152
152
  | `options.onSyncError` | `(error: Error) => void` | Callback invoked when a sync error occurs |
153
153
 
154
- All other [AI SDK `useChat` options](https://sdk.vercel.ai/docs/reference/ai-sdk-ui/use-chat) are also accepted.
154
+ A subset of [AI SDK `useChat` options](https://sdk.vercel.ai/docs/reference/ai-sdk-ui/use-chat) are also accepted (those defined on `ChatInit`). Some options available on `useChat` such as `experimental_throttle` and `resume` are not supported.
155
155
 
156
156
  **Returns:** `UseCloudChatResult`
157
157
 
@@ -169,12 +169,15 @@ Plus all other properties from AI SDK's [`UseChatHelpers`](https://sdk.vercel.ai
169
169
 
170
170
  | Value | Type | Description |
171
171
  |-------|------|-------------|
172
+ | `threads.cloud` | `AssistantCloud` | The cloud instance used for thread operations |
172
173
  | `threads.threads` | `CloudThread[]` | Active threads sorted by recency |
173
174
  | `threads.threadId` | `string \| null` | Current thread ID (`null` for a new unsaved chat) |
174
175
  | `threads.selectThread` | `(id: string \| null) => void` | Switch threads or pass `null` for a new chat |
175
176
  | `threads.isLoading` | `boolean` | `true` during initial load or refresh |
176
177
  | `threads.error` | `Error \| null` | Last error, if any |
177
178
  | `threads.refresh` | `() => Promise<boolean>` | Re-fetch the thread list |
179
+ | `threads.get` | `(id: string) => Promise<CloudThread \| null>` | Fetch a single thread by ID |
180
+ | `threads.create` | `(options?: \{ externalId?: string \}) => Promise<CloudThread \| null>` | Create a new thread |
178
181
  | `threads.delete` | `(id: string) => Promise<boolean>` | Delete a thread |
179
182
  | `threads.rename` | `(id: string, title: string) => Promise<boolean>` | Rename a thread |
180
183
  | `threads.archive` | `(id: string) => Promise<boolean>` | Archive a thread |
@@ -206,31 +209,40 @@ The `useCloudChat` hook automatically reports run telemetry to Assistant Cloud a
206
209
 
207
210
  **Automatically captured:**
208
211
  - `status` — `"completed"` or `"incomplete"` based on response content
209
- - `tool_calls` — Tool invocations with name, arguments, results, and source (MCP, frontend, or backend)
212
+ - `tool_calls` — Tool invocations with name, arguments, and results. MCP tool calls are explicitly tagged with `tool_source: "mcp"`
210
213
  - `total_steps` — Number of reasoning/tool steps in the response
211
214
  - `output_text` — Full response text (truncated at 50K characters)
212
215
 
213
216
  **Requires route configuration:**
214
217
  - `model_id` — The model used for the response
215
218
  - `input_tokens` / `output_tokens` — Token usage statistics
219
+ - `reasoning_tokens` — Tokens used for chain-of-thought reasoning (e.g. o1/o3 models)
220
+ - `cached_input_tokens` — Input tokens served from the provider's prompt cache
216
221
 
217
222
  To capture model and usage data, configure the `messageMetadata` callback in your AI SDK route:
218
223
 
219
224
  ```tsx title="app/api/chat/route.ts"
220
225
  import { streamText } from "ai";
226
+ import { openai } from "@ai-sdk/openai";
221
227
 
222
228
  export async function POST(req: Request) {
229
+ const { messages } = await req.json();
230
+
223
231
  const result = streamText({
224
- model: openai("gpt-5-mini"),
232
+ model: openai("gpt-4o-mini"),
225
233
  messages,
226
234
  });
227
235
 
228
236
  return result.toUIMessageStreamResponse({
229
237
  messageMetadata: ({ part }) => {
238
+ if (part.type === "finish") {
239
+ return {
240
+ usage: part.totalUsage,
241
+ };
242
+ }
230
243
  if (part.type === "finish-step") {
231
244
  return {
232
245
  modelId: part.response.modelId,
233
- usage: part.usage,
234
246
  };
235
247
  }
236
248
  return undefined;
@@ -250,6 +262,7 @@ Use the `beforeReport` hook to enrich or filter telemetry:
250
262
  ```tsx
251
263
  const cloud = new AssistantCloud({
252
264
  baseUrl: process.env.NEXT_PUBLIC_ASSISTANT_BASE_URL!,
265
+ anonymous: true,
253
266
  telemetry: {
254
267
  beforeReport: (report) => ({
255
268
  ...report,
@@ -266,6 +279,7 @@ Return `null` from `beforeReport` to skip reporting a specific run. To disable t
266
279
  The example above uses anonymous mode (browser session-based user ID) via the env var. For production apps with user accounts, pass an explicit cloud instance:
267
280
 
268
281
  ```tsx
282
+ import { useMemo } from "react";
269
283
  import { useAuth } from "@clerk/nextjs";
270
284
  import { AssistantCloud } from "assistant-cloud";
271
285
  import { useCloudChat } from "@assistant-ui/cloud-ai-sdk";
@@ -74,7 +74,7 @@ import {
74
74
  AssistantRuntimeProvider,
75
75
  } from "@assistant-ui/react";
76
76
  import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
77
- import { createThread, getThreadState, sendMessage } from "@/lib/chatApi";
77
+ import { createThread, deleteThread, getThreadState, sendMessage } from "@/lib/chatApi";
78
78
  import { LangChainMessage } from "@assistant-ui/react-langgraph";
79
79
  import { useMemo } from "react";
80
80
 
@@ -114,6 +114,9 @@ export function MyRuntimeProvider({
114
114
  (state.values as { messages?: LangChainMessage[] }).messages ?? [],
115
115
  };
116
116
  },
117
+ delete: async (externalId) => {
118
+ await deleteThread(externalId);
119
+ },
117
120
  });
118
121
 
119
122
  return (
@@ -136,7 +139,7 @@ import {
136
139
  AssistantRuntimeProvider,
137
140
  } from "@assistant-ui/react";
138
141
  import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
139
- import { createThread, getThreadState, sendMessage } from "@/lib/chatApi";
142
+ import { createThread, deleteThread, getThreadState, sendMessage } from "@/lib/chatApi";
140
143
  import { LangChainMessage } from "@assistant-ui/react-langgraph";
141
144
  import { useAuth } from "@clerk/nextjs";
142
145
  import { useMemo } from "react";
@@ -179,6 +182,9 @@ export function MyRuntimeProvider({
179
182
  (state.values as { messages?: LangChainMessage[] }).messages ?? [],
180
183
  };
181
184
  },
185
+ delete: async (externalId) => {
186
+ await deleteThread(externalId);
187
+ },
182
188
  });
183
189
 
184
190
  return (
@@ -199,7 +205,11 @@ export function MyRuntimeProvider({
199
205
  </Tabs>
200
206
 
201
207
  <Callout type="info">
202
- The `useLangGraphRuntime` hook now directly accepts `cloud`, `create`, and `load` parameters for simplified thread management. The runtime handles thread lifecycle internally.
208
+ The `useLangGraphRuntime` hook accepts `cloud`, `create`, `load`, and `delete` parameters for simplified thread management. The runtime handles the thread lifecycle internally.
209
+
210
+ - **`create`**: Called when creating a new thread. Returns `{ externalId }` with your backend's thread ID.
211
+ - **`load`**: Called when switching to an existing thread. Returns the thread's messages (and optionally interrupts).
212
+ - **`delete`**: Called when deleting a thread. Receives the thread's `externalId`. When provided, users can delete threads from the thread list UI.
203
213
  </Callout>
204
214
 
205
215
  </Step>
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Adapters
3
+ description: Title generation adapters for React Ink.
4
+ ---
5
+
6
+ Adapters customize runtime behavior. They can be passed as options to `useLocalRuntime` or `useRemoteThreadListRuntime`.
7
+
8
+ ## RemoteThreadListAdapter
9
+
10
+ Title generation is configured via the `generateTitle` method on `RemoteThreadListAdapter`. See the [Custom Backend](/docs/ink/custom-backend) page for a full example.
11
+
12
+ ```tsx
13
+ import type { RemoteThreadListAdapter } from "@assistant-ui/react-ink";
14
+ import { createAssistantStream } from "assistant-stream";
15
+
16
+ const myAdapter: RemoteThreadListAdapter = {
17
+ // ... other methods ...
18
+
19
+ async generateTitle(remoteId, unstable_messages) {
20
+ return createAssistantStream(async (controller) => {
21
+ const res = await fetch(`/api/threads/${remoteId}/title`, {
22
+ method: "POST",
23
+ headers: { "Content-Type": "application/json" },
24
+ body: JSON.stringify({ messages: unstable_messages }),
25
+ });
26
+ const { title } = await res.json();
27
+ controller.appendText(title);
28
+ });
29
+ },
30
+ };
31
+ ```
32
+
33
+ ## Which option to choose?
34
+
35
+ | | ChatModelAdapter + `useLocalRuntime` | RemoteThreadListAdapter + `useRemoteThreadListRuntime` |
36
+ |---|---|---|
37
+ | **Thread storage** | In-memory | Your backend |
38
+ | **Message storage** | In-memory | In-memory (can add history adapter for server-side) |
39
+ | **Cross-session persistence** | No | Yes |
40
+ | **Setup complexity** | Minimal | Moderate |
41
+ | **Best for** | CLI tools, demos, prototypes | Production apps with persistence |
@@ -0,0 +1,203 @@
1
+ ---
2
+ title: Custom Backend
3
+ description: Connect your terminal app to your own backend API.
4
+ ---
5
+
6
+ By default, `useLocalRuntime` manages threads and messages in memory. You can connect to your own backend in two ways depending on your needs.
7
+
8
+ ## Option 1: ChatModelAdapter only
9
+
10
+ The simplest approach — keep thread management local, but send messages to your backend for inference.
11
+
12
+ ```tsx title="adapters/my-chat-adapter.ts"
13
+ import type { ChatModelAdapter } from "@assistant-ui/react-ink";
14
+
15
+ export const myChatAdapter: ChatModelAdapter = {
16
+ async *run({ messages, abortSignal }) {
17
+ const response = await fetch("https://my-api.com/chat", {
18
+ method: "POST",
19
+ headers: { "Content-Type": "application/json" },
20
+ body: JSON.stringify({ messages }),
21
+ signal: abortSignal,
22
+ });
23
+
24
+ const reader = response.body?.getReader();
25
+ if (!reader) throw new Error("No response body");
26
+
27
+ const decoder = new TextDecoder();
28
+ let fullText = "";
29
+
30
+ while (true) {
31
+ const { done, value } = await reader.read();
32
+ if (done) break;
33
+
34
+ const chunk = decoder.decode(value, { stream: true });
35
+ fullText += chunk;
36
+ yield { content: [{ type: "text", text: fullText }] };
37
+ }
38
+ },
39
+ };
40
+ ```
41
+
42
+ ```tsx title="app.tsx"
43
+ import { useLocalRuntime, AssistantRuntimeProvider } from "@assistant-ui/react-ink";
44
+ import { myChatAdapter } from "./adapters/my-chat-adapter.js";
45
+
46
+ export function App() {
47
+ const runtime = useLocalRuntime(myChatAdapter);
48
+ return (
49
+ <AssistantRuntimeProvider runtime={runtime}>
50
+ {/* your chat UI */}
51
+ </AssistantRuntimeProvider>
52
+ );
53
+ }
54
+ ```
55
+
56
+ This gives you:
57
+
58
+ - Streaming chat responses from your API
59
+ - In-memory thread list (lost on process exit)
60
+ - Multi-thread support
61
+
62
+ ## Option 2: Full backend thread management
63
+
64
+ When you want your backend to own thread state (e.g. for persistence across sessions, team sharing, or server-side history), implement a `RemoteThreadListAdapter`.
65
+
66
+ <Steps>
67
+ <Step>
68
+
69
+ ### Implement the adapter
70
+
71
+ ```tsx title="adapters/my-thread-list-adapter.ts"
72
+ import type { RemoteThreadListAdapter } from "@assistant-ui/react-ink";
73
+ import { createAssistantStream } from "assistant-stream";
74
+
75
+ const API_BASE = "https://my-api.com";
76
+
77
+ export const myThreadListAdapter: RemoteThreadListAdapter = {
78
+ async list() {
79
+ const res = await fetch(`${API_BASE}/threads`);
80
+ const threads = await res.json();
81
+ return {
82
+ threads: threads.map((t: any) => ({
83
+ remoteId: t.id,
84
+ status: t.archived ? "archived" : "regular",
85
+ title: t.title,
86
+ })),
87
+ };
88
+ },
89
+
90
+ async initialize(localId) {
91
+ const res = await fetch(`${API_BASE}/threads`, {
92
+ method: "POST",
93
+ headers: { "Content-Type": "application/json" },
94
+ body: JSON.stringify({ localId }),
95
+ });
96
+ const { id } = await res.json();
97
+ return { remoteId: id, externalId: undefined };
98
+ },
99
+
100
+ async rename(remoteId, title) {
101
+ await fetch(`${API_BASE}/threads/${remoteId}`, {
102
+ method: "PATCH",
103
+ headers: { "Content-Type": "application/json" },
104
+ body: JSON.stringify({ title }),
105
+ });
106
+ },
107
+
108
+ async archive(remoteId) {
109
+ await fetch(`${API_BASE}/threads/${remoteId}/archive`, {
110
+ method: "POST",
111
+ });
112
+ },
113
+
114
+ async unarchive(remoteId) {
115
+ await fetch(`${API_BASE}/threads/${remoteId}/unarchive`, {
116
+ method: "POST",
117
+ });
118
+ },
119
+
120
+ async delete(remoteId) {
121
+ await fetch(`${API_BASE}/threads/${remoteId}`, { method: "DELETE" });
122
+ },
123
+
124
+ async fetch(remoteId) {
125
+ const res = await fetch(`${API_BASE}/threads/${remoteId}`);
126
+ const t = await res.json();
127
+ return {
128
+ remoteId: t.id,
129
+ status: t.archived ? "archived" : "regular",
130
+ title: t.title,
131
+ };
132
+ },
133
+
134
+ async generateTitle(remoteId, unstable_messages) {
135
+ return createAssistantStream(async (controller) => {
136
+ const res = await fetch(`${API_BASE}/threads/${remoteId}/title`, {
137
+ method: "POST",
138
+ headers: { "Content-Type": "application/json" },
139
+ body: JSON.stringify({ messages: unstable_messages }),
140
+ });
141
+ const { title } = await res.json();
142
+ controller.appendText(title);
143
+ });
144
+ },
145
+ };
146
+ ```
147
+
148
+ </Step>
149
+ <Step>
150
+
151
+ ### Compose the runtime
152
+
153
+ ```tsx title="app.tsx"
154
+ import {
155
+ useLocalRuntime,
156
+ useRemoteThreadListRuntime,
157
+ AssistantRuntimeProvider,
158
+ } from "@assistant-ui/react-ink";
159
+ import { myChatAdapter } from "./adapters/my-chat-adapter.js";
160
+ import { myThreadListAdapter } from "./adapters/my-thread-list-adapter.js";
161
+
162
+ function useAppRuntime() {
163
+ return useRemoteThreadListRuntime({
164
+ runtimeHook: () => useLocalRuntime(myChatAdapter),
165
+ adapter: myThreadListAdapter,
166
+ });
167
+ }
168
+
169
+ export function App() {
170
+ const runtime = useAppRuntime();
171
+ return (
172
+ <AssistantRuntimeProvider runtime={runtime}>
173
+ {/* your chat UI */}
174
+ </AssistantRuntimeProvider>
175
+ );
176
+ }
177
+ ```
178
+
179
+ </Step>
180
+ </Steps>
181
+
182
+ ## Adapter methods
183
+
184
+ | Method | Description |
185
+ |--------|-------------|
186
+ | `list()` | Return all threads on mount |
187
+ | `initialize(localId)` | Create a thread server-side, return `{ remoteId }` |
188
+ | `rename(remoteId, title)` | Persist title changes |
189
+ | `archive(remoteId)` | Mark thread as archived |
190
+ | `unarchive(remoteId)` | Restore archived thread |
191
+ | `delete(remoteId)` | Permanently remove thread |
192
+ | `fetch(remoteId)` | Fetch single thread metadata |
193
+ | `generateTitle(remoteId, unstable_messages)` | Return an `AssistantStream` with the generated title |
194
+
195
+ ## Which option to choose?
196
+
197
+ | | Option 1: ChatModelAdapter | Option 2: RemoteThreadListAdapter |
198
+ |---|---|---|
199
+ | **Thread storage** | In-memory (process lifetime) | Your backend |
200
+ | **Message storage** | In-memory | On-device (can add history adapter for server-side) |
201
+ | **Cross-session persistence** | No | Yes |
202
+ | **Setup complexity** | Minimal | Moderate |
203
+ | **Best for** | CLI tools, demos, prototypes | Production apps with persistence |