@flanksource/clicky-ui 0.3.44 → 0.3.45

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 (471) hide show
  1. package/README.md +2 -0
  2. package/dist/ai.cjs +4 -2
  3. package/dist/ai.cjs.map +1 -1
  4. package/dist/ai.js +3 -1
  5. package/dist/components/MdxEditorField.cjs +40 -22
  6. package/dist/components/MdxEditorField.cjs.map +1 -1
  7. package/dist/components/MdxEditorField.d.ts.map +1 -1
  8. package/dist/components/MdxEditorField.js +41 -23
  9. package/dist/components/MdxEditorField.js.map +1 -1
  10. package/dist/components/json-schema-form-item-summary.cjs +6 -1
  11. package/dist/components/json-schema-form-item-summary.cjs.map +1 -1
  12. package/dist/components/json-schema-form-item-summary.d.ts.map +1 -1
  13. package/dist/components/json-schema-form-item-summary.js +6 -1
  14. package/dist/components/json-schema-form-item-summary.js.map +1 -1
  15. package/dist/data/CodeBlock.cjs +3 -2
  16. package/dist/data/CodeBlock.cjs.map +1 -1
  17. package/dist/data/CodeBlock.d.ts +3 -1
  18. package/dist/data/CodeBlock.d.ts.map +1 -1
  19. package/dist/data/CodeBlock.js +3 -2
  20. package/dist/data/CodeBlock.js.map +1 -1
  21. package/dist/data/GraphDiagram.cjs +18 -6
  22. package/dist/data/GraphDiagram.cjs.map +1 -1
  23. package/dist/data/GraphDiagram.d.ts +9 -1
  24. package/dist/data/GraphDiagram.d.ts.map +1 -1
  25. package/dist/data/GraphDiagram.js +18 -6
  26. package/dist/data/GraphDiagram.js.map +1 -1
  27. package/dist/data/GraphDiagramNodes.cjs +38 -29
  28. package/dist/data/GraphDiagramNodes.cjs.map +1 -1
  29. package/dist/data/GraphDiagramNodes.d.ts +8 -2
  30. package/dist/data/GraphDiagramNodes.d.ts.map +1 -1
  31. package/dist/data/GraphDiagramNodes.js +38 -29
  32. package/dist/data/GraphDiagramNodes.js.map +1 -1
  33. package/dist/data/JsonView.cjs +118 -49
  34. package/dist/data/JsonView.cjs.map +1 -1
  35. package/dist/data/JsonView.d.ts +13 -10
  36. package/dist/data/JsonView.d.ts.map +1 -1
  37. package/dist/data/JsonView.js +118 -49
  38. package/dist/data/JsonView.js.map +1 -1
  39. package/dist/data/MarkdownEditor.cjs +2 -2
  40. package/dist/data/MarkdownEditor.cjs.map +1 -1
  41. package/dist/data/MarkdownEditor.js +2 -2
  42. package/dist/data/MarkdownEditor.js.map +1 -1
  43. package/dist/data/ai/AdvancedChatConfig.cjs +90 -249
  44. package/dist/data/ai/AdvancedChatConfig.cjs.map +1 -1
  45. package/dist/data/ai/AdvancedChatConfig.d.ts +2 -5
  46. package/dist/data/ai/AdvancedChatConfig.d.ts.map +1 -1
  47. package/dist/data/ai/AdvancedChatConfig.js +91 -250
  48. package/dist/data/ai/AdvancedChatConfig.js.map +1 -1
  49. package/dist/data/ai/ChatButton.cjs +2 -0
  50. package/dist/data/ai/ChatButton.cjs.map +1 -1
  51. package/dist/data/ai/ChatButton.d.ts +1 -1
  52. package/dist/data/ai/ChatButton.d.ts.map +1 -1
  53. package/dist/data/ai/ChatButton.js +2 -0
  54. package/dist/data/ai/ChatButton.js.map +1 -1
  55. package/dist/data/ai/ChatFab.cjs +5 -1
  56. package/dist/data/ai/ChatFab.cjs.map +1 -1
  57. package/dist/data/ai/ChatFab.d.ts +5 -1
  58. package/dist/data/ai/ChatFab.d.ts.map +1 -1
  59. package/dist/data/ai/ChatFab.js +5 -1
  60. package/dist/data/ai/ChatFab.js.map +1 -1
  61. package/dist/data/ai/ChatWindow.cjs +2 -8
  62. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  63. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  64. package/dist/data/ai/ChatWindow.js +2 -8
  65. package/dist/data/ai/ChatWindow.js.map +1 -1
  66. package/dist/data/ai/ChatWindow.runtime.cjs +0 -5
  67. package/dist/data/ai/ChatWindow.runtime.cjs.map +1 -1
  68. package/dist/data/ai/ChatWindow.runtime.d.ts +0 -2
  69. package/dist/data/ai/ChatWindow.runtime.d.ts.map +1 -1
  70. package/dist/data/ai/ChatWindow.runtime.js +0 -5
  71. package/dist/data/ai/ChatWindow.runtime.js.map +1 -1
  72. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs +2 -2
  73. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs.map +1 -1
  74. package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts.map +1 -1
  75. package/dist/data/ai/PromptRunEditor/runtimeActions.js +2 -2
  76. package/dist/data/ai/PromptRunEditor/runtimeActions.js.map +1 -1
  77. package/dist/data/ai/SessionInspector.approvals.cjs +3 -6
  78. package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
  79. package/dist/data/ai/SessionInspector.approvals.js +3 -6
  80. package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
  81. package/dist/data/ai/SessionViewer.cjs +13 -4
  82. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  83. package/dist/data/ai/SessionViewer.d.ts +5 -1
  84. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  85. package/dist/data/ai/SessionViewer.header.cjs +1 -1
  86. package/dist/data/ai/SessionViewer.header.cjs.map +1 -1
  87. package/dist/data/ai/SessionViewer.header.js +1 -1
  88. package/dist/data/ai/SessionViewer.header.js.map +1 -1
  89. package/dist/data/ai/SessionViewer.js +13 -4
  90. package/dist/data/ai/SessionViewer.js.map +1 -1
  91. package/dist/data/ai/SessionViewer.model.cjs +2 -0
  92. package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
  93. package/dist/data/ai/SessionViewer.model.d.ts +1 -0
  94. package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
  95. package/dist/data/ai/SessionViewer.model.js +2 -0
  96. package/dist/data/ai/SessionViewer.model.js.map +1 -1
  97. package/dist/data/ai/SessionViewer.rows.cjs +41 -27
  98. package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
  99. package/dist/data/ai/SessionViewer.rows.d.ts +4 -2
  100. package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
  101. package/dist/data/ai/SessionViewer.rows.js +41 -27
  102. package/dist/data/ai/SessionViewer.rows.js.map +1 -1
  103. package/dist/data/ai/SessionViewer.tokens.cjs +35 -0
  104. package/dist/data/ai/SessionViewer.tokens.cjs.map +1 -0
  105. package/dist/data/ai/SessionViewer.tokens.d.ts +5 -0
  106. package/dist/data/ai/SessionViewer.tokens.d.ts.map +1 -0
  107. package/dist/data/ai/SessionViewer.tokens.js +35 -0
  108. package/dist/data/ai/SessionViewer.tokens.js.map +1 -0
  109. package/dist/data/ai/SessionViewer.tool-cost.cjs +128 -0
  110. package/dist/data/ai/SessionViewer.tool-cost.cjs.map +1 -0
  111. package/dist/data/ai/SessionViewer.tool-cost.d.ts +6 -0
  112. package/dist/data/ai/SessionViewer.tool-cost.d.ts.map +1 -0
  113. package/dist/data/ai/SessionViewer.tool-cost.js +128 -0
  114. package/dist/data/ai/SessionViewer.tool-cost.js.map +1 -0
  115. package/dist/data/ai/SessionViewer.tool-details.cjs +3 -1
  116. package/dist/data/ai/SessionViewer.tool-details.cjs.map +1 -1
  117. package/dist/data/ai/SessionViewer.tool-details.d.ts.map +1 -1
  118. package/dist/data/ai/SessionViewer.tool-details.js +3 -1
  119. package/dist/data/ai/SessionViewer.tool-details.js.map +1 -1
  120. package/dist/data/ai/SessionViewer.tool-row.cjs +55 -35
  121. package/dist/data/ai/SessionViewer.tool-row.cjs.map +1 -1
  122. package/dist/data/ai/SessionViewer.tool-row.d.ts +2 -1
  123. package/dist/data/ai/SessionViewer.tool-row.d.ts.map +1 -1
  124. package/dist/data/ai/SessionViewer.tool-row.js +55 -35
  125. package/dist/data/ai/SessionViewer.tool-row.js.map +1 -1
  126. package/dist/data/ai/SessionViewer.unified.d.ts +4 -0
  127. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  128. package/dist/data/ai/SessionViewerMenu.cjs +18 -1
  129. package/dist/data/ai/SessionViewerMenu.cjs.map +1 -1
  130. package/dist/data/ai/SessionViewerMenu.d.ts +6 -1
  131. package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -1
  132. package/dist/data/ai/SessionViewerMenu.js +18 -1
  133. package/dist/data/ai/SessionViewerMenu.js.map +1 -1
  134. package/dist/data/ai/ToolPreferences.cjs +149 -143
  135. package/dist/data/ai/ToolPreferences.cjs.map +1 -1
  136. package/dist/data/ai/ToolPreferences.d.ts +20 -6
  137. package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
  138. package/dist/data/ai/ToolPreferences.js +151 -146
  139. package/dist/data/ai/ToolPreferences.js.map +1 -1
  140. package/dist/data/ai/ToolPreferences.model.cjs +14 -10
  141. package/dist/data/ai/ToolPreferences.model.cjs.map +1 -1
  142. package/dist/data/ai/ToolPreferences.model.d.ts +1 -0
  143. package/dist/data/ai/ToolPreferences.model.d.ts.map +1 -1
  144. package/dist/data/ai/ToolPreferences.model.js +15 -11
  145. package/dist/data/ai/ToolPreferences.model.js.map +1 -1
  146. package/dist/data/ai/ToolPreferencesList.cjs +1 -0
  147. package/dist/data/ai/ToolPreferencesList.cjs.map +1 -1
  148. package/dist/data/ai/ToolPreferencesList.d.ts +4 -1
  149. package/dist/data/ai/ToolPreferencesList.d.ts.map +1 -1
  150. package/dist/data/ai/ToolPreferencesList.js +2 -1
  151. package/dist/data/ai/ToolPreferencesList.js.map +1 -1
  152. package/dist/data/ai/ToolSchemaBrowser.cjs +52 -53
  153. package/dist/data/ai/ToolSchemaBrowser.cjs.map +1 -1
  154. package/dist/data/ai/ToolSchemaBrowser.d.ts +6 -3
  155. package/dist/data/ai/ToolSchemaBrowser.d.ts.map +1 -1
  156. package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs +9 -13
  157. package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs.map +1 -1
  158. package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts +5 -2
  159. package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts.map +1 -1
  160. package/dist/data/ai/ToolSchemaBrowser.directory-header.js +9 -13
  161. package/dist/data/ai/ToolSchemaBrowser.directory-header.js.map +1 -1
  162. package/dist/data/ai/ToolSchemaBrowser.js +53 -54
  163. package/dist/data/ai/ToolSchemaBrowser.js.map +1 -1
  164. package/dist/data/ai/ToolSchemaBrowser.model.cjs +19 -27
  165. package/dist/data/ai/ToolSchemaBrowser.model.cjs.map +1 -1
  166. package/dist/data/ai/ToolSchemaBrowser.model.d.ts +9 -6
  167. package/dist/data/ai/ToolSchemaBrowser.model.d.ts.map +1 -1
  168. package/dist/data/ai/ToolSchemaBrowser.model.js +20 -28
  169. package/dist/data/ai/ToolSchemaBrowser.model.js.map +1 -1
  170. package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs +12 -213
  171. package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs.map +1 -1
  172. package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts +1 -3
  173. package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts.map +1 -1
  174. package/dist/data/ai/ToolSchemaBrowser.sidebar.js +13 -214
  175. package/dist/data/ai/ToolSchemaBrowser.sidebar.js.map +1 -1
  176. package/dist/data/ai/ToolSchemaBrowser.strategies.cjs +54 -0
  177. package/dist/data/ai/ToolSchemaBrowser.strategies.cjs.map +1 -0
  178. package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts +9 -0
  179. package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts.map +1 -0
  180. package/dist/data/ai/ToolSchemaBrowser.strategies.js +54 -0
  181. package/dist/data/ai/ToolSchemaBrowser.strategies.js.map +1 -0
  182. package/dist/data/ai/ToolSchemaBrowser.tree.cjs +179 -0
  183. package/dist/data/ai/ToolSchemaBrowser.tree.cjs.map +1 -0
  184. package/dist/data/ai/ToolSchemaBrowser.tree.d.ts +20 -0
  185. package/dist/data/ai/ToolSchemaBrowser.tree.d.ts.map +1 -0
  186. package/dist/data/ai/ToolSchemaBrowser.tree.js +179 -0
  187. package/dist/data/ai/ToolSchemaBrowser.tree.js.map +1 -0
  188. package/dist/data/ai/index.d.ts +2 -2
  189. package/dist/data/ai/index.d.ts.map +1 -1
  190. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs +8 -28
  191. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs.map +1 -1
  192. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.d.ts.map +1 -1
  193. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js +9 -29
  194. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js.map +1 -1
  195. package/dist/data/ai/session-token-sizing.d.ts +32 -0
  196. package/dist/data/ai/session-token-sizing.d.ts.map +1 -0
  197. package/dist/data/ai/use-session-token-sizing.cjs +73 -0
  198. package/dist/data/ai/use-session-token-sizing.cjs.map +1 -0
  199. package/dist/data/ai/use-session-token-sizing.d.ts +21 -0
  200. package/dist/data/ai/use-session-token-sizing.d.ts.map +1 -0
  201. package/dist/data/ai/use-session-token-sizing.js +73 -0
  202. package/dist/data/ai/use-session-token-sizing.js.map +1 -0
  203. package/dist/data/call-graph/CallGraph.cjs +250 -0
  204. package/dist/data/call-graph/CallGraph.cjs.map +1 -0
  205. package/dist/data/call-graph/CallGraph.d.ts +69 -0
  206. package/dist/data/call-graph/CallGraph.d.ts.map +1 -0
  207. package/dist/data/call-graph/CallGraph.js +250 -0
  208. package/dist/data/call-graph/CallGraph.js.map +1 -0
  209. package/dist/data/call-graph/CallGraphGlyphs.cjs +39 -0
  210. package/dist/data/call-graph/CallGraphGlyphs.cjs.map +1 -0
  211. package/dist/data/call-graph/CallGraphGlyphs.d.ts +19 -0
  212. package/dist/data/call-graph/CallGraphGlyphs.d.ts.map +1 -0
  213. package/dist/data/call-graph/CallGraphGlyphs.js +39 -0
  214. package/dist/data/call-graph/CallGraphGlyphs.js.map +1 -0
  215. package/dist/data/call-graph/CallGraphMembers.cjs +50 -0
  216. package/dist/data/call-graph/CallGraphMembers.cjs.map +1 -0
  217. package/dist/data/call-graph/CallGraphMembers.d.ts +22 -0
  218. package/dist/data/call-graph/CallGraphMembers.d.ts.map +1 -0
  219. package/dist/data/call-graph/CallGraphMembers.js +50 -0
  220. package/dist/data/call-graph/CallGraphMembers.js.map +1 -0
  221. package/dist/data/call-graph/CallGraphParts.cjs +204 -0
  222. package/dist/data/call-graph/CallGraphParts.cjs.map +1 -0
  223. package/dist/data/call-graph/CallGraphParts.d.ts +44 -0
  224. package/dist/data/call-graph/CallGraphParts.d.ts.map +1 -0
  225. package/dist/data/call-graph/CallGraphParts.js +204 -0
  226. package/dist/data/call-graph/CallGraphParts.js.map +1 -0
  227. package/dist/data/call-graph/CallGraphToolbar.cjs +186 -0
  228. package/dist/data/call-graph/CallGraphToolbar.cjs.map +1 -0
  229. package/dist/data/call-graph/CallGraphToolbar.d.ts +45 -0
  230. package/dist/data/call-graph/CallGraphToolbar.d.ts.map +1 -0
  231. package/dist/data/call-graph/CallGraphToolbar.js +186 -0
  232. package/dist/data/call-graph/CallGraphToolbar.js.map +1 -0
  233. package/dist/data/call-graph/call-graph-exclude.cjs +75 -0
  234. package/dist/data/call-graph/call-graph-exclude.cjs.map +1 -0
  235. package/dist/data/call-graph/call-graph-exclude.d.ts +31 -0
  236. package/dist/data/call-graph/call-graph-exclude.d.ts.map +1 -0
  237. package/dist/data/call-graph/call-graph-exclude.js +75 -0
  238. package/dist/data/call-graph/call-graph-exclude.js.map +1 -0
  239. package/dist/data/call-graph/call-graph-labels.cjs +96 -0
  240. package/dist/data/call-graph/call-graph-labels.cjs.map +1 -0
  241. package/dist/data/call-graph/call-graph-labels.d.ts +53 -0
  242. package/dist/data/call-graph/call-graph-labels.d.ts.map +1 -0
  243. package/dist/data/call-graph/call-graph-labels.js +96 -0
  244. package/dist/data/call-graph/call-graph-labels.js.map +1 -0
  245. package/dist/data/call-graph/call-graph-model.cjs +161 -0
  246. package/dist/data/call-graph/call-graph-model.cjs.map +1 -0
  247. package/dist/data/call-graph/call-graph-model.d.ts +102 -0
  248. package/dist/data/call-graph/call-graph-model.d.ts.map +1 -0
  249. package/dist/data/call-graph/call-graph-model.js +161 -0
  250. package/dist/data/call-graph/call-graph-model.js.map +1 -0
  251. package/dist/data/call-graph/call-graph-vocabulary.cjs +177 -0
  252. package/dist/data/call-graph/call-graph-vocabulary.cjs.map +1 -0
  253. package/dist/data/call-graph/call-graph-vocabulary.d.ts +72 -0
  254. package/dist/data/call-graph/call-graph-vocabulary.d.ts.map +1 -0
  255. package/dist/data/call-graph/call-graph-vocabulary.js +177 -0
  256. package/dist/data/call-graph/call-graph-vocabulary.js.map +1 -0
  257. package/dist/data/call-graph/call-graph.fixtures.d.ts +63 -0
  258. package/dist/data/call-graph/call-graph.fixtures.d.ts.map +1 -0
  259. package/dist/data/call-graph/index.d.ts +7 -0
  260. package/dist/data/call-graph/index.d.ts.map +1 -0
  261. package/dist/data/call-graph/types.cjs +5 -0
  262. package/dist/data/call-graph/types.cjs.map +1 -0
  263. package/dist/data/call-graph/types.d.ts +135 -0
  264. package/dist/data/call-graph/types.d.ts.map +1 -0
  265. package/dist/data/call-graph/types.js +5 -0
  266. package/dist/data/call-graph/types.js.map +1 -0
  267. package/dist/data/call-graph/use-call-graph.cjs +93 -0
  268. package/dist/data/call-graph/use-call-graph.cjs.map +1 -0
  269. package/dist/data/call-graph/use-call-graph.d.ts +24 -0
  270. package/dist/data/call-graph/use-call-graph.d.ts.map +1 -0
  271. package/dist/data/call-graph/use-call-graph.js +93 -0
  272. package/dist/data/call-graph/use-call-graph.js.map +1 -0
  273. package/dist/data/chat/Chat.cjs +39 -15
  274. package/dist/data/chat/Chat.cjs.map +1 -1
  275. package/dist/data/chat/Chat.d.ts.map +1 -1
  276. package/dist/data/chat/Chat.fixtures.cjs +2 -2
  277. package/dist/data/chat/Chat.fixtures.cjs.map +1 -1
  278. package/dist/data/chat/Chat.fixtures.js +2 -2
  279. package/dist/data/chat/Chat.fixtures.js.map +1 -1
  280. package/dist/data/chat/Chat.js +40 -16
  281. package/dist/data/chat/Chat.js.map +1 -1
  282. package/dist/data/chat/ChatRuntimeToolbar.cjs +3 -6
  283. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  284. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  285. package/dist/data/chat/ChatRuntimeToolbar.js +3 -6
  286. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  287. package/dist/data/chat/ContextMeter.bar.cjs +5 -8
  288. package/dist/data/chat/ContextMeter.bar.cjs.map +1 -1
  289. package/dist/data/chat/ContextMeter.bar.d.ts +1 -1
  290. package/dist/data/chat/ContextMeter.bar.d.ts.map +1 -1
  291. package/dist/data/chat/ContextMeter.bar.js +5 -8
  292. package/dist/data/chat/ContextMeter.bar.js.map +1 -1
  293. package/dist/data/chat/ContextMeter.cjs +18 -19
  294. package/dist/data/chat/ContextMeter.cjs.map +1 -1
  295. package/dist/data/chat/ContextMeter.d.ts +1 -1
  296. package/dist/data/chat/ContextMeter.d.ts.map +1 -1
  297. package/dist/data/chat/ContextMeter.js +18 -19
  298. package/dist/data/chat/ContextMeter.js.map +1 -1
  299. package/dist/data/chat/Conversation.cjs +2 -1
  300. package/dist/data/chat/Conversation.cjs.map +1 -1
  301. package/dist/data/chat/Conversation.d.ts +4 -1
  302. package/dist/data/chat/Conversation.d.ts.map +1 -1
  303. package/dist/data/chat/Conversation.js +2 -1
  304. package/dist/data/chat/Conversation.js.map +1 -1
  305. package/dist/data/chat/Message.cjs +39 -12
  306. package/dist/data/chat/Message.cjs.map +1 -1
  307. package/dist/data/chat/Message.d.ts +1 -1
  308. package/dist/data/chat/Message.d.ts.map +1 -1
  309. package/dist/data/chat/Message.js +40 -13
  310. package/dist/data/chat/Message.js.map +1 -1
  311. package/dist/data/chat/ToolCall.cjs +60 -5
  312. package/dist/data/chat/ToolCall.cjs.map +1 -1
  313. package/dist/data/chat/ToolCall.d.ts +7 -2
  314. package/dist/data/chat/ToolCall.d.ts.map +1 -1
  315. package/dist/data/chat/ToolCall.js +60 -5
  316. package/dist/data/chat/ToolCall.js.map +1 -1
  317. package/dist/data/chat/approval.cjs.map +1 -1
  318. package/dist/data/chat/approval.d.ts +2 -2
  319. package/dist/data/chat/approval.d.ts.map +1 -1
  320. package/dist/data/chat/approval.js.map +1 -1
  321. package/dist/data/chat/tool-policy.cjs +59 -2
  322. package/dist/data/chat/tool-policy.cjs.map +1 -1
  323. package/dist/data/chat/tool-policy.d.ts +9 -0
  324. package/dist/data/chat/tool-policy.d.ts.map +1 -1
  325. package/dist/data/chat/tool-policy.js +59 -2
  326. package/dist/data/chat/tool-policy.js.map +1 -1
  327. package/dist/data/chat/types.cjs +6 -0
  328. package/dist/data/chat/types.cjs.map +1 -1
  329. package/dist/data/chat/types.d.ts +13 -4
  330. package/dist/data/chat/types.d.ts.map +1 -1
  331. package/dist/data/chat/types.js +7 -1
  332. package/dist/data/chat/types.js.map +1 -1
  333. package/dist/data/chat/usage-snapshot.cjs +11 -6
  334. package/dist/data/chat/usage-snapshot.cjs.map +1 -1
  335. package/dist/data/chat/usage-snapshot.d.ts +0 -1
  336. package/dist/data/chat/usage-snapshot.d.ts.map +1 -1
  337. package/dist/data/chat/usage-snapshot.js +11 -6
  338. package/dist/data/chat/usage-snapshot.js.map +1 -1
  339. package/dist/data/diagnostics/StackFrameRow.cjs +3 -3
  340. package/dist/data/diagnostics/StackFrameRow.cjs.map +1 -1
  341. package/dist/data/diagnostics/StackFrameRow.js +3 -3
  342. package/dist/data/diagnostics/StackFrameRow.js.map +1 -1
  343. package/dist/data/graph-columns-layout.cjs +26 -10
  344. package/dist/data/graph-columns-layout.cjs.map +1 -1
  345. package/dist/data/graph-columns-layout.d.ts +8 -0
  346. package/dist/data/graph-columns-layout.d.ts.map +1 -1
  347. package/dist/data/graph-columns-layout.js +26 -10
  348. package/dist/data/graph-columns-layout.js.map +1 -1
  349. package/dist/data/graph-diagram-model.cjs.map +1 -1
  350. package/dist/data/graph-diagram-model.d.ts +5 -0
  351. package/dist/data/graph-diagram-model.d.ts.map +1 -1
  352. package/dist/data/graph-diagram-model.js.map +1 -1
  353. package/dist/data/graph-edge-routing.cjs +9 -3
  354. package/dist/data/graph-edge-routing.cjs.map +1 -1
  355. package/dist/data/graph-edge-routing.d.ts +2 -0
  356. package/dist/data/graph-edge-routing.d.ts.map +1 -1
  357. package/dist/data/graph-edge-routing.js +9 -3
  358. package/dist/data/graph-edge-routing.js.map +1 -1
  359. package/dist/data/json-view/JsonSource.cjs +84 -0
  360. package/dist/data/json-view/JsonSource.cjs.map +1 -0
  361. package/dist/data/json-view/JsonSource.d.ts +7 -0
  362. package/dist/data/json-view/JsonSource.d.ts.map +1 -0
  363. package/dist/data/json-view/JsonSource.js +84 -0
  364. package/dist/data/json-view/JsonSource.js.map +1 -0
  365. package/dist/data/json-view/parse-prefix.cjs +132 -0
  366. package/dist/data/json-view/parse-prefix.cjs.map +1 -0
  367. package/dist/data/json-view/parse-prefix.d.ts +11 -0
  368. package/dist/data/json-view/parse-prefix.d.ts.map +1 -0
  369. package/dist/data/json-view/parse-prefix.js +132 -0
  370. package/dist/data/json-view/parse-prefix.js.map +1 -0
  371. package/dist/data/json-view/parse-source.cjs +62 -0
  372. package/dist/data/json-view/parse-source.cjs.map +1 -0
  373. package/dist/data/json-view/parse-source.d.ts +16 -0
  374. package/dist/data/json-view/parse-source.d.ts.map +1 -0
  375. package/dist/data/json-view/parse-source.js +62 -0
  376. package/dist/data/json-view/parse-source.js.map +1 -0
  377. package/dist/data/json-view/story-fixtures.d.ts +6 -0
  378. package/dist/data/json-view/story-fixtures.d.ts.map +1 -0
  379. package/dist/data/json-view/types.d.ts +14 -0
  380. package/dist/data/json-view/types.d.ts.map +1 -0
  381. package/dist/data/runtime/RuntimeBar.cjs +2 -5
  382. package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
  383. package/dist/data/runtime/RuntimeBar.d.ts +2 -4
  384. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
  385. package/dist/data/runtime/RuntimeBar.fields.cjs +2 -2
  386. package/dist/data/runtime/RuntimeBar.fields.cjs.map +1 -1
  387. package/dist/data/runtime/RuntimeBar.fields.js +2 -2
  388. package/dist/data/runtime/RuntimeBar.fields.js.map +1 -1
  389. package/dist/data/runtime/RuntimeBar.js +2 -5
  390. package/dist/data/runtime/RuntimeBar.js.map +1 -1
  391. package/dist/data/runtime/RuntimeBar.selection.cjs +4 -1
  392. package/dist/data/runtime/RuntimeBar.selection.cjs.map +1 -1
  393. package/dist/data/runtime/RuntimeBar.selection.d.ts.map +1 -1
  394. package/dist/data/runtime/RuntimeBar.selection.js +5 -2
  395. package/dist/data/runtime/RuntimeBar.selection.js.map +1 -1
  396. package/dist/data/runtime/RuntimeBarActions.cjs +1 -5
  397. package/dist/data/runtime/RuntimeBarActions.cjs.map +1 -1
  398. package/dist/data/runtime/RuntimeBarActions.d.ts +1 -1
  399. package/dist/data/runtime/RuntimeBarActions.d.ts.map +1 -1
  400. package/dist/data/runtime/RuntimeBarActions.js +1 -5
  401. package/dist/data/runtime/RuntimeBarActions.js.map +1 -1
  402. package/dist/data/runtime/RuntimeBarIdentity.cjs +6 -14
  403. package/dist/data/runtime/RuntimeBarIdentity.cjs.map +1 -1
  404. package/dist/data/runtime/RuntimeBarIdentity.d.ts +0 -1
  405. package/dist/data/runtime/RuntimeBarIdentity.d.ts.map +1 -1
  406. package/dist/data/runtime/RuntimeBarIdentity.js +6 -14
  407. package/dist/data/runtime/RuntimeBarIdentity.js.map +1 -1
  408. package/dist/data/runtime/RuntimeBarLayout.cjs +8 -27
  409. package/dist/data/runtime/RuntimeBarLayout.cjs.map +1 -1
  410. package/dist/data/runtime/RuntimeBarLayout.d.ts.map +1 -1
  411. package/dist/data/runtime/RuntimeBarLayout.js +8 -27
  412. package/dist/data/runtime/RuntimeBarLayout.js.map +1 -1
  413. package/dist/data/runtime/RuntimeBarSegment.cjs +1 -5
  414. package/dist/data/runtime/RuntimeBarSegment.cjs.map +1 -1
  415. package/dist/data/runtime/RuntimeBarSegment.d.ts.map +1 -1
  416. package/dist/data/runtime/RuntimeBarSegment.js +1 -5
  417. package/dist/data/runtime/RuntimeBarSegment.js.map +1 -1
  418. package/dist/data/runtime/use-runtime-bar-overflow.cjs +4 -10
  419. package/dist/data/runtime/use-runtime-bar-overflow.cjs.map +1 -1
  420. package/dist/data/runtime/use-runtime-bar-overflow.d.ts +1 -2
  421. package/dist/data/runtime/use-runtime-bar-overflow.d.ts.map +1 -1
  422. package/dist/data/runtime/use-runtime-bar-overflow.js +4 -10
  423. package/dist/data/runtime/use-runtime-bar-overflow.js.map +1 -1
  424. package/dist/data/test-runner/TestRunner.fixtures.d.ts +0 -20
  425. package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
  426. package/dist/data/test-runner/TestRunner.large-fixtures.d.ts +22 -0
  427. package/dist/data/test-runner/TestRunner.large-fixtures.d.ts.map +1 -0
  428. package/dist/data/use-pan-zoom.cjs +23 -10
  429. package/dist/data/use-pan-zoom.cjs.map +1 -1
  430. package/dist/data/use-pan-zoom.d.ts +16 -2
  431. package/dist/data/use-pan-zoom.d.ts.map +1 -1
  432. package/dist/data/use-pan-zoom.js +23 -10
  433. package/dist/data/use-pan-zoom.js.map +1 -1
  434. package/dist/data/version-info.cjs +3 -3
  435. package/dist/data/version-info.js +3 -3
  436. package/dist/data.cjs +26 -2
  437. package/dist/data.cjs.map +1 -1
  438. package/dist/data.d.ts +1 -0
  439. package/dist/data.d.ts.map +1 -1
  440. package/dist/data.js +24 -0
  441. package/dist/data.js.map +1 -1
  442. package/dist/index.cjs +28 -4
  443. package/dist/index.cjs.map +1 -1
  444. package/dist/index.js +24 -0
  445. package/dist/index.js.map +1 -1
  446. package/dist/layout/Workspace.cjs +13 -4
  447. package/dist/layout/Workspace.cjs.map +1 -1
  448. package/dist/layout/Workspace.d.ts +7 -2
  449. package/dist/layout/Workspace.d.ts.map +1 -1
  450. package/dist/layout/Workspace.js +13 -4
  451. package/dist/layout/Workspace.js.map +1 -1
  452. package/dist/lib/permission-strategies.cjs +71 -11
  453. package/dist/lib/permission-strategies.cjs.map +1 -1
  454. package/dist/lib/permission-strategies.d.ts +3 -0
  455. package/dist/lib/permission-strategies.d.ts.map +1 -1
  456. package/dist/lib/permission-strategies.js +71 -11
  457. package/dist/lib/permission-strategies.js.map +1 -1
  458. package/dist/styles.css +1 -1
  459. package/package.json +5 -3
  460. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs +0 -57
  461. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs.map +0 -1
  462. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts +0 -7
  463. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts.map +0 -1
  464. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js +0 -57
  465. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js.map +0 -1
  466. package/dist/data/runtime/RuntimeBar.context.cjs +0 -8
  467. package/dist/data/runtime/RuntimeBar.context.cjs.map +0 -1
  468. package/dist/data/runtime/RuntimeBar.context.d.ts +0 -2
  469. package/dist/data/runtime/RuntimeBar.context.d.ts.map +0 -1
  470. package/dist/data/runtime/RuntimeBar.context.js +0 -8
  471. package/dist/data/runtime/RuntimeBar.context.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Conversation.cjs","sources":["../../../src/data/chat/Conversation.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiArrowDown, UiCheck, UiCircleX, UiCopy, UiLoader } from \"../../icons\";\nimport { Message, type MessageActionHandlers } from \"./Message\";\nimport type { ChatStatus, UIMessage } from \"./types\";\n\nexport type ConversationProps = MessageActionHandlers & {\n messages: UIMessage[];\n /** Current chat status; used for transient pending/error affordances. */\n status?: ChatStatus | undefined;\n /** Last request error from the chat transport, if any. */\n error?: Error | undefined;\n /** Clears the visible transport error. */\n onClearError?: (() => void) | undefined;\n /** Conversation/thread id, surfaced in the copyable error report. */\n sessionId?: string | undefined;\n /** Selected model id, surfaced in the copyable error report. */\n model?: string | undefined;\n /** Shown when there are no messages yet. */\n emptyState?: React.ReactNode;\n className?: string;\n};\n\n/** A scrollable message log that sticks to the bottom as new content streams\n * in, unless the user has scrolled up — in which case a jump-to-bottom button\n * appears. */\nexport function Conversation({\n messages,\n status,\n error,\n onClearError,\n sessionId,\n model,\n emptyState,\n className,\n ...actions\n}: ConversationProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const [pinned, setPinned] = useState(true);\n const isWaiting = status === \"submitted\" || (status === \"streaming\" && !hasVisibleAssistantResponse(messages));\n const errorText = error?.message || (status === \"error\" ? \"The assistant request failed.\" : undefined);\n\n const onScroll = () => {\n const el = scrollRef.current;\n if (!el) return;\n const distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n setPinned(distance < 32);\n };\n\n useEffect(() => {\n const el = scrollRef.current;\n if (el && pinned) {\n el.scrollTop = el.scrollHeight;\n }\n });\n\n const scrollToBottom = () => {\n const el = scrollRef.current;\n if (el) el.scrollTo({ top: el.scrollHeight, behavior: \"smooth\" });\n };\n\n return (\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n <div\n ref={scrollRef}\n onScroll={onScroll}\n role=\"log\"\n className={cn(\"flex-1 overflow-y-auto\", className)}\n >\n {messages.length === 0 && emptyState ? (\n <div className=\"flex size-full flex-col items-center justify-center gap-3 p-8 text-center\">\n {emptyState}\n </div>\n ) : (\n <div className=\"flex flex-col gap-8 p-4\">\n {messages.map((message) => (\n <Message key={message.id} message={message} {...actions} />\n ))}\n {isWaiting && <LoadingIndicator />}\n {errorText && (\n <ErrorNotice\n message={errorText}\n error={error}\n sessionId={sessionId}\n model={model}\n onClear={onClearError}\n />\n )}\n </div>\n )}\n </div>\n\n {!pinned && messages.length > 0 && (\n <button\n type=\"button\"\n aria-label=\"Scroll to latest\"\n onClick={scrollToBottom}\n className=\"absolute bottom-3 left-1/2 flex size-8 -translate-x-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-md hover:text-foreground\"\n >\n <Icon icon={UiArrowDown} className=\"size-4\" />\n </button>\n )}\n </div>\n );\n}\n\nfunction hasVisibleAssistantResponse(messages: UIMessage[]) {\n const last = messages[messages.length - 1];\n if (last?.role !== \"assistant\") return false;\n return last.parts.some((part) => {\n if (part.type === \"step-start\") return false;\n if (part.type === \"text\" || part.type === \"reasoning\") return part.text.length > 0;\n return true;\n });\n}\n\nfunction LoadingIndicator() {\n return (\n <div className=\"flex w-full max-w-[95%] items-center gap-2 text-sm text-muted-foreground\">\n <Icon icon={UiLoader} className=\"size-4 shrink-0 animate-spin\" />\n <span>Waiting for response...</span>\n </div>\n );\n}\n\ntype ErrorReport = {\n message: string;\n error?: Error | undefined;\n sessionId?: string | undefined;\n model?: string | undefined;\n};\n\n/** Assembles a support-ready plain-text report: the error, the session/model\n * that produced it, the page, and the full stack/cause — everything needed to\n * file or triage the failure without a back-and-forth. */\nfunction buildErrorReport({ message, error, sessionId, model }: ErrorReport): string {\n const lines = [`Error: ${message}`];\n if (error?.name && error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (sessionId) lines.push(`Session: ${sessionId}`);\n if (model) lines.push(`Model: ${model}`);\n if (typeof window !== \"undefined\") lines.push(`Page: ${window.location.href}`);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) lines.push(`User agent: ${navigator.userAgent}`);\n lines.push(`Time: ${new Date().toISOString()}`);\n const cause = (error as { cause?: unknown } | undefined)?.cause;\n const detail = error?.stack ?? (cause != null ? String(cause) : \"\");\n if (detail.trim() && detail.trim() !== message) lines.push(\"\", detail.trim());\n return lines.join(\"\\n\");\n}\n\nfunction ErrorNotice({ message, error, sessionId, model, onClear }: ErrorReport & { onClear?: (() => void) | undefined }) {\n const [copied, setCopied] = useState(false);\n const copyReport = () => {\n const clip = typeof navigator !== \"undefined\" ? navigator.clipboard : undefined;\n if (!clip) return;\n void clip\n .writeText(buildErrorReport({ message, error, sessionId, model }))\n .then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n })\n .catch(() => {});\n };\n return (\n <div\n role=\"alert\"\n className=\"flex w-full max-w-[95%] items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\"\n >\n <Icon icon={UiCircleX} className=\"mt-0.5 size-4 shrink-0\" />\n <div className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{message}</div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n aria-label=\"Copy error details\"\n title=\"Copy session id, model, page and full error\"\n className=\"inline-flex items-center gap-1 text-xs underline-offset-2 hover:underline\"\n onClick={copyReport}\n >\n <Icon icon={copied ? UiCheck : UiCopy} className=\"size-3.5\" />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n {onClear && (\n <button type=\"button\" className=\"text-xs underline-offset-2 hover:underline\" onClick={onClear}>\n Dismiss\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"names":["useRef","useState","useEffect","jsxs","jsx","cn","Message","Icon","UiArrowDown","UiLoader","UiCircleX","UiCheck","UiCopy"],"mappings":"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"}
