@assistant-ui/react 0.10.24 → 0.10.26

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 (267) hide show
  1. package/dist/api/{ContentPartRuntime.d.ts → MessagePartRuntime.d.ts} +14 -14
  2. package/dist/api/{ContentPartRuntime.d.ts.map → MessagePartRuntime.d.ts.map} +1 -1
  3. package/dist/api/{ContentPartRuntime.js → MessagePartRuntime.js} +6 -6
  4. package/dist/api/{ContentPartRuntime.js.map → MessagePartRuntime.js.map} +1 -1
  5. package/dist/api/MessageRuntime.d.ts +8 -8
  6. package/dist/api/MessageRuntime.js +17 -17
  7. package/dist/api/MessageRuntime.js.map +1 -1
  8. package/dist/api/RuntimePathTypes.d.ts +2 -2
  9. package/dist/api/ThreadListRuntime.d.ts +3 -0
  10. package/dist/api/ThreadListRuntime.d.ts.map +1 -1
  11. package/dist/api/ThreadListRuntime.js +5 -1
  12. package/dist/api/ThreadListRuntime.js.map +1 -1
  13. package/dist/api/ThreadRuntime.d.ts +5 -0
  14. package/dist/api/ThreadRuntime.d.ts.map +1 -1
  15. package/dist/api/ThreadRuntime.js +1 -0
  16. package/dist/api/ThreadRuntime.js.map +1 -1
  17. package/dist/api/index.d.ts +2 -1
  18. package/dist/api/index.d.ts.map +1 -1
  19. package/dist/cloud/auiV0.d.ts +2 -2
  20. package/dist/cloud/auiV0.js +1 -1
  21. package/dist/cloud/auiV0.js.map +1 -1
  22. package/dist/context/providers/MessagePartRuntimeProvider.d.ts +9 -0
  23. package/dist/context/providers/{ContentPartRuntimeProvider.d.ts.map → MessagePartRuntimeProvider.d.ts.map} +1 -1
  24. package/dist/context/providers/{ContentPartRuntimeProvider.js → MessagePartRuntimeProvider.js} +9 -9
  25. package/dist/context/providers/MessagePartRuntimeProvider.js.map +1 -0
  26. package/dist/context/providers/{TextContentPartProvider.d.ts → TextMessagePartProvider.d.ts} +3 -3
  27. package/dist/context/providers/{TextContentPartProvider.d.ts.map → TextMessagePartProvider.d.ts.map} +1 -1
  28. package/dist/context/providers/{TextContentPartProvider.js → TextMessagePartProvider.js} +19 -19
  29. package/dist/context/providers/{TextContentPartProvider.js.map → TextMessagePartProvider.js.map} +1 -1
  30. package/dist/context/providers/index.d.ts +2 -1
  31. package/dist/context/providers/index.d.ts.map +1 -1
  32. package/dist/context/providers/index.js +4 -2
  33. package/dist/context/providers/index.js.map +1 -1
  34. package/dist/context/react/AttachmentContext.d.ts +72 -72
  35. package/dist/context/react/MessagePartContext.d.ts +41 -0
  36. package/dist/context/react/{ContentPartContext.d.ts.map → MessagePartContext.d.ts.map} +1 -1
  37. package/dist/context/react/MessagePartContext.js +25 -0
  38. package/dist/context/react/MessagePartContext.js.map +1 -0
  39. package/dist/context/react/index.d.ts +1 -1
  40. package/dist/context/react/index.js +3 -3
  41. package/dist/context/react/index.js.map +1 -1
  42. package/dist/context/stores/AssistantToolUIs.d.ts +3 -3
  43. package/dist/context/stores/AssistantToolUIs.js.map +1 -1
  44. package/dist/model-context/useAssistantTool.d.ts +2 -2
  45. package/dist/model-context/useAssistantTool.js.map +1 -1
  46. package/dist/model-context/useAssistantToolUI.d.ts +2 -2
  47. package/dist/model-context/useAssistantToolUI.js.map +1 -1
  48. package/dist/model-context/useInlineRender.d.ts +2 -2
  49. package/dist/model-context/useInlineRender.js.map +1 -1
  50. package/dist/primitives/assistantModal/AssistantModalContent.d.ts +2 -0
  51. package/dist/primitives/assistantModal/AssistantModalContent.d.ts.map +1 -1
  52. package/dist/primitives/assistantModal/AssistantModalContent.js +2 -1
  53. package/dist/primitives/assistantModal/AssistantModalContent.js.map +1 -1
  54. package/dist/primitives/index.d.ts +12 -6
  55. package/dist/primitives/index.d.ts.map +1 -1
  56. package/dist/primitives/index.js +23 -11
  57. package/dist/primitives/index.js.map +1 -1
  58. package/dist/primitives/message/MessageParts.d.ts +116 -0
  59. package/dist/primitives/message/MessageParts.d.ts.map +1 -0
  60. package/dist/primitives/message/MessageParts.js +208 -0
  61. package/dist/primitives/message/MessageParts.js.map +1 -0
  62. package/dist/primitives/message/index.d.ts +2 -1
  63. package/dist/primitives/message/index.d.ts.map +1 -1
  64. package/dist/primitives/message/index.js +4 -2
  65. package/dist/primitives/message/index.js.map +1 -1
  66. package/dist/primitives/{contentPart/ContentPartImage.d.ts → messagePart/MessagePartImage.d.ts} +8 -8
  67. package/dist/primitives/{contentPart/ContentPartImage.d.ts.map → messagePart/MessagePartImage.d.ts.map} +1 -1
  68. package/dist/primitives/messagePart/MessagePartImage.js +16 -0
  69. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -0
  70. package/dist/primitives/messagePart/MessagePartInProgress.d.ts +6 -0
  71. package/dist/primitives/{contentPart/ContentPartInProgress.d.ts.map → messagePart/MessagePartInProgress.d.ts.map} +1 -1
  72. package/dist/primitives/messagePart/MessagePartInProgress.js +13 -0
  73. package/dist/primitives/messagePart/MessagePartInProgress.js.map +1 -0
  74. package/dist/primitives/{contentPart/ContentPartText.d.ts → messagePart/MessagePartText.d.ts} +6 -6
  75. package/dist/primitives/{contentPart/ContentPartText.d.ts.map → messagePart/MessagePartText.d.ts.map} +1 -1
  76. package/dist/primitives/messagePart/MessagePartText.js +18 -0
  77. package/dist/primitives/{contentPart/ContentPartText.js.map → messagePart/MessagePartText.js.map} +1 -1
  78. package/dist/primitives/messagePart/index.d.ts +4 -0
  79. package/dist/primitives/{contentPart → messagePart}/index.d.ts.map +1 -1
  80. package/dist/primitives/messagePart/index.js +10 -0
  81. package/dist/primitives/messagePart/index.js.map +1 -0
  82. package/dist/primitives/messagePart/useMessagePartFile.d.ts +5 -0
  83. package/dist/primitives/messagePart/useMessagePartFile.d.ts.map +1 -0
  84. package/dist/primitives/messagePart/useMessagePartFile.js +18 -0
  85. package/dist/primitives/messagePart/useMessagePartFile.js.map +1 -0
  86. package/dist/primitives/messagePart/useMessagePartImage.d.ts +5 -0
  87. package/dist/primitives/messagePart/useMessagePartImage.d.ts.map +1 -0
  88. package/dist/primitives/messagePart/useMessagePartImage.js +18 -0
  89. package/dist/primitives/messagePart/useMessagePartImage.js.map +1 -0
  90. package/dist/primitives/messagePart/useMessagePartReasoning.d.ts +5 -0
  91. package/dist/primitives/messagePart/useMessagePartReasoning.d.ts.map +1 -0
  92. package/dist/primitives/messagePart/useMessagePartReasoning.js +18 -0
  93. package/dist/primitives/messagePart/useMessagePartReasoning.js.map +1 -0
  94. package/dist/primitives/messagePart/useMessagePartSource.d.ts +5 -0
  95. package/dist/primitives/messagePart/useMessagePartSource.d.ts.map +1 -0
  96. package/dist/primitives/messagePart/useMessagePartSource.js +18 -0
  97. package/dist/primitives/messagePart/useMessagePartSource.js.map +1 -0
  98. package/dist/primitives/messagePart/useMessagePartText.d.ts +7 -0
  99. package/dist/primitives/messagePart/useMessagePartText.d.ts.map +1 -0
  100. package/dist/primitives/messagePart/useMessagePartText.js +18 -0
  101. package/dist/primitives/messagePart/useMessagePartText.js.map +1 -0
  102. package/dist/runtimes/core/BaseThreadRuntimeCore.d.ts +1 -0
  103. package/dist/runtimes/core/BaseThreadRuntimeCore.d.ts.map +1 -1
  104. package/dist/runtimes/core/BaseThreadRuntimeCore.js.map +1 -1
  105. package/dist/runtimes/core/ThreadListRuntimeCore.d.ts +1 -0
  106. package/dist/runtimes/core/ThreadListRuntimeCore.d.ts.map +1 -1
  107. package/dist/runtimes/core/ThreadRuntimeCore.d.ts +1 -0
  108. package/dist/runtimes/core/ThreadRuntimeCore.d.ts.map +1 -1
  109. package/dist/runtimes/external-store/ExternalStoreAdapter.d.ts +2 -0
  110. package/dist/runtimes/external-store/ExternalStoreAdapter.d.ts.map +1 -1
  111. package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.d.ts +1 -0
  112. package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.d.ts.map +1 -1
  113. package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.js +3 -0
  114. package/dist/runtimes/external-store/ExternalStoreThreadListRuntimeCore.js.map +1 -1
  115. package/dist/runtimes/external-store/ExternalStoreThreadRuntimeCore.d.ts +1 -0
  116. package/dist/runtimes/external-store/ExternalStoreThreadRuntimeCore.d.ts.map +1 -1
  117. package/dist/runtimes/external-store/ExternalStoreThreadRuntimeCore.js +3 -8
  118. package/dist/runtimes/external-store/ExternalStoreThreadRuntimeCore.js.map +1 -1
  119. package/dist/runtimes/external-store/ThreadMessageLike.d.ts +3 -3
  120. package/dist/runtimes/external-store/ThreadMessageLike.js +4 -4
  121. package/dist/runtimes/external-store/ThreadMessageLike.js.map +1 -1
  122. package/dist/runtimes/external-store/createMessageConverter.js +3 -3
  123. package/dist/runtimes/external-store/createMessageConverter.js.map +1 -1
  124. package/dist/runtimes/external-store/external-message-converter.js.map +1 -1
  125. package/dist/runtimes/local/ChatModelAdapter.d.ts +4 -4
  126. package/dist/runtimes/local/LocalThreadListRuntimeCore.d.ts +1 -0
  127. package/dist/runtimes/local/LocalThreadListRuntimeCore.d.ts.map +1 -1
  128. package/dist/runtimes/local/LocalThreadListRuntimeCore.js +3 -0
  129. package/dist/runtimes/local/LocalThreadListRuntimeCore.js.map +1 -1
  130. package/dist/runtimes/local/LocalThreadRuntimeCore.d.ts +2 -0
  131. package/dist/runtimes/local/LocalThreadRuntimeCore.d.ts.map +1 -1
  132. package/dist/runtimes/local/LocalThreadRuntimeCore.js +12 -1
  133. package/dist/runtimes/local/LocalThreadRuntimeCore.js.map +1 -1
  134. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.d.ts.map +1 -1
  135. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js +1 -0
  136. package/dist/runtimes/remote-thread-list/EMPTY_THREAD_CORE.js.map +1 -1
  137. package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts +2 -0
  138. package/dist/runtimes/remote-thread-list/RemoteThreadListHookInstanceManager.d.ts.map +1 -1
  139. package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts +3 -0
  140. package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.d.ts.map +1 -1
  141. package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js +3 -0
  142. package/dist/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.js.map +1 -1
  143. package/dist/runtimes/utils/MessageRepository.js +1 -1
  144. package/dist/runtimes/utils/MessageRepository.js.map +1 -1
  145. package/dist/tests/setup.js +8 -8
  146. package/dist/tests/setup.js.map +1 -1
  147. package/dist/types/AssistantTypes.d.ts +15 -15
  148. package/dist/types/AttachmentTypes.d.ts +3 -3
  149. package/dist/types/MessagePartComponentTypes.d.ts +25 -0
  150. package/dist/types/{ContentPartComponentTypes.d.ts.map → MessagePartComponentTypes.d.ts.map} +1 -1
  151. package/dist/types/MessagePartComponentTypes.js +1 -0
  152. package/dist/types/index.d.ts +4 -2
  153. package/dist/types/index.d.ts.map +1 -1
  154. package/dist/utils/getThreadMessageText.js.map +1 -1
  155. package/dist/utils/smooth/SmoothContext.js +3 -3
  156. package/dist/utils/smooth/SmoothContext.js.map +1 -1
  157. package/dist/utils/smooth/useSmooth.d.ts +3 -3
  158. package/dist/utils/smooth/useSmooth.js.map +1 -1
  159. package/dist/utils/useToolArgsFieldStatus.js +3 -3
  160. package/dist/utils/useToolArgsFieldStatus.js.map +1 -1
  161. package/package.json +8 -8
  162. package/src/api/{ContentPartRuntime.ts → MessagePartRuntime.ts} +20 -20
  163. package/src/api/MessageRuntime.ts +32 -32
  164. package/src/api/RuntimePathTypes.ts +2 -2
  165. package/src/api/ThreadListRuntime.ts +8 -0
  166. package/src/api/ThreadRuntime.ts +6 -0
  167. package/src/api/index.ts +11 -3
  168. package/src/cloud/auiV0.ts +3 -3
  169. package/src/context/providers/MessagePartRuntimeProvider.tsx +42 -0
  170. package/src/context/providers/{TextContentPartProvider.tsx → TextMessagePartProvider.tsx} +27 -27
  171. package/src/context/providers/index.ts +4 -1
  172. package/src/context/react/MessagePartContext.ts +37 -0
  173. package/src/context/react/index.ts +1 -1
  174. package/src/context/stores/AssistantToolUIs.ts +4 -4
  175. package/src/model-context/useAssistantTool.tsx +2 -2
  176. package/src/model-context/useAssistantToolUI.tsx +2 -2
  177. package/src/model-context/useInlineRender.tsx +3 -3
  178. package/src/primitives/assistantModal/AssistantModalContent.tsx +5 -1
  179. package/src/primitives/index.ts +14 -6
  180. package/src/primitives/message/MessageParts.tsx +423 -0
  181. package/src/primitives/message/index.ts +2 -1
  182. package/src/primitives/messagePart/MessagePartImage.tsx +39 -0
  183. package/src/primitives/messagePart/MessagePartInProgress.tsx +19 -0
  184. package/src/primitives/{contentPart/ContentPartText.tsx → messagePart/MessagePartText.tsx} +10 -10
  185. package/src/primitives/messagePart/index.ts +3 -0
  186. package/src/primitives/messagePart/useMessagePartFile.tsx +18 -0
  187. package/src/primitives/messagePart/useMessagePartImage.tsx +18 -0
  188. package/src/primitives/messagePart/useMessagePartReasoning.tsx +18 -0
  189. package/src/primitives/messagePart/useMessagePartSource.tsx +18 -0
  190. package/src/primitives/messagePart/useMessagePartText.tsx +18 -0
  191. package/src/runtimes/core/BaseThreadRuntimeCore.tsx +1 -0
  192. package/src/runtimes/core/ThreadListRuntimeCore.tsx +1 -0
  193. package/src/runtimes/core/ThreadRuntimeCore.tsx +1 -0
  194. package/src/runtimes/external-store/ExternalStoreAdapter.tsx +2 -0
  195. package/src/runtimes/external-store/ExternalStoreThreadListRuntimeCore.tsx +4 -0
  196. package/src/runtimes/external-store/ExternalStoreThreadRuntimeCore.tsx +3 -8
  197. package/src/runtimes/external-store/ThreadMessageLike.tsx +21 -21
  198. package/src/runtimes/external-store/createMessageConverter.tsx +3 -3
  199. package/src/runtimes/external-store/external-message-converter.tsx +2 -2
  200. package/src/runtimes/local/ChatModelAdapter.tsx +13 -13
  201. package/src/runtimes/local/LocalThreadListRuntimeCore.tsx +4 -0
  202. package/src/runtimes/local/LocalThreadRuntimeCore.tsx +30 -15
  203. package/src/runtimes/remote-thread-list/EMPTY_THREAD_CORE.tsx +1 -0
  204. package/src/runtimes/remote-thread-list/RemoteThreadListThreadListRuntimeCore.tsx +4 -0
  205. package/src/runtimes/utils/MessageRepository.tsx +1 -1
  206. package/src/tests/MessageRepository.test.ts +6 -6
  207. package/src/types/AssistantTypes.ts +24 -24
  208. package/src/types/AttachmentTypes.ts +3 -3
  209. package/src/types/MessagePartComponentTypes.tsx +52 -0
  210. package/src/types/index.ts +69 -28
  211. package/src/utils/getThreadMessageText.tsx +2 -2
  212. package/src/utils/smooth/SmoothContext.tsx +7 -7
  213. package/src/utils/smooth/useSmooth.tsx +7 -7
  214. package/src/utils/useToolArgsFieldStatus.tsx +3 -3
  215. package/dist/context/providers/ContentPartRuntimeProvider.d.ts +0 -9
  216. package/dist/context/providers/ContentPartRuntimeProvider.js.map +0 -1
  217. package/dist/context/react/ContentPartContext.d.ts +0 -41
  218. package/dist/context/react/ContentPartContext.js +0 -25
  219. package/dist/context/react/ContentPartContext.js.map +0 -1
  220. package/dist/primitives/contentPart/ContentPartImage.js +0 -16
  221. package/dist/primitives/contentPart/ContentPartImage.js.map +0 -1
  222. package/dist/primitives/contentPart/ContentPartInProgress.d.ts +0 -6
  223. package/dist/primitives/contentPart/ContentPartInProgress.js +0 -13
  224. package/dist/primitives/contentPart/ContentPartInProgress.js.map +0 -1
  225. package/dist/primitives/contentPart/ContentPartText.js +0 -18
  226. package/dist/primitives/contentPart/index.d.ts +0 -4
  227. package/dist/primitives/contentPart/index.js +0 -10
  228. package/dist/primitives/contentPart/index.js.map +0 -1
  229. package/dist/primitives/contentPart/useContentPartFile.d.ts +0 -5
  230. package/dist/primitives/contentPart/useContentPartFile.d.ts.map +0 -1
  231. package/dist/primitives/contentPart/useContentPartFile.js +0 -18
  232. package/dist/primitives/contentPart/useContentPartFile.js.map +0 -1
  233. package/dist/primitives/contentPart/useContentPartImage.d.ts +0 -5
  234. package/dist/primitives/contentPart/useContentPartImage.d.ts.map +0 -1
  235. package/dist/primitives/contentPart/useContentPartImage.js +0 -18
  236. package/dist/primitives/contentPart/useContentPartImage.js.map +0 -1
  237. package/dist/primitives/contentPart/useContentPartReasoning.d.ts +0 -5
  238. package/dist/primitives/contentPart/useContentPartReasoning.d.ts.map +0 -1
  239. package/dist/primitives/contentPart/useContentPartReasoning.js +0 -18
  240. package/dist/primitives/contentPart/useContentPartReasoning.js.map +0 -1
  241. package/dist/primitives/contentPart/useContentPartSource.d.ts +0 -5
  242. package/dist/primitives/contentPart/useContentPartSource.d.ts.map +0 -1
  243. package/dist/primitives/contentPart/useContentPartSource.js +0 -18
  244. package/dist/primitives/contentPart/useContentPartSource.js.map +0 -1
  245. package/dist/primitives/contentPart/useContentPartText.d.ts +0 -7
  246. package/dist/primitives/contentPart/useContentPartText.d.ts.map +0 -1
  247. package/dist/primitives/contentPart/useContentPartText.js +0 -18
  248. package/dist/primitives/contentPart/useContentPartText.js.map +0 -1
  249. package/dist/primitives/message/MessageContent.d.ts +0 -64
  250. package/dist/primitives/message/MessageContent.d.ts.map +0 -1
  251. package/dist/primitives/message/MessageContent.js +0 -141
  252. package/dist/primitives/message/MessageContent.js.map +0 -1
  253. package/dist/types/ContentPartComponentTypes.d.ts +0 -25
  254. package/dist/types/ContentPartComponentTypes.js +0 -1
  255. package/src/context/providers/ContentPartRuntimeProvider.tsx +0 -42
  256. package/src/context/react/ContentPartContext.ts +0 -37
  257. package/src/primitives/contentPart/ContentPartImage.tsx +0 -39
  258. package/src/primitives/contentPart/ContentPartInProgress.tsx +0 -19
  259. package/src/primitives/contentPart/index.ts +0 -3
  260. package/src/primitives/contentPart/useContentPartFile.tsx +0 -18
  261. package/src/primitives/contentPart/useContentPartImage.tsx +0 -18
  262. package/src/primitives/contentPart/useContentPartReasoning.tsx +0 -18
  263. package/src/primitives/contentPart/useContentPartSource.tsx +0 -18
  264. package/src/primitives/contentPart/useContentPartText.tsx +0 -18
  265. package/src/primitives/message/MessageContent.tsx +0 -277
  266. package/src/types/ContentPartComponentTypes.tsx +0 -52
  267. /package/dist/types/{ContentPartComponentTypes.js.map → MessagePartComponentTypes.js.map} +0 -0
