@assistant-ui/mcp-docs-server 0.1.29 → 0.1.31

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 (214) hide show
  1. package/.docs/organized/code-examples/waterfall.md +15 -7
  2. package/.docs/organized/code-examples/with-a2a.md +9 -21
  3. package/.docs/organized/code-examples/with-ag-ui.md +11 -8
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +10 -10
  5. package/.docs/organized/code-examples/with-artifacts.md +12 -10
  6. package/.docs/organized/code-examples/with-assistant-transport.md +11 -12
  7. package/.docs/organized/code-examples/with-chain-of-thought.md +83 -54
  8. package/.docs/organized/code-examples/with-cloud-standalone.md +14 -11
  9. package/.docs/organized/code-examples/with-cloud.md +9 -10
  10. package/.docs/organized/code-examples/with-custom-thread-list.md +61 -16
  11. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +17 -12
  12. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +13 -13
  13. package/.docs/organized/code-examples/with-expo.md +25 -21
  14. package/.docs/organized/code-examples/with-external-store.md +8 -8
  15. package/.docs/organized/code-examples/with-ffmpeg.md +17 -12
  16. package/.docs/organized/code-examples/with-generative-ui.md +9 -9
  17. package/.docs/organized/code-examples/with-google-adk.md +8 -8
  18. package/.docs/organized/code-examples/with-heat-graph.md +5 -5
  19. package/.docs/organized/code-examples/with-interactables.md +10 -25
  20. package/.docs/organized/code-examples/with-langchain.md +437 -0
  21. package/.docs/organized/code-examples/with-langgraph.md +16 -16
  22. package/.docs/organized/code-examples/with-livekit.md +18 -13
  23. package/.docs/organized/code-examples/with-opencode.md +105 -62
  24. package/.docs/organized/code-examples/with-parent-id-grouping.md +10 -10
  25. package/.docs/organized/code-examples/with-react-hook-form.md +220 -148
  26. package/.docs/organized/code-examples/with-react-ink.md +2 -2
  27. package/.docs/organized/code-examples/with-react-router.md +12 -12
  28. package/.docs/organized/code-examples/with-store.md +8 -5
  29. package/.docs/organized/code-examples/with-tanstack.md +10 -10
  30. package/.docs/organized/code-examples/with-tap-runtime.md +10 -6
  31. package/.docs/raw/docs/(docs)/cli.mdx +2 -1
  32. package/.docs/raw/docs/(docs)/copilots/assistant-frame.mdx +1 -0
  33. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +10 -3
  34. package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +8 -3
  35. package/.docs/raw/docs/(docs)/copilots/make-assistant-visible.mdx +1 -0
  36. package/.docs/raw/docs/(docs)/copilots/model-context.mdx +1 -0
  37. package/.docs/raw/docs/(docs)/copilots/motivation.mdx +1 -0
  38. package/.docs/raw/docs/(docs)/copilots/use-assistant-instructions.mdx +1 -0
  39. package/.docs/raw/docs/(docs)/devtools.mdx +1 -0
  40. package/.docs/raw/docs/(docs)/index.mdx +1 -0
  41. package/.docs/raw/docs/(docs)/installation.mdx +1 -0
  42. package/.docs/raw/docs/(docs)/rtl.mdx +80 -0
  43. package/.docs/raw/docs/(reference)/api-reference/adapters/attachments.mdx +34 -0
  44. package/.docs/raw/docs/(reference)/api-reference/adapters/feedback-speech.mdx +41 -0
  45. package/.docs/raw/docs/(reference)/api-reference/adapters/index.mdx +26 -0
  46. package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +34 -0
  47. package/.docs/raw/docs/(reference)/api-reference/adapters/runtime.mdx +31 -0
  48. package/.docs/raw/docs/(reference)/api-reference/context-providers/index.mdx +20 -0
  49. package/.docs/raw/docs/(reference)/api-reference/hooks/index.mdx +26 -0
  50. package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +72 -0
  51. package/.docs/raw/docs/(reference)/api-reference/hooks/runtimes.mdx +41 -0
  52. package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +48 -0
  53. package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +30 -0
  54. package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +23 -0
  55. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +21 -0
  56. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +7 -0
  57. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +149 -40
  58. package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +65 -0
  59. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +2 -0
  60. package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +50 -6
  61. package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +15 -0
  62. package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +36 -1
  63. package/.docs/raw/docs/(reference)/api-reference/runtimes/index.mdx +38 -0
  64. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +9 -0
  65. package/.docs/raw/docs/(reference)/migrations/v0-14.mdx +144 -6
  66. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +231 -3
  67. package/.docs/raw/docs/cloud/ai-sdk.mdx +221 -3
  68. package/.docs/raw/docs/cloud/langgraph.mdx +274 -2
  69. package/.docs/raw/docs/{(docs)/guides → guides}/attachments.mdx +41 -36
  70. package/.docs/raw/docs/guides/branching.mdx +76 -0
  71. package/.docs/raw/docs/guides/chain-of-thought.mdx +166 -0
  72. package/.docs/raw/docs/{(docs)/guides → guides}/context-api.mdx +50 -22
  73. package/.docs/raw/docs/{(docs)/guides → guides}/dictation.mdx +2 -0
  74. package/.docs/raw/docs/guides/editing.mdx +102 -0
  75. package/.docs/raw/docs/guides/index.mdx +103 -0
  76. package/.docs/raw/docs/{(docs)/guides → guides}/interactables.mdx +49 -0
  77. package/.docs/raw/docs/{(docs)/guides → guides}/latex.mdx +51 -8
  78. package/.docs/raw/docs/guides/mentions.mdx +520 -0
  79. package/.docs/raw/docs/{(docs)/guides → guides}/message-timing.mdx +8 -2
  80. package/.docs/raw/docs/{(docs)/guides → guides}/multi-agent.mdx +64 -4
  81. package/.docs/raw/docs/{(docs)/guides → guides}/quoting.mdx +10 -17
  82. package/.docs/raw/docs/guides/slash-commands.mdx +361 -0
  83. package/.docs/raw/docs/guides/speech.mdx +156 -0
  84. package/.docs/raw/docs/{(docs)/guides → guides}/suggestions.mdx +21 -83
  85. package/.docs/raw/docs/{(docs)/guides → guides}/tool-ui.mdx +108 -36
  86. package/.docs/raw/docs/{(docs)/guides → guides}/tools.mdx +131 -35
  87. package/.docs/raw/docs/{(docs)/guides → guides}/voice.mdx +39 -0
  88. package/.docs/raw/docs/ink/index.mdx +1 -3
  89. package/.docs/raw/docs/ink/migration.mdx +1 -3
  90. package/.docs/raw/docs/ink/primitives.mdx +37 -1
  91. package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +520 -0
  92. package/.docs/raw/docs/integrations/auth/better-auth.mdx +191 -0
  93. package/.docs/raw/docs/integrations/auth/clerk.mdx +172 -0
  94. package/.docs/raw/docs/integrations/auth/next-auth.mdx +196 -0
  95. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +79 -0
  96. package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +188 -0
  97. package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +57 -0
  98. package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +201 -0
  99. package/.docs/raw/docs/integrations/gateways/index.mdx +157 -0
  100. package/.docs/raw/docs/integrations/index.mdx +173 -0
  101. package/.docs/raw/docs/integrations/observability/helicone.mdx +130 -0
  102. package/.docs/raw/docs/integrations/observability/langfuse.mdx +156 -0
  103. package/.docs/raw/docs/integrations/observability/langsmith.mdx +146 -0
  104. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +712 -0
  105. package/.docs/raw/docs/integrations/tools/mcp.mdx +267 -0
  106. package/.docs/raw/docs/primitives/action-bar.mdx +1 -0
  107. package/.docs/raw/docs/primitives/assistant-modal.mdx +1 -0
  108. package/.docs/raw/docs/primitives/attachment.mdx +1 -0
  109. package/.docs/raw/docs/primitives/branch-picker.mdx +1 -0
  110. package/.docs/raw/docs/primitives/chain-of-thought.mdx +90 -85
  111. package/.docs/raw/docs/primitives/composer.mdx +96 -63
  112. package/.docs/raw/docs/primitives/error.mdx +1 -0
  113. package/.docs/raw/docs/primitives/index.mdx +2 -1
  114. package/.docs/raw/docs/primitives/message.mdx +68 -5
  115. package/.docs/raw/docs/primitives/selection-toolbar.mdx +1 -0
  116. package/.docs/raw/docs/primitives/suggestion.mdx +1 -0
  117. package/.docs/raw/docs/primitives/thread-list.mdx +39 -0
  118. package/.docs/raw/docs/primitives/thread.mdx +16 -13
  119. package/.docs/raw/docs/react-native/index.mdx +1 -3
  120. package/.docs/raw/docs/react-native/migration.mdx +1 -3
  121. package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +396 -0
  122. package/.docs/raw/docs/runtimes/a2a/overview.mdx +60 -0
  123. package/.docs/raw/docs/runtimes/a2a/quickstart.mdx +216 -0
  124. package/.docs/raw/docs/runtimes/ag-ui/overview.mdx +70 -0
  125. package/.docs/raw/docs/runtimes/ag-ui/quickstart.mdx +243 -0
  126. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +123 -0
  127. package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +52 -0
  128. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +71 -131
  129. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +69 -63
  130. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +365 -101
  131. package/.docs/raw/docs/runtimes/concepts/adapters.mdx +265 -0
  132. package/.docs/raw/docs/runtimes/concepts/architecture.mdx +125 -0
  133. package/.docs/raw/docs/runtimes/concepts/stability.mdx +67 -0
  134. package/.docs/raw/docs/runtimes/concepts/threads.mdx +428 -0
  135. package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +703 -0
  136. package/.docs/raw/docs/runtimes/custom/data-stream.mdx +323 -0
  137. package/.docs/raw/docs/runtimes/custom/external-store.mdx +253 -1236
  138. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +746 -0
  139. package/.docs/raw/docs/runtimes/custom/overview.mdx +71 -0
  140. package/.docs/raw/docs/runtimes/google-adk/api.mdx +256 -0
  141. package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +717 -0
  142. package/.docs/raw/docs/runtimes/google-adk/overview.mdx +69 -0
  143. package/.docs/raw/docs/runtimes/google-adk/quickstart.mdx +229 -0
  144. package/.docs/raw/docs/runtimes/langchain.mdx +533 -0
  145. package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +305 -0
  146. package/.docs/raw/docs/runtimes/langgraph/interrupts.mdx +104 -0
  147. package/.docs/raw/docs/runtimes/langgraph/overview.mdx +84 -0
  148. package/.docs/raw/docs/runtimes/langgraph/quickstart.mdx +496 -0
  149. package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +127 -0
  150. package/.docs/raw/docs/runtimes/langgraph/threads.mdx +113 -0
  151. package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +3 -3
  152. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +0 -23
  153. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +1 -1
  154. package/.docs/raw/docs/runtimes/opencode/hooks.mdx +191 -0
  155. package/.docs/raw/docs/runtimes/opencode/overview.mdx +48 -0
  156. package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +119 -0
  157. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +74 -198
  158. package/.docs/raw/docs/ui/accordion.mdx +1 -0
  159. package/.docs/raw/docs/ui/assistant-modal.mdx +1 -0
  160. package/.docs/raw/docs/ui/assistant-sidebar.mdx +1 -0
  161. package/.docs/raw/docs/ui/attachment.mdx +1 -0
  162. package/.docs/raw/docs/ui/badge.mdx +1 -0
  163. package/.docs/raw/docs/ui/composer-trigger-popover.mdx +200 -0
  164. package/.docs/raw/docs/ui/context-display.mdx +1 -0
  165. package/.docs/raw/docs/ui/diff-viewer.mdx +1 -0
  166. package/.docs/raw/docs/ui/directive-text.mdx +114 -0
  167. package/.docs/raw/docs/ui/file.mdx +1 -0
  168. package/.docs/raw/docs/ui/image.mdx +1 -0
  169. package/.docs/raw/docs/ui/markdown.mdx +2 -14
  170. package/.docs/raw/docs/ui/mermaid.mdx +1 -0
  171. package/.docs/raw/docs/ui/message-timing.mdx +3 -2
  172. package/.docs/raw/docs/ui/model-selector.mdx +1 -0
  173. package/.docs/raw/docs/ui/part-grouping.mdx +325 -313
  174. package/.docs/raw/docs/ui/quote.mdx +1 -0
  175. package/.docs/raw/docs/ui/reasoning.mdx +69 -32
  176. package/.docs/raw/docs/ui/scrollbar.mdx +1 -0
  177. package/.docs/raw/docs/ui/select.mdx +1 -0
  178. package/.docs/raw/docs/ui/sources.mdx +1 -0
  179. package/.docs/raw/docs/ui/streamdown.mdx +1 -0
  180. package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -0
  181. package/.docs/raw/docs/ui/tabs.mdx +1 -0
  182. package/.docs/raw/docs/ui/thread-list.mdx +17 -0
  183. package/.docs/raw/docs/ui/thread.mdx +56 -1
  184. package/.docs/raw/docs/ui/tool-fallback.mdx +1 -0
  185. package/.docs/raw/docs/ui/tool-group.mdx +39 -11
  186. package/.docs/raw/docs/ui/voice.mdx +1 -0
  187. package/.docs/raw/docs/utilities/heat-graph.mdx +1 -0
  188. package/.docs/raw/docs/utilities/react-o11y.mdx +278 -0
  189. package/.docs/raw/docs/utilities/tw-shimmer.mdx +1 -0
  190. package/dist/utils/logger.js +1 -1
  191. package/dist/utils/logger.js.map +1 -1
  192. package/package.json +4 -4
  193. package/src/tools/tests/path-traversal.test.ts +1 -1
  194. package/src/utils/logger.ts +1 -1
  195. package/.docs/raw/docs/(docs)/guides/branching.mdx +0 -65
  196. package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +0 -164
  197. package/.docs/raw/docs/(docs)/guides/editing.mdx +0 -66
  198. package/.docs/raw/docs/(docs)/guides/mentions.mdx +0 -406
  199. package/.docs/raw/docs/(docs)/guides/slash-commands.mdx +0 -275
  200. package/.docs/raw/docs/(docs)/guides/speech.mdx +0 -38
  201. package/.docs/raw/docs/runtimes/a2a/index.mdx +0 -298
  202. package/.docs/raw/docs/runtimes/assistant-transport.mdx +0 -1033
  203. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +0 -268
  204. package/.docs/raw/docs/runtimes/custom/local.mdx +0 -1464
  205. package/.docs/raw/docs/runtimes/data-stream.mdx +0 -422
  206. package/.docs/raw/docs/runtimes/google-adk/index.mdx +0 -686
  207. package/.docs/raw/docs/runtimes/helicone.mdx +0 -61
  208. package/.docs/raw/docs/runtimes/langgraph/index.mdx +0 -607
  209. package/.docs/raw/docs/runtimes/langgraph/tutorial/index.mdx +0 -12
  210. package/.docs/raw/docs/runtimes/langserve.mdx +0 -116
  211. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +0 -218
  212. package/.docs/raw/docs/runtimes/mastra/overview.mdx +0 -18
  213. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +0 -217
  214. package/.docs/raw/docs/ui/mention.mdx +0 -168
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  title: Attachments
3
3
  description: Let users attach files, images, and documents to messages.