1
+ {"version":3,"file":"Conversation.cjs","sources":["../../../src/data/chat/Conversation.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiArrowDown, UiCheck, UiCircleX, UiCopy, UiLoader } from \"../../icons\";\nimport { Message, type MessageActionHandlers } from \"./Message\";\nimport type { ChatStatus, UIMessage } from \"./types\";\n\nexport type ConversationProps = MessageActionHandlers & {\n messages: UIMessage[];\n /** Current chat status; used for transient pending/error affordances. */\n status?: ChatStatus | undefined;\n /** Last request error from the chat transport, if any. */\n error?: Error | undefined;\n /** Clears the visible transport error. */\n onClearError?: (() => void) | undefined;\n /** Conversation/thread id, surfaced in the copyable error report. */\n sessionId?: string | undefined;\n /** Selected model id, surfaced in the copyable error report. */\n model?: string | undefined;\n /** Hide the waiting indicator because another control (e.g. an approval\n * button) is already showing progress. */\n suppressWaiting?: boolean | undefined;\n /** Shown when there are no messages yet. */\n emptyState?: React.ReactNode;\n className?: string;\n};\n\n/** A scrollable message log that sticks to the bottom as new content streams\n * in, unless the user has scrolled up — in which case a jump-to-bottom button\n * appears. */\nexport function Conversation({\n messages,\n status,\n error,\n onClearError,\n sessionId,\n model,\n suppressWaiting,\n emptyState,\n className,\n ...actions\n}: ConversationProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const [pinned, setPinned] = useState(true);\n const isWaiting =\n !suppressWaiting &&\n (status === \"submitted\" || (status === \"streaming\" && !hasVisibleAssistantResponse(messages)));\n const errorText = error?.message || (status === \"error\" ? \"The assistant request failed.\" : undefined);\n\n const onScroll = () => {\n const el = scrollRef.current;\n if (!el) return;\n const distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n setPinned(distance < 32);\n };\n\n useEffect(() => {\n const el = scrollRef.current;\n if (el && pinned) {\n el.scrollTop = el.scrollHeight;\n }\n });\n\n const scrollToBottom = () => {\n const el = scrollRef.current;\n if (el) el.scrollTo({ top: el.scrollHeight, behavior: \"smooth\" });\n };\n\n return (\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n <div\n ref={scrollRef}\n onScroll={onScroll}\n role=\"log\"\n className={cn(\"flex-1 overflow-y-auto\", className)}\n >\n {messages.length === 0 && emptyState ? (\n <div className=\"flex size-full flex-col items-center justify-center gap-3 p-8 text-center\">\n {emptyState}\n </div>\n ) : (\n <div className=\"flex flex-col gap-8 p-4\">\n {messages.map((message) => (\n <Message key={message.id} message={message} {...actions} />\n ))}\n {isWaiting && <LoadingIndicator />}\n {errorText && (\n <ErrorNotice\n message={errorText}\n error={error}\n sessionId={sessionId}\n model={model}\n onClear={onClearError}\n />\n )}\n </div>\n )}\n </div>\n\n {!pinned && messages.length > 0 && (\n <button\n type=\"button\"\n aria-label=\"Scroll to latest\"\n onClick={scrollToBottom}\n className=\"absolute bottom-3 left-1/2 flex size-8 -translate-x-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-md hover:text-foreground\"\n >\n <Icon icon={UiArrowDown} className=\"size-4\" />\n </button>\n )}\n </div>\n );\n}\n\nfunction hasVisibleAssistantResponse(messages: UIMessage[]) {\n const last = messages[messages.length - 1];\n if (last?.role !== \"assistant\") return false;\n return last.parts.some((part) => {\n if (part.type === \"step-start\") return false;\n if (part.type === \"text\" || part.type === \"reasoning\") return part.text.length > 0;\n return true;\n });\n}\n\nfunction LoadingIndicator() {\n return (\n <div className=\"flex w-full max-w-[95%] items-center gap-2 text-sm text-muted-foreground\">\n <Icon icon={UiLoader} className=\"size-4 shrink-0 animate-spin\" />\n <span>Waiting for response...</span>\n </div>\n );\n}\n\ntype ErrorReport = {\n message: string;\n error?: Error | undefined;\n sessionId?: string | undefined;\n model?: string | undefined;\n};\n\n/** Assembles a support-ready plain-text report: the error, the session/model\n * that produced it, the page, and the full stack/cause — everything needed to\n * file or triage the failure without a back-and-forth. */\nfunction buildErrorReport({ message, error, sessionId, model }: ErrorReport): string {\n const lines = [`Error: ${message}`];\n if (error?.name && error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (sessionId) lines.push(`Session: ${sessionId}`);\n if (model) lines.push(`Model: ${model}`);\n if (typeof window !== \"undefined\") lines.push(`Page: ${window.location.href}`);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) lines.push(`User agent: ${navigator.userAgent}`);\n lines.push(`Time: ${new Date().toISOString()}`);\n const cause = (error as { cause?: unknown } | undefined)?.cause;\n const detail = error?.stack ?? (cause != null ? String(cause) : \"\");\n if (detail.trim() && detail.trim() !== message) lines.push(\"\", detail.trim());\n return lines.join(\"\\n\");\n}\n\nfunction ErrorNotice({ message, error, sessionId, model, onClear }: ErrorReport & { onClear?: (() => void) | undefined }) {\n const [copied, setCopied] = useState(false);\n const copyReport = () => {\n const clip = typeof navigator !== \"undefined\" ? navigator.clipboard : undefined;\n if (!clip) return;\n void clip\n .writeText(buildErrorReport({ message, error, sessionId, model }))\n .then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n })\n .catch(() => {});\n };\n return (\n <div\n role=\"alert\"\n className=\"flex w-full max-w-[95%] items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\"\n >\n <Icon icon={UiCircleX} className=\"mt-0.5 size-4 shrink-0\" />\n <div className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{message}</div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n aria-label=\"Copy error details\"\n title=\"Copy session id, model, page and full error\"\n className=\"inline-flex items-center gap-1 text-xs underline-offset-2 hover:underline\"\n onClick={copyReport}\n >\n <Icon icon={copied ? UiCheck : UiCopy} className=\"size-3.5\" />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n {onClear && (\n <button type=\"button\" className=\"text-xs underline-offset-2 hover:underline\" onClick={onClear}>\n Dismiss\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"names":["useRef","useState","useEffect","jsxs","jsx","cn","Message","Icon","UiArrowDown","UiLoader","UiCircleX","UiCheck","UiCopy"],"mappings":"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"}
@@ -12,6 +12,9 @@ export type ConversationProps = MessageActionHandlers & {
12
12
  sessionId?: string | undefined;
13
13
  /** Selected model id, surfaced in the copyable error report. */
14
14
  model?: string | undefined;
15
+ /** Hide the waiting indicator because another control (e.g. an approval
16
+ * button) is already showing progress. */
17
+ suppressWaiting?: boolean | undefined;
15
18
  /** Shown when there are no messages yet. */
16
19
  emptyState?: React.ReactNode;
17
20
  className?: string;
@@ -19,5 +22,5 @@ export type ConversationProps = MessageActionHandlers & {
19
22
  /** A scrollable message log that sticks to the bottom as new content streams
20
23
  * in, unless the user has scrolled up — in which case a jump-to-bottom button
21
24
  * appears. */
22
- export declare function Conversation({ messages, status, error, onClearError, sessionId, model, emptyState, className, ...actions }: ConversationProps): import("react").JSX.Element;
25
+ export declare function Conversation({ messages, status, error, onClearError, sessionId, model, suppressWaiting, emptyState, className, ...actions }: ConversationProps): import("react").JSX.Element;
23
26
  //# sourceMappingURL=Conversation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Conversation.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Conversation.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAW,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG;IACtD,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,0CAA0C;IAC1C,YAAY,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACxC,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,4CAA4C;IAC5C,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;eAEe;AACf,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAM,EACN,KAAK,EACL,YAAY,EACZ,SAAS,EACT,KAAK,EACL,UAAU,EACV,SAAS,EACT,GAAG,OAAO,EACX,EAAE,iBAAiB,+BAoEnB"}
1
+ {"version":3,"file":"Conversation.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Conversation.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAW,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG;IACtD,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,0CAA0C;IAC1C,YAAY,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACxC,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;+CAC2C;IAC3C,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,4CAA4C;IAC5C,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;eAEe;AACf,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAM,EACN,KAAK,EACL,YAAY,EACZ,SAAS,EACT,KAAK,EACL,eAAe,EACf,UAAU,EACV,SAAS,EACT,GAAG,OAAO,EACX,EAAE,iBAAiB,+BAsEnB"}
@@ -15,13 +15,14 @@ function Conversation({
15
15
  onClearError,
16
16
  sessionId,
17
17
  model,
18
+ suppressWaiting,
18
19
  emptyState,
19
20
  className,
20
21
  ...actions
21
22
  }) {
22
23
  const scrollRef = useRef(null);
23
24
  const [pinned, setPinned] = useState(true);
24
- const isWaiting = status === "submitted" || status === "streaming" && !hasVisibleAssistantResponse(messages);
25
+ const isWaiting = !suppressWaiting && (status === "submitted" || status === "streaming" && !hasVisibleAssistantResponse(messages));
25
26
  const errorText = (error == null ? void 0 : error.message) || (status === "error" ? "The assistant request failed." : void 0);
26
27
  const onScroll = () => {
27
28
  const el = scrollRef.current;
@@ -1 +1 @@
1
- {"version":3,"file":"Conversation.js","sources":["../../../src/data/chat/Conversation.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiArrowDown, UiCheck, UiCircleX, UiCopy, UiLoader } from \"../../icons\";\nimport { Message, type MessageActionHandlers } from \"./Message\";\nimport type { ChatStatus, UIMessage } from \"./types\";\n\nexport type ConversationProps = MessageActionHandlers & {\n messages: UIMessage[];\n /** Current chat status; used for transient pending/error affordances. */\n status?: ChatStatus | undefined;\n /** Last request error from the chat transport, if any. */\n error?: Error | undefined;\n /** Clears the visible transport error. */\n onClearError?: (() => void) | undefined;\n /** Conversation/thread id, surfaced in the copyable error report. */\n sessionId?: string | undefined;\n /** Selected model id, surfaced in the copyable error report. */\n model?: string | undefined;\n /** Shown when there are no messages yet. */\n emptyState?: React.ReactNode;\n className?: string;\n};\n\n/** A scrollable message log that sticks to the bottom as new content streams\n * in, unless the user has scrolled up — in which case a jump-to-bottom button\n * appears. */\nexport function Conversation({\n messages,\n status,\n error,\n onClearError,\n sessionId,\n model,\n emptyState,\n className,\n ...actions\n}: ConversationProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const [pinned, setPinned] = useState(true);\n const isWaiting = status === \"submitted\" || (status === \"streaming\" && !hasVisibleAssistantResponse(messages));\n const errorText = error?.message || (status === \"error\" ? \"The assistant request failed.\" : undefined);\n\n const onScroll = () => {\n const el = scrollRef.current;\n if (!el) return;\n const distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n setPinned(distance < 32);\n };\n\n useEffect(() => {\n const el = scrollRef.current;\n if (el && pinned) {\n el.scrollTop = el.scrollHeight;\n }\n });\n\n const scrollToBottom = () => {\n const el = scrollRef.current;\n if (el) el.scrollTo({ top: el.scrollHeight, behavior: \"smooth\" });\n };\n\n return (\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n <div\n ref={scrollRef}\n onScroll={onScroll}\n role=\"log\"\n className={cn(\"flex-1 overflow-y-auto\", className)}\n >\n {messages.length === 0 && emptyState ? (\n <div className=\"flex size-full flex-col items-center justify-center gap-3 p-8 text-center\">\n {emptyState}\n </div>\n ) : (\n <div className=\"flex flex-col gap-8 p-4\">\n {messages.map((message) => (\n <Message key={message.id} message={message} {...actions} />\n ))}\n {isWaiting && <LoadingIndicator />}\n {errorText && (\n <ErrorNotice\n message={errorText}\n error={error}\n sessionId={sessionId}\n model={model}\n onClear={onClearError}\n />\n )}\n </div>\n )}\n </div>\n\n {!pinned && messages.length > 0 && (\n <button\n type=\"button\"\n aria-label=\"Scroll to latest\"\n onClick={scrollToBottom}\n className=\"absolute bottom-3 left-1/2 flex size-8 -translate-x-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-md hover:text-foreground\"\n >\n <Icon icon={UiArrowDown} className=\"size-4\" />\n </button>\n )}\n </div>\n );\n}\n\nfunction hasVisibleAssistantResponse(messages: UIMessage[]) {\n const last = messages[messages.length - 1];\n if (last?.role !== \"assistant\") return false;\n return last.parts.some((part) => {\n if (part.type === \"step-start\") return false;\n if (part.type === \"text\" || part.type === \"reasoning\") return part.text.length > 0;\n return true;\n });\n}\n\nfunction LoadingIndicator() {\n return (\n <div className=\"flex w-full max-w-[95%] items-center gap-2 text-sm text-muted-foreground\">\n <Icon icon={UiLoader} className=\"size-4 shrink-0 animate-spin\" />\n <span>Waiting for response...</span>\n </div>\n );\n}\n\ntype ErrorReport = {\n message: string;\n error?: Error | undefined;\n sessionId?: string | undefined;\n model?: string | undefined;\n};\n\n/** Assembles a support-ready plain-text report: the error, the session/model\n * that produced it, the page, and the full stack/cause — everything needed to\n * file or triage the failure without a back-and-forth. */\nfunction buildErrorReport({ message, error, sessionId, model }: ErrorReport): string {\n const lines = [`Error: ${message}`];\n if (error?.name && error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (sessionId) lines.push(`Session: ${sessionId}`);\n if (model) lines.push(`Model: ${model}`);\n if (typeof window !== \"undefined\") lines.push(`Page: ${window.location.href}`);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) lines.push(`User agent: ${navigator.userAgent}`);\n lines.push(`Time: ${new Date().toISOString()}`);\n const cause = (error as { cause?: unknown } | undefined)?.cause;\n const detail = error?.stack ?? (cause != null ? String(cause) : \"\");\n if (detail.trim() && detail.trim() !== message) lines.push(\"\", detail.trim());\n return lines.join(\"\\n\");\n}\n\nfunction ErrorNotice({ message, error, sessionId, model, onClear }: ErrorReport & { onClear?: (() => void) | undefined }) {\n const [copied, setCopied] = useState(false);\n const copyReport = () => {\n const clip = typeof navigator !== \"undefined\" ? navigator.clipboard : undefined;\n if (!clip) return;\n void clip\n .writeText(buildErrorReport({ message, error, sessionId, model }))\n .then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n })\n .catch(() => {});\n };\n return (\n <div\n role=\"alert\"\n className=\"flex w-full max-w-[95%] items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\"\n >\n <Icon icon={UiCircleX} className=\"mt-0.5 size-4 shrink-0\" />\n <div className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{message}</div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n aria-label=\"Copy error details\"\n title=\"Copy session id, model, page and full error\"\n className=\"inline-flex items-center gap-1 text-xs underline-offset-2 hover:underline\"\n onClick={copyReport}\n >\n <Icon icon={copied ? UiCheck : UiCopy} className=\"size-3.5\" />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n {onClear && (\n <button type=\"button\" className=\"text-xs underline-offset-2 hover:underline\" onClick={onClear}>\n Dismiss\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Conversation.js","sources":["../../../src/data/chat/Conversation.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiArrowDown, UiCheck, UiCircleX, UiCopy, UiLoader } from \"../../icons\";\nimport { Message, type MessageActionHandlers } from \"./Message\";\nimport type { ChatStatus, UIMessage } from \"./types\";\n\nexport type ConversationProps = MessageActionHandlers & {\n messages: UIMessage[];\n /** Current chat status; used for transient pending/error affordances. */\n status?: ChatStatus | undefined;\n /** Last request error from the chat transport, if any. */\n error?: Error | undefined;\n /** Clears the visible transport error. */\n onClearError?: (() => void) | undefined;\n /** Conversation/thread id, surfaced in the copyable error report. */\n sessionId?: string | undefined;\n /** Selected model id, surfaced in the copyable error report. */\n model?: string | undefined;\n /** Hide the waiting indicator because another control (e.g. an approval\n * button) is already showing progress. */\n suppressWaiting?: boolean | undefined;\n /** Shown when there are no messages yet. */\n emptyState?: React.ReactNode;\n className?: string;\n};\n\n/** A scrollable message log that sticks to the bottom as new content streams\n * in, unless the user has scrolled up — in which case a jump-to-bottom button\n * appears. */\nexport function Conversation({\n messages,\n status,\n error,\n onClearError,\n sessionId,\n model,\n suppressWaiting,\n emptyState,\n className,\n ...actions\n}: ConversationProps) {\n const scrollRef = useRef<HTMLDivElement>(null);\n const [pinned, setPinned] = useState(true);\n const isWaiting =\n !suppressWaiting &&\n (status === \"submitted\" || (status === \"streaming\" && !hasVisibleAssistantResponse(messages)));\n const errorText = error?.message || (status === \"error\" ? \"The assistant request failed.\" : undefined);\n\n const onScroll = () => {\n const el = scrollRef.current;\n if (!el) return;\n const distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n setPinned(distance < 32);\n };\n\n useEffect(() => {\n const el = scrollRef.current;\n if (el && pinned) {\n el.scrollTop = el.scrollHeight;\n }\n });\n\n const scrollToBottom = () => {\n const el = scrollRef.current;\n if (el) el.scrollTo({ top: el.scrollHeight, behavior: \"smooth\" });\n };\n\n return (\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n <div\n ref={scrollRef}\n onScroll={onScroll}\n role=\"log\"\n className={cn(\"flex-1 overflow-y-auto\", className)}\n >\n {messages.length === 0 && emptyState ? (\n <div className=\"flex size-full flex-col items-center justify-center gap-3 p-8 text-center\">\n {emptyState}\n </div>\n ) : (\n <div className=\"flex flex-col gap-8 p-4\">\n {messages.map((message) => (\n <Message key={message.id} message={message} {...actions} />\n ))}\n {isWaiting && <LoadingIndicator />}\n {errorText && (\n <ErrorNotice\n message={errorText}\n error={error}\n sessionId={sessionId}\n model={model}\n onClear={onClearError}\n />\n )}\n </div>\n )}\n </div>\n\n {!pinned && messages.length > 0 && (\n <button\n type=\"button\"\n aria-label=\"Scroll to latest\"\n onClick={scrollToBottom}\n className=\"absolute bottom-3 left-1/2 flex size-8 -translate-x-1/2 items-center justify-center rounded-full border border-border bg-background text-muted-foreground shadow-md hover:text-foreground\"\n >\n <Icon icon={UiArrowDown} className=\"size-4\" />\n </button>\n )}\n </div>\n );\n}\n\nfunction hasVisibleAssistantResponse(messages: UIMessage[]) {\n const last = messages[messages.length - 1];\n if (last?.role !== \"assistant\") return false;\n return last.parts.some((part) => {\n if (part.type === \"step-start\") return false;\n if (part.type === \"text\" || part.type === \"reasoning\") return part.text.length > 0;\n return true;\n });\n}\n\nfunction LoadingIndicator() {\n return (\n <div className=\"flex w-full max-w-[95%] items-center gap-2 text-sm text-muted-foreground\">\n <Icon icon={UiLoader} className=\"size-4 shrink-0 animate-spin\" />\n <span>Waiting for response...</span>\n </div>\n );\n}\n\ntype ErrorReport = {\n message: string;\n error?: Error | undefined;\n sessionId?: string | undefined;\n model?: string | undefined;\n};\n\n/** Assembles a support-ready plain-text report: the error, the session/model\n * that produced it, the page, and the full stack/cause — everything needed to\n * file or triage the failure without a back-and-forth. */\nfunction buildErrorReport({ message, error, sessionId, model }: ErrorReport): string {\n const lines = [`Error: ${message}`];\n if (error?.name && error.name !== \"Error\") lines.push(`Type: ${error.name}`);\n if (sessionId) lines.push(`Session: ${sessionId}`);\n if (model) lines.push(`Model: ${model}`);\n if (typeof window !== \"undefined\") lines.push(`Page: ${window.location.href}`);\n if (typeof navigator !== \"undefined\" && navigator.userAgent) lines.push(`User agent: ${navigator.userAgent}`);\n lines.push(`Time: ${new Date().toISOString()}`);\n const cause = (error as { cause?: unknown } | undefined)?.cause;\n const detail = error?.stack ?? (cause != null ? String(cause) : \"\");\n if (detail.trim() && detail.trim() !== message) lines.push(\"\", detail.trim());\n return lines.join(\"\\n\");\n}\n\nfunction ErrorNotice({ message, error, sessionId, model, onClear }: ErrorReport & { onClear?: (() => void) | undefined }) {\n const [copied, setCopied] = useState(false);\n const copyReport = () => {\n const clip = typeof navigator !== \"undefined\" ? navigator.clipboard : undefined;\n if (!clip) return;\n void clip\n .writeText(buildErrorReport({ message, error, sessionId, model }))\n .then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n })\n .catch(() => {});\n };\n return (\n <div\n role=\"alert\"\n className=\"flex w-full max-w-[95%] items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\"\n >\n <Icon icon={UiCircleX} className=\"mt-0.5 size-4 shrink-0\" />\n <div className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{message}</div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n aria-label=\"Copy error details\"\n title=\"Copy session id, model, page and full error\"\n className=\"inline-flex items-center gap-1 text-xs underline-offset-2 hover:underline\"\n onClick={copyReport}\n >\n <Icon icon={copied ? UiCheck : UiCopy} className=\"size-3.5\" />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n {onClear && (\n <button type=\"button\" className=\"text-xs underline-offset-2 hover:underline\" onClick={onClear}>\n Dismiss\n </button>\n )}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -23,6 +23,7 @@ function Message({
23
23
  }
24
24
  const isUser = message.role === "user";
25
25
  const text = message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
26
+ const { subcalls, nested } = groupSubagentCalls(message.parts);
26
27
  return /* @__PURE__ */ jsxRuntime.jsxs(
27
28
  "div",
28
29
  {
@@ -39,16 +40,20 @@ function Message({
39
40
  "flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm",
40
41
  isUser && "rounded-lg bg-secondary px-4 py-3 text-secondary-foreground"
41
42
  ),
42
- children: message.parts.map((part, i) => /* @__PURE__ */ jsxRuntime.jsx(
43
- MessagePart,
44
- {
45
- part,
46
- isUser,
47
- onApprove,
48
- renderToolResult
49
- },
50
- `${message.id}-${i}`
51
- ))
43
+ children: message.parts.map(
44
+ (part, i) => nested.has(part) ? null : /* @__PURE__ */ jsxRuntime.jsx(
45
+ MessagePart,
46
+ {
47
+ part,
48
+ isUser,
49
+ onApprove,
50
+ renderToolResult,
51
+ subcalls: isToolPart(part) ? subcalls.get(part.toolCallId) : void 0,
52
+ subcallsByParent: subcalls
53
+ },
54
+ `${message.id}-${i}`
55
+ )
56
+ )
52
57
  }
53
58
  ),
54
59
  !isUser && text && /* @__PURE__ */ jsxRuntime.jsx(
@@ -62,6 +67,24 @@ function Message({
62
67
  }
63
68
  );
64
69
  }
70
+ function isToolPart(part) {
71
+ return types.isDynamicToolPart(part) || types.isTypedToolPart(part);
72
+ }
73
+ function groupSubagentCalls(parts) {
74
+ const callIds = new Set(
75
+ parts.filter(isToolPart).map((part) => part.toolCallId)
76
+ );
77
+ const subcalls = /* @__PURE__ */ new Map();
78
+ const nested = /* @__PURE__ */ new Set();
79
+ for (const part of parts) {
80
+ if (!isToolPart(part)) continue;
81
+ const parent = types.toolPartParentId(part);
82
+ if (!parent || !callIds.has(parent)) continue;
83
+ subcalls.set(parent, [...subcalls.get(parent) ?? [], part]);
84
+ nested.add(part);
85
+ }
86
+ return { subcalls, nested };
87
+ }
65
88
  function ForkSeedMessage({
66
89
  message,
67
90
  className
@@ -90,7 +113,9 @@ function MessagePart({
90
113
  part,
91
114
  isUser,
92
115
  onApprove,
93
- renderToolResult
116
+ renderToolResult,
117
+ subcalls,
118
+ subcallsByParent
94
119
  }) {
95
120
  if (part.type === "text") {
96
121
  if (isUser) {
@@ -104,12 +129,14 @@ function MessagePart({
104
129
  if (types.isFilePart(part)) {
105
130
  return /* @__PURE__ */ jsxRuntime.jsx(MessageFilePart.MessageFilePart, { part });
106
131
  }
107
- if (types.isDynamicToolPart(part) || types.isTypedToolPart(part)) {
132
+ if (isToolPart(part)) {
108
133
  return /* @__PURE__ */ jsxRuntime.jsx(
109
134
  ToolCall.ToolCall,
110
135
  {
111
136
  part,
112
137
  onApprove,
138
+ subcalls,
139
+ subcallsByParent,
113
140
  ...renderToolResult ? { renderToolResult } : {}
114
141
  }
115
142
  );
@@ -1 +1 @@
1
- {"version":3,"file":"Message.cjs","sources":["../../../src/data/chat/Message.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiGitBranch } from \"../../icons\";\nimport { Markdown } from \"../Markdown\";\nimport { ToolCall } from \"./ToolCall\";\nimport { MessageActions } from \"./MessageActions\";\nimport { Reasoning } from \"./Reasoning\";\nimport type { UIMessage } from \"./types\";\nimport {\n isDynamicToolPart,\n isTypedToolPart,\n isReasoningPart,\n isFilePart,\n type AnyToolPart,\n type ToolResultRenderer,\n} from \"./types\";\nimport { forkSeedProvenance, isForkSeedMessage } from \"./fork-seed\";\nimport { MessageFilePart } from \"./MessageFilePart\";\n\n/** Callbacks the conversation threads down to each message. */\nexport type MessageActionHandlers = {\n /** Re-generate the assistant message with the given id. */\n onRegenerate?: ((messageId: string) => void) | undefined;\n /** Respond to a tool approval request. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void)\n | undefined;\n /** Optional host renderer for recognized completed tool outputs. */\n renderToolResult?: ToolResultRenderer;\n};\n\nexport type MessageProps = MessageActionHandlers & {\n message: UIMessage;\n className?: string;\n};\n\n/** Renders one chat message. User messages are right-aligned bubbles; assistant\n * messages render text as markdown, reasoning and tool parts inline, file parts\n * as thumbnails/chips, and a hover action row (copy / regenerate). */\nexport function Message({\n message,\n className,\n onRegenerate,\n onApprove,\n renderToolResult,\n}: MessageProps) {\n if (isForkSeedMessage(message)) {\n return <ForkSeedMessage message={message} className={className} />;\n }\n const isUser = message.role === \"user\";\n const text = message.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n\n return (\n <div\n className={cn(\n \"group flex w-full max-w-[95%] flex-col gap-2\",\n isUser ? \"ml-auto items-end\" : \"items-start\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm\",\n isUser &&\n \"rounded-lg bg-secondary px-4 py-3 text-secondary-foreground\",\n )}\n >\n {message.parts.map((part, i) => (\n <MessagePart\n key={`${message.id}-${i}`}\n part={part}\n isUser={isUser}\n onApprove={onApprove}\n renderToolResult={renderToolResult}\n />\n ))}\n </div>\n\n {!isUser && text && (\n <MessageActions\n text={text}\n onRegenerate={\n onRegenerate ? () => onRegenerate(message.id) : undefined\n }\n />\n )}\n </div>\n );\n}\n\nfunction ForkSeedMessage({\n message,\n className,\n}: {\n message: UIMessage;\n className?: string | undefined;\n}) {\n const provenance = forkSeedProvenance(message);\n const transcript = message.parts\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\\n\");\n const label = provenance.title\n ? `Forked from ${provenance.title}`\n : \"Forked from another conversation\";\n return (\n <details\n className={cn(\n \"group/fork max-w-full self-center rounded-full border border-border bg-muted/40 px-3 py-1.5 text-xs text-muted-foreground open:w-full open:rounded-lg\",\n className,\n )}\n >\n <summary className=\"flex cursor-pointer list-none items-center justify-center gap-1.5 font-medium text-foreground/80\">\n <Icon icon={UiGitBranch} className=\"size-3.5\" />\n <span>{label}</span>\n </summary>\n {transcript && (\n <pre className=\"mt-2 max-h-64 overflow-auto whitespace-pre-wrap border-t border-border pt-2 font-mono text-[11px] text-muted-foreground\">\n {transcript}\n </pre>\n )}\n </details>\n );\n}\n\nfunction MessagePart({\n part,\n isUser,\n onApprove,\n renderToolResult,\n}: {\n part: UIMessage[\"parts\"][number];\n isUser: boolean;\n onApprove: MessageActionHandlers[\"onApprove\"];\n renderToolResult: MessageActionHandlers[\"renderToolResult\"];\n}) {\n if (part.type === \"text\") {\n if (isUser) {\n return (\n <span className=\"whitespace-pre-wrap break-words\">{part.text}</span>\n );\n }\n return <Markdown text={part.text} />;\n }\n if (isReasoningPart(part)) {\n return <Reasoning text={part.text} />;\n }\n if (isFilePart(part)) {\n return <MessageFilePart part={part} />;\n }\n if (isDynamicToolPart(part) || isTypedToolPart(part)) {\n return (\n <ToolCall\n part={part as AnyToolPart}\n onApprove={onApprove}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n );\n }\n return null;\n}\n"],"names":["isForkSeedMessage","jsx","jsxs","cn","MessageActions","forkSeedProvenance","Icon","UiGitBranch","Markdown","isReasoningPart","Reasoning","isFilePart","MessageFilePart","isDynamicToolPart","isTypedToolPart","ToolCall"],"mappings":"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"}
1
+ {"version":3,"file":"Message.cjs","sources":["../../../src/data/chat/Message.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiGitBranch } from \"../../icons\";\nimport { Markdown } from \"../Markdown\";\nimport { ToolCall } from \"./ToolCall\";\nimport { MessageActions } from \"./MessageActions\";\nimport { Reasoning } from \"./Reasoning\";\nimport type { UIMessage } from \"./types\";\nimport {\n isDynamicToolPart,\n isTypedToolPart,\n isReasoningPart,\n isFilePart,\n toolPartParentId,\n type AnyToolPart,\n type ToolResultRenderer,\n} from \"./types\";\nimport { forkSeedProvenance, isForkSeedMessage } from \"./fork-seed\";\nimport { MessageFilePart } from \"./MessageFilePart\";\n\n/** Callbacks the conversation threads down to each message. */\nexport type MessageActionHandlers = {\n /** Re-generate the assistant message with the given id. */\n onRegenerate?: ((messageId: string) => void) | undefined;\n /** Respond to a tool approval request. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void | Promise<unknown>)\n | undefined;\n /** Optional host renderer for recognized completed tool outputs. */\n renderToolResult?: ToolResultRenderer;\n};\n\nexport type MessageProps = MessageActionHandlers & {\n message: UIMessage;\n className?: string;\n};\n\n/** Renders one chat message. User messages are right-aligned bubbles; assistant\n * messages render text as markdown, reasoning and tool parts inline, file parts\n * as thumbnails/chips, and a hover action row (copy / regenerate). */\nexport function Message({\n message,\n className,\n onRegenerate,\n onApprove,\n renderToolResult,\n}: MessageProps) {\n if (isForkSeedMessage(message)) {\n return <ForkSeedMessage message={message} className={className} />;\n }\n const isUser = message.role === \"user\";\n const text = message.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n const { subcalls, nested } = groupSubagentCalls(message.parts);\n\n return (\n <div\n className={cn(\n \"group flex w-full max-w-[95%] flex-col gap-2\",\n isUser ? \"ml-auto items-end\" : \"items-start\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm\",\n isUser &&\n \"rounded-lg bg-secondary px-4 py-3 text-secondary-foreground\",\n )}\n >\n {message.parts.map((part, i) =>\n nested.has(part) ? null : (\n <MessagePart\n key={`${message.id}-${i}`}\n part={part}\n isUser={isUser}\n onApprove={onApprove}\n renderToolResult={renderToolResult}\n subcalls={isToolPart(part) ? subcalls.get(part.toolCallId) : undefined}\n subcallsByParent={subcalls}\n />\n ),\n )}\n </div>\n\n {!isUser && text && (\n <MessageActions\n text={text}\n onRegenerate={\n onRegenerate ? () => onRegenerate(message.id) : undefined\n }\n />\n )}\n </div>\n );\n}\n\ntype MessagePartValue = UIMessage[\"parts\"][number];\n\nfunction isToolPart(part: MessagePartValue): part is AnyToolPart {\n return isDynamicToolPart(part) || isTypedToolPart(part);\n}\n\n/** Groups a subagent's tool calls under the call that spawned it. A call whose\n * parent is not in this message (e.g. a resumed turn) stays top-level. */\nfunction groupSubagentCalls(parts: UIMessage[\"parts\"]) {\n const callIds = new Set(\n parts.filter(isToolPart).map((part) => part.toolCallId),\n );\n const subcalls = new Map<string, AnyToolPart[]>();\n const nested = new Set<MessagePartValue>();\n for (const part of parts) {\n if (!isToolPart(part)) continue;\n const parent = toolPartParentId(part);\n if (!parent || !callIds.has(parent)) continue;\n subcalls.set(parent, [...(subcalls.get(parent) ?? []), part]);\n nested.add(part);\n }\n return { subcalls, nested };\n}\n\nfunction ForkSeedMessage({\n message,\n className,\n}: {\n message: UIMessage;\n className?: string | undefined;\n}) {\n const provenance = forkSeedProvenance(message);\n const transcript = message.parts\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\\n\");\n const label = provenance.title\n ? `Forked from ${provenance.title}`\n : \"Forked from another conversation\";\n return (\n <details\n className={cn(\n \"group/fork max-w-full self-center rounded-full border border-border bg-muted/40 px-3 py-1.5 text-xs text-muted-foreground open:w-full open:rounded-lg\",\n className,\n )}\n >\n <summary className=\"flex cursor-pointer list-none items-center justify-center gap-1.5 font-medium text-foreground/80\">\n <Icon icon={UiGitBranch} className=\"size-3.5\" />\n <span>{label}</span>\n </summary>\n {transcript && (\n <pre className=\"mt-2 max-h-64 overflow-auto whitespace-pre-wrap border-t border-border pt-2 font-mono text-[11px] text-muted-foreground\">\n {transcript}\n </pre>\n )}\n </details>\n );\n}\n\nfunction MessagePart({\n part,\n isUser,\n onApprove,\n renderToolResult,\n subcalls,\n subcallsByParent,\n}: {\n part: MessagePartValue;\n isUser: boolean;\n onApprove: MessageActionHandlers[\"onApprove\"];\n renderToolResult: MessageActionHandlers[\"renderToolResult\"];\n subcalls: AnyToolPart[] | undefined;\n subcallsByParent: ReadonlyMap<string, AnyToolPart[]>;\n}) {\n if (part.type === \"text\") {\n if (isUser) {\n return (\n <span className=\"whitespace-pre-wrap break-words\">{part.text}</span>\n );\n }\n return <Markdown text={part.text} />;\n }\n if (isReasoningPart(part)) {\n return <Reasoning text={part.text} />;\n }\n if (isFilePart(part)) {\n return <MessageFilePart part={part} />;\n }\n if (isToolPart(part)) {\n return (\n <ToolCall\n part={part}\n onApprove={onApprove}\n subcalls={subcalls}\n subcallsByParent={subcallsByParent}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n );\n }\n return null;\n}\n"],"names":["isForkSeedMessage","jsx","jsxs","cn","MessageActions","isDynamicToolPart","isTypedToolPart","toolPartParentId","forkSeedProvenance","Icon","UiGitBranch","Markdown","isReasoningPart","Reasoning","isFilePart","MessageFilePart","ToolCall"],"mappings":";;;;;;;;;;;;;AAwCO,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AACf,MAAIA,SAAAA,kBAAkB,OAAO,GAAG;AAC9B,WAAOC,2BAAAA,IAAC,iBAAA,EAAgB,SAAkB,UAAA,CAAsB;AAAA,EAClE;AACA,QAAM,SAAS,QAAQ,SAAS;AAChC,QAAM,OAAO,QAAQ,MAClB,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAuB,IAAI,EACvC,KAAK,EAAE;AACV,QAAM,EAAE,UAAU,OAAA,IAAW,mBAAmB,QAAQ,KAAK;AAE7D,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA,SAAS,sBAAsB;AAAA,QAC/B;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAAF,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWE,MAAAA;AAAAA,cACT;AAAA,cACA,UACE;AAAA,YAAA;AAAA,YAGH,kBAAQ,MAAM;AAAA,cAAI,CAAC,MAAM,MACxB,OAAO,IAAI,IAAI,IAAI,OACjBF,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,UAAU,WAAW,IAAI,IAAI,SAAS,IAAI,KAAK,UAAU,IAAI;AAAA,kBAC7D,kBAAkB;AAAA,gBAAA;AAAA,gBANb,GAAG,QAAQ,EAAE,IAAI,CAAC;AAAA,cAAA;AAAA,YAOzB;AAAA,UAEJ;AAAA,QAAA;AAAA,QAGD,CAAC,UAAU,QACVA,2BAAAA;AAAAA,UAACG,eAAAA;AAAAA,UAAA;AAAA,YACC;AAAA,YACA,cACE,eAAe,MAAM,aAAa,QAAQ,EAAE,IAAI;AAAA,UAAA;AAAA,QAAA;AAAA,MAEpD;AAAA,IAAA;AAAA,EAAA;AAIR;AAIA,SAAS,WAAW,MAA6C;AAC/D,SAAOC,wBAAkB,IAAI,KAAKC,MAAAA,gBAAgB,IAAI;AACxD;AAIA,SAAS,mBAAmB,OAA2B;AACrD,QAAM,UAAU,IAAI;AAAA,IAClB,MAAM,OAAO,UAAU,EAAE,IAAI,CAAC,SAAS,KAAK,UAAU;AAAA,EAAA;AAExD,QAAM,+BAAe,IAAA;AACrB,QAAM,6BAAa,IAAA;AACnB,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,WAAW,IAAI,EAAG;AACvB,UAAM,SAASC,MAAAA,iBAAiB,IAAI;AACpC,QAAI,CAAC,UAAU,CAAC,QAAQ,IAAI,MAAM,EAAG;AACrC,aAAS,IAAI,QAAQ,CAAC,GAAI,SAAS,IAAI,MAAM,KAAK,IAAK,IAAI,CAAC;AAC5D,WAAO,IAAI,IAAI;AAAA,EACjB;AACA,SAAO,EAAE,UAAU,OAAA;AACrB;AAEA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AACF,GAGG;AACD,QAAM,aAAaC,SAAAA,mBAAmB,OAAO;AAC7C,QAAM,aAAa,QAAQ,MACxB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK,IAAI;AACZ,QAAM,QAAQ,WAAW,QACrB,eAAe,WAAW,KAAK,KAC/B;AACJ,SACEN,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAAD,2BAAAA,KAAC,WAAA,EAAQ,WAAU,oGACjB,UAAA;AAAA,UAAAD,2BAAAA,IAACQ,KAAAA,MAAA,EAAK,MAAMC,YAAAA,aAAa,WAAU,YAAW;AAAA,UAC9CT,2BAAAA,IAAC,UAAM,UAAA,MAAA,CAAM;AAAA,QAAA,GACf;AAAA,QACC,cACCA,2BAAAA,IAAC,OAAA,EAAI,WAAU,2HACZ,UAAA,WAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,MAAI,KAAK,SAAS,QAAQ;AACxB,QAAI,QAAQ;AACV,aACEA,2BAAAA,IAAC,QAAA,EAAK,WAAU,mCAAmC,eAAK,MAAK;AAAA,IAEjE;AACA,WAAOA,2BAAAA,IAACU,SAAAA,UAAA,EAAS,MAAM,KAAK,KAAA,CAAM;AAAA,EACpC;AACA,MAAIC,MAAAA,gBAAgB,IAAI,GAAG;AACzB,WAAOX,2BAAAA,IAACY,UAAAA,WAAA,EAAU,MAAM,KAAK,KAAA,CAAM;AAAA,EACrC;AACA,MAAIC,MAAAA,WAAW,IAAI,GAAG;AACpB,WAAOb,+BAACc,gBAAAA,mBAAgB,MAAY;AAAA,EACtC;AACA,MAAI,WAAW,IAAI,GAAG;AACpB,WACEd,2BAAAA;AAAAA,MAACe,SAAAA;AAAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACC,GAAI,mBAAmB,EAAE,qBAAqB,CAAA;AAAA,MAAC;AAAA,IAAA;AAAA,EAGtD;AACA,SAAO;AACT;;"}
@@ -4,7 +4,7 @@ export type MessageActionHandlers = {
4
4
  /** Re-generate the assistant message with the given id. */
5
5
  onRegenerate?: ((messageId: string) => void) | undefined;
6
6
  /** Respond to a tool approval request. */
7
- onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void) | undefined;
7
+ onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void | Promise<unknown>) | undefined;
8
8
  /** Optional host renderer for recognized completed tool outputs. */
9
9
  renderToolResult?: ToolResultRenderer;
10
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Message.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AAIjB,+DAA+D;AAC/D,MAAM,MAAM,qBAAqB,GAAG;IAClC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzD,0CAA0C;IAC1C,SAAS,CAAC,EACN,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAClE,SAAS,CAAC;IACd,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,qBAAqB,GAAG;IACjD,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;uEAEuE;AACvE,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,SAAS,EACT,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,EAAE,YAAY,+BA8Cd"}
1
+ {"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Message.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AAIjB,+DAA+D;AAC/D,MAAM,MAAM,qBAAqB,GAAG;IAClC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzD,0CAA0C;IAC1C,SAAS,CAAC,EACN,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,GACrF,SAAS,CAAC;IACd,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,qBAAqB,GAAG;IACjD,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;uEAEuE;AACvE,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,SAAS,EACT,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,EAAE,YAAY,+BAmDd"}
@@ -5,7 +5,7 @@ import { Markdown } from "../Markdown.js";
5
5
  import { ToolCall } from "./ToolCall.js";
6
6
  import { MessageActions } from "./MessageActions.js";
7
7
  import { Reasoning } from "./Reasoning.js";
8
- import { isReasoningPart, isFilePart, isDynamicToolPart, isTypedToolPart } from "./types.js";
8
+ import { toolPartParentId, isReasoningPart, isFilePart, isDynamicToolPart, isTypedToolPart } from "./types.js";
9
9
  import { isForkSeedMessage, forkSeedProvenance } from "./fork-seed.js";
10
10
  import { MessageFilePart } from "./MessageFilePart.js";
11
11
  import { UiGitBranch } from "../../icons/components/UiGitBranch.js";
@@ -21,6 +21,7 @@ function Message({
21
21
  }
22
22
  const isUser = message.role === "user";
23
23
  const text = message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
24
+ const { subcalls, nested } = groupSubagentCalls(message.parts);
24
25
  return /* @__PURE__ */ jsxs(
25
26
  "div",
26
27
  {
@@ -37,16 +38,20 @@ function Message({
37
38
  "flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm",
38
39
  isUser && "rounded-lg bg-secondary px-4 py-3 text-secondary-foreground"
39
40
  ),
40
- children: message.parts.map((part, i) => /* @__PURE__ */ jsx(
41
- MessagePart,
42
- {
43
- part,
44
- isUser,
45
- onApprove,
46
- renderToolResult
47
- },
48
- `${message.id}-${i}`
49
- ))
41
+ children: message.parts.map(
42
+ (part, i) => nested.has(part) ? null : /* @__PURE__ */ jsx(
43
+ MessagePart,
44
+ {
45
+ part,
46
+ isUser,
47
+ onApprove,
48
+ renderToolResult,
49
+ subcalls: isToolPart(part) ? subcalls.get(part.toolCallId) : void 0,
50
+ subcallsByParent: subcalls
51
+ },
52
+ `${message.id}-${i}`
53
+ )
54
+ )
50
55
  }
51
56
  ),
52
57
  !isUser && text && /* @__PURE__ */ jsx(
@@ -60,6 +65,24 @@ function Message({
60
65
  }
61
66
  );
62
67
  }
68
+ function isToolPart(part) {
69
+ return isDynamicToolPart(part) || isTypedToolPart(part);
70
+ }
71
+ function groupSubagentCalls(parts) {
72
+ const callIds = new Set(
73
+ parts.filter(isToolPart).map((part) => part.toolCallId)
74
+ );
75
+ const subcalls = /* @__PURE__ */ new Map();
76
+ const nested = /* @__PURE__ */ new Set();
77
+ for (const part of parts) {
78
+ if (!isToolPart(part)) continue;
79
+ const parent = toolPartParentId(part);
80
+ if (!parent || !callIds.has(parent)) continue;
81
+ subcalls.set(parent, [...subcalls.get(parent) ?? [], part]);
82
+ nested.add(part);
83
+ }
84
+ return { subcalls, nested };
85
+ }
63
86
  function ForkSeedMessage({
64
87
  message,
65
88
  className
@@ -88,7 +111,9 @@ function MessagePart({
88
111
  part,
89
112
  isUser,
90
113
  onApprove,
91
- renderToolResult
114
+ renderToolResult,
115
+ subcalls,
116
+ subcallsByParent
92
117
  }) {
93
118
  if (part.type === "text") {
94
119
  if (isUser) {
@@ -102,12 +127,14 @@ function MessagePart({
102
127
  if (isFilePart(part)) {
103
128
  return /* @__PURE__ */ jsx(MessageFilePart, { part });
104
129
  }
105
- if (isDynamicToolPart(part) || isTypedToolPart(part)) {
130
+ if (isToolPart(part)) {
106
131
  return /* @__PURE__ */ jsx(
107
132
  ToolCall,
108
133
  {
109
134
  part,
110
135
  onApprove,
136
+ subcalls,
137
+ subcallsByParent,
111
138
  ...renderToolResult ? { renderToolResult } : {}
112
139
  }
113
140
  );
@@ -1 +1 @@
1
- {"version":3,"file":"Message.js","sources":["../../../src/data/chat/Message.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiGitBranch } from \"../../icons\";\nimport { Markdown } from \"../Markdown\";\nimport { ToolCall } from \"./ToolCall\";\nimport { MessageActions } from \"./MessageActions\";\nimport { Reasoning } from \"./Reasoning\";\nimport type { UIMessage } from \"./types\";\nimport {\n isDynamicToolPart,\n isTypedToolPart,\n isReasoningPart,\n isFilePart,\n type AnyToolPart,\n type ToolResultRenderer,\n} from \"./types\";\nimport { forkSeedProvenance, isForkSeedMessage } from \"./fork-seed\";\nimport { MessageFilePart } from \"./MessageFilePart\";\n\n/** Callbacks the conversation threads down to each message. */\nexport type MessageActionHandlers = {\n /** Re-generate the assistant message with the given id. */\n onRegenerate?: ((messageId: string) => void) | undefined;\n /** Respond to a tool approval request. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void)\n | undefined;\n /** Optional host renderer for recognized completed tool outputs. */\n renderToolResult?: ToolResultRenderer;\n};\n\nexport type MessageProps = MessageActionHandlers & {\n message: UIMessage;\n className?: string;\n};\n\n/** Renders one chat message. User messages are right-aligned bubbles; assistant\n * messages render text as markdown, reasoning and tool parts inline, file parts\n * as thumbnails/chips, and a hover action row (copy / regenerate). */\nexport function Message({\n message,\n className,\n onRegenerate,\n onApprove,\n renderToolResult,\n}: MessageProps) {\n if (isForkSeedMessage(message)) {\n return <ForkSeedMessage message={message} className={className} />;\n }\n const isUser = message.role === \"user\";\n const text = message.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n\n return (\n <div\n className={cn(\n \"group flex w-full max-w-[95%] flex-col gap-2\",\n isUser ? \"ml-auto items-end\" : \"items-start\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm\",\n isUser &&\n \"rounded-lg bg-secondary px-4 py-3 text-secondary-foreground\",\n )}\n >\n {message.parts.map((part, i) => (\n <MessagePart\n key={`${message.id}-${i}`}\n part={part}\n isUser={isUser}\n onApprove={onApprove}\n renderToolResult={renderToolResult}\n />\n ))}\n </div>\n\n {!isUser && text && (\n <MessageActions\n text={text}\n onRegenerate={\n onRegenerate ? () => onRegenerate(message.id) : undefined\n }\n />\n )}\n </div>\n );\n}\n\nfunction ForkSeedMessage({\n message,\n className,\n}: {\n message: UIMessage;\n className?: string | undefined;\n}) {\n const provenance = forkSeedProvenance(message);\n const transcript = message.parts\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\\n\");\n const label = provenance.title\n ? `Forked from ${provenance.title}`\n : \"Forked from another conversation\";\n return (\n <details\n className={cn(\n \"group/fork max-w-full self-center rounded-full border border-border bg-muted/40 px-3 py-1.5 text-xs text-muted-foreground open:w-full open:rounded-lg\",\n className,\n )}\n >\n <summary className=\"flex cursor-pointer list-none items-center justify-center gap-1.5 font-medium text-foreground/80\">\n <Icon icon={UiGitBranch} className=\"size-3.5\" />\n <span>{label}</span>\n </summary>\n {transcript && (\n <pre className=\"mt-2 max-h-64 overflow-auto whitespace-pre-wrap border-t border-border pt-2 font-mono text-[11px] text-muted-foreground\">\n {transcript}\n </pre>\n )}\n </details>\n );\n}\n\nfunction MessagePart({\n part,\n isUser,\n onApprove,\n renderToolResult,\n}: {\n part: UIMessage[\"parts\"][number];\n isUser: boolean;\n onApprove: MessageActionHandlers[\"onApprove\"];\n renderToolResult: MessageActionHandlers[\"renderToolResult\"];\n}) {\n if (part.type === \"text\") {\n if (isUser) {\n return (\n <span className=\"whitespace-pre-wrap break-words\">{part.text}</span>\n );\n }\n return <Markdown text={part.text} />;\n }\n if (isReasoningPart(part)) {\n return <Reasoning text={part.text} />;\n }\n if (isFilePart(part)) {\n return <MessageFilePart part={part} />;\n }\n if (isDynamicToolPart(part) || isTypedToolPart(part)) {\n return (\n <ToolCall\n part={part as AnyToolPart}\n onApprove={onApprove}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n );\n }\n return null;\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAuCO,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AACf,MAAI,kBAAkB,OAAO,GAAG;AAC9B,WAAO,oBAAC,iBAAA,EAAgB,SAAkB,UAAA,CAAsB;AAAA,EAClE;AACA,QAAM,SAAS,QAAQ,SAAS;AAChC,QAAM,OAAO,QAAQ,MAClB,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAuB,IAAI,EACvC,KAAK,EAAE;AAEV,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,SAAS,sBAAsB;AAAA,QAC/B;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,UACE;AAAA,YAAA;AAAA,YAGH,UAAA,QAAQ,MAAM,IAAI,CAAC,MAAM,MACxB;AAAA,cAAC;AAAA,cAAA;AAAA,gBAEC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cAAA;AAAA,cAJK,GAAG,QAAQ,EAAE,IAAI,CAAC;AAAA,YAAA,CAM1B;AAAA,UAAA;AAAA,QAAA;AAAA,QAGF,CAAC,UAAU,QACV;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA,cACE,eAAe,MAAM,aAAa,QAAQ,EAAE,IAAI;AAAA,UAAA;AAAA,QAAA;AAAA,MAEpD;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AACF,GAGG;AACD,QAAM,aAAa,mBAAmB,OAAO;AAC7C,QAAM,aAAa,QAAQ,MACxB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK,IAAI;AACZ,QAAM,QAAQ,WAAW,QACrB,eAAe,WAAW,KAAK,KAC/B;AACJ,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAA,qBAAC,WAAA,EAAQ,WAAU,oGACjB,UAAA;AAAA,UAAA,oBAAC,MAAA,EAAK,MAAM,aAAa,WAAU,YAAW;AAAA,UAC9C,oBAAC,UAAM,UAAA,MAAA,CAAM;AAAA,QAAA,GACf;AAAA,QACC,cACC,oBAAC,OAAA,EAAI,WAAU,2HACZ,UAAA,WAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,MAAI,KAAK,SAAS,QAAQ;AACxB,QAAI,QAAQ;AACV,aACE,oBAAC,QAAA,EAAK,WAAU,mCAAmC,eAAK,MAAK;AAAA,IAEjE;AACA,WAAO,oBAAC,UAAA,EAAS,MAAM,KAAK,KAAA,CAAM;AAAA,EACpC;AACA,MAAI,gBAAgB,IAAI,GAAG;AACzB,WAAO,oBAAC,WAAA,EAAU,MAAM,KAAK,KAAA,CAAM;AAAA,EACrC;AACA,MAAI,WAAW,IAAI,GAAG;AACpB,WAAO,oBAAC,mBAAgB,MAAY;AAAA,EACtC;AACA,MAAI,kBAAkB,IAAI,KAAK,gBAAgB,IAAI,GAAG;AACpD,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACC,GAAI,mBAAmB,EAAE,qBAAqB,CAAA;AAAA,MAAC;AAAA,IAAA;AAAA,EAGtD;AACA,SAAO;AACT;"}
1
+ {"version":3,"file":"Message.js","sources":["../../../src/data/chat/Message.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiGitBranch } from \"../../icons\";\nimport { Markdown } from \"../Markdown\";\nimport { ToolCall } from \"./ToolCall\";\nimport { MessageActions } from \"./MessageActions\";\nimport { Reasoning } from \"./Reasoning\";\nimport type { UIMessage } from \"./types\";\nimport {\n isDynamicToolPart,\n isTypedToolPart,\n isReasoningPart,\n isFilePart,\n toolPartParentId,\n type AnyToolPart,\n type ToolResultRenderer,\n} from \"./types\";\nimport { forkSeedProvenance, isForkSeedMessage } from \"./fork-seed\";\nimport { MessageFilePart } from \"./MessageFilePart\";\n\n/** Callbacks the conversation threads down to each message. */\nexport type MessageActionHandlers = {\n /** Re-generate the assistant message with the given id. */\n onRegenerate?: ((messageId: string) => void) | undefined;\n /** Respond to a tool approval request. */\n onApprove?:\n | ((approvalId: string, approved: boolean, reason?: string) => void | Promise<unknown>)\n | undefined;\n /** Optional host renderer for recognized completed tool outputs. */\n renderToolResult?: ToolResultRenderer;\n};\n\nexport type MessageProps = MessageActionHandlers & {\n message: UIMessage;\n className?: string;\n};\n\n/** Renders one chat message. User messages are right-aligned bubbles; assistant\n * messages render text as markdown, reasoning and tool parts inline, file parts\n * as thumbnails/chips, and a hover action row (copy / regenerate). */\nexport function Message({\n message,\n className,\n onRegenerate,\n onApprove,\n renderToolResult,\n}: MessageProps) {\n if (isForkSeedMessage(message)) {\n return <ForkSeedMessage message={message} className={className} />;\n }\n const isUser = message.role === \"user\";\n const text = message.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\"\");\n const { subcalls, nested } = groupSubagentCalls(message.parts);\n\n return (\n <div\n className={cn(\n \"group flex w-full max-w-[95%] flex-col gap-2\",\n isUser ? \"ml-auto items-end\" : \"items-start\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm\",\n isUser &&\n \"rounded-lg bg-secondary px-4 py-3 text-secondary-foreground\",\n )}\n >\n {message.parts.map((part, i) =>\n nested.has(part) ? null : (\n <MessagePart\n key={`${message.id}-${i}`}\n part={part}\n isUser={isUser}\n onApprove={onApprove}\n renderToolResult={renderToolResult}\n subcalls={isToolPart(part) ? subcalls.get(part.toolCallId) : undefined}\n subcallsByParent={subcalls}\n />\n ),\n )}\n </div>\n\n {!isUser && text && (\n <MessageActions\n text={text}\n onRegenerate={\n onRegenerate ? () => onRegenerate(message.id) : undefined\n }\n />\n )}\n </div>\n );\n}\n\ntype MessagePartValue = UIMessage[\"parts\"][number];\n\nfunction isToolPart(part: MessagePartValue): part is AnyToolPart {\n return isDynamicToolPart(part) || isTypedToolPart(part);\n}\n\n/** Groups a subagent's tool calls under the call that spawned it. A call whose\n * parent is not in this message (e.g. a resumed turn) stays top-level. */\nfunction groupSubagentCalls(parts: UIMessage[\"parts\"]) {\n const callIds = new Set(\n parts.filter(isToolPart).map((part) => part.toolCallId),\n );\n const subcalls = new Map<string, AnyToolPart[]>();\n const nested = new Set<MessagePartValue>();\n for (const part of parts) {\n if (!isToolPart(part)) continue;\n const parent = toolPartParentId(part);\n if (!parent || !callIds.has(parent)) continue;\n subcalls.set(parent, [...(subcalls.get(parent) ?? []), part]);\n nested.add(part);\n }\n return { subcalls, nested };\n}\n\nfunction ForkSeedMessage({\n message,\n className,\n}: {\n message: UIMessage;\n className?: string | undefined;\n}) {\n const provenance = forkSeedProvenance(message);\n const transcript = message.parts\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\\n\");\n const label = provenance.title\n ? `Forked from ${provenance.title}`\n : \"Forked from another conversation\";\n return (\n <details\n className={cn(\n \"group/fork max-w-full self-center rounded-full border border-border bg-muted/40 px-3 py-1.5 text-xs text-muted-foreground open:w-full open:rounded-lg\",\n className,\n )}\n >\n <summary className=\"flex cursor-pointer list-none items-center justify-center gap-1.5 font-medium text-foreground/80\">\n <Icon icon={UiGitBranch} className=\"size-3.5\" />\n <span>{label}</span>\n </summary>\n {transcript && (\n <pre className=\"mt-2 max-h-64 overflow-auto whitespace-pre-wrap border-t border-border pt-2 font-mono text-[11px] text-muted-foreground\">\n {transcript}\n </pre>\n )}\n </details>\n );\n}\n\nfunction MessagePart({\n part,\n isUser,\n onApprove,\n renderToolResult,\n subcalls,\n subcallsByParent,\n}: {\n part: MessagePartValue;\n isUser: boolean;\n onApprove: MessageActionHandlers[\"onApprove\"];\n renderToolResult: MessageActionHandlers[\"renderToolResult\"];\n subcalls: AnyToolPart[] | undefined;\n subcallsByParent: ReadonlyMap<string, AnyToolPart[]>;\n}) {\n if (part.type === \"text\") {\n if (isUser) {\n return (\n <span className=\"whitespace-pre-wrap break-words\">{part.text}</span>\n );\n }\n return <Markdown text={part.text} />;\n }\n if (isReasoningPart(part)) {\n return <Reasoning text={part.text} />;\n }\n if (isFilePart(part)) {\n return <MessageFilePart part={part} />;\n }\n if (isToolPart(part)) {\n return (\n <ToolCall\n part={part}\n onApprove={onApprove}\n subcalls={subcalls}\n subcallsByParent={subcallsByParent}\n {...(renderToolResult ? { renderToolResult } : {})}\n />\n );\n }\n return null;\n}\n"],"names":[],"mappings":"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"}
@@ -46,10 +46,13 @@ function ToolCall({
46
46
  renderToolResult,
47
47
  tool,
48
48
  registry: registryProp,
49
+ subcalls = [],
50
+ subcallsByParent,
49
51
  className
50
52
  }) {
51
53
  const needsApproval = part.state === "approval-requested";
52
- const [open, setOpen] = react.useState(defaultOpen || needsApproval);
54
+ const [userOpen, setOpen] = react.useState(defaultOpen || needsApproval);
55
+ const open = userOpen || needsApproval || hasPendingApproval(subcalls, subcallsByParent);
53
56
  const contextRegistry = context.useToolRenderRegistry();
54
57
  const registry = registryProp ?? contextRegistry;
55
58
  const status = STATUS_ICON[part.state];
@@ -90,6 +93,7 @@ function ToolCall({
90
93
  className: utils.cn("size-3 shrink-0", status.className)
91
94
  }
92
95
  ),
96
+ subcalls.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs", children: subcallsLabel(subcalls) }) : null,
93
97
  !open && summary ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-xs", children: summary }) : null
94
98
  ] }),
95
99
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -116,24 +120,72 @@ function ToolCall({
116
120
  output: normalized.value,
117
121
  ...renderToolResult ? { renderToolResult } : {}
118
122
  }
123
+ ),
124
+ subcalls.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
125
+ "div",
126
+ {
127
+ "data-slot": "tool-call-subcalls",
128
+ className: "border-l border-border pl-2",
129
+ children: subcalls.map((call) => /* @__PURE__ */ jsxRuntime.jsx(
130
+ ToolCall,
131
+ {
132
+ part: call,
133
+ subcalls: subcallsByParent == null ? void 0 : subcallsByParent.get(call.toolCallId),
134
+ subcallsByParent,
135
+ onApprove,
136
+ registry,
137
+ ...renderToolResult ? { renderToolResult } : {}
138
+ },
139
+ call.toolCallId
140
+ ))
141
+ }
119
142
  )
120
143
  ] }),
121
144
  needsApproval && /* @__PURE__ */ jsxRuntime.jsx(ApprovalControls, { part, onApprove })
122
145
  ] });
123
146
  }
147
+ function hasPendingApproval(calls, grouped) {
148
+ return calls.some(
149
+ (call) => call.state === "approval-requested" || hasPendingApproval((grouped == null ? void 0 : grouped.get(call.toolCallId)) ?? [], grouped)
150
+ );
151
+ }
152
+ function subcallsLabel(subcalls) {
153
+ const running = subcalls.filter(
154
+ (call) => call.state === "input-streaming" || call.state === "input-available"
155
+ ).length;
156
+ const count = `${subcalls.length} ${subcalls.length === 1 ? "call" : "calls"}`;
157
+ return running > 0 ? `${count} · ${running} running` : count;
158
+ }
124
159
  function ApprovalControls({
125
160
  part,
126
161
  onApprove
127
162
  }) {
163
+ const [pending, setPending] = react.useState();
164
+ const [error, setError] = react.useState();
128
165
  const approval = "approval" in part ? part.approval : void 0;
129
166
  if (!approval || !onApprove) return null;
130
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex items-center gap-2 pl-4", children: [
167
+ const decide = async (approved) => {
168
+ setPending(approved ? "approve" : "deny");
169
+ setError(void 0);
170
+ try {
171
+ await onApprove(approval.id, approved);
172
+ } catch (cause) {
173
+ setError(
174
+ `Cannot ${approved ? "approve" : "deny"} tool call: ${cause instanceof Error ? cause.message : String(cause)}`
175
+ );
176
+ } finally {
177
+ setPending(void 0);
178
+ }
179
+ };
180
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-2 pl-4", children: [
131
181
  /* @__PURE__ */ jsxRuntime.jsx(
132
182
  button.Button,
133
183
  {
134
184
  type: "button",
135
185
  size: "sm",
136
- onClick: () => onApprove(approval.id, true),
186
+ loading: pending === "approve",
187
+ disabled: pending !== void 0,
188
+ onClick: () => void decide(true),
137
189
  children: "Approve"
138
190
  }
139
191
  ),
@@ -143,10 +195,13 @@ function ApprovalControls({
143
195
  type: "button",
144
196
  size: "sm",
145
197
  variant: "outline",
146
- onClick: () => onApprove(approval.id, false),
198
+ loading: pending === "deny",
199
+ disabled: pending !== void 0,
200
+ onClick: () => void decide(false),
147
201
  children: "Deny"
148
202
  }
149
- )
203
+ ),
204
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", className: "w-full text-xs text-destructive", children: error })
150
205
  ] });
151
206
  }
152
207
  function ToolOutput({