@@ -0,0 +1,423 @@
1
+ "use client";
2
+
3
+ import {
4
+ type ComponentType,
5
+ type FC,
6
+ memo,
7
+ PropsWithChildren,
8
+ useMemo,
9
+ } from "react";
10
+ import {
11
+ TextMessagePartProvider,
12
+ useMessagePart,
13
+ useMessagePartRuntime,
14
+ useToolUIs,
15
+ } from "../../context";
16
+ import {
17
+ useMessage,
18
+ useMessageRuntime,
19
+ } from "../../context/react/MessageContext";
20
+ import { MessagePartRuntimeProvider } from "../../context/providers/MessagePartRuntimeProvider";
21
+ import { MessagePartPrimitiveText } from "../messagePart/MessagePartText";
22
+ import { MessagePartPrimitiveImage } from "../messagePart/MessagePartImage";
23
+ import type {
24
+ Unstable_AudioMessagePartComponent,
25
+ EmptyMessagePartComponent,
26
+ TextMessagePartComponent,
27
+ ImageMessagePartComponent,
28
+ SourceMessagePartComponent,
29
+ ToolCallMessagePartComponent,
30
+ ToolCallMessagePartProps,
31
+ FileMessagePartComponent,
32
+ ReasoningMessagePartComponent,
33
+ } from "../../types/MessagePartComponentTypes";
34
+ import { MessagePartPrimitiveInProgress } from "../messagePart/MessagePartInProgress";
35
+ import { MessagePartStatus } from "../../types/AssistantTypes";
36
+ import { useShallow } from "zustand/shallow";
37
+
38
+ type MessagePartRange =
39
+ | { type: "single"; index: number }
40
+ | { type: "toolGroup"; startIndex: number; endIndex: number };
41
+
42
+ /**
43
+ * Groups consecutive tool-call message parts into ranges.
44
+ * Always groups tool calls, even if there's only one.
45
+ */
46
+ const groupMessageParts = (
47
+ messageTypes: readonly string[],
48
+ ): MessagePartRange[] => {
49
+ const ranges: MessagePartRange[] = [];
50
+ let currentToolGroupStart = -1;
51
+
52
+ for (let i = 0; i < messageTypes.length; i++) {
53
+ const type = messageTypes[i];
54
+
55
+ if (type === "tool-call") {
56
+ // Start a new tool group if we haven't started one
57
+ if (currentToolGroupStart === -1) {
58
+ currentToolGroupStart = i;
59
+ }
60
+ } else {
61
+ // End current tool group if it exists
62
+ if (currentToolGroupStart !== -1) {
63
+ ranges.push({
64
+ type: "toolGroup",
65
+ startIndex: currentToolGroupStart,
66
+ endIndex: i - 1,
67
+ });
68
+ currentToolGroupStart = -1;
69
+ }
70
+
71
+ // Add non-tool-call part individually
72
+ ranges.push({ type: "single", index: i });
73
+ }
74
+ }
75
+
76
+ // Handle any remaining tool group at the end
77
+ if (currentToolGroupStart !== -1) {
78
+ ranges.push({
79
+ type: "toolGroup",
80
+ startIndex: currentToolGroupStart,
81
+ endIndex: messageTypes.length - 1,
82
+ });
83
+ }
84
+
85
+ return ranges;
86
+ };
87
+
88
+ const useMessagePartsGroups = (): MessagePartRange[] => {
89
+ const messageTypes = useMessage(
90
+ useShallow((m) => m.content.map((c) => c.type)),
91
+ );
92
+
93
+ return useMemo(() => {
94
+ if (messageTypes.length === 0) {
95
+ return [];
96
+ }
97
+ return groupMessageParts(messageTypes);
98
+ }, [messageTypes]);
99
+ };
100
+
101
+ export namespace MessagePrimitiveParts {
102
+ export type Props = {
103
+ /**
104
+ * Component configuration for rendering different types of message content.
105
+ *
106
+ * You can provide custom components for each content type (text, image, file, etc.)
107
+ * and configure tool rendering behavior. If not provided, default components will be used.
108
+ */
109
+ components?:
110
+ | {
111
+ /** Component for rendering empty messages */
112
+ Empty?: EmptyMessagePartComponent | undefined;
113
+ /** Component for rendering text content */
114
+ Text?: TextMessagePartComponent | undefined;
115
+ /** Component for rendering reasoning content (typically hidden) */
116
+ Reasoning?: ReasoningMessagePartComponent | undefined;
117
+ /** Component for rendering source content */
118
+ Source?: SourceMessagePartComponent | undefined;
119
+ /** Component for rendering image content */
120
+ Image?: ImageMessagePartComponent | undefined;
121
+ /** Component for rendering file content */
122
+ File?: FileMessagePartComponent | undefined;
123
+ /** Component for rendering audio content (experimental) */
124
+ Unstable_Audio?: Unstable_AudioMessagePartComponent | undefined;
125
+ /** Configuration for tool call rendering */
126
+ tools?:
127
+ | {
128
+ /** Map of tool names to their specific components */
129
+ by_name?:
130
+ | Record<string, ToolCallMessagePartComponent | undefined>
131
+ | undefined;
132
+ /** Fallback component for unregistered tools */
133
+ Fallback?: ComponentType<ToolCallMessagePartProps> | undefined;
134
+ }
135
+ | {
136
+ /** Override component that handles all tool calls */
137
+ Override: ComponentType<ToolCallMessagePartProps>;
138
+ }
139
+ | undefined;
140
+
141
+ /**
142
+ * Component for rendering grouped consecutive tool calls.
143
+ *
144
+ * When provided, this component will automatically wrap consecutive tool-call
145
+ * message parts, allowing you to create collapsible sections, custom styling,
146
+ * or other grouped presentations for multiple tool calls.
147
+ *
148
+ * The component receives:
149
+ * - `startIndex`: The index of the first tool call in the group
150
+ * - `endIndex`: The index of the last tool call in the group
151
+ * - `children`: The rendered tool call components
152
+ *
153
+ * @example
154
+ * ```tsx
155
+ * // Collapsible tool group
156
+ * ToolGroup: ({ startIndex, endIndex, children }) => (
157
+ * <details className="tool-group">
158
+ * <summary>
159
+ * {endIndex - startIndex + 1} tool calls
160
+ * </summary>
161
+ * <div className="tool-group-content">
162
+ * {children}
163
+ * </div>
164
+ * </details>
165
+ * )
166
+ * ```
167
+ *
168
+ * @example
169
+ * ```tsx
170
+ * // Custom styled tool group with header
171
+ * ToolGroup: ({ startIndex, endIndex, children }) => (
172
+ * <div className="border rounded-lg p-4 my-2">
173
+ * <div className="text-sm text-gray-600 mb-2">
174
+ * Tool execution #{startIndex + 1}-{endIndex + 1}
175
+ * </div>
176
+ * <div className="space-y-2">
177
+ * {children}
178
+ * </div>
179
+ * </div>
180
+ * )
181
+ * ```
182
+ *
183
+ * @param startIndex - Index of the first tool call in the group
184
+ * @param endIndex - Index of the last tool call in the group
185
+ * @param children - Rendered tool call components to display within the group
186
+ *
187
+ * @deprecated This feature is still experimental and subject to change.
188
+ */
189
+ ToolGroup?: ComponentType<
190
+ PropsWithChildren<{ startIndex: number; endIndex: number }>
191
+ >;
192
+ }
193
+ | undefined;
194
+ };
195
+ }
196
+
197
+ const ToolUIDisplay = ({
198
+ Fallback,
199
+ ...props
200
+ }: {
201
+ Fallback: ToolCallMessagePartComponent | undefined;
202
+ } & ToolCallMessagePartProps) => {
203
+ const Render = useToolUIs((s) => s.getToolUI(props.toolName)) ?? Fallback;
204
+ if (!Render) return null;
205
+ return <Render {...props} />;
206
+ };
207
+
208
+ const defaultComponents = {
209
+ Text: () => (
210
+ <p style={{ whiteSpace: "pre-line" }}>
211
+ <MessagePartPrimitiveText />
212
+ <MessagePartPrimitiveInProgress>
213
+ <span style={{ fontFamily: "revert" }}>{" \u25CF"}</span>
214
+ </MessagePartPrimitiveInProgress>
215
+ </p>
216
+ ),
217
+ Reasoning: () => null,
218
+ Source: () => null,
219
+ Image: () => <MessagePartPrimitiveImage />,
220
+ File: () => null,
221
+ Unstable_Audio: () => null,
222
+ ToolGroup: ({ children }) => children,
223
+ } satisfies MessagePrimitiveParts.Props["components"];
224
+
225
+ type MessagePartComponentProps = {
226
+ components: MessagePrimitiveParts.Props["components"];
227
+ };
228
+
229
+ const MessagePartComponent: FC<MessagePartComponentProps> = ({
230
+ components: {
231
+ Text = defaultComponents.Text,
232
+ Reasoning = defaultComponents.Reasoning,
233
+ Image = defaultComponents.Image,
234
+ Source = defaultComponents.Source,
235
+ File = defaultComponents.File,
236
+ Unstable_Audio: Audio = defaultComponents.Unstable_Audio,
237
+ tools = {},
238
+ } = {},
239
+ }) => {
240
+ const MessagePartRuntime = useMessagePartRuntime();
241
+
242
+ const part = useMessagePart();
243
+
244
+ const type = part.type;
245
+ if (type === "tool-call") {
246
+ const addResult = (result: any) => MessagePartRuntime.addToolResult(result);
247
+ if ("Override" in tools)
248
+ return <tools.Override {...part} addResult={addResult} />;
249
+ const Tool = tools.by_name?.[part.toolName] ?? tools.Fallback;
250
+ return <ToolUIDisplay {...part} Fallback={Tool} addResult={addResult} />;
251
+ }
252
+
253
+ if (part.status.type === "requires-action")
254
+ throw new Error("Encountered unexpected requires-action status");
255
+
256
+ switch (type) {
257
+ case "text":
258
+ return <Text {...part} />;
259
+
260
+ case "reasoning":
261
+ return <Reasoning {...part} />;
262
+
263
+ case "source":
264
+ return <Source {...part} />;
265
+
266
+ case "image":
267
+ // eslint-disable-next-line jsx-a11y/alt-text
268
+ return <Image {...part} />;
269
+
270
+ case "file":
271
+ return <File {...part} />;
272
+
273
+ case "audio":
274
+ return <Audio {...part} />;
275
+
276
+ default:
277
+ const unhandledType: never = type;
278
+ throw new Error(`Unknown message part type: ${unhandledType}`);
279
+ }
280
+ };
281
+
282
+ type MessagePartProps = {
283
+ partIndex: number;
284
+ components: MessagePrimitiveParts.Props["components"];
285
+ };
286
+
287
+ const MessagePartImpl: FC<MessagePartProps> = ({ partIndex, components }) => {
288
+ const messageRuntime = useMessageRuntime();
289
+ const runtime = useMemo(
290
+ () => messageRuntime.getMessagePartByIndex(partIndex),
291
+ [messageRuntime, partIndex],
292
+ );
293
+
294
+ return (
295
+ <MessagePartRuntimeProvider runtime={runtime}>
296
+ <MessagePartComponent components={components} />
297
+ </MessagePartRuntimeProvider>
298
+ );
299
+ };
300
+
301
+ const MessagePart = memo(
302
+ MessagePartImpl,
303
+ (prev, next) =>
304
+ prev.partIndex === next.partIndex &&
305
+ prev.components?.Text === next.components?.Text &&
306
+ prev.components?.Reasoning === next.components?.Reasoning &&
307
+ prev.components?.Source === next.components?.Source &&
308
+ prev.components?.Image === next.components?.Image &&
309
+ prev.components?.File === next.components?.File &&
310
+ prev.components?.Unstable_Audio === next.components?.Unstable_Audio &&
311
+ prev.components?.tools === next.components?.tools &&
312
+ prev.components?.ToolGroup === next.components?.ToolGroup,
313
+ );
314
+
315
+ const COMPLETE_STATUS: MessagePartStatus = Object.freeze({
316
+ type: "complete",
317
+ });
318
+
319
+ const EmptyPartFallback: FC<{
320
+ status: MessagePartStatus;
321
+ component: TextMessagePartComponent;
322
+ }> = ({ status, component: Component }) => {
323
+ return (
324
+ <TextMessagePartProvider text="" isRunning={status.type === "running"}>
325
+ <Component type="text" text="" status={status} />
326
+ </TextMessagePartProvider>
327
+ );
328
+ };
329
+
330
+ const EmptyPartsImpl: FC<MessagePartComponentProps> = ({ components }) => {
331
+ const status =
332
+ useMessage((s) => s.status as MessagePartStatus) ?? COMPLETE_STATUS;
333
+
334
+ if (components?.Empty) return <components.Empty status={status} />;
335
+
336
+ return (
337
+ <EmptyPartFallback
338
+ status={status}
339
+ component={components?.Text ?? defaultComponents.Text}
340
+ />
341
+ );
342
+ };
343
+
344
+ const EmptyParts = memo(
345
+ EmptyPartsImpl,
346
+ (prev, next) =>
347
+ prev.components?.Empty === next.components?.Empty &&
348
+ prev.components?.Text === next.components?.Text,
349
+ );
350
+
351
+ /**
352
+ * Renders the parts of a message with support for multiple content types.
353
+ *
354
+ * This component automatically handles different types of message content including
355
+ * text, images, files, tool calls, and more. It provides a flexible component
356
+ * system for customizing how each content type is rendered.
357
+ *
358
+ * @example
359
+ * ```tsx
360
+ * <MessagePrimitive.Parts
361
+ * components={{
362
+ * Text: ({ text }) => <p className="message-text">{text}</p>,
363
+ * Image: ({ image }) => <img src={image} alt="Message image" />,
364
+ * tools: {
365
+ * by_name: {
366
+ * calculator: CalculatorTool,
367
+ * weather: WeatherTool,
368
+ * },
369
+ * Fallback: DefaultToolComponent
370
+ * }
371
+ * }}
372
+ * />
373
+ * ```
374
+ */
375
+ export const MessagePrimitiveParts: FC<MessagePrimitiveParts.Props> = ({
376
+ components,
377
+ }) => {
378
+ const contentLength = useMessage((s) => s.content.length);
379
+ const messageRanges = useMessagePartsGroups();
380
+
381
+ const partsElements = useMemo(() => {
382
+ if (contentLength === 0) {
383
+ return <EmptyParts components={components} />;
384
+ }
385
+
386
+ return messageRanges.map((range) => {
387
+ if (range.type === "single") {
388
+ return (
389
+ <MessagePart
390
+ key={range.index}
391
+ partIndex={range.index}
392
+ components={components}
393
+ />
394
+ );
395
+ } else {
396
+ const ToolGroupComponent =
397
+ components!.ToolGroup ?? defaultComponents.ToolGroup;
398
+ return (
399
+ <ToolGroupComponent
400
+ key={range.startIndex}
401
+ startIndex={range.startIndex}
402
+ endIndex={range.endIndex}
403
+ >
404
+ {Array.from(
405
+ { length: range.endIndex - range.startIndex + 1 },
406
+ (_, i) => (
407
+ <MessagePart
408
+ key={i}
409
+ partIndex={range.startIndex + i}
410
+ components={components}
411
+ />
412
+ ),
413
+ )}
414
+ </ToolGroupComponent>
415
+ );
416
+ }
417
+ });
418
+ }, [messageRanges, components, contentLength]);
419
+
420
+ return <>{partsElements}</>;
421
+ };
422
+
423
+ MessagePrimitiveParts.displayName = "MessagePrimitive.Parts";
@@ -1,5 +1,6 @@
1
1
  export { MessagePrimitiveRoot as Root } from "./MessageRoot";