4
+ platforms: ["react"]
4
5
  ---
5
6
 
6
7
  import { AttachmentSample } from "@/components/docs/samples/attachment";
@@ -57,37 +58,7 @@ const runtime = useChatRuntime();
57
58
 
58
59
  ### Add UI Components
59
60
 
60
- Integrate attachment components into your chat interface:
61
-
62
- ```tsx title="/components/assistant-ui/thread.tsx"
63
- // In your Composer component
64
- import {
65
- ComposerAttachments,
66
- ComposerAddAttachment,
67
- } from "@/components/assistant-ui/attachment";
68
-
69
- const Composer = () => {
70
- return (
71
- <ComposerPrimitive.Root>
72
- <ComposerAttachments />
73
- <ComposerAddAttachment />
74
- <ComposerPrimitive.Input placeholder="Type a message..." />
75
- </ComposerPrimitive.Root>
76
- );
77
- };
78
-
79
- // In your UserMessage component
80
- import { UserMessageAttachments } from "@/components/assistant-ui/attachment";
81
-
82
- const UserMessage = () => {
83
- return (
84
- <MessagePrimitive.Root>
85
- <UserMessageAttachments />
86
- <MessagePrimitive.Parts />
87
- </MessagePrimitive.Root>
88
- );
89
- };
90
- ```
61
+ Integrate the attachment components into your chat interface. See [Attachment UI components](/docs/ui/attachment) for the full install and usage guide.
91
62
 
