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

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 (341) hide show
  1. package/.docs/organized/code-examples/waterfall.md +8 -8
  2. package/.docs/organized/code-examples/with-a2a.md +10 -10
  3. package/.docs/organized/code-examples/with-ag-ui.md +12 -12
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +14 -14
  5. package/.docs/organized/code-examples/with-artifacts.md +14 -14
  6. package/.docs/organized/code-examples/with-assistant-transport.md +11 -11
  7. package/.docs/organized/code-examples/with-browser-extension.md +345 -0
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +129 -63
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +13 -13
  10. package/.docs/organized/code-examples/with-cloud.md +13 -13
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +65 -20
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +18 -17
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +18 -17
  14. package/.docs/organized/code-examples/with-expo.md +25 -25
  15. package/.docs/organized/code-examples/with-external-store.md +10 -10
  16. package/.docs/organized/code-examples/with-ffmpeg.md +14 -14
  17. package/.docs/organized/code-examples/with-generative-ui.md +211 -14
  18. package/.docs/organized/code-examples/with-google-adk.md +12 -12
  19. package/.docs/organized/code-examples/with-heat-graph.md +8 -8
  20. package/.docs/organized/code-examples/with-image-generation.md +454 -0
  21. package/.docs/organized/code-examples/with-interactables.md +14 -14
  22. package/.docs/organized/code-examples/with-langchain.md +12 -12
  23. package/.docs/organized/code-examples/with-langgraph.md +15 -12
  24. package/.docs/organized/code-examples/with-livekit.md +19 -18
  25. package/.docs/organized/code-examples/with-mcp.md +748 -0
  26. package/.docs/organized/code-examples/with-opencode.md +107 -62
  27. package/.docs/organized/code-examples/with-parent-id-grouping.md +12 -12
  28. package/.docs/organized/code-examples/with-react-hook-form.md +14 -14
  29. package/.docs/organized/code-examples/with-react-ink.md +4 -4
  30. package/.docs/organized/code-examples/with-react-router.md +16 -16
  31. package/.docs/organized/code-examples/with-resumable-stream.md +660 -0
  32. package/.docs/organized/code-examples/with-store.md +8 -8
  33. package/.docs/organized/code-examples/with-tanstack.md +14 -14
  34. package/.docs/organized/code-examples/with-tap-runtime.md +11 -10
  35. package/.docs/raw/docs/(docs)/cli.mdx +3 -1
  36. package/.docs/raw/docs/(docs)/copilots/assistant-frame.mdx +1 -0
  37. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +10 -3
  38. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +8 -3
  39. package/.docs/raw/docs/(docs)/copilots/make-assistant-visible.mdx +1 -0
  40. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +1 -0
  41. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +1 -0
  42. package/.docs/raw/docs/(docs)/copilots/use-assistant-instructions.mdx +1 -0
  43. package/.docs/raw/docs/(docs)/devtools.mdx +1 -0
  44. package/.docs/raw/docs/(docs)/index.mdx +3 -2
  45. package/.docs/raw/docs/(docs)/installation.mdx +2 -1
  46. package/.docs/raw/docs/(docs)/rtl.mdx +1 -0
  47. package/.docs/raw/docs/(reference)/api-reference/adapters/attachments.mdx +36 -0
  48. package/.docs/raw/docs/(reference)/api-reference/adapters/feedback.mdx +20 -0
  49. package/.docs/raw/docs/(reference)/api-reference/adapters/index.mdx +34 -0
  50. package/.docs/raw/docs/(reference)/api-reference/adapters/model.mdx +44 -0
  51. package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +55 -0
  52. package/.docs/raw/docs/(reference)/api-reference/adapters/runtime.mdx +20 -0
  53. package/.docs/raw/docs/(reference)/api-reference/adapters/suggestions.mdx +20 -0
  54. package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +37 -8
  55. package/.docs/raw/docs/(reference)/api-reference/context-providers/index.mdx +22 -0
  56. package/.docs/raw/docs/(reference)/api-reference/context-providers/scoped-providers.mdx +64 -0
  57. package/.docs/raw/docs/(reference)/api-reference/external-store/index.mdx +22 -0
  58. package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +52 -0
  59. package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +36 -0
  60. package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +98 -0
  61. package/.docs/raw/docs/(reference)/api-reference/hooks/index.mdx +31 -0
  62. package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +33 -0
  63. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +640 -0
  64. package/.docs/raw/docs/(reference)/api-reference/hooks/runtimes.mdx +28 -0
  65. package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +94 -0
  66. package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +464 -0
  67. package/.docs/raw/docs/(reference)/api-reference/integrations/cloud-ai-sdk.mdx +24 -0
  68. package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +22 -0
  69. package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +79 -0
  70. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +52 -0
  71. package/.docs/raw/docs/(reference)/api-reference/model-context/index.mdx +22 -0
  72. package/.docs/raw/docs/(reference)/api-reference/model-context/registry.mdx +20 -0
  73. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +125 -125
  74. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +78 -221
  75. package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +127 -242
  76. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +46 -20
  77. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +66 -87
  78. package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +50 -58
  79. package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +80 -48
  80. package/.docs/raw/docs/(reference)/api-reference/primitives/chain-of-thought.mdx +67 -0
  81. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +323 -461
  82. package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +36 -43
  83. package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +70 -0
  84. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +63 -245
  85. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +182 -554
  86. package/.docs/raw/docs/(reference)/api-reference/primitives/queue-item.mdx +65 -0
  87. package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +35 -22
  88. package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +57 -140
  89. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +70 -161
  90. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +84 -108
  91. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +82 -86
  92. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +173 -314
  93. package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +9 -21
  94. package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +10 -21
  95. package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +15 -70
  96. package/.docs/raw/docs/(reference)/api-reference/runtimes/index.mdx +43 -0
  97. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +25 -28
  98. package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +11 -63
  99. package/.docs/raw/docs/(reference)/api-reference/runtimes/queue-state.mdx +20 -0
  100. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +11 -48
  101. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +10 -42
  102. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +18 -30
  103. package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +68 -0
  104. package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +39 -0
  105. package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +79 -0
  106. package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +42 -0
  107. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +92 -0
  108. package/.docs/raw/docs/(reference)/api-reference/transport/assistant-transport.mdx +48 -0
  109. package/.docs/raw/docs/(reference)/api-reference/transport/frame.mdx +62 -0
  110. package/.docs/raw/docs/(reference)/api-reference/transport/index.mdx +22 -0
  111. package/.docs/raw/docs/(reference)/api-reference/utilities/index.mdx +19 -0
  112. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +131 -0
  113. package/.docs/raw/docs/(reference)/api-reference/voice/index.mdx +22 -0
  114. package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +54 -0
  115. package/.docs/raw/docs/(reference)/api-reference/voice/speech-dictation.mdx +36 -0
  116. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +230 -2
  117. package/.docs/raw/docs/cloud/ai-sdk.mdx +222 -4
  118. package/.docs/raw/docs/cloud/index.mdx +2 -2
  119. package/.docs/raw/docs/cloud/langgraph.mdx +274 -2
  120. package/.docs/raw/docs/{(docs)/guides → guides}/attachments.mdx +45 -40
  121. package/.docs/raw/docs/guides/branching.mdx +76 -0
  122. package/.docs/raw/docs/guides/chain-of-thought.mdx +166 -0
  123. package/.docs/raw/docs/{(docs)/guides → guides}/context-api.mdx +54 -26
  124. package/.docs/raw/docs/{(docs)/guides → guides}/dictation.mdx +3 -1
  125. package/.docs/raw/docs/guides/editing.mdx +102 -0
  126. package/.docs/raw/docs/guides/generative-ui.mdx +142 -0
  127. package/.docs/raw/docs/guides/image-generation.mdx +74 -0
  128. package/.docs/raw/docs/guides/index.mdx +103 -0
  129. package/.docs/raw/docs/{(docs)/guides → guides}/interactables.mdx +51 -2
  130. package/.docs/raw/docs/{(docs)/guides → guides}/latex.mdx +53 -10
  131. package/.docs/raw/docs/guides/mcp-apps.mdx +231 -0
  132. package/.docs/raw/docs/{(docs)/guides → guides}/mentions.mdx +63 -88
  133. package/.docs/raw/docs/{(docs)/guides → guides}/message-timing.mdx +45 -6
  134. package/.docs/raw/docs/{(docs)/guides → guides}/multi-agent.mdx +66 -6
  135. package/.docs/raw/docs/{(docs)/guides → guides}/quoting.mdx +11 -18
  136. package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +212 -0
  137. package/.docs/raw/docs/guides/resumable-stream-stores.mdx +152 -0
  138. package/.docs/raw/docs/guides/resumable-streams.mdx +210 -0
  139. package/.docs/raw/docs/{(docs)/guides → guides}/slash-commands.mdx +104 -38
  140. package/.docs/raw/docs/guides/speech.mdx +156 -0
  141. package/.docs/raw/docs/{(docs)/guides → guides}/suggestions.mdx +91 -69
  142. package/.docs/raw/docs/{(docs)/guides → guides}/tool-ui.mdx +110 -38
  143. package/.docs/raw/docs/{(docs)/guides → guides}/tools.mdx +197 -40
  144. package/.docs/raw/docs/{(docs)/guides → guides}/voice.mdx +41 -2
  145. package/.docs/raw/docs/ink/adapters.mdx +37 -1
  146. package/.docs/raw/docs/ink/custom-backend.mdx +59 -8
  147. package/.docs/raw/docs/ink/index.mdx +11 -14
  148. package/.docs/raw/docs/ink/migration.mdx +1 -3
  149. package/.docs/raw/docs/ink/primitives.mdx +386 -9
  150. package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +520 -0
  151. package/.docs/raw/docs/integrations/auth/better-auth.mdx +191 -0
  152. package/.docs/raw/docs/integrations/auth/clerk.mdx +172 -0
  153. package/.docs/raw/docs/integrations/auth/next-auth.mdx +196 -0
  154. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +79 -0
  155. package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +282 -0
  156. package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +188 -0
  157. package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +57 -0
  158. package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +201 -0
  159. package/.docs/raw/docs/integrations/gateways/index.mdx +162 -0
  160. package/.docs/raw/docs/integrations/index.mdx +185 -0
  161. package/.docs/raw/docs/integrations/observability/helicone.mdx +130 -0
  162. package/.docs/raw/docs/integrations/observability/langfuse.mdx +163 -0
  163. package/.docs/raw/docs/integrations/observability/langsmith.mdx +150 -0
  164. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +712 -0
  165. package/.docs/raw/docs/integrations/tools/mcp.mdx +267 -0
  166. package/.docs/raw/docs/integrations/tools/react-mcp.mdx +337 -0
  167. package/.docs/raw/docs/migrations/v0-14.mdx +297 -0
  168. package/.docs/raw/docs/primitives/action-bar.mdx +1 -0
  169. package/.docs/raw/docs/primitives/assistant-modal.mdx +1 -0
  170. package/.docs/raw/docs/primitives/attachment.mdx +1 -0
  171. package/.docs/raw/docs/primitives/branch-picker.mdx +1 -0
  172. package/.docs/raw/docs/primitives/chain-of-thought.mdx +90 -85
  173. package/.docs/raw/docs/primitives/composer.mdx +55 -1
  174. package/.docs/raw/docs/primitives/error.mdx +1 -0
  175. package/.docs/raw/docs/primitives/index.mdx +4 -3
  176. package/.docs/raw/docs/primitives/message.mdx +68 -5
  177. package/.docs/raw/docs/primitives/selection-toolbar.mdx +1 -0
  178. package/.docs/raw/docs/primitives/suggestion.mdx +10 -0
  179. package/.docs/raw/docs/primitives/thread-list.mdx +39 -0
  180. package/.docs/raw/docs/primitives/thread.mdx +16 -13
  181. package/.docs/raw/docs/react-native/hooks.mdx +2 -2
  182. package/.docs/raw/docs/react-native/index.mdx +5 -7
  183. package/.docs/raw/docs/react-native/migration.mdx +1 -3
  184. package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +396 -0
  185. package/.docs/raw/docs/runtimes/a2a/overview.mdx +60 -0
  186. package/.docs/raw/docs/runtimes/a2a/quickstart.mdx +216 -0
  187. package/.docs/raw/docs/runtimes/ag-ui/overview.mdx +70 -0
  188. package/.docs/raw/docs/runtimes/ag-ui/quickstart.mdx +243 -0
  189. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +154 -0
  190. package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +52 -0
  191. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +73 -128
  192. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +70 -64
  193. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +337 -123
  194. package/.docs/raw/docs/runtimes/concepts/adapters.mdx +265 -0
  195. package/.docs/raw/docs/runtimes/concepts/architecture.mdx +125 -0
  196. package/.docs/raw/docs/runtimes/concepts/stability.mdx +67 -0
  197. package/.docs/raw/docs/runtimes/concepts/threads.mdx +428 -0
  198. package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +703 -0
  199. package/.docs/raw/docs/runtimes/custom/data-stream.mdx +348 -0
  200. package/.docs/raw/docs/runtimes/custom/external-store.mdx +261 -1236
  201. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +746 -0
  202. package/.docs/raw/docs/runtimes/custom/overview.mdx +71 -0
  203. package/.docs/raw/docs/runtimes/google-adk/api.mdx +256 -0
  204. package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +717 -0
  205. package/.docs/raw/docs/runtimes/google-adk/overview.mdx +69 -0
  206. package/.docs/raw/docs/runtimes/google-adk/quickstart.mdx +229 -0
  207. package/.docs/raw/docs/runtimes/langchain.mdx +533 -0
  208. package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +305 -0
  209. package/.docs/raw/docs/runtimes/langgraph/interrupts.mdx +104 -0
  210. package/.docs/raw/docs/runtimes/langgraph/overview.mdx +84 -0
  211. package/.docs/raw/docs/runtimes/langgraph/quickstart.mdx +496 -0
  212. package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +127 -0
  213. package/.docs/raw/docs/runtimes/langgraph/threads.mdx +113 -0
  214. package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +3 -3
  215. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +0 -23
  216. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
  217. package/.docs/raw/docs/runtimes/opencode/hooks.mdx +191 -0
  218. package/.docs/raw/docs/runtimes/opencode/overview.mdx +48 -0
  219. package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +119 -0
  220. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +78 -203
  221. package/.docs/raw/docs/ui/accordion.mdx +1 -0
  222. package/.docs/raw/docs/ui/assistant-modal.mdx +1 -0
  223. package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -0
  224. package/.docs/raw/docs/ui/attachment.mdx +1 -0
  225. package/.docs/raw/docs/ui/badge.mdx +1 -0
  226. package/.docs/raw/docs/ui/composer-trigger-popover.mdx +12 -1
  227. package/.docs/raw/docs/ui/context-display.mdx +1 -0
  228. package/.docs/raw/docs/ui/diff-viewer.mdx +1 -0
  229. package/.docs/raw/docs/ui/directive-text.mdx +1 -0
  230. package/.docs/raw/docs/ui/file.mdx +1 -0
  231. package/.docs/raw/docs/ui/image.mdx +1 -0
  232. package/.docs/raw/docs/ui/markdown.mdx +2 -14
  233. package/.docs/raw/docs/ui/mcp-config.mdx +102 -0
  234. package/.docs/raw/docs/ui/mermaid.mdx +1 -0
  235. package/.docs/raw/docs/ui/message-timing.mdx +3 -2
  236. package/.docs/raw/docs/ui/model-selector.mdx +9 -8
  237. package/.docs/raw/docs/ui/part-grouping.mdx +325 -313
  238. package/.docs/raw/docs/ui/quote.mdx +1 -0
  239. package/.docs/raw/docs/ui/reasoning.mdx +66 -33
  240. package/.docs/raw/docs/ui/scrollbar.mdx +1 -0
  241. package/.docs/raw/docs/ui/select.mdx +1 -0
  242. package/.docs/raw/docs/ui/sources.mdx +18 -0
  243. package/.docs/raw/docs/ui/streamdown.mdx +35 -2
  244. package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -0
  245. package/.docs/raw/docs/ui/tabs.mdx +1 -0
  246. package/.docs/raw/docs/ui/thread-list.mdx +19 -2
  247. package/.docs/raw/docs/ui/thread.mdx +58 -3
  248. package/.docs/raw/docs/ui/tool-fallback.mdx +1 -0
  249. package/.docs/raw/docs/ui/tool-group.mdx +39 -11
  250. package/.docs/raw/docs/ui/voice.mdx +1 -0
  251. package/.docs/raw/docs/utilities/heat-graph.mdx +1 -0
  252. package/.docs/raw/docs/utilities/react-o11y.mdx +278 -0
  253. package/.docs/raw/docs/utilities/tw-shimmer.mdx +1 -0
  254. package/README.md +14 -72
  255. package/dist/constants.d.ts +12 -9
  256. package/dist/constants.d.ts.map +1 -1
  257. package/dist/constants.js +13 -9
  258. package/dist/constants.js.map +1 -1
  259. package/dist/index.d.ts +7 -3
  260. package/dist/index.d.ts.map +1 -1
  261. package/dist/index.js +25 -24
  262. package/dist/index.js.map +1 -1
  263. package/dist/prepare-docs/code-examples.d.ts +4 -1
  264. package/dist/prepare-docs/code-examples.d.ts.map +1 -1
  265. package/dist/prepare-docs/code-examples.js +109 -121
  266. package/dist/prepare-docs/code-examples.js.map +1 -1
  267. package/dist/prepare-docs/copy-raw.d.ts +4 -1
  268. package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
  269. package/dist/prepare-docs/copy-raw.js +45 -42
  270. package/dist/prepare-docs/copy-raw.js.map +1 -1
  271. package/dist/prepare-docs/prepare.d.ts +1 -2
  272. package/dist/prepare-docs/prepare.js +17 -17
  273. package/dist/prepare-docs/prepare.js.map +1 -1
  274. package/dist/stdio.d.ts +1 -3
  275. package/dist/stdio.js +6 -3
  276. package/dist/stdio.js.map +1 -1
  277. package/dist/tools/docs.d.ts +20 -15
  278. package/dist/tools/docs.d.ts.map +1 -1
  279. package/dist/tools/docs.js +140 -161
  280. package/dist/tools/docs.js.map +1 -1
  281. package/dist/tools/examples.d.ts +20 -15
  282. package/dist/tools/examples.d.ts.map +1 -1
  283. package/dist/tools/examples.js +74 -86
  284. package/dist/tools/examples.js.map +1 -1
  285. package/dist/tools/tests/test-setup.d.ts +5 -2
  286. package/dist/tools/tests/test-setup.d.ts.map +1 -1
  287. package/dist/tools/tests/test-setup.js +21 -28
  288. package/dist/tools/tests/test-setup.js.map +1 -1
  289. package/dist/utils/logger.d.ts +8 -5
  290. package/dist/utils/logger.d.ts.map +1 -1
  291. package/dist/utils/logger.js +17 -17
  292. package/dist/utils/logger.js.map +1 -1
  293. package/dist/utils/mcp-format.d.ts +8 -5
  294. package/dist/utils/mcp-format.d.ts.map +1 -1
  295. package/dist/utils/mcp-format.js +9 -9
  296. package/dist/utils/mcp-format.js.map +1 -1
  297. package/dist/utils/mdx.d.ts +8 -6
  298. package/dist/utils/mdx.d.ts.map +1 -1
  299. package/dist/utils/mdx.js +22 -22
  300. package/dist/utils/mdx.js.map +1 -1
  301. package/dist/utils/paths.d.ts +9 -6
  302. package/dist/utils/paths.d.ts.map +1 -1
  303. package/dist/utils/paths.js +66 -76
  304. package/dist/utils/paths.js.map +1 -1
  305. package/dist/utils/security.d.ts +4 -1
  306. package/dist/utils/security.d.ts.map +1 -1
  307. package/dist/utils/security.js +19 -40
  308. package/dist/utils/security.js.map +1 -1
  309. package/package.json +6 -6
  310. package/src/tools/tests/path-traversal.test.ts +1 -1
  311. package/.docs/raw/docs/(docs)/guides/branching.mdx +0 -65
  312. package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +0 -164
  313. package/.docs/raw/docs/(docs)/guides/editing.mdx +0 -66
  314. package/.docs/raw/docs/(docs)/guides/speech.mdx +0 -38
  315. package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +0 -40
  316. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +0 -260
  317. package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +0 -103
  318. package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +0 -254
  319. package/.docs/raw/docs/(reference)/migrations/v0-14.mdx +0 -159
  320. package/.docs/raw/docs/runtimes/a2a/index.mdx +0 -298
  321. package/.docs/raw/docs/runtimes/assistant-transport.mdx +0 -1033
  322. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +0 -314
  323. package/.docs/raw/docs/runtimes/custom/local.mdx +0 -1464
  324. package/.docs/raw/docs/runtimes/data-stream.mdx +0 -422
  325. package/.docs/raw/docs/runtimes/google-adk/index.mdx +0 -686
  326. package/.docs/raw/docs/runtimes/helicone.mdx +0 -61
  327. package/.docs/raw/docs/runtimes/langchain/comparison.mdx +0 -60
  328. package/.docs/raw/docs/runtimes/langchain/index.mdx +0 -210
  329. package/.docs/raw/docs/runtimes/langgraph/index.mdx +0 -699
  330. package/.docs/raw/docs/runtimes/langgraph/tutorial/index.mdx +0 -12
  331. package/.docs/raw/docs/runtimes/langserve.mdx +0 -116
  332. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +0 -218
  333. package/.docs/raw/docs/runtimes/mastra/overview.mdx +0 -18
  334. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +0 -217
  335. package/dist/prepare-docs/prepare.d.ts.map +0 -1
  336. package/dist/stdio.d.ts.map +0 -1
  337. /package/.docs/raw/docs/{(reference)/migrations → migrations}/deprecation-policy.mdx +0 -0
  338. /package/.docs/raw/docs/{(reference) → migrations}/react-compatibility.mdx +0 -0
  339. /package/.docs/raw/docs/{(reference)/migrations → migrations}/react-langgraph-v0-7.mdx +0 -0
  340. /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-11.mdx +0 -0
  341. /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-12.mdx +0 -0