2
+ export { MessagePrimitiveParts as Parts } from "./MessageParts";
3
+ export { MessagePrimitiveParts as Content } from "./MessageParts";
2
4
  export { MessagePrimitiveIf as If } from "./MessageIf";
3
- export { MessagePrimitiveContent as Content } from "./MessageContent";
4
5
  export { MessagePrimitiveAttachments as Attachments } from "./MessageAttachments";
5
6
  export { MessagePrimitiveError as Error } from "./MessageError";
@@ -0,0 +1,39 @@
1
+ "use client";
2
+
3
+ import { Primitive } from "@radix-ui/react-primitive";
4
+ import { type ComponentRef, forwardRef, ComponentPropsWithoutRef } from "react";
5
+ import { useMessagePartImage } from "./useMessagePartImage";
6
+
7
+ export namespace MessagePartPrimitiveImage {
8
+ export type Element = ComponentRef<typeof Primitive.img>;
9
+ /**
10
+ * Props for the MessagePartPrimitive.Image component.
11
+ * Accepts all standard img element props.
12
+ */
13
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.img>;
14
+ }
15
+
16
+ /**
17
+ * Renders an image from the current message part context.
18
+ *
19
+ * This component displays image content from the current message part,
20
+ * automatically setting the src attribute from the message part's image data.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * <MessagePartPrimitive.Image
25
+ * alt="Generated image"
26
+ * className="message-image"
27
+ * style={{ maxWidth: '100%' }}
28
+ * />
29
+ * ```
30
+ */
31
+ export const MessagePartPrimitiveImage = forwardRef<
32
+ MessagePartPrimitiveImage.Element,
33
+ MessagePartPrimitiveImage.Props
34
+ >((props, forwardedRef) => {
35
+ const { image } = useMessagePartImage();
36
+ return <Primitive.img src={image} {...props} ref={forwardedRef} />;
37
+ });
38
+
39
+ MessagePartPrimitiveImage.displayName = "MessagePartPrimitive.Image";
@@ -0,0 +1,19 @@
1
+ "use client";
2
+
3
+ import { FC, PropsWithChildren } from "react";
4
+ import { useMessagePart } from "../../context";
5
+
6
+ export namespace MessagePartPrimitiveInProgress {
7
+ export type Props = PropsWithChildren;
8
+ }
9
+
10
+ // TODO should this be renamed to IsRunning?
11
+ export const MessagePartPrimitiveInProgress: FC<
12
+ MessagePartPrimitiveInProgress.Props
13
+ > = ({ children }) => {
14
+ const isInProgress = useMessagePart((c) => c.status.type === "running");
15
+
16
+ return isInProgress ? children : null;
17
+ };
18
+
19
+ MessagePartPrimitiveInProgress.displayName = "MessagePartPrimitive.InProgress";
@@ -7,10 +7,10 @@ import {
7
7
  ComponentPropsWithoutRef,
8
8
  ElementType,
9
9
  } from "react";