92
63
  </Step>
93
64
  </Steps>
@@ -143,7 +114,7 @@ const compositeAdapter = new CompositeAttachmentAdapter([
143
114
 
144
115
  ## Creating Custom Attachment Adapters
145
116
 
146
- Build your own adapters for specialized file handling. Below are complete examples for common use cases.
117
+ Build your own adapters for specialized file handling. Below are complete examples for common use cases. For `PendingAttachment` and `CompleteAttachment` type definitions, see [Attachment types](/docs/ui/attachment#attachment-types).
147
118
 
148
119
  ### Vision-Capable Image Adapter
149
120
 
@@ -364,7 +335,7 @@ Provide real-time upload progress using async generators:
364
335
 
365
336
  ```tsx
366
337
  class UploadAttachmentAdapter implements AttachmentAdapter {
367
- accept = "*/*";
338
+ accept = "*";
368
339
 
369
340
  async *add({ file }: { file: File }) {
370
341
  const id = generateId();
@@ -391,8 +362,8 @@ class UploadAttachmentAdapter implements AttachmentAdapter {
391
362
  } as PendingAttachment;
392
363
  }
393
364
 
394
- // Return final pending state
395
- return {
365
+ // Yield final progress so the 100% state reaches the composer
366
+ yield {
396
367
  id,
397
368
  type: "file",
398
369
  name: file.name,
@@ -490,6 +461,40 @@ class ValidatedImageAdapter implements AttachmentAdapter {
490
461
  }
491
462
  ```
492
463
 
464
+ To surface failures in the UI, subscribe to `composer.attachmentAddError`. It fires whenever an add operation produces a failure, in either of two ways:
465
+
466
+ 1. `addAttachment()` rejects: no adapter is configured, the file type does not match `accept`, or the adapter's `add()` throws.
467
+ 2. `addAttachment()` resolves but the adapter returned (or, for async-iterator adapters, yielded) an attachment whose `status.reason === "error"`. The promise resolves successfully, yet the event still fires so the UI can react.
468
+
469
+ The event payload carries a `reason` discriminator and a human-readable `message`, so you can branch UI on the failure mode:
470
+
471
+ | `reason` | When It Fires |
472
+ | ---------------- | ------------------------------------------------------------------------------------------------------ |
473
+ | `no-adapter` | `addAttachment(File)` was called but no `AttachmentAdapter` is configured. |
474
+ | `not-accepted` | The file's content type (or filename extension) did not match `adapter.accept`. External `CreateAttachment` descriptors also trigger this when their `contentType` does not match `adapter.accept`. |
475
+ | `adapter-error` | The adapter's `add()` threw, or returned/yielded an attachment with `status.reason === "error"`. If the adapter produced any attachment before failing, the errored attachment is also visible in `composer.attachments`; if it threw before producing one, the event is the only signal. |
476
+
477
+ ```tsx
478
+ import { toast } from "sonner"; // or your toast library of choice
479
+ import { useAuiEvent } from "@assistant-ui/react";
480
+
481
+ function AttachmentErrorToast() {
482
+ useAuiEvent("composer.attachmentAddError", ({ reason, message, error }) => {
483
+ if (reason === "not-accepted") {
484
+ toast.error("This file type is not supported.");
485
+ } else if (reason === "no-adapter") {
486
+ toast.error("Attachments are not configured for this composer.");
487
+ } else {
488
+ if (error) console.error(error); // underlying Error, useful for logging
489
+ toast.error(message || "Attachment failed to upload.");
490
+ }
491
+ });
492
+ return null;
493
+ }
494
+ ```
495
+
496
+ `attachmentId` is included when the failure is associated with an attachment that was registered (typically `adapter-error` cases). It is `undefined` for `no-adapter` and `not-accepted` failures because those reject before any attachment is registered.
497
+
493
498
  ### External Source Attachments
494
499
 
495
500
  Add attachments from external sources (URLs, API data, CMS references) without needing a `File` object or an `AttachmentAdapter`:
@@ -513,7 +518,7 @@ await aui.composer().addAttachment({
513
518
  });
514
519
  ```
515
520
 
516
- External attachments are added as complete attachments directly — they skip the `AttachmentAdapter` entirely and can be removed without one.
521
+ External attachments are added as complete attachments directly. They bypass the `AttachmentAdapter`'s `add()` step (no upload), but `adapter.accept` is still enforced when an `AttachmentAdapter` is configured: a `CreateAttachment` whose `contentType` does not match `adapter.accept` is rejected and emits `composer.attachmentAddError`. If `contentType` is omitted, the descriptor's filename extension is matched against `adapter.accept` only when `accept` itself contains explicit extension entries (e.g. `.png,.pdf`); MIME-wildcard `accept` strings such as `image/*` always require a matching `contentType`. When no `AttachmentAdapter` is configured, external attachments are added without any content-type check, and they can be removed without an adapter.
517
522
 
518
523
  ### Multiple File Selection
519
524
 
@@ -0,0 +1,76 @@
1
+ ---
2
+ title: Message Branching
3
+ description: Navigate between alternative message versions created by editing or reloading.
4
+ platforms: ["react"]
5
+ ---
6
+
7
+ import { BranchingSample } from "@/components/docs/samples/branching";
8
+
9
+ Branching lets users navigate between alternative versions of a message. A new branch is created when:
10
+
11
+ - A user message is edited
12
+ - An assistant message is reloaded (reload creates a new branch on the same message)
13
+
14
+ Branches are automatically tracked by assistant-ui by observing changes to the `messages` array.
15
+
16
+ ## Shortest Working Pattern
17
+
18
+ <BranchingSample />
19
+
20
+ Place a branch picker inside your message component:
21
+
22
+ ```tsx
23
+ import { BranchPickerPrimitive } from "@assistant-ui/react";
24
+
25
+ const BranchPicker = () => (
26
+ <BranchPickerPrimitive.Root hideWhenSingleBranch>
27
+ <BranchPickerPrimitive.Previous />
28
+ <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
29
+ <BranchPickerPrimitive.Next />
30
+ </BranchPickerPrimitive.Root>
31
+ );
32
+ ```
33
+
34
+ `BranchPickerPrimitive.Previous` and `.Next` automatically disable at branch boundaries and while a run is in flight (unless the runtime supports `switchBranchDuringRun`). For the full primitive API, see [BranchPickerPrimitive](/docs/primitives/branch-picker).
35
+
36
+ ## Triggering Reload
37
+
38
+ `ActionBarPrimitive.Reload` creates a new branch on an assistant message and re-runs from there:
39
+
40
+ ```tsx
41
+ import { ActionBarPrimitive, MessagePrimitive } from "@assistant-ui/react";
42
+
43
+ const AssistantMessage = () => (
44
+ <MessagePrimitive.Root>
45
+ <MessagePrimitive.Parts />
46
+ <ActionBarPrimitive.Root>
47
+ <ActionBarPrimitive.Reload />
48
+ </ActionBarPrimitive.Root>
49
+ </MessagePrimitive.Root>
50
+ );
51
+ ```
52
+
53
+ `Reload` is disabled while `thread.isRunning` or `thread.isDisabled` is true. See [ActionBarPrimitive](/docs/primitives/action-bar) for the full reference.
54
+
55
+ ## Programmatic Branch Navigation
56
+
57
+ For headless or keyboard-shortcut flows, navigate directly to a branch by id via `aui.message().switchToBranch`:
58
+
59
+ ```tsx
60
+ import { useAui } from "@assistant-ui/react";
61
+
62
+ const SwitchToBranch = ({ branchId }: { branchId: string }) => {
63
+ const aui = useAui();
64
+ return (
65
+ <button onClick={() => aui.message().switchToBranch({ branchId })}>
66
+ Go to branch
67
+ </button>
68
+ );
69
+ };
70
+ ```
71
+
72
+ This must be called inside a message context (e.g. nested within `MessagePrimitive.Root`).
73
+
74
+ ## Grouped Parts After Branching
75
+
76
+ Each branch is a distinct message version with its own content parts. `MessagePrimitive.GroupedParts` provides hierarchical adjacent grouping of those parts, useful when a message mixes tool calls and text across branches. See the [MessagePrimitive](/docs/primitives/message) reference for `GroupedParts` usage.
@@ -0,0 +1,166 @@
1
+ ---
2
+ title: Chain of Thought
3
+ description: Group reasoning and tool calls into a collapsible accordion UI.
4
+ platforms: ["react"]
5
+ ---
6
+
7
+ LLMs often produce reasoning steps and tool calls in succession. Chain of Thought lets you visually group these consecutive parts into a single collapsible accordion, giving users a clean "thinking" UI.
8
+
9
+ ## Overview
10
+
11
+ When a model like OpenAI's `o4-mini` responds, it may emit a sequence of reasoning tokens and tool calls before producing its final text answer. Use `MessagePrimitive.GroupedParts` to group those adjacent reasoning and tool-call parts into a single collapsible "thinking" section.
12
+
13
+ <Callout type="info">
14
+ The older `components.ChainOfThought` prop on `MessagePrimitive.Parts` and `components` prop on `ChainOfThoughtPrimitive.Parts` are legacy APIs. They still work for existing code, but new code should use `MessagePrimitive.GroupedParts`.
15
+ </Callout>
16
+
17
+ ## Quick Start
18
+
19
+ <Steps>
20
+ <Step>
21
+
22
+ ### Wire GroupedParts into your assistant message
23
+
24
+ Return the same top-level group for reasoning and tool calls, with nested groups for each type:
25
+
26
+ ```tsx
27
+ import {
28
+ MessagePrimitive,
29
+ } from "@assistant-ui/react";
30
+ import { MarkdownText } from "@/components/assistant-ui/markdown-text";
31
+ import {
32
+ Reasoning,
33
+ ReasoningContent,
34
+ ReasoningRoot,
35
+ ReasoningText,
36
+ ReasoningTrigger,
37
+ } from "@/components/assistant-ui/reasoning";
38
+ import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
39
+ import {
40
+ ToolGroupContent,
41
+ ToolGroupRoot,
42
+ ToolGroupTrigger,
43
+ } from "@/components/assistant-ui/tool-group";
44
+ import type { FC } from "react";
45
+
46
+ const AssistantMessage: FC = () => {
47
+ return (
48
+ <MessagePrimitive.Root>
49
+ <MessagePrimitive.GroupedParts
50
+ groupBy={(part) => {
51
+ if (part.type === "reasoning")
52
+ return ["group-chainOfThought", "group-reasoning"];
53
+ if (part.type === "tool-call")
54
+ return ["group-chainOfThought", "group-tool"];
55
+ return null;
56
+ }}
57
+ >
58
+ {({ part, children }) => {
59
+ switch (part.type) {
60
+ case "group-chainOfThought":
61
+ return <div className="my-2">{children}</div>;
62
+ case "group-reasoning": {
63
+ const running = part.status.type === "running";
64
+ return (
65
+ <ReasoningRoot defaultOpen={running}>
66
+ <ReasoningTrigger active={running} />
67
+ <ReasoningContent aria-busy={running}>
68
+ <ReasoningText>{children}</ReasoningText>
69
+ </ReasoningContent>
70
+ </ReasoningRoot>
71
+ );
72
+ }
73
+ case "group-tool":
74
+ return (
75
+ <ToolGroupRoot>
76
+ <ToolGroupTrigger
77
+ count={part.indices.length}
78
+ active={part.status.type === "running"}
79
+ />
80
+ <ToolGroupContent>{children}</ToolGroupContent>
81
+ </ToolGroupRoot>
82
+ );
83
+ case "text":
84
+ return <MarkdownText />;
85
+ case "reasoning":
86
+ return <Reasoning {...part} />;
87
+ case "tool-call":
88
+ return part.toolUI ?? <ToolFallback {...part} />;
89
+ default:
90
+ return null;
91
+ }
92
+ }}
93
+ </MessagePrimitive.GroupedParts>
94
+ </MessagePrimitive.Root>
95
+ );
96
+ };
97
+ ```
98
+
99
+ </Step>
100
+ <Step>
101
+
102
+ ### Use a Reasoning Model
103
+
104
+ Chain of Thought is most useful with models that produce reasoning tokens (e.g. OpenAI `o4-mini`). Here's an example backend route using the AI SDK:
105
+
106
+ ```tsx title="app/api/chat/route.ts"
107
+ import { openai } from "@ai-sdk/openai";
108
+ import { streamText, convertToModelMessages } from "ai";
109
+
110
+ export async function POST(req: Request) {
111
+ const { messages } = await req.json();
112
+
113
+ const result = streamText({
114
+ model: openai("o4-mini"),
115
+ messages: await convertToModelMessages(messages),
116
+ });
117
+
118
+ return result.toUIMessageStreamResponse();
119
+ }
120
+ ```
121
+
122
+ </Step>
123
+ </Steps>
124
+
125
+ ## LangGraph
126
+
127
+ Chain-of-thought parts are surfaced by the AI SDK's built-in reasoning stream. LangGraph does not emit reasoning tokens in that format, so reasoning grouping will not activate automatically. If you want to display reasoning text from a LangGraph agent, emit it as a custom data part from your graph and render it with `makeAssistantDataUI`. See [generative UI with LangGraph](/docs/runtimes/langgraph/generative-ui) for details.
128
+
129
+ ## Legacy: ChainOfThoughtPrimitive
130
+
131
+ ### Reading Collapsed State
132
+
133
+ For existing `ChainOfThoughtPrimitive` code, use `AuiIf` to conditionally render based on the accordion state:
134
+
135
+ ```tsx
136
+ import { AuiIf, ChainOfThoughtPrimitive } from "@assistant-ui/react";
137
+ import { ChevronDownIcon, ChevronRightIcon } from "lucide-react";
138
+
139
+ const ChainOfThoughtAccordionTrigger = () => {
140
+ return (
141
+ <ChainOfThoughtPrimitive.AccordionTrigger className="flex w-full cursor-pointer items-center gap-2 px-4 py-2 text-sm">
142
+ <AuiIf condition={(s) => s.chainOfThought.collapsed}>
143
+ <ChevronRightIcon className="size-4" />
144
+ </AuiIf>
145
+ <AuiIf condition={(s) => !s.chainOfThought.collapsed}>
146
+ <ChevronDownIcon className="size-4" />
147
+ </AuiIf>
148
+ Thinking
149
+ </ChainOfThoughtPrimitive.AccordionTrigger>
150
+ );
151
+ };
152
+ ```
153
+
154
+ ### API Reference
155
+
156
+ For lower-level legacy compatibility details, see the [`ChainOfThought` primitive reference](/docs/primitives/chain-of-thought).
157
+
158
+ ## Full Example
159
+
160
+ See the complete [with-chain-of-thought example](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-chain-of-thought) for a working implementation with tool calls and reasoning.
161
+
162
+ ## Related Guides
163
+
164
+ - [Reasoning](/docs/ui/reasoning) — reasoning UI primitives for grouped parts
165
+ - [Generative UI](/docs/guides/tool-ui) — custom UI for tool calls
166
+ - [Tools](/docs/guides/tools) — defining and using tools
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  title: Context API
3
3
  description: Read and update assistant state to build custom components.
4
+ platforms: ["react"]
4
5
  ---
5
6
 
6
7
  The Context API provides direct access to assistant-ui's state management system, enabling you to build custom components that integrate seamlessly with the assistant runtime.
@@ -211,6 +212,8 @@ aui.attachment().getState();
211
212
  // ThreadList actions
212
213
  aui.threads().switchToNewThread();
213
214
  aui.threads().switchToThread(threadId);
215
+ aui.threads().reload();
216
+ await aui.threads().getLoadThreadsPromise();
214
217
  aui.threads().getState();
215
218
 
216
219
  // ThreadListItem actions
@@ -233,9 +236,9 @@ aui.chainOfThought().getState();
233
236
  aui.chainOfThought().setCollapsed(collapsed);
234
237
  aui.chainOfThought().part({ index: 0 });
235
238
 
236
- // ModelContext actions
237
- aui.modelContext().getState();
239
+ // ModelContext actions — see /docs/copilots/model-context for full usage
238
240
  aui.modelContext().register(provider);
241
+ aui.modelContext().getState();
239
242
 
240
243
  // Tools actions
241
244
  aui.tools().setToolUI(toolName, render);
@@ -355,9 +358,14 @@ const partByToolCall = aui.message().part({ toolCallId: "call_123" });
355
358
  // Access attachment by index
356
359
  const attachment = aui.composer().attachment({ index: 0 }).getState();
357
360
 
358
- // Access thread list item by ID or index
361
+ // Access thread list item by ID, index, or the "main" selector
359
362
  const threadItem = aui.threads().item({ id: "thread_123" });
360
363
  const threadByIndex = aui.threads().item({ index: 0 });
364
+ const archivedThread = aui.threads().item({ index: 0, archived: true });
365
+
366
+ // Traverse to the main thread directly
367
+ const mainThread = aui.threads().thread("main");
368
+ const message = aui.threads().thread("main").message({ id: "msg_123" });
361
369
  ```
362
370
 
363
371
  ## Common Patterns
@@ -490,9 +498,9 @@ const isRunning = useAuiState((s) => s.thread.isRunning);
490
498
 
491
499
  | Scope | Key State Properties | Description |
492
500
  | -------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------- |
493
- | ThreadList | `mainThreadId`, `newThreadId`, `threadIds`, `archivedThreadIds`, `isLoading`, `threadItems` | Manages all available conversation threads |
494
- | ThreadListItem | `id`, `title`, `status`, `remoteId`, `externalId` | Individual thread metadata and status |
495
- | Thread | `isRunning`, `isLoading`, `isDisabled`, `isEmpty`, `messages`, `capabilities`, `suggestions` | Active conversation state and message history |
501
+ | ThreadList | `mainThreadId`, `newThreadId`, `threadIds`, `archivedThreadIds`, `isLoading`, `threadItems` (`readonly ThreadListItemState[]`) | Manages all available conversation threads |
502
+ | ThreadListItem | `id`, `title`, `status`, `remoteId`, `externalId`, `custom?: Record<string, unknown>` | Individual thread metadata and status; `custom` carries arbitrary per-thread metadata set by remote runtimes |
503
+ | Thread | `isRunning` (may be explicitly set by the runtime rather than derived from last-message status), `isLoading`, `isDisabled`, `isEmpty`, `messages`, `capabilities`, `suggestions` | Active conversation state and message history |
496
504
  | Message | `role`, `content`, `status`, `attachments`, `parts`, `parentId`, `branchNumber`, `branchCount`, `isLast`, `index` | Individual message content and metadata |
497
505
  | Part | `type`, `status`, `text`, `toolCallId`, `toolName` | Content parts within messages (text, tool calls) |
498
506
  | ChainOfThought | `parts`, `collapsed`, `status` | Reasoning steps grouped within a message |
@@ -500,13 +508,15 @@ const isRunning = useAuiState((s) => s.thread.isRunning);
500
508
  | Attachment | `id`, `type`, `name`, `contentType`, `status` | File attachments metadata and content |
501
509
  | Suggestions | `suggestions` | Collection of follow-up message suggestions |
502
510
  | Suggestion | `title`, `label`, `prompt` | Individual suggestion with title, label, and prompt |
503
- | ModelContext | *(empty — use `register()` / `getToolCallParams()` methods)* | Model context and tool registration |
511
+ | ModelContext | *(empty — use `register()` / `getToolCallParams()` methods; see [Model Context](/docs/copilots/model-context))* | System instructions, tools, and context providers |
504
512
 
505
513
  ### Available Actions by Scope
506
514
 
515
+ The table below covers the most commonly used actions. For the full catalog, see the [API Reference](/docs/api-reference/overview).
516
+
507
517
  | Scope | Actions | Use Cases |
508
518
  | -------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
509
- | ThreadList | `switchToNewThread()`, `switchToThread(id)`, `item(selector)`, `thread("main")`, `getState()` | Thread navigation and creation |
519
+ | ThreadList | `switchToNewThread()`, `switchToThread(id)`, `reload()`, `getLoadThreadsPromise()`, `item(selector)`, `thread("main")`, `getState()` | Thread navigation, creation, and sync |
510
520
  | ThreadListItem | `switchTo()`, `rename(title)`, `archive()`, `unarchive()`, `delete()`, `getState()` | Thread management operations |
511
521
  | Thread | `append(message)`, `startRun(config)`, `resumeRun(config)`, `cancelRun()`, `reset()`, `export()`, `import(repository)`, `message(selector)`, `composer()`, `getState()` | Message handling and conversation control |
512
522
  | Message | `reload()`, `speak()`, `stopSpeaking()`, `submitFeedback(feedback)`, `switchToBranch(options)`, `getCopyText()`, `part(selector)`, `attachment(selector)`, `composer()`, `setIsCopied(value)`, `setIsHovering(value)`, `getState()` | Message interactions and regeneration |
@@ -516,20 +526,38 @@ const isRunning = useAuiState((s) => s.thread.isRunning);
516
526
  | Attachment | `remove()`, `getState()` | File management |
517
527
  | Suggestions | `suggestion({ index })`, `getState()` | Access follow-up suggestions |
518
528
  | Suggestion | `getState()` | Read individual suggestion data |
519
- | ModelContext | `register(provider)`, `getState()` | Register model context providers |
520
-
521
- ### Common Events
522
-
523
- | Event | Description |
524
- | ----------------------------- | ----------------------------- |
525
- | `thread.runStart` | Assistant starts generating |
526
- | `thread.runEnd` | Assistant finishes generating |
527
- | `thread.initialize` | Thread is initialized |
528
- | `thread.modelContextUpdate` | Model context is updated |
529
- | `composer.send` | Message is sent |
530
- | `composer.attachmentAdd` | Attachment added to composer |
531
- | `threadListItem.switchedTo` | Switched to a thread |
532
- | `threadListItem.switchedAway` | Switched away from a thread |
529
+ | ModelContext | `register(provider)`, `getState()` | Register providers; full details in [Model Context](/docs/copilots/model-context) |
530
+
531
+ ### Events vs State Observation
532
+
533
+ `useAuiEvent` is the escape hatch for **transient occurrences that are not derivable from state**. State-derivable transitions (attachment list changing, run progress, thread switching) should be observed with `useAuiState`, not subscribed via events.
534
+
535
+ The rule of thumb:
536
+
537
+ 1. Can you read the new value from state right now? → use `useAuiState`.
538
+ 2. Are you the caller and want immediate feedback? → catch the rejection / read the return value.
539
+ 3. Did something happen that has no representation in state at all? → use `useAuiEvent`.
540
+
541
+ Most existing events are kept for backward compatibility but duplicate state. They are marked `@deprecated` in the type definitions; new code should follow the rule above.
542
+
543
+ #### Currently Recommended (Truly Transient)
544
+
545
+ | Event | When It Fires |
546
+ | ----------------------------- | ---------------------------------------------------------------------------- |
547
+ | `composer.attachmentAddError` | An `addAttachment()` call failed. Payload `reason` discriminates `no-adapter` / `not-accepted` / `adapter-error`. `no-adapter` and `not-accepted` are non-state-derivable. `adapter-error` is partially state-derivable: if the adapter produced any attachment before failing, the errored attachment also appears in `composer.attachments` with `status.reason === "error"`. The event additionally surfaces a human-readable `message` (and the underlying `Error` instance via the low-level `runtime.unstable_on("attachmentAddError")` API; `useAuiEvent` payloads omit it because raw `Error` objects are not store-serializable). |
548
+ | `thread.modelContextUpdate` | The model context provider notified a change. The model context lives in a provider, not in thread state, so this event has no state-derivable equivalent. |
549
+
550
+ #### Legacy (State-Derivable, Prefer `useAuiState`)
551
+
552
+ These events fire at the same transition you can observe via state. They are kept for backward compatibility but new code should observe state instead.
553
+
554
+ | Legacy Event | Observe Instead |
555
+ | -------------------------------------------- | -------------------------------------------------------------- |
556
+ | `composer.send` | composer `text` clearing |
557
+ | `composer.attachmentAdd` | composer `attachments` |
558
+ | `thread.runStart` / `runEnd` | thread `isRunning` flipping to `true` / `false` |
559
+ | `thread.initialize` | thread `messages` becoming non-empty (or `isEmpty` flipping) |
560
+ | `threadListItem.switchedTo` / `switchedAway` | compare `s.threads.mainThreadId` against `s.threadListItem.id` |
533
561
 
534
562
  ## Troubleshooting
535
563
 
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  title: Speech-to-Text (Dictation)
3
+ description: Let users speak into the composer using Web Speech API or a custom dictation adapter.
4
+ platforms: ["react"]
3
5
  ---
4
6
 
5
7
  import { DictationSample } from "@/components/docs/samples/dictation";
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: Message Editing
3
+ description: Allow users to edit their messages with custom editor interfaces.
4
+ platforms: ["react"]
5
+ ---
6
+
7
+ ## Mental Model
8
+
9
+ Editing re-submits a message from a past point in the conversation and creates a new branch. The messages after the edited one are discarded, and the assistant generates a fresh response from that point forward. Each user message has an independent edit composer; only one can be active at a time.
10
+
11
+ The recommended way to wire this up is via the `children` render prop on `ThreadPrimitive.Messages`, branching on `message.role` and on `message.composer.isEditing` to swap in an edit composer when needed.
12
+
13
+ ## Enabling Edit Support
14
+
15
+ ```tsx
16
+ import {
17
+ ActionBarPrimitive,
18
+ ComposerPrimitive,
19
+ MessagePrimitive,
20
+ ThreadPrimitive,
21
+ } from "@assistant-ui/react";
22
+
23
+ const Thread = () => {
24
+ return (
25
+ <ThreadPrimitive.Root>
26
+ <ThreadPrimitive.Viewport>
27
+ <ThreadPrimitive.Messages>
28
+ {({ message }) => {
29
+ if (message.role === "user") {
30
+ if (message.composer.isEditing) return <UserEditComposer />;
31
+ return <UserMessage />;
32
+ }
33
+ return <AssistantMessage />;
34
+ }}
35
+ </ThreadPrimitive.Messages>
36
+ </ThreadPrimitive.Viewport>
37
+ </ThreadPrimitive.Root>
38
+ );
39
+ };
40
+
41
+ const UserMessage = () => {
42
+ return (
43
+ <MessagePrimitive.Root>
44
+ {/* message content */}
45
+ <ActionBarPrimitive.Root>
46
+ <ActionBarPrimitive.Edit />
47
+ </ActionBarPrimitive.Root>
48
+ </MessagePrimitive.Root>
49
+ );
50
+ };
51
+
52
+ const UserEditComposer = () => {
53
+ return (
54
+ <MessagePrimitive.Root>
55
+ <ComposerPrimitive.Root>
56
+ <ComposerPrimitive.Input />
57
+ <ComposerPrimitive.Cancel />
58
+ <ComposerPrimitive.Send />
59
+ </ComposerPrimitive.Root>
60
+ </MessagePrimitive.Root>
61
+ );
62
+ };
63
+
64
+ const AssistantMessage = () => {
65
+ return <MessagePrimitive.Root>{/* message content */}</MessagePrimitive.Root>;
66
+ };
67
+ ```
68
+
69
+ `ActionBarPrimitive.Edit` calls `aui.composer().beginEdit()` under the hood and is disabled when the composer is already in edit mode.
70
+
71
+ `ComposerPrimitive.Cancel` calls `aui.composer().cancel()`, which exits edit mode and restores the original message content. See [Composer primitives](/docs/primitives/composer) for the full composer API.
72
+
73
+ ## Detecting Edit Mode
74
+
75
+ The `isEditing` flag is available on both `ThreadComposerState` and `EditComposerState`, so `useAuiState((s) => s.composer.isEditing)` works inside any composer context. The more idiomatic path is to rely on the `UserEditComposer` slot in the render function (shown above), which scopes the component tree automatically and avoids manual state checks.
76
+
77
+ ## Imperative API
78
+
79
+ `aui.composer().beginEdit()` is the programmatic entry point for entering edit mode on a message. Use it for headless or keyboard-shortcut-driven flows where `ActionBarPrimitive.Edit` is not rendered:
80
+
81
+ ```tsx
82
+ import { useAui } from "@assistant-ui/react";
83
+
84
+ const EditButton = () => {
85
+ const aui = useAui();
86
+ return (
87
+ <button onClick={() => aui.composer().beginEdit()}>Edit</button>
88
+ );
89
+ };
90
+ ```
91
+
92
+ `aui.composer().cancel()` exits edit mode without re-submitting.
93
+
94
+ ## Editing While Streaming
95
+
96
+ If a user triggers edit mode while the assistant is still generating a response, the in-progress run is cancelled and a new branch is started from the edited message. The hook does not block this. If your UI should prevent editing during streaming, gate the edit button on the thread run state before rendering `ActionBarPrimitive.Edit` or calling `beginEdit()`.
97
+
98
+ ## References
99
+
100
+ - [ActionBar primitives](/docs/primitives/action-bar) — `ActionBarPrimitive.Edit` and related actions
101
+ - [Composer primitives](/docs/primitives/composer) — full composer anatomy including `Cancel`, `Send`, and `Input`
102
+ - [Message primitives](/docs/primitives/message) — `MessagePrimitive.Root` and content parts