@@ -0,0 +1,152 @@
1
+ ---
2
+ title: Custom Resumable Stream Stores
3
+ description: Implement the ResumableStreamStore interface to back resumable streams with Postgres, Cloudflare Durable Objects, Upstash REST, InstantDB, or any other backend.
4
+ platforms: ["react"]
5
+ ---
6
+
7
+ The built-in InMemory and Redis adapters cover most deployments. Write your own `ResumableStreamStore` when you need a backend you already operate (Postgres, MySQL), an edge-native primitive (Cloudflare Durable Objects, Workers KV), an HTTP-only key-value service (Upstash REST), or a realtime database (InstantDB). The contract is six async methods over an opaque `streamId` and a monotonic byte log.
8
+
9
+ ## Interface walkthrough
10
+
11
+ The full interface lives in `assistant-stream/resumable`:
12
+
13
+ ```ts title="packages/assistant-stream/src/resumable/types.ts"
14
+ export interface ResumableStreamStore {
15
+ acquire(
16
+ streamId: string,
17
+ options?: ResumableStreamAcquireOptions,
18
+ ): Promise<ResumableStreamRole>;
19
+ append(streamId: string, chunk: Uint8Array): Promise<void>;
20
+ finalize(
21
+ streamId: string,
22
+ status: "done" | "error",
23
+ error?: string,
24
+ ): Promise<void>;
25
+ read(
26
+ streamId: string,
27
+ cursor: string,
28
+ signal: AbortSignal,
29
+ ): AsyncIterable<ResumableStreamEntry>;
30
+ status(streamId: string): Promise<ResumableStreamStatus>;
31
+ delete(streamId: string): Promise<void>;
32
+ }
33
+ ```
34
+
35
+ `acquire(streamId, options?)` arbitrates ownership. The first caller for a given `streamId` resolves to `"producer"`; every later caller, including those arriving after `finalize`, resolves to `"consumer"`. Implementations must perform the check and the insert atomically (see below). `options.ttlMs` overrides the store default for this stream; honor it when you set the expiration timestamp.
36
+
37
+ `append(streamId, chunk)` adds a `Uint8Array` to the log under a fresh, monotonically increasing cursor. Callers expect the chunk to be observable to `read` before the promise resolves. Implementations should refresh the TTL on each call so a stream that is still actively producing does not expire mid-flight, and should reject when the stream is missing or already finalized.
38
+
39
+ `finalize(streamId, status, error?)` flips the stream into a terminal state. Pending and future `read` iterables drain buffered entries and then either complete (`"done"`) or throw with `error` (`"error"`). Implementations must make `finalize` idempotent: a duplicate call with the same status is a no-op, and the producer task may retry on transient errors.
40
+
41
+ `read(streamId, cursor, signal)` is the only streaming method. It yields every entry whose cursor sorts strictly after the supplied `cursor`, then waits for new appends, then completes when the stream finalizes. Aborting `signal` resolves the iterable cleanly without throwing. Networked stores typically combine a bounded fetch loop with pub/sub, long-poll, or notify wakeups; do not busy-loop.
42
+
43
+ `status(streamId)` returns one of `"streaming" | "done" | "error" | "missing"` synchronously with respect to the underlying store. It exists so the context can decide whether to start a new producer or attach a consumer without holding a `read` iterator open.
44
+
45
+ `delete(streamId)` removes all state for the stream. It must be a no-op when the stream does not exist, and it should cause active `read` iterables to terminate (treat outstanding readers as if the stream finalized).
46
+
47
+ ## Acquire semantics
48
+
49
+ `acquire` is the only method that requires linearizability across processes. Two route handlers that race to start the same `streamId` must see exactly one `"producer"` result; the loser becomes a `"consumer"` and replays the winner's bytes. A single-process store can guard a `Map` with a synchronous `if (!map.has(id)) map.set(id, ...)`. Networked stores need a primitive that does the check and the insert in one round trip:
50
+
51
+ - Redis: `SET key value NX EX ttl`, or `INCR` against a per-stream counter.
52
+ - Postgres: `INSERT ... ON CONFLICT (stream_id) DO NOTHING RETURNING ...`.
53
+ - Durable Objects: a single object instance per `streamId` plus a boolean field.
54
+ - Upstash REST: `set` with `nx=true`.
55
+
56
+ If your backend cannot offer atomicity, do not paper over it with read-then-write; you will silently produce two writers for the same stream under contention, and consumers will observe interleaved bytes.
57
+
58
+ ## The cursor contract
59
+
60
+ Cursors are opaque strings. Callers never inspect them; the store assigns them, the context echoes them back on the next `read` call, and the store uses them to resume from the correct position. Two rules:
61
+
62
+ - Cursors must be strictly monotonic per stream. Whatever scheme you pick (sequence number, ULID, Postgres `bigserial`, Redis stream id), entry N+1 sorts after entry N.
63
+ - The empty string means start from the beginning. `read(streamId, "", signal)` yields every entry the store has, oldest first.
64
+
65
+ You do not need cross-stream ordering. You do need a deterministic mapping from cursor back to position so that `read` can resume a consumer that disconnected mid-replay.
66
+
67
+ ## A worked example
68
+
69
+ A `Map`-backed implementation suitable for a single-process server. It is deliberately small and skips TTL eviction; treat it as a starting point for a custom backend rather than a replacement for `createInMemoryResumableStreamStore`.
70
+
71
+ ```ts title="/lib/map-resumable-store.ts"
72
+ import type { ResumableStreamStore } from "assistant-stream/resumable";
73
+
74
+ type State = {
75
+ entries: { cursor: string; chunk: Uint8Array }[];
76
+ seq: number;
77
+ final?: { status: "done" | "error"; error?: string };
78
+ waiters: Array<() => void>;
79
+ };
80
+
81
+ export function createMapResumableStreamStore(): ResumableStreamStore {
82
+ const streams = new Map<string, State>();
83
+ const wake = (s: State) => s.waiters.splice(0).forEach((fn) => fn());
84
+ return {
85
+ async acquire(id) {
86
+ if (streams.has(id)) return "consumer";
87
+ streams.set(id, { entries: [], seq: 0, waiters: [] });
88
+ return "producer";
89
+ },
90
+ async append(id, chunk) {
91
+ const s = streams.get(id);
92
+ if (!s || s.final) throw new Error(`Cannot append: ${id}`);
93
+ s.entries.push({ cursor: (++s.seq).toString(36), chunk });
94
+ wake(s);
95
+ },
96
+ async finalize(id, status, error) {
97
+ const s = streams.get(id);
98
+ if (!s || s.final) return;
99
+ s.final = { status, error };
100
+ wake(s);
101
+ },
102
+ async *read(id, cursor, signal) {
103
+ const s = streams.get(id);
104
+ if (!s) throw new Error(`Stream not found: ${id}`);
105
+ let i = cursor === "" ? 0 : Number.parseInt(cursor, 36);
106
+ while (!signal.aborted) {
107
+ while (i < s.entries.length) yield s.entries[i++]!;
108
+ if (s.final) {
109
+ if (s.final.status === "error") throw new Error(s.final.error);
110
+ return;
111
+ }
112
+ await new Promise<void>((r) => {
113
+ s.waiters.push(r);
114
+ signal.addEventListener("abort", () => r(), { once: true });
115
+ });
116
+ }
117
+ },
118
+ async status(id) {
119
+ const s = streams.get(id);
120
+ return !s ? "missing" : s.final ? s.final.status : "streaming";
121
+ },
122
+ async delete(id) {
123
+ const s = streams.get(id);
124
+ if (!s) return;
125
+ streams.delete(id);
126
+ s.final ??= { status: "done" };
127
+ wake(s);
128
+ },
129
+ };
130
+ }
131
+ ```
132
+
133
+ ## TTL and eviction
134
+
135
+ `acquire` receives `options.ttlMs`; if absent, fall back to a store-level default (the built-in stores use 24 hours). Refresh the expiration on every `append` and on `finalize` so a stream that finishes near the deadline still has time to be consumed. Persist the TTL alongside the entries so a worker reading the stream much later can decide whether the data is still valid.
136
+
137
+ When a stream expires, treat it the same as `finalize(streamId, "error", "Stream expired")`: any active `read` iterable must throw or terminate, and `status` must transition to `"missing"` once the eviction has run. Stores backed by Redis or a similar TTL-aware engine can lean on the engine's own expiration; SQL-backed stores need a periodic sweep, and Durable Objects can use `setAlarm`.
138
+
139
+ ## Wiring it up
140
+
141
+ `createResumableStreamContext` takes any object that satisfies `ResumableStreamStore`. There is no registry and no extra configuration; pass your instance as `store`:
142
+
143
+ ```ts title="/lib/resumable-context.ts"
144
+ import { createResumableStreamContext } from "assistant-stream/resumable";
145
+ import { createMapResumableStreamStore } from "@/lib/map-resumable-store";
146
+
147
+ export const resumableContext = createResumableStreamContext({
148
+ store: createMapResumableStreamStore(),
149
+ });
150
+ ```
151
+
152
+ From this point the route handlers in [Resumable Streams](/docs/guides/resumable-streams) work unchanged: `resumableContext.run(streamId, makeStream)` calls your `acquire`, `append`, and `finalize`, and `resumableContext.resume(streamId)` calls your `read`.
@@ -0,0 +1,210 @@
1
+ ---
2
+ title: "Resumable Streams"
3
+ description: Persist an in-flight LLM response on the server so the client can reload, lose its connection, or open a new tab and pick up the same stream.
4
+ platforms: ["react"]
5
+ ---
6
+
7
+ `assistant-stream/resumable` lets you continue a streaming LLM response across client reconnects. The server keeps writing to a store while the original request is in flight; if the browser reloads or loses its connection, a follow-up request replays the persisted bytes plus any new ones until the producer finalizes.
8
+
9
+ It works with any encoder that already ships in `assistant-stream` (the AI SDK UI message stream, the data stream protocol, the assistant transport SSE format, or your own), because persistence happens at the byte level after encoding.
10
+
11
+ ## What it solves
12
+
13
+ A user sends a long prompt, walks away, and reloads the tab. Without resumable streams the LLM call is wasted; with them the client picks up where it left off. The same flow handles dropped mobile connections and lets a stream started on one device be read on another, gated by an opaque stream id.
14
+
15
+ If your responses are short or you do not care about reload survival, the standard `streamText().toUIMessageStreamResponse()` path is enough.
16
+
17
+ ## Server side: minimum wiring
18
+
19
+ Construct a `ResumableStreamContext` once per process and reuse it across requests. The context is the seam between your route handlers and the storage backend.
20
+
21
+ ```ts title="/lib/resumable-context.ts"
22
+ import {
23
+ createInMemoryResumableStreamStore,
24
+ createResumableStreamContext,
25
+ } from "assistant-stream/resumable";
26
+
27
+ const store = createInMemoryResumableStreamStore();
28
+ export const resumableContext = createResumableStreamContext({ store });
29
+ ```
30
+
31
+ In your chat route, wrap the response body in `ctx.run(streamId, makeStream)`. The first caller for `streamId` becomes the producer (your `makeStream` callback runs); later callers and reconnects become consumers that replay the persisted bytes.
32
+
33
+ ```ts title="/app/api/chat/route.ts"
34
+ import { streamText } from "ai";
35
+ import { RESUMABLE_STREAM_ID_HEADER } from "assistant-stream/resumable";
36
+ import { resumableContext } from "@/lib/resumable-context";
37
+
38
+ export async function POST(req: Request) {
39
+ const { messages } = await req.json();
40
+ const streamId = crypto.randomUUID();
41
+
42
+ const result = streamText({ /* model, messages, tools, ... */ });
43
+ const sourceBody = result.toUIMessageStreamResponse().body!;
44
+
45
+ const stream = await resumableContext.run(streamId, () => sourceBody);
46
+
47
+ return new Response(stream, {
48
+ headers: {
49
+ "Content-Type": "text/event-stream",
50
+ [RESUMABLE_STREAM_ID_HEADER]: streamId,
51
+ },
52
+ });
53
+ }
54
+ ```
55
+
56
+ A separate GET endpoint replays the persisted bytes for reconnecting clients. `ctx.resume(streamId)` returns `null` when no stream exists; use `ctx.requireResume(streamId)` if you prefer to surface a `ResumableStreamError` with code `"missing"` instead.
57
+
58
+ ```ts title="/app/api/chat/resume/[streamId]/route.ts"
59
+ import { RESUMABLE_STREAM_ID_HEADER } from "assistant-stream/resumable";
60
+ import { resumableContext } from "@/lib/resumable-context";
61
+
62
+ export async function GET(
63
+ _req: Request,
64
+ ctx: { params: Promise<{ streamId: string }> },
65
+ ) {
66
+ const { streamId } = await ctx.params;
67
+ const stream = await resumableContext.resume(streamId);
68
+ if (!stream) {
69
+ return new Response(JSON.stringify({ error: "stream not found" }), {
70
+ status: 404,
71
+ headers: { "Content-Type": "application/json" },
72
+ });
73
+ }
74
+ return new Response(stream, {
75
+ headers: {
76
+ "Content-Type": "text/event-stream",
77
+ [RESUMABLE_STREAM_ID_HEADER]: streamId,
78
+ },
79
+ });
80
+ }
81
+ ```
82
+
83
+ The context exposes two more verbs: `ctx.status(streamId)` returns `"streaming" | "done" | "error" | "missing"`, and `ctx.delete(streamId)` removes all persisted state for a stream and terminates active readers. The remaining options on `createResumableStreamContext` (`onAcquire`, `onAppend`, `onFinalize`, `onError`) are observability hooks covered in [Resumable Stream Deployment](/docs/guides/resumable-stream-deployment).
84
+
85
+ ## Client side: native integration
86
+
87
+ `@assistant-ui/react-ai-sdk` ships a `resumable` option on `AssistantChatTransport`. It captures the stream id from the response header, redirects `chat.resumeStream()` reconnects to your resume route, and clears the stored id when the response finishes naturally. Pair it with `useChatRuntime`, which fires `chat.resumeStream()` on mount whenever a pending id is present in storage.
88
+
89
+ ```tsx title="/app/page.tsx"
90
+ "use client";
91
+
92
+ import { AssistantRuntimeProvider } from "@assistant-ui/react";
93
+ import {
94
+ AssistantChatTransport,
95
+ createResumableSessionStorage,
96
+ useChatRuntime,
97
+ } from "@assistant-ui/react-ai-sdk";
98
+ import { useMemo } from "react";
99
+ import { Thread } from "@/components/assistant-ui/thread";
100
+
101
+ const storage = createResumableSessionStorage();
102
+
103
+ export default function Page() {
104
+ const transport = useMemo(
105
+ () =>
106
+ new AssistantChatTransport({
107
+ api: "/api/chat",
108
+ resumable: {
109
+ storage,
110
+ resumeApi: (streamId) => `/api/chat/resume/${streamId}`,
111
+ },
112
+ }),
113
+ [],
114
+ );
115
+ const runtime = useChatRuntime({ transport });
116
+
117
+ return (
118
+ <AssistantRuntimeProvider runtime={runtime}>
119
+ <Thread />
120
+ </AssistantRuntimeProvider>
121
+ );
122
+ }
123
+ ```
124
+
125
+ `createResumableSessionStorage` returns a `ResumableClientStorage` backed by `window.sessionStorage`. Pass `{ key }` to namespace per route or per chat surface, or supply your own implementation of the three methods (`getStreamId`, `setStreamId`, `clear`). If you are running on a transport that already wraps `fetch` or `prepareReconnectToStreamRequest`, the `resumable` option composes with your existing handlers.
126
+
127
+ The default finish detector scans the SSE body for the AI SDK `"type":"finish"` marker. Override `isFinishEvent` on the `resumable` option when you ship a custom encoder.
128
+
129
+ ## Storage choices
130
+
131
+ The core package ships `createInMemoryResumableStreamStore` for development and tests. State lives in a process-local `Map`, so it does not survive a server restart. Useful options include `defaultTtlMs`, `maxChunkBytes`, `maxEntriesPerStream`, `maxStreams`, and `gcIntervalMs` for periodic eviction.
132
+
133
+ For production, use one of the optional Redis adapters via the `assistant-stream/resumable/redis` (node-redis v5) or `assistant-stream/resumable/ioredis` sub-paths. Both adapters batch the per-append `XADD` and TTL refresh into a single pipelined round trip, store chunk values as binary, and accept the same `keyPrefix`, `defaultTtlMs`, `pollIntervalMs`, and `maxChunkBytes` options. Cluster routing works because each stream's keys share a `{streamId}` hash tag.
134
+
135
+ ```ts title="/lib/resumable-context.ts"
136
+ import {
137
+ createResumableStreamContext,
138
+ type ResumableStreamStore,
139
+ } from "assistant-stream/resumable";
140
+
141
+ async function createStore(): Promise<ResumableStreamStore> {
142
+ if (!process.env.REDIS_URL) {
143
+ const { createInMemoryResumableStreamStore } = await import(
144
+ "assistant-stream/resumable"
145
+ );
146
+ return createInMemoryResumableStreamStore();
147
+ }
148
+ const { createClient } = await import("redis");
149
+ const { createRedisResumableStreamStore } = await import(
150
+ "assistant-stream/resumable/redis"
151
+ );
152
+ const client = createClient({ url: process.env.REDIS_URL });
153
+ await client.connect();
154
+ return createRedisResumableStreamStore(client);
155
+ }
156
+
157
+ export const resumableContext = createResumableStreamContext({
158
+ store: await createStore(),
159
+ });
160
+ ```
161
+
162
+ For Postgres, Cloudflare Durable Objects, Upstash REST, or any other backend, implement the `ResumableStreamStore` interface directly. See [Custom Resumable Stream Stores](/docs/guides/resumable-stream-stores) for the contract walkthrough and a worked example.
163
+
164
+ ## Production checklist
165
+
166
+ - **Auth.** The resume route in the snippets above will serve any caller that knows the stream id. Bind `streamId` to the requesting user at acquire time and verify the binding inside the resume handler. Treat the id as opaque, not as a credential; it leaks via response headers, `sessionStorage`, browser history, and access logs.
167
+ - **`waitUntil` on serverless.** On Vercel and Cloudflare the request handler is killed once the response returns, which interrupts the producer task. Pass `after` from `next/server` (or your platform's `ctx.waitUntil`) when constructing the context so the task survives past the response: `createResumableStreamContext({ store, waitUntil: after })`.
168
+ - **TTL.** Streams expire 24 hours after the last write by default. Configure with `defaultTtlMs` on the store, or override per deployment via `ttlMs` on the context. Match TTLs across the store, any owner-binding key, and any signed cookie that references a `streamId`.
169
+ - **Stream id format.** The Redis adapters validate `streamId` against `/^[A-Za-z0-9_.:-]{1,256}$/` to keep keys well-formed. UUIDv4 is fine.
170
+
171
+ For the full treatment of authorization, multi-tenant key prefixes, observability hooks, resource limits, and incident response, see [Resumable Stream Deployment](/docs/guides/resumable-stream-deployment).
172
+
173
+ A new `ResumableStreamError` class is exported from `assistant-stream/resumable` with codes `"missing" | "exists" | "finalized" | "invalid-id"`; catch it in the resume route to distinguish "stream gone" from other failures.
174
+
175
+ ## Helpers for `AssistantStreamController` callbacks
176
+
177
+ If you produce streams via `createAssistantStream` rather than the AI SDK, the package ships two helpers that bridge the controller-callback style and any encoder to the store:
178
+
179
+ ```ts
180
+ import {
181
+ createResumableAssistantStreamResponse,
182
+ createResumeAssistantStreamResponse,
183
+ } from "assistant-stream/resumable";
184
+ import { resumableContext } from "@/lib/resumable-context";
185
+
186
+ // POST handler
187
+ return createResumableAssistantStreamResponse({
188
+ context: resumableContext,
189
+ streamId,
190
+ callback: (controller) => {
191
+ /* same shape as createAssistantStreamResponse */
192
+ },
193
+ });
194
+
195
+ // GET resume handler
196
+ return createResumeAssistantStreamResponse({
197
+ context: resumableContext,
198
+ streamId,
199
+ });
200
+ ```
201
+
202
+ Both helpers default to the data-stream encoder; pass `encoder: () => new AssistantTransportEncoder()` (or any custom encoder) to override. They set the `x-resumable-stream-id` response header automatically, which is what `AssistantChatTransport`'s `resumable` adapter looks for.
203
+
204
+ ## Example app
205
+
206
+ [`examples/with-resumable-stream`](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-resumable-stream) is a runnable Next.js app that uses `useChat`, the `resumable` transport option, and `useChatRuntime`. It falls back to a built-in mock when `OPENAI_API_KEY` is unset, and switches the store from in-memory to Redis when `REDIS_URL` is set.
207
+
208
+ ```sh
209
+ npx assistant-ui create my-app -e with-resumable-stream
210
+ ```
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  title: Slash Commands
3
- description: Let users type / in the composer to trigger predefined actions from a popover picker.
3
+ description: Trigger predefined actions in your AI chat by typing / — slash command palette with popover, search, and action handlers in React via assistant-ui.
4
+ platforms: ["react"]
4
5
  ---
5
6
 
6
7
  Slash commands let users type `/` in the composer to open a popover, browse available commands, and execute one. Unlike [mentions](/docs/guides/mentions) (which only insert a directive into the message), slash commands additionally fire an **action callback** at the moment of selection.
@@ -89,6 +90,17 @@ function MyComposer() {
89
90
 
90
91
  The label defaults to `/${id}`; override via `label` on the command. Icons are strings that your `iconMap` on the picker UI resolves to components (see [ComposerTriggerPopover](/docs/ui/composer-trigger-popover)).
91
92
 
93
+ ### `unstable_useSlashCommandAdapter` options
94
+
95
+ | Option | Type | Default | Description |
96
+ | --- | --- | --- | --- |
97
+ | `commands` | `Unstable_SlashCommand[]` | — | Command definitions — each has `id`, optional `label`, `description`, `icon`, and an `execute` callback (required) |
98
+ | `removeOnExecute` | `boolean` | `false` | When `true`, strips the trigger text from the composer after executing instead of leaving a directive chip |
99
+ | `iconMap` | `Record<string, IconComponent>` | — | Maps `metadata.icon` / category `id` strings to React icon components; forwarded to `ComposerTriggerPopover` |
100
+ | `fallbackIcon` | `IconComponent` | — | Fallback when no `iconMap` entry matches; forwarded to `ComposerTriggerPopover` |
101
+
102
+ The hook returns `{ adapter, action, iconMap?, fallbackIcon? }` — spread directly into `<ComposerTriggerPopover char="/" {...slash} />` for one-line wiring.
103
+
92
104
  ### 2. Controlling the Chip
93
105
 
94
106
  By default, a selected `/summarize` is converted into a directive chip (`:command[/summarize]{name=summarize}`) in the composer text and the command's `execute` fires. This keeps an audit trail of which commands were invoked.
@@ -236,57 +248,111 @@ Slash commands and mentions live under the same `TriggerPopoverRoot`. Declare on
236
248
 
237
249
  Each `TriggerPopover` is its own scope — the `@` popover and the `/` popover read state from their own declaration and never collide. Keyboard events route to whichever popover is currently active.
238
250
 
239
- ## Keyboard Navigation
251
+ ## Commands with Arguments
252
+
253
+ Some commands accept inline arguments typed after the command word — for example `/translate en` or `/ask what is TypeScript`. Because the adapter's `search` method receives the full text after `/`, you can split on the first space to separate the command from its arguments:
240
254
 
241
- Same keyboard bindings as mentions:
255
+ ```tsx
256
+ const SLASH_COMMANDS: readonly Unstable_SlashCommand[] = [
257
+ {
258
+ id: "translate",
259
+ description: "Translate to a language, e.g. /translate en",
260
+ execute: () => {/* arguments extracted separately, see below */},
261
+ },
262
+ {
263
+ id: "ask",
264
+ description: "Ask about a topic, e.g. /ask what is TypeScript",
265
+ execute: () => {/* arguments extracted separately, see below */},
266
+ },
267
+ ];
242
268
 
243
- | Key | Action |
244
- | --- | --- |
245
- | <Kbd>ArrowDown</Kbd> | Highlight next item |
246
- | <Kbd>ArrowUp</Kbd> | Highlight previous item |
247
- | <Kbd>Enter</Kbd> | Execute highlighted command / drill into category |
248
- | <Kbd>Escape</Kbd> | Close popover |
249
- | <Kbd>Backspace</Kbd> | Go back to categories (when query is empty) |
269
+ function MyComposer() {
270
+ const composerRef = useRef<HTMLTextAreaElement>(null);
271
+ const slash = unstable_useSlashCommandAdapter({
272
+ commands: SLASH_COMMANDS.map((cmd) => ({
273
+ ...cmd,
274
+ execute: () => {
275
+ // Read the full composer text to extract arguments
276
+ const raw = composerRef.current?.value ?? "";
277
+ // Match "/<id> <args>" at start of input
278
+ const match = raw.match(new RegExp(`^\\/${cmd.id}\\s+(.*)`));
279
+ const args = match?.[1]?.trim() ?? "";
280
+ handleCommand(cmd.id, args);
281
+ },
282
+ })),
283
+ removeOnExecute: true,
284
+ });
250
285
 
251
- ## Trigger Popover Architecture
286
+ return (
287
+ <ComposerPrimitive.Unstable_TriggerPopoverRoot>
288
+ <ComposerPrimitive.Root>
289
+ <ComposerPrimitive.Input ref={composerRef} placeholder="Type / for commands..." />
290
+ <ComposerPrimitive.Unstable_TriggerPopover char="/" adapter={slash.adapter}>
291
+ <ComposerPrimitive.Unstable_TriggerPopover.Action {...slash.action} />
292
+ <ComposerPrimitive.Unstable_TriggerPopoverItems>
293
+ {(items) => items.map((item, i) => (
294
+ <ComposerPrimitive.Unstable_TriggerPopoverItem key={item.id} item={item} index={i}>
295
+ <strong>{item.label}</strong>
296
+ {item.description && <span>{item.description}</span>}
297
+ </ComposerPrimitive.Unstable_TriggerPopoverItem>
298
+ ))}
299
+ </ComposerPrimitive.Unstable_TriggerPopoverItems>
300
+ </ComposerPrimitive.Unstable_TriggerPopover>
301
+ <ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
302
+ </ComposerPrimitive.Root>
303
+ </ComposerPrimitive.Unstable_TriggerPopoverRoot>
304
+ );
305
+ }
306
+ ```
307
+
308
+ `removeOnExecute: true` strips the `/translate en` text from the composer so the argument is consumed by the handler rather than sent to the LLM.
309
+
310
+ ## Async Command Loading
252
311
 
253
- Both mentions and slash commands are built on a generic **trigger popover** system:
312
+ The adapter interface is synchronous, but the command list can come from any async source. Load commands into state (or a query cache) and pass the current snapshot to the hook. Because `unstable_useSlashCommandAdapter` re-runs on every render, the adapter always reflects the latest list.
254
313
 
255
- - `ComposerPrimitive.Unstable_TriggerPopoverRoot` — root provider that groups triggers and owns the input plugin registry
256
- - `ComposerPrimitive.Unstable_TriggerPopover` — declares one trigger (id, char, adapter) and renders its popover container
257
- - Behavior sub-primitives — exactly one per `TriggerPopover`:
258
- - `Unstable_TriggerPopover.Directive` — writes a formatted directive on selection ("mention" path)
259
- - `Unstable_TriggerPopover.Action` — fires a callback on selection ("slash" path); inserts a chip by default, strip with `removeOnExecute`
260
- - Shared sub-primitives (`TriggerPopoverCategories`, `TriggerPopoverItems`, `TriggerPopoverBack`) live inside a `TriggerPopover`
314
+ **With React state:**
261
315
 
262
- You can declare any number of triggers under one root and mix behavior types.
316
+ ```tsx
317
+ function MyComposer() {
318
+ const [commands, setCommands] = useState<Unstable_SlashCommand[]>([]);
263
319
 
264
- ### ComposerInput Plugin Protocol
320
+ useEffect(() => {
321
+ fetchAvailableCommands().then(setCommands);
322
+ }, []);
265
323
 
266
- Under the hood, each `TriggerPopover` registers a **ComposerInputPlugin** with the composer input. This is a generic protocol that decouples the input from any specific trigger:
324
+ const slash = unstable_useSlashCommandAdapter({ commands });
267
325
 
268
- ```ts
269
- type ComposerInputPlugin = {
270
- handleKeyDown(e: KeyboardEvent): boolean;
271
- setCursorPosition(pos: number): void;
272
- };
326
+ return (/* ... */);
327
+ }
328
+ ```
329
+
330
+ **With React Query:**
331
+
332
+ ```tsx
333
+ function MyComposer() {
334
+ const { data: commands = [] } = useQuery({
335
+ queryKey: ["slash-commands"],
336
+ queryFn: fetchAvailableCommands,
337
+ });
338
+
339
+ const slash = unstable_useSlashCommandAdapter({ commands });
340
+
341
+ return (/* ... */);
342
+ }
273
343
  ```
274
344
 
275
- The input iterates over registered plugins for keyboard events and cursor changes. This is what enables multiple triggers to coexist without conflict.
345
+ ## Keyboard Navigation
346
+
347
+ See [ComposerTriggerPopover keyboard navigation](/docs/ui/composer-trigger-popover#keyboard-navigation) for the full key bindings table.
348
+
349
+ ## Trigger Popover Architecture
350
+
351
+ Both mentions and slash commands are built on a generic trigger popover system where each `Unstable_TriggerPopover` declares one trigger character, an adapter, and exactly one behavior sub-primitive (`Directive` or `Action`). Multiple triggers coexist under a single `Unstable_TriggerPopoverRoot`. See the [Composer Primitives](/docs/primitives/composer) reference for the complete API.
276
352
 
277
353
  ## Primitives Reference
278
354
 
279
- | Primitive | Description |
280
- | --- | --- |
281
- | `Unstable_TriggerPopoverRoot` | Root — groups triggers, provides input plugin registry |
282
- | `Unstable_TriggerPopover` | Declares a trigger and renders its popover container |
283
- | `Unstable_TriggerPopover.Directive` | Behavior sub-primitive — inserts a formatted directive on selection |
284
- | `Unstable_TriggerPopover.Action` | Behavior sub-primitive — runs `onExecute` on selection; chip-by-default |
285
- | `Unstable_TriggerPopoverCategories` | Render-function for the top-level category list |
286
- | `Unstable_TriggerPopoverCategoryItem` | Button that drills into a category (`role="option"`, auto `data-highlighted`) |
287
- | `Unstable_TriggerPopoverItems` | Render-function for items within the active category or search results |
288
- | `Unstable_TriggerPopoverItem` | Button that selects an item (`role="option"`, auto `data-highlighted`) |
289
- | `Unstable_TriggerPopoverBack` | Button that navigates back from items to categories |
355
+ See the [Composer Primitives](/docs/primitives/composer) reference for the full list of trigger popover primitives and their props.
290
356
 
291
357
  ## Related
292
358