10
- import { useContentPartText } from "./useContentPartText";
10
+ import { useMessagePartText } from "./useMessagePartText";
11
11
  import { useSmooth } from "../../utils/smooth/useSmooth";
12
12
 
13
- export namespace ContentPartPrimitiveText {
13
+ export namespace MessagePartPrimitiveText {
14
14
  export type Element = ComponentRef<typeof Primitive.span>;
15
15
  export type Props = Omit<
16
16
  ComponentPropsWithoutRef<typeof Primitive.span>,
@@ -31,26 +31,26 @@ export namespace ContentPartPrimitiveText {
31
31
  }
32
32
 
33
33
  /**
34
- * Renders the text content of a content part with optional smooth streaming.
34
+ * Renders the text content of a message part with optional smooth streaming.
35
35
  *
36
- * This component displays text content from the current content part context,
36
+ * This component displays text content from the current message part context,
37
37
  * with support for smooth streaming animation that shows text appearing
38
38
  * character by character as it's generated.
39
39
  *
40
40
  * @example
41
41
  * ```tsx
42
- * <ContentPartPrimitive.Text
42
+ * <MessagePartPrimitive.Text
43
43
  * smooth={true}
44
44
  * component="p"
45
45
  * className="message-text"
46
46
  * />
47
47
  * ```
48
48
  */
49
- export const ContentPartPrimitiveText = forwardRef<
50
- ContentPartPrimitiveText.Element,
51
- ContentPartPrimitiveText.Props
49
+ export const MessagePartPrimitiveText = forwardRef<
50
+ MessagePartPrimitiveText.Element,
51
+ MessagePartPrimitiveText.Props
52
52
  >(({ smooth = true, component: Component = "span", ...rest }, forwardedRef) => {
53
- const { text, status } = useSmooth(useContentPartText(), smooth);
53
+ const { text, status } = useSmooth(useMessagePartText(), smooth);
54
54
 
55
55
  return (
56
56
  <Component data-status={status.type} {...rest} ref={forwardedRef}>
@@ -59,4 +59,4 @@ export const ContentPartPrimitiveText = forwardRef<
59
59
  );
60
60
  });
61
61
 
62
- ContentPartPrimitiveText.displayName = "ContentPartPrimitive.Text";
62
+ MessagePartPrimitiveText.displayName = "MessagePartPrimitive.Text";
@@ -0,0 +1,3 @@
1
+ export { MessagePartPrimitiveText as Text } from "./MessagePartText";
2
+ export { MessagePartPrimitiveImage as Image } from "./MessagePartImage";
3
+ export { MessagePartPrimitiveInProgress as InProgress } from "./MessagePartInProgress";
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { MessagePartState } from "../../api/MessagePartRuntime";
4
+ import { useMessagePart } from "../../context/react/MessagePartContext";
5
+ import { FileMessagePart } from "../../types";
6
+
7
+ export const useMessagePartFile = () => {
8
+ const file = useMessagePart((c) => {
9
+ if (c.type !== "file")
10
+ throw new Error(
11
+ "MessagePartFile can only be used inside file message parts.",
12
+ );
13
+
14
+ return c as MessagePartState & FileMessagePart;
15
+ });
16
+
17
+ return file;
18
+ };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { MessagePartState } from "../../api/MessagePartRuntime";
4
+ import { useMessagePart } from "../../context/react/MessagePartContext";
5
+ import { ImageMessagePart } from "../../types";
6
+
7
+ export const useMessagePartImage = () => {
8
+ const image = useMessagePart((c) => {
9
+ if (c.type !== "image")
10
+ throw new Error(
11
+ "MessagePartImage can only be used inside image message parts.",
12
+ );
13
+
14
+ return c as MessagePartState & ImageMessagePart;
15
+ });
16
+
17
+ return image;
18
+ };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { MessagePartState } from "../../api/MessagePartRuntime";
4
+ import { useMessagePart } from "../../context/react/MessagePartContext";
5
+ import { ReasoningMessagePart } from "../../types";
6
+
7
+ export const useMessagePartReasoning = () => {
8
+ const text = useMessagePart((c) => {
9
+ if (c.type !== "reasoning")
10
+ throw new Error(
11
+ "MessagePartReasoning can only be used inside reasoning message parts.",
12
+ );
13
+
14
+ return c as MessagePartState & ReasoningMessagePart;
15
+ });
16
+
17
+ return text;
18
+ };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { MessagePartState } from "../../api/MessagePartRuntime";
4
+ import { useMessagePart } from "../../context/react/MessagePartContext";
5
+ import { SourceMessagePart } from "../../types";
6
+
7
+ export const useMessagePartSource = () => {
8
+ const source = useMessagePart((c) => {
9
+ if (c.type !== "source")
10
+ throw new Error(
11
+ "MessagePartSource can only be used inside source message parts.",
12
+ );
13
+
14
+ return c as MessagePartState & SourceMessagePart;
15
+ });
16
+
17
+ return source;
18
+ };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { MessagePartState } from "../../api/MessagePartRuntime";
4
+ import { useMessagePart } from "../../context/react/MessagePartContext";
5
+ import { TextMessagePart, ReasoningMessagePart } from "../../types";
6
+
7
+ export const useMessagePartText = () => {
8
+ const text = useMessagePart((c) => {
9
+ if (c.type !== "text" && c.type !== "reasoning")
10
+ throw new Error(
11
+ "MessagePartText can only be used inside text or reasoning message parts.",
12
+ );
13
+
14
+ return c as MessagePartState & (TextMessagePart | ReasoningMessagePart);
15
+ });
16
+
17
+ return text;
18
+ };
@@ -36,6 +36,7 @@ export abstract class BaseThreadRuntimeCore implements ThreadRuntimeCore {
36
36
  protected readonly repository = new MessageRepository();
37
37
  public abstract get adapters(): BaseThreadAdapters | undefined;
38
38
  public abstract get isDisabled(): boolean;
39
+ public abstract get isLoading(): boolean;
39
40
  public abstract get suggestions(): readonly ThreadSuggestion[];
40
41
  public abstract get extras(): unknown;
41
42
 
@@ -13,6 +13,7 @@ type ThreadListItemCoreState = {
13
13
  };
14
14
 
15
15
  export type ThreadListRuntimeCore = {
16
+ readonly isLoading: boolean;
16
17
  mainThreadId: string;
17
18
  newThreadId: string | undefined;
18
19
 
@@ -101,6 +101,7 @@ export type ThreadRuntimeCore = Readonly<{
101
101
 
102
102
  capabilities: Readonly<RuntimeCapabilities>;
103
103
  isDisabled: boolean;
104
+ isLoading: boolean;
104
105
  messages: readonly ThreadMessage[];
105
106
  state: ReadonlyJSONValue;
106
107
  suggestions: readonly ThreadSuggestion[];
@@ -20,6 +20,7 @@ export type ExternalStoreThreadListAdapter = {
20
20
  * @deprecated This API is still under active development and might change without notice.
21
21
  */
22
22
  threadId?: string | undefined;
23
+ isLoading?: boolean | undefined;
23
24
  threads?: readonly ExternalStoreThreadData<"regular">[] | undefined;
24
25
  archivedThreads?: readonly ExternalStoreThreadData<"archived">[] | undefined;
25
26
  /**
@@ -51,6 +52,7 @@ type ExternalStoreMessageConverterAdapter<T> = {
51
52
  type ExternalStoreAdapterBase<T> = {
52
53
  isDisabled?: boolean | undefined;
53
54
  isRunning?: boolean | undefined;
55
+ isLoading?: boolean | undefined;
54
56
  messages: readonly T[];
55
57
  suggestions?: readonly ThreadSuggestion[] | undefined;
56
58
  extras?: unknown;