@parallelworks/ui 0.18.0 → 0.19.1

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 (349) hide show
  1. package/README.md +86 -6
  2. package/dist/ai/adapter/memoryStore.d.ts +8 -0
  3. package/dist/ai/adapter/memoryStore.js +152 -0
  4. package/dist/ai/adapter/mock/index.d.ts +2 -0
  5. package/dist/ai/adapter/mock/index.js +3 -0
  6. package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
  7. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  8. package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
  9. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  10. package/dist/ai/adapter/openai/errors.d.ts +3 -0
  11. package/dist/ai/adapter/openai/errors.js +37 -0
  12. package/dist/ai/adapter/openai/index.d.ts +6 -0
  13. package/dist/ai/adapter/openai/index.js +6 -0
  14. package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
  15. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  16. package/dist/ai/adapter/openai/responses.d.ts +4 -0
  17. package/dist/ai/adapter/openai/responses.js +108 -0
  18. package/dist/ai/adapter/openai/sse.d.ts +24 -0
  19. package/dist/ai/adapter/openai/sse.js +112 -0
  20. package/dist/ai/adapter/openai/wire.d.ts +40 -0
  21. package/dist/ai/adapter/types.d.ts +131 -0
  22. package/dist/ai/adapter/types.js +11 -0
  23. package/dist/ai/agent/classifier.d.ts +2 -0
  24. package/dist/ai/agent/classifier.js +12 -0
  25. package/dist/ai/agent/diff.d.ts +35 -0
  26. package/dist/ai/agent/diff.js +223 -0
  27. package/dist/ai/agent/diffHighlight.d.ts +6 -0
  28. package/dist/ai/agent/diffHighlight.js +101 -0
  29. package/dist/ai/agent/index.d.ts +6 -0
  30. package/dist/ai/agent/permissions.d.ts +11 -0
  31. package/dist/ai/agent/permissions.js +29 -0
  32. package/dist/ai/agent/toolfmt.d.ts +18 -0
  33. package/dist/ai/agent/toolfmt.js +383 -0
  34. package/dist/ai/agent/transcript.d.ts +38 -0
  35. package/dist/ai/agent/transcript.js +127 -0
  36. package/dist/ai/ai.css +325 -0
  37. package/dist/ai/components/AllocationSelector.d.ts +4 -0
  38. package/dist/ai/components/AllocationSelector.js +56 -0
  39. package/dist/ai/components/AttachmentManager.d.ts +1 -0
  40. package/dist/ai/components/AttachmentManager.js +144 -0
  41. package/dist/ai/components/AttachmentUpload.d.ts +24 -0
  42. package/dist/ai/components/AttachmentUpload.js +179 -0
  43. package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
  44. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  45. package/dist/ai/components/BranchNavigator.d.ts +8 -0
  46. package/dist/ai/components/BranchNavigator.js +57 -0
  47. package/dist/ai/components/ChatEmptyState.d.ts +3 -0
  48. package/dist/ai/components/ChatEmptyState.js +171 -0
  49. package/dist/ai/components/ChatInput.d.ts +45 -0
  50. package/dist/ai/components/ChatInput.js +265 -0
  51. package/dist/ai/components/ChatLayout.d.ts +5 -0
  52. package/dist/ai/components/ChatLayout.js +15 -0
  53. package/dist/ai/components/ChatMessage.d.ts +24 -0
  54. package/dist/ai/components/ChatMessage.js +338 -0
  55. package/dist/ai/components/ChatMessageList.d.ts +35 -0
  56. package/dist/ai/components/ChatMessageList.js +301 -0
  57. package/dist/ai/components/ChatSidebar.d.ts +5 -0
  58. package/dist/ai/components/ChatSidebar.js +345 -0
  59. package/dist/ai/components/ChatThread.d.ts +3 -0
  60. package/dist/ai/components/ChatThread.js +198 -0
  61. package/dist/ai/components/ComposerChrome.d.ts +18 -0
  62. package/dist/ai/components/ComposerChrome.js +50 -0
  63. package/dist/ai/components/ComposerFrame.d.ts +16 -0
  64. package/dist/ai/components/ComposerFrame.js +33 -0
  65. package/dist/ai/components/DragOverlay.d.ts +5 -0
  66. package/dist/ai/components/DragOverlay.js +20 -0
  67. package/dist/ai/components/ModelSelector.d.ts +6 -0
  68. package/dist/ai/components/ModelSelector.js +343 -0
  69. package/dist/ai/components/ShareDialog.d.ts +11 -0
  70. package/dist/ai/components/ShareDialog.js +260 -0
  71. package/dist/ai/components/SlashMenu.d.ts +28 -0
  72. package/dist/ai/components/SlashMenu.js +91 -0
  73. package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
  74. package/dist/ai/components/agent/ActivityLine.js +151 -0
  75. package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
  76. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  77. package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
  78. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  79. package/dist/ai/components/attachmentKeys.d.ts +4 -0
  80. package/dist/ai/components/attachmentKeys.js +10 -0
  81. package/dist/ai/core/ChatProvider.d.ts +66 -0
  82. package/dist/ai/core/ChatProvider.js +848 -0
  83. package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
  84. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  85. package/dist/ai/core/chatReducer.d.ts +114 -0
  86. package/dist/ai/core/chatReducer.js +223 -0
  87. package/dist/ai/core/config.d.ts +47 -0
  88. package/dist/ai/core/config.js +45 -0
  89. package/dist/ai/core/events.d.ts +1 -0
  90. package/dist/ai/core/events.js +4 -0
  91. package/dist/ai/core/exportConversation.d.ts +4 -0
  92. package/dist/ai/core/exportConversation.js +42 -0
  93. package/dist/ai/core/greeting.d.ts +3 -0
  94. package/dist/ai/core/greeting.js +38 -0
  95. package/dist/ai/core/parts.d.ts +11 -0
  96. package/dist/ai/core/parts.js +84 -0
  97. package/dist/ai/core/useDragDrop.d.ts +14 -0
  98. package/dist/ai/core/useDragDrop.js +36 -0
  99. package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
  100. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  101. package/dist/ai/core/useSSEStream.d.ts +34 -0
  102. package/dist/ai/core/useSSEStream.js +98 -0
  103. package/dist/ai/index.d.ts +40 -0
  104. package/dist/ai/index.js +44 -0
  105. package/dist/ai/strings.d.ts +167 -0
  106. package/dist/ai/strings.js +175 -0
  107. package/dist/ai/types.d.ts +236 -0
  108. package/dist/ai/ui/Avatar.d.ts +8 -0
  109. package/dist/ai/ui/Avatar.js +35 -0
  110. package/dist/ai/ui/Dropdown.d.ts +31 -0
  111. package/dist/ai/ui/Dropdown.js +110 -0
  112. package/dist/ai/ui/Markdown.d.ts +8 -0
  113. package/dist/ai/ui/Markdown.js +79 -0
  114. package/dist/ai/ui/Notice.d.ts +21 -0
  115. package/dist/ai/ui/Notice.js +77 -0
  116. package/dist/ai/ui/buttons.d.ts +1 -0
  117. package/dist/ai/ui/codeBreaks.d.ts +16 -0
  118. package/dist/ai/ui/codeBreaks.js +36 -0
  119. package/dist/ai/ui/prose.d.ts +1 -0
  120. package/dist/ai/ui/prose.js +13 -0
  121. package/dist/ai/ui/sidebar.d.ts +81 -0
  122. package/dist/ai/ui/sidebar.js +148 -0
  123. package/dist/ai/utils.d.ts +4 -0
  124. package/dist/ai/utils.js +23 -0
  125. package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
  126. package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
  127. package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
  128. package/dist/components/AddMenu.js +46 -0
  129. package/dist/components/Avatar.d.ts +1 -1
  130. package/dist/components/Avatar.js +46 -0
  131. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  132. package/dist/components/Breadcrumbs.d.ts +1 -1
  133. package/dist/components/Breadcrumbs.js +83 -0
  134. package/dist/components/Button.js +83 -0
  135. package/dist/components/Callout.js +23 -0
  136. package/dist/components/Card.js +31 -0
  137. package/dist/components/CollapsiblePanel.js +77 -0
  138. package/dist/components/ConfirmModal.js +74 -0
  139. package/dist/components/CopyToClipboard.js +81 -0
  140. package/dist/{chunks/CreateModal-BY6DLmur.js → components/CreateModal.js} +10 -189
  141. package/dist/components/DescriptionList.js +42 -0
  142. package/dist/components/Dropdown.d.ts +1 -1
  143. package/dist/components/Dropdown.js +349 -0
  144. package/dist/components/EmptyState.d.ts +1 -1
  145. package/dist/components/EmptyState.js +27 -0
  146. package/dist/components/Filter.js +32 -0
  147. package/dist/components/FilterPill.js +13 -0
  148. package/dist/components/IconButton.js +34 -0
  149. package/dist/components/Indicator.d.ts +2 -2
  150. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  151. package/dist/components/Input.d.ts +1 -1
  152. package/dist/components/Input.js +88 -0
  153. package/dist/components/LetterBadge.d.ts +1 -1
  154. package/dist/components/LetterBadge.js +13 -0
  155. package/dist/components/Listbox.js +123 -0
  156. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  157. package/dist/components/Markdown.js +15 -0
  158. package/dist/components/MarkdownImpl.d.ts +1 -1
  159. package/dist/components/MultiSelect.js +171 -0
  160. package/dist/components/Overview.js +39 -0
  161. package/dist/components/PageHeader.js +194 -0
  162. package/dist/components/Pagination.js +35 -0
  163. package/dist/components/Provider.d.ts +16 -65
  164. package/dist/{chunks/Provider-Ghua9PkN.js → components/Provider.js} +54 -20
  165. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  166. package/dist/components/SectionHeader.js +11 -0
  167. package/dist/components/SettingModeOption.js +30 -0
  168. package/dist/components/SettingRow.d.ts +1 -1
  169. package/dist/components/SettingRow.js +35 -0
  170. package/dist/components/SettingsCard.js +31 -0
  171. package/dist/components/SettingsGroup.d.ts +1 -1
  172. package/dist/components/SettingsGroup.js +17 -0
  173. package/dist/components/Sort.js +42 -0
  174. package/dist/components/StatusBadge.js +63 -0
  175. package/dist/components/SwitchToggle.js +59 -0
  176. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  177. package/dist/{chunks/Table-4OHjdKdO.js → components/Table.js} +7 -5
  178. package/dist/components/Toggle.js +20 -0
  179. package/dist/{chunks/Tooltip-Crxo_eU_.js → components/Tooltip.js} +6 -4
  180. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  181. package/dist/components/focus.d.ts +2 -0
  182. package/dist/components/focus.js +7 -0
  183. package/dist/components/ghostButton.js +7 -0
  184. package/dist/components/inputClasses.js +4 -0
  185. package/dist/components/keys.d.ts +12 -0
  186. package/dist/components/keys.js +27 -0
  187. package/dist/components/relativeTime.js +32 -0
  188. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  189. package/dist/duration.d.ts +3 -0
  190. package/dist/duration.js +17 -0
  191. package/dist/editor/Editor.js +13 -0
  192. package/dist/editor/EditorField.js +53 -0
  193. package/dist/editor/FormCodePanel.js +173 -0
  194. package/dist/editor/Monaco.d.ts +1 -20
  195. package/dist/editor/Monaco.js +112 -0
  196. package/dist/editor/index.d.ts +2 -1
  197. package/dist/editor/index.js +7 -2
  198. package/dist/editor/themes.js +91 -0
  199. package/dist/editor/workers.js +29 -0
  200. package/dist/editor/yaml.d.ts +5 -0
  201. package/dist/editor/yaml.js +15 -0
  202. package/dist/engine.d.ts +98 -0
  203. package/dist/file-explorer/FileExplorer.d.ts +11 -2
  204. package/dist/file-explorer/FileExplorer.js +1402 -0
  205. package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
  206. package/dist/file-explorer/FileExplorerContext.js +370 -0
  207. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
  208. package/dist/{chunks/CodePreviewEditor-4lx3kE-w.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  209. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  210. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  211. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  212. package/dist/file-explorer/FilePreview/index.js +266 -0
  213. package/dist/file-explorer/FilePreview/parse.js +63 -0
  214. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  215. package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
  216. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  217. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  218. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  219. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  220. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  221. package/dist/file-explorer/FileRow.d.ts +1 -1
  222. package/dist/file-explorer/FileRow.js +165 -0
  223. package/dist/file-explorer/FileRowsWindow.js +92 -0
  224. package/dist/file-explorer/FileTable.js +172 -0
  225. package/dist/file-explorer/FileTableHeaders.js +49 -0
  226. package/dist/file-explorer/LoadMoreRow.js +46 -0
  227. package/dist/file-explorer/TreeView.js +376 -0
  228. package/dist/file-explorer/helpers.d.ts +4 -4
  229. package/dist/file-explorer/helpers.js +537 -0
  230. package/dist/file-explorer/index.d.ts +3 -3
  231. package/dist/file-explorer/index.js +7 -5705
  232. package/dist/file-explorer/lib/batch.js +39 -0
  233. package/dist/file-explorer/lib/errors.js +9 -0
  234. package/dist/file-explorer/lib/paging.js +124 -0
  235. package/dist/file-explorer/lib/types.d.ts +6 -1
  236. package/dist/file-explorer/lib/utils.d.ts +1 -3
  237. package/dist/file-explorer/lib/utils.js +322 -0
  238. package/dist/file-explorer/toasts.js +400 -0
  239. package/dist/file-explorer/treeRows.js +73 -0
  240. package/dist/file-explorer/useNearEnd.d.ts +1 -1
  241. package/dist/file-explorer/useNearEnd.js +27 -0
  242. package/dist/form/FieldWrapper.d.ts +2 -2
  243. package/dist/form/FieldWrapper.js +54 -0
  244. package/dist/form/Fields/BooleanField.js +51 -0
  245. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  246. package/dist/form/Fields/ColorField.js +33 -0
  247. package/dist/form/Fields/DropdownField.js +49 -0
  248. package/dist/form/Fields/DurationField.js +130 -0
  249. package/dist/form/Fields/LabelField.js +19 -0
  250. package/dist/form/Fields/MultiDropdownField.js +40 -0
  251. package/dist/form/Fields/NumberField.js +51 -0
  252. package/dist/form/Fields/ObjectField.js +54 -0
  253. package/dist/form/Fields/RadioField.js +49 -0
  254. package/dist/form/Fields/RangeField.js +58 -0
  255. package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
  256. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  257. package/dist/form/Fields/StepField.js +6 -0
  258. package/dist/form/Fields/StringField.js +37 -0
  259. package/dist/form/Fields/TextAreaField.js +31 -0
  260. package/dist/form/Fields/durationValidity.js +11 -0
  261. package/dist/form/Form.d.ts +4 -21
  262. package/dist/form/Form.js +643 -0
  263. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  264. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  265. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  266. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  267. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  268. package/dist/form/Wizard/WizardContainer.js +138 -0
  269. package/dist/form/Wizard/WizardNavigation.js +92 -0
  270. package/dist/form/Wizard/WizardStepContent.js +35 -0
  271. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  272. package/dist/form/Wizard/useWizardState.js +118 -0
  273. package/dist/form/Wizard/utils.js +34 -0
  274. package/dist/form/fieldContext.js +26 -0
  275. package/dist/form/fieldRegistry.js +50 -0
  276. package/dist/form/index.d.ts +11 -12
  277. package/dist/form/index.js +18 -2445
  278. package/dist/form/lib.d.ts +6 -1
  279. package/dist/{chunks/FieldWrapper-Bef01EWO.js → form/lib.js} +5 -104
  280. package/dist/form/types/fieldComponentTypes.d.ts +3 -2
  281. package/dist/form/types/fieldTypes.d.ts +6 -20
  282. package/dist/form/useParsedOpts.d.ts +1 -1
  283. package/dist/form/useParsedOpts.js +62 -0
  284. package/dist/form/usePrevious.js +11 -0
  285. package/dist/form/utils/checkShowIfObject.js +14 -0
  286. package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
  287. package/dist/form/utils/duration.js +69 -0
  288. package/dist/form/utils/getParentValue.js +23 -0
  289. package/dist/form/utils/getPlaceholder.js +9 -0
  290. package/dist/form/utils/getValueUsingPath.js +23 -0
  291. package/dist/form/utils/secondaryField.js +22 -0
  292. package/dist/graph/AnnotationBanner.js +141 -0
  293. package/dist/graph/Collapse.js +41 -0
  294. package/dist/{workflow/index.js → graph/DependencyGraph.js} +76 -1163
  295. package/dist/graph/JobSummary.js +104 -0
  296. package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
  297. package/dist/graph/MatrixGroup.js +107 -0
  298. package/dist/graph/Reveal.js +57 -0
  299. package/dist/graph/TreeView.js +711 -0
  300. package/dist/{workflow → graph}/index.d.ts +1 -1
  301. package/dist/graph/index.js +2 -0
  302. package/dist/{workflow → graph}/types.d.ts +3 -3
  303. package/dist/graph/types.js +6 -0
  304. package/dist/icons.d.ts +20 -21
  305. package/dist/index.d.ts +38 -40
  306. package/dist/index.js +47 -599
  307. package/dist/list/ActionToolbar.js +184 -0
  308. package/dist/list/HoverCard.js +73 -0
  309. package/dist/list/ListPage.js +145 -0
  310. package/dist/list/ListPager.js +59 -0
  311. package/dist/list/ListTable.d.ts +1 -1
  312. package/dist/list/ListTable.js +163 -0
  313. package/dist/list/ListViewControls.d.ts +2 -2
  314. package/dist/list/ListViewControls.js +372 -0
  315. package/dist/list/RowContextMenu.js +350 -0
  316. package/dist/list/UserHoverCard.js +117 -0
  317. package/dist/list/index.d.ts +9 -9
  318. package/dist/list/index.js +11 -2
  319. package/dist/list/listSearch.js +137 -0
  320. package/dist/list/listView.js +210 -0
  321. package/dist/list/textEntry.js +10 -0
  322. package/dist/logviewer/LogViewer.d.ts +1 -1
  323. package/dist/logviewer/LogViewer.js +750 -0
  324. package/dist/logviewer/index.d.ts +1 -0
  325. package/dist/logviewer/index.js +3 -742
  326. package/dist/logviewer/segments.d.ts +9 -0
  327. package/dist/logviewer/segments.js +80 -0
  328. package/dist/styles/fonts.css +4 -4
  329. package/dist/styles/theme.css +6 -4
  330. package/dist/styles.css +1 -1
  331. package/dist/theme/index.js +2 -2
  332. package/package.json +38 -14
  333. package/LICENSE +0 -202
  334. package/dist/chunks/Monaco-C1POOdVv.js +0 -1046
  335. package/dist/chunks/PageHeader-l49p1nM9.js +0 -690
  336. package/dist/chunks/SwitchToggle-CHPP8uZQ.js +0 -755
  337. package/dist/chunks/editor-9_uVtUyy.js +0 -347
  338. package/dist/chunks/list-qrojZZNv.js +0 -1411
  339. package/dist/editor/usesGitlab.d.ts +0 -97
  340. package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
  341. package/dist/form/types/workflow-schema.d.ts +0 -1145
  342. package/dist/form/utils/pwResolver.d.ts +0 -18
  343. package/dist/{chunks/MarkdownImpl-Bq4QhrtA.js → components/MarkdownImpl.js} +1 -1
  344. /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
  345. /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
  346. /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
  347. /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
  348. /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
  349. /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
@@ -0,0 +1,721 @@
1
+ import { CheckIcon, ChevronRightIcon, LoaderIcon } from "../../../icons.js";
2
+ import { useCssIsDark } from "../../../components/useCssIsDark.js";
3
+ import { LogViewer } from "../../../logviewer/LogViewer.js";
4
+ import { agentColorHex, bashExitCode, fullToolArgs, isGroupableTool, rollupSentence, summarizeToolArgs, toolHeaderFor, toolSummary } from "../../agent/toolfmt.js";
5
+ import { computeEditDiff, computeWriteRows, editSummary, isEditDiffTool, parseEditArgs } from "../../agent/diff.js";
6
+ import { languageForPath, tokenizeDiffLines } from "../../agent/diffHighlight.js";
7
+ import { thinkingHeading } from "../../agent/transcript.js";
8
+ import { useChatConfig } from "../../core/config.js";
9
+ import Markdown from "../../ui/Markdown.js";
10
+ import { chatProseClasses } from "../../ui/prose.js";
11
+ import cx from "classnames";
12
+ import { useEffect, useMemo, useState } from "react";
13
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
14
+ //#region src/ai/components/agent/AgentMessageParts.tsx
15
+ var COLLAPSED_RESULT_LINES = 12;
16
+ function LineSpans({ text, tokens, emphasis }) {
17
+ const pieces = tokens ?? [{ content: text }];
18
+ if (!emphasis || emphasis.length === 0) return /* @__PURE__ */ jsx(Fragment$1, { children: pieces.map((t, i) => /* @__PURE__ */ jsx("span", {
19
+ style: t.color ? { color: t.color } : void 0,
20
+ children: t.content
21
+ }, i)) });
22
+ const inEmphasis = (pos) => emphasis.some(([a, b]) => pos >= a && pos < b);
23
+ const out = [];
24
+ let offset = 0;
25
+ let key = 0;
26
+ for (const t of pieces) {
27
+ let start = 0;
28
+ while (start < t.content.length) {
29
+ const emphasized = inEmphasis(offset + start);
30
+ let end = start + 1;
31
+ while (end < t.content.length && inEmphasis(offset + end) === emphasized) end++;
32
+ out.push(/* @__PURE__ */ jsx("span", {
33
+ className: emphasized ? "bg-green-500/30 rounded-[2px]" : void 0,
34
+ style: t.color ? { color: t.color } : void 0,
35
+ children: t.content.slice(start, end)
36
+ }, key++));
37
+ start = end;
38
+ }
39
+ offset += t.content.length;
40
+ }
41
+ return /* @__PURE__ */ jsx(Fragment$1, { children: out });
42
+ }
43
+ function DiffRows({ rows, lang }) {
44
+ const isDark = useCssIsDark();
45
+ const [tokens, setTokens] = useState(null);
46
+ const lineKey = useMemo(() => rows.map((r) => r.kind === "gap" ? "" : r.text).join("\n"), [rows]);
47
+ useEffect(() => {
48
+ if (!lang) {
49
+ setTokens(null);
50
+ return;
51
+ }
52
+ let live = true;
53
+ tokenizeDiffLines(lineKey.split("\n"), lang, isDark).then((t) => {
54
+ if (live) setTokens(t);
55
+ });
56
+ return () => {
57
+ live = false;
58
+ };
59
+ }, [
60
+ lang,
61
+ lineKey,
62
+ isDark
63
+ ]);
64
+ const numbered = rows.some((r) => r.oldNo !== void 0 || r.newNo !== void 0);
65
+ return /* @__PURE__ */ jsx("div", {
66
+ className: "overflow-x-auto rounded-md border theme-border font-mono text-xs leading-5",
67
+ children: rows.map((row, i) => /* @__PURE__ */ jsxs("div", {
68
+ className: cx("flex whitespace-pre", row.kind === "add" && "bg-green-500/15", row.kind === "del" && "bg-red-500/15", row.kind === "gap" && "theme-muted-text"),
69
+ children: [
70
+ numbered && /* @__PURE__ */ jsx("span", {
71
+ className: "w-10 shrink-0 select-none text-right pr-2 theme-muted-text",
72
+ children: row.kind === "gap" ? "⋯" : row.newNo ?? row.oldNo ?? ""
73
+ }),
74
+ /* @__PURE__ */ jsx("span", {
75
+ className: "w-4 shrink-0 select-none text-center",
76
+ children: row.kind === "add" ? "+" : row.kind === "del" ? "-" : " "
77
+ }),
78
+ /* @__PURE__ */ jsx("span", {
79
+ className: "pr-3",
80
+ children: row.kind === "gap" ? "" : /* @__PURE__ */ jsx(LineSpans, {
81
+ text: row.text,
82
+ tokens: tokens?.[i],
83
+ emphasis: row.kind === "add" ? row.emphasis : void 0
84
+ })
85
+ })
86
+ ]
87
+ }, i))
88
+ });
89
+ }
90
+ function EditDiffBlock({ part }) {
91
+ const { strings } = useChatConfig();
92
+ const t = strings.agentTranscript;
93
+ const a = parseEditArgs(part.args);
94
+ if (!a) return null;
95
+ const outcome = editSummary(part.name, part.args);
96
+ const model = part.name === "EditFile" ? computeEditDiff(a.old_string ?? "", a.new_string ?? "", part.startLine) : computeWriteRows(a.content ?? "");
97
+ return /* @__PURE__ */ jsxs("div", {
98
+ className: "mt-1.5 space-y-1",
99
+ children: [
100
+ outcome && /* @__PURE__ */ jsx("div", {
101
+ className: "text-xs theme-muted-text",
102
+ children: outcome
103
+ }),
104
+ /* @__PURE__ */ jsx(DiffRows, {
105
+ rows: model.rows,
106
+ lang: languageForPath(a.path)
107
+ }),
108
+ model.truncated && /* @__PURE__ */ jsx("div", {
109
+ className: "text-xs theme-muted-text",
110
+ children: t.diffTruncated
111
+ })
112
+ ]
113
+ });
114
+ }
115
+ function ResultBody({ part }) {
116
+ const { strings } = useChatConfig();
117
+ const t = strings.agentTranscript;
118
+ const [showAll, setShowAll] = useState(false);
119
+ const result = part.result ?? "";
120
+ if (result.trim() === "") return /* @__PURE__ */ jsx("div", {
121
+ className: "text-xs theme-muted-text",
122
+ children: t.noOutput
123
+ });
124
+ if (part.name === "Bash") {
125
+ const [out] = bashExitCode(result.replace(/\n+$/, ""));
126
+ return /* @__PURE__ */ jsx("div", {
127
+ className: "rounded-md overflow-hidden border theme-border",
128
+ children: /* @__PURE__ */ jsx(LogViewer, {
129
+ log: out || result,
130
+ width: "100%",
131
+ height: "unset",
132
+ inline: true,
133
+ lineNumbers: false,
134
+ hideExpand: true
135
+ })
136
+ });
137
+ }
138
+ const lines = result.replace(/\n+$/, "").split("\n");
139
+ const shown = showAll ? lines : lines.slice(0, COLLAPSED_RESULT_LINES);
140
+ const hidden = lines.length - shown.length;
141
+ return /* @__PURE__ */ jsxs("div", {
142
+ className: "space-y-1",
143
+ children: [
144
+ /* @__PURE__ */ jsx("pre", {
145
+ className: "overflow-x-auto rounded-md border theme-border p-2 font-mono text-xs leading-5 whitespace-pre",
146
+ children: shown.join("\n")
147
+ }),
148
+ hidden > 0 && /* @__PURE__ */ jsx("button", {
149
+ type: "button",
150
+ onClick: () => setShowAll(true),
151
+ className: "text-xs text-(--theme-link) hover:underline",
152
+ children: t.moreLines.replace("{count}", String(hidden))
153
+ }),
154
+ showAll && lines.length > COLLAPSED_RESULT_LINES && /* @__PURE__ */ jsx("button", {
155
+ type: "button",
156
+ onClick: () => setShowAll(false),
157
+ className: "text-xs text-(--theme-link) hover:underline",
158
+ children: t.showLess
159
+ })
160
+ ]
161
+ });
162
+ }
163
+ function ToolStatusDot({ part }) {
164
+ if (part.status === "running") return /* @__PURE__ */ jsx(LoaderIcon, { className: "w-3.5 h-3.5 animate-spin theme-muted-text" });
165
+ if (part.status === "error") return /* @__PURE__ */ jsx("span", {
166
+ className: "text-red-500 leading-none",
167
+ children: "●"
168
+ });
169
+ return /* @__PURE__ */ jsx("span", {
170
+ className: "text-green-600 leading-none",
171
+ children: "●"
172
+ });
173
+ }
174
+ function ToolCallBlock({ part }) {
175
+ const { strings } = useChatConfig();
176
+ const t = strings.agentTranscript;
177
+ const [expanded, setExpanded] = useState(false);
178
+ const header = toolHeaderFor(part.name);
179
+ const argSummary = summarizeToolArgs(header.arg, part.args);
180
+ const isDiff = isEditDiffTool(part.name);
181
+ const summary = part.status === "running" ? t.running : toolSummary(part.name, part.args, part.result ?? "", part.status === "error", editSummary);
182
+ return /* @__PURE__ */ jsxs("div", {
183
+ className: "py-1.5 text-sm",
184
+ "data-testid": "tool-call-part",
185
+ children: [
186
+ /* @__PURE__ */ jsxs("button", {
187
+ type: "button",
188
+ onClick: () => setExpanded((v) => !v),
189
+ "aria-expanded": expanded,
190
+ className: "flex min-h-6 items-start gap-2 w-full text-left group/tool",
191
+ children: [
192
+ /* @__PURE__ */ jsx(ToolStatusDot, { part }),
193
+ /* @__PURE__ */ jsxs("span", {
194
+ className: "font-mono text-[13px] leading-5 min-w-0 truncate",
195
+ children: [/* @__PURE__ */ jsx("span", {
196
+ className: "font-semibold",
197
+ children: header.label
198
+ }), argSummary && /* @__PURE__ */ jsxs("span", {
199
+ className: "theme-muted-text",
200
+ children: [
201
+ "(",
202
+ argSummary,
203
+ ")"
204
+ ]
205
+ })]
206
+ }),
207
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: cx("w-3.5 h-3.5 mt-1 shrink-0 theme-muted-text transition-transform", expanded && "rotate-90") })
208
+ ]
209
+ }),
210
+ !isDiff && /* @__PURE__ */ jsx("div", {
211
+ className: cx("ml-5 mt-0.5 text-[13px]", part.status === "error" ? "text-red-600" : "theme-muted-text"),
212
+ children: expanded ? null : summary
213
+ }),
214
+ expanded && !isDiff && /* @__PURE__ */ jsxs("div", {
215
+ className: "ml-5 mt-1 space-y-1.5",
216
+ children: [fullToolArgs(header.arg, part.args) && /* @__PURE__ */ jsx("pre", {
217
+ className: "overflow-x-auto rounded-md bg-(--theme-muted-panel-bg) p-2 font-mono text-xs whitespace-pre-wrap",
218
+ children: fullToolArgs(header.arg, part.args)
219
+ }), /* @__PURE__ */ jsx(ResultBody, { part })]
220
+ }),
221
+ isDiff && /* @__PURE__ */ jsx("div", {
222
+ className: "ml-5",
223
+ children: /* @__PURE__ */ jsx(EditDiffBlock, { part })
224
+ })
225
+ ]
226
+ });
227
+ }
228
+ /** Drawn the way the TUI draws a delegated Task: a tool-shaped header
229
+ * `Task(description)`, and under it the latest action while running or
230
+ * `Done (summary)` once finished. Expanding shows the whole activity feed. */
231
+ function SubagentCard({ part }) {
232
+ const { strings } = useChatConfig();
233
+ const t = strings.agentTranscript;
234
+ const [expanded, setExpanded] = useState(false);
235
+ const color = agentColorHex(part.color);
236
+ const label = part.agentType && part.agentType !== "default" ? part.agentType : t.subagent;
237
+ const actions = part.actions ?? [];
238
+ const latest = actions[actions.length - 1];
239
+ const canExpand = actions.length > 0 || !!part.report;
240
+ const outcome = part.status === "running" ? latest || t.running : `${part.status === "done" ? t.done : t.failed}${part.summary ? ` (${part.summary})` : ""}`;
241
+ return /* @__PURE__ */ jsxs("div", {
242
+ className: "py-1.5 text-sm",
243
+ "data-testid": "subagent-part",
244
+ children: [/* @__PURE__ */ jsxs("button", {
245
+ type: "button",
246
+ onClick: () => canExpand && setExpanded((v) => !v),
247
+ "aria-expanded": expanded,
248
+ className: "flex min-h-6 items-start gap-2 w-full text-left",
249
+ children: [
250
+ part.status === "running" ? /* @__PURE__ */ jsx(LoaderIcon, { className: "w-3.5 h-3.5 mt-[3px] animate-spin theme-muted-text" }) : /* @__PURE__ */ jsx("span", {
251
+ className: cx("leading-none", part.status === "failed" ? "text-red-500" : "text-green-600"),
252
+ style: color && part.status !== "failed" ? { color } : void 0,
253
+ children: "●"
254
+ }),
255
+ /* @__PURE__ */ jsxs("span", {
256
+ className: "font-mono text-[13px] leading-5 min-w-0 truncate",
257
+ children: [/* @__PURE__ */ jsx("span", {
258
+ className: "font-semibold",
259
+ children: label
260
+ }), part.description && /* @__PURE__ */ jsxs("span", {
261
+ className: "theme-muted-text",
262
+ children: [
263
+ "(",
264
+ part.description,
265
+ ")"
266
+ ]
267
+ })]
268
+ }),
269
+ canExpand && /* @__PURE__ */ jsx(ChevronRightIcon, { className: cx("w-3.5 h-3.5 mt-1 shrink-0 theme-muted-text transition-transform", expanded && "rotate-90") })
270
+ ]
271
+ }), /* @__PURE__ */ jsx("div", {
272
+ className: cx("ml-5 mt-0.5 text-[13px]", part.status === "failed" ? "text-red-600" : "theme-muted-text"),
273
+ children: expanded ? /* @__PURE__ */ jsxs("div", {
274
+ className: "space-y-1",
275
+ children: [actions.length > 0 && /* @__PURE__ */ jsxs("ul", {
276
+ className: "space-y-0.5",
277
+ children: [actions.map((a, i) => /* @__PURE__ */ jsx("li", { children: a }, i)), part.status !== "running" && /* @__PURE__ */ jsx("li", { children: outcome })]
278
+ }), part.report && /* @__PURE__ */ jsx("div", {
279
+ className: "border-l-2 theme-border pl-3 text-sm theme-muted-text",
280
+ children: /* @__PURE__ */ jsx(Markdown, { children: part.report })
281
+ })]
282
+ }) : outcome
283
+ })]
284
+ });
285
+ }
286
+ function ConfirmApproval({ part, onAnswer }) {
287
+ const { strings } = useChatConfig();
288
+ const t = strings.agentTranscript;
289
+ const [feedback, setFeedback] = useState(null);
290
+ const answer = (a) => onAnswer?.(part.id, a);
291
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
292
+ part.command && /* @__PURE__ */ jsx("pre", {
293
+ className: "overflow-x-auto rounded-md bg-(--theme-muted-panel-bg) p-2 font-mono text-xs whitespace-pre-wrap",
294
+ children: part.command
295
+ }),
296
+ part.reason && /* @__PURE__ */ jsx("div", {
297
+ className: "text-xs theme-muted-text",
298
+ children: part.reason
299
+ }),
300
+ !onAnswer ? /* @__PURE__ */ jsx("div", {
301
+ className: "text-xs theme-muted-text",
302
+ children: t.approvalPending
303
+ }) : feedback === null ? /* @__PURE__ */ jsxs("div", {
304
+ className: "flex flex-wrap gap-2",
305
+ children: [
306
+ /* @__PURE__ */ jsx("button", {
307
+ type: "button",
308
+ onClick: () => answer({
309
+ kind: "confirm",
310
+ allowed: true
311
+ }),
312
+ className: "px-3 py-1 text-xs font-medium rounded-full bg-(--theme-element) text-(--theme-element-text)",
313
+ children: t.allowOnce
314
+ }),
315
+ part.canAllowDirectory !== false && /* @__PURE__ */ jsx("button", {
316
+ type: "button",
317
+ onClick: () => answer({
318
+ kind: "confirm",
319
+ allowed: true,
320
+ allowDir: true
321
+ }),
322
+ className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover",
323
+ children: t.allowDirectory
324
+ }),
325
+ /* @__PURE__ */ jsx("button", {
326
+ type: "button",
327
+ onClick: () => answer({
328
+ kind: "confirm",
329
+ allowed: false
330
+ }),
331
+ className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover text-red-600",
332
+ children: t.deny
333
+ }),
334
+ /* @__PURE__ */ jsx("button", {
335
+ type: "button",
336
+ onClick: () => setFeedback(""),
337
+ className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover",
338
+ children: t.denyWithFeedback
339
+ })
340
+ ]
341
+ }) : /* @__PURE__ */ jsxs("div", {
342
+ className: "flex gap-2",
343
+ children: [/* @__PURE__ */ jsx("input", {
344
+ value: feedback,
345
+ onChange: (e) => setFeedback(e.target.value),
346
+ placeholder: t.feedbackPlaceholder,
347
+ className: "flex-1 text-xs rounded-md border theme-border bg-(--theme-input-bg) px-2 py-1"
348
+ }), /* @__PURE__ */ jsx("button", {
349
+ type: "button",
350
+ disabled: !feedback.trim(),
351
+ onClick: () => answer({
352
+ kind: "confirm",
353
+ allowed: false,
354
+ denyMessage: feedback.trim()
355
+ }),
356
+ className: "px-3 py-1 text-xs font-medium rounded-full bg-(--theme-element) text-(--theme-element-text) disabled:opacity-50",
357
+ children: t.send
358
+ })]
359
+ })
360
+ ] });
361
+ }
362
+ function AskApproval({ part, onAnswer }) {
363
+ const { strings } = useChatConfig();
364
+ const t = strings.agentTranscript;
365
+ const [own, setOwn] = useState(null);
366
+ const answer = (text) => onAnswer?.(part.id, {
367
+ kind: "ask",
368
+ text
369
+ });
370
+ if (!onAnswer) return /* @__PURE__ */ jsxs(Fragment$1, { children: [
371
+ part.question && /* @__PURE__ */ jsx("div", {
372
+ className: "text-sm",
373
+ children: part.question
374
+ }),
375
+ (part.options ?? []).length > 0 && /* @__PURE__ */ jsxs("div", {
376
+ className: "text-xs theme-muted-text",
377
+ children: [/* @__PURE__ */ jsxs("span", {
378
+ className: "font-medium",
379
+ children: [t.approvalOptions, ": "]
380
+ }), (part.options ?? []).map((o) => o.label).join(" · ")]
381
+ }),
382
+ /* @__PURE__ */ jsx("div", {
383
+ className: "text-xs theme-muted-text",
384
+ children: t.approvalPending
385
+ })
386
+ ] });
387
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [part.question && /* @__PURE__ */ jsx("div", {
388
+ className: "text-sm",
389
+ children: part.question
390
+ }), own === null ? /* @__PURE__ */ jsxs("div", {
391
+ className: "flex flex-col items-start gap-1.5",
392
+ children: [(part.options ?? []).map((o) => /* @__PURE__ */ jsx("button", {
393
+ type: "button",
394
+ onClick: () => answer(o.label),
395
+ className: "px-3 py-1 text-xs font-medium rounded-full border theme-border hover:theme-hover text-left",
396
+ title: o.description,
397
+ children: o.label
398
+ }, o.label)), /* @__PURE__ */ jsx("button", {
399
+ type: "button",
400
+ onClick: () => setOwn(""),
401
+ className: "px-3 py-1 text-xs rounded-full theme-muted-text hover:theme-hover",
402
+ children: t.writeOwnAnswer
403
+ })]
404
+ }) : /* @__PURE__ */ jsxs("div", {
405
+ className: "flex gap-2",
406
+ children: [/* @__PURE__ */ jsx("input", {
407
+ value: own,
408
+ onChange: (e) => setOwn(e.target.value),
409
+ className: "flex-1 text-xs rounded-md border theme-border bg-(--theme-input-bg) px-2 py-1"
410
+ }), /* @__PURE__ */ jsx("button", {
411
+ type: "button",
412
+ disabled: !own.trim(),
413
+ onClick: () => answer(own.trim()),
414
+ className: "px-3 py-1 text-xs font-medium rounded-full bg-(--theme-element) text-(--theme-element-text) disabled:opacity-50",
415
+ children: t.send
416
+ })]
417
+ })] });
418
+ }
419
+ function ApprovalBlock({ part, onApprovalAnswer }) {
420
+ const { strings } = useChatConfig();
421
+ const t = strings.agentTranscript;
422
+ if (part.resolved) return /* @__PURE__ */ jsxs("div", {
423
+ className: "my-1.5 rounded-lg border theme-border p-2.5 text-xs theme-muted-text space-y-1",
424
+ "data-testid": "approval-part",
425
+ children: [part.question && /* @__PURE__ */ jsx("div", {
426
+ className: "theme-text",
427
+ children: part.question
428
+ }), /* @__PURE__ */ jsxs("div", {
429
+ className: "flex items-center gap-2",
430
+ children: [/* @__PURE__ */ jsx(CheckIcon, { className: "w-3.5 h-3.5" }), /* @__PURE__ */ jsxs("span", { children: [t.answered, part.answer ? `: ${part.answer}` : ""] })]
431
+ })]
432
+ });
433
+ return /* @__PURE__ */ jsxs("div", {
434
+ className: "my-1.5 rounded-lg border border-(--theme-element) p-3 space-y-2",
435
+ "data-testid": "approval-part",
436
+ children: [(part.header || part.toolName) && /* @__PURE__ */ jsx("div", {
437
+ className: "text-xs font-semibold",
438
+ children: part.header ?? part.toolName
439
+ }), part.approvalKind === "confirm" ? /* @__PURE__ */ jsx(ConfirmApproval, {
440
+ part,
441
+ onAnswer: onApprovalAnswer
442
+ }) : part.approvalKind === "plan" ? /* @__PURE__ */ jsx(PlanApproval, { part }) : /* @__PURE__ */ jsx(AskApproval, {
443
+ part,
444
+ onAnswer: onApprovalAnswer
445
+ })]
446
+ });
447
+ }
448
+ function PlanApproval({ part }) {
449
+ const { strings } = useChatConfig();
450
+ const t = strings.agentTranscript;
451
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
452
+ className: "text-xs theme-muted-text",
453
+ children: t.planPending
454
+ }), part.plan && /* @__PURE__ */ jsx("div", {
455
+ className: "prose prose-sm max-w-none rounded-md bg-(--theme-muted-panel-bg) p-2 text-(--theme-panel)",
456
+ children: /* @__PURE__ */ jsx(Markdown, {
457
+ isStreaming: false,
458
+ children: part.plan
459
+ })
460
+ })] });
461
+ }
462
+ function TodoSnapshotBlock({ part }) {
463
+ const { strings } = useChatConfig();
464
+ const t = strings.agentTranscript;
465
+ return /* @__PURE__ */ jsxs("div", {
466
+ className: "my-1.5 rounded-lg border theme-border p-2.5",
467
+ "data-testid": "todo-part",
468
+ children: [/* @__PURE__ */ jsx("div", {
469
+ className: "text-xs font-semibold theme-muted-text mb-1",
470
+ children: t.tasks
471
+ }), /* @__PURE__ */ jsx("ul", {
472
+ className: "space-y-0.5 text-sm",
473
+ children: part.todos.map((todo) => /* @__PURE__ */ jsxs("li", {
474
+ className: cx("flex items-start gap-2", todo.status === "completed" && "line-through theme-muted-text", todo.status === "in_progress" && "font-semibold"),
475
+ children: [/* @__PURE__ */ jsx("span", {
476
+ className: "select-none font-mono",
477
+ children: todo.status === "completed" ? "✔" : todo.status === "in_progress" ? "■" : "□"
478
+ }), /* @__PURE__ */ jsx("span", { children: todo.status === "in_progress" && todo.activeForm ? todo.activeForm : todo.content })]
479
+ }, todo.content))
480
+ })]
481
+ });
482
+ }
483
+ function NoticeBlock({ part }) {
484
+ const [expanded, setExpanded] = useState(false);
485
+ if (part.kind === "notice") {
486
+ if (!part.detail) return /* @__PURE__ */ jsx("div", {
487
+ className: "my-1.5 whitespace-pre-wrap text-[13px] theme-muted-text",
488
+ "data-testid": "notice-part",
489
+ children: part.text
490
+ });
491
+ return /* @__PURE__ */ jsxs("div", {
492
+ className: "my-1.5",
493
+ "data-testid": "notice-part",
494
+ children: [/* @__PURE__ */ jsxs("button", {
495
+ type: "button",
496
+ onClick: () => setExpanded((v) => !v),
497
+ "aria-expanded": expanded,
498
+ className: "flex items-start gap-1.5 text-left text-[13px] theme-muted-text hover:theme-text",
499
+ children: [/* @__PURE__ */ jsx("span", {
500
+ className: "min-w-0 flex-1 whitespace-pre-wrap",
501
+ children: part.text
502
+ }), /* @__PURE__ */ jsx(ChevronRightIcon, { className: cx("mt-0.5 h-3.5 w-3.5 shrink-0 transition-transform", expanded && "rotate-90") })]
503
+ }), expanded && /* @__PURE__ */ jsx("div", {
504
+ className: "ml-4 mt-1 border-l-2 theme-border pl-3 text-sm theme-muted-text",
505
+ children: /* @__PURE__ */ jsx(Markdown, { children: part.detail })
506
+ })]
507
+ });
508
+ }
509
+ return /* @__PURE__ */ jsx("div", {
510
+ className: cx("my-1 text-xs rounded-md px-2.5 py-1.5", part.kind === "error" ? "bg-red-500/10 text-red-700" : "bg-yellow-500/10 text-yellow-700"),
511
+ "data-testid": `${part.kind}-part`,
512
+ children: part.text
513
+ });
514
+ }
515
+ function formatThinkingDuration(ms) {
516
+ const s = Math.round(ms / 1e3);
517
+ if (s < 1) return "<1s";
518
+ if (s < 60) return `${s}s`;
519
+ return `${Math.floor(s / 60)}m ${s % 60}s`;
520
+ }
521
+ /** The TUI's thought: the body shows while it streams, then folds to its
522
+ * label and opens on request. The composer's activity line carries the
523
+ * live signal, so nothing here animates. */
524
+ function ReasoningBlock({ part, isStreaming }) {
525
+ const { strings } = useChatConfig();
526
+ const t = strings.thinking;
527
+ const [expanded, setExpanded] = useState(false);
528
+ const label = thinkingHeading(part.text) || (part.durationMs ? t.thoughtFor(formatThinkingDuration(part.durationMs)) : t.label);
529
+ const hasBody = part.text.trim() !== "";
530
+ const body = hasBody && /* @__PURE__ */ jsx("div", {
531
+ className: "ml-1 border-l theme-border pl-3 text-sm theme-muted-text",
532
+ "data-testid": "reasoning-body",
533
+ children: /* @__PURE__ */ jsx(Markdown, {
534
+ isStreaming: isStreaming ?? false,
535
+ children: part.text
536
+ })
537
+ });
538
+ if (isStreaming) return /* @__PURE__ */ jsx("div", {
539
+ className: "py-1.5",
540
+ "data-testid": "reasoning-part",
541
+ children: body
542
+ });
543
+ return /* @__PURE__ */ jsxs("div", {
544
+ className: "py-1.5",
545
+ "data-testid": "reasoning-part",
546
+ children: [/* @__PURE__ */ jsxs("button", {
547
+ type: "button",
548
+ onClick: () => hasBody && setExpanded((v) => !v),
549
+ "aria-expanded": expanded,
550
+ className: cx("flex min-h-6 items-center gap-x-1 text-sm theme-muted-text transition-colors", hasBody && "hover:theme-text"),
551
+ children: [/* @__PURE__ */ jsx("span", { children: label }), hasBody && /* @__PURE__ */ jsx(ChevronRightIcon, { className: cx("w-3.5 h-3.5 transition-transform", expanded && "rotate-90") })]
552
+ }), expanded && /* @__PURE__ */ jsx("div", {
553
+ className: "mt-1.5",
554
+ children: body
555
+ })]
556
+ });
557
+ }
558
+ function TextBlock({ part, isStreaming }) {
559
+ return /* @__PURE__ */ jsx("div", {
560
+ className: cx(chatProseClasses, "[&:not(:first-child)]:mt-4"),
561
+ children: /* @__PURE__ */ jsx(Markdown, {
562
+ isStreaming: isStreaming ?? false,
563
+ children: part.text
564
+ })
565
+ });
566
+ }
567
+ function PartDispatch(props) {
568
+ const { slots } = useChatConfig();
569
+ const Override = slots.partRenderers?.[props.part.kind];
570
+ if (Override) return /* @__PURE__ */ jsx(Override, { ...props });
571
+ const { part } = props;
572
+ switch (part.kind) {
573
+ case "text": return /* @__PURE__ */ jsx(TextBlock, {
574
+ part,
575
+ isStreaming: props.isStreaming ?? false
576
+ });
577
+ case "reasoning": return /* @__PURE__ */ jsx(ReasoningBlock, {
578
+ part,
579
+ isStreaming: props.isStreaming ?? false
580
+ });
581
+ case "tool_call": return /* @__PURE__ */ jsx(ToolCallBlock, { part });
582
+ case "subagent": return /* @__PURE__ */ jsx(SubagentCard, { part });
583
+ case "approval": return /* @__PURE__ */ jsx(ApprovalBlock, {
584
+ part,
585
+ onApprovalAnswer: props.onApprovalAnswer
586
+ });
587
+ case "notice":
588
+ case "warning":
589
+ case "error": return /* @__PURE__ */ jsx(NoticeBlock, { part });
590
+ case "todo_snapshot": return /* @__PURE__ */ jsx(TodoSnapshotBlock, { part });
591
+ default: return null;
592
+ }
593
+ }
594
+ function isReasoning(m) {
595
+ return m.part.kind === "reasoning";
596
+ }
597
+ /** Two thoughts with nothing visible between them read as one, not as a
598
+ * stack of identical lines. */
599
+ function mergeReasoning(parts) {
600
+ const durationMs = parts.reduce((sum, p) => sum + (p.durationMs ?? 0), 0);
601
+ return {
602
+ kind: "reasoning",
603
+ text: parts.map((p) => p.text).join("\n\n"),
604
+ ...durationMs > 0 ? { durationMs } : {}
605
+ };
606
+ }
607
+ function buildRenderItems(parts) {
608
+ const items = [];
609
+ let run = [];
610
+ const emitThoughts = (members) => {
611
+ if (members.length > 0) items.push({
612
+ kind: "reasoning",
613
+ parts: members.map((m) => m.part),
614
+ index: members[0]?.index ?? 0
615
+ });
616
+ };
617
+ const emitLoose = (members) => {
618
+ let thoughts = [];
619
+ for (const m of members) {
620
+ if (isReasoning(m)) {
621
+ thoughts.push(m);
622
+ continue;
623
+ }
624
+ emitThoughts(thoughts);
625
+ thoughts = [];
626
+ items.push({
627
+ kind: "single",
628
+ part: m.part,
629
+ index: m.index
630
+ });
631
+ }
632
+ emitThoughts(thoughts);
633
+ };
634
+ const flush = () => {
635
+ let start = 0;
636
+ while (start < run.length && isReasoning(run[start])) start++;
637
+ let end = run.length;
638
+ while (end > start && isReasoning(run[end - 1])) end--;
639
+ emitThoughts(run.slice(0, start));
640
+ const core = run.slice(start, end);
641
+ if (core.filter((m) => !isReasoning(m)).length >= 2) items.push({
642
+ kind: "rollup",
643
+ members: core
644
+ });
645
+ else emitLoose(core);
646
+ emitThoughts(run.slice(end));
647
+ run = [];
648
+ };
649
+ parts.forEach((part, index) => {
650
+ if (part.kind === "reasoning" || part.kind === "tool_call" && part.status === "ok" && isGroupableTool(part.name)) {
651
+ run.push({
652
+ part,
653
+ index
654
+ });
655
+ return;
656
+ }
657
+ flush();
658
+ items.push({
659
+ kind: "single",
660
+ part,
661
+ index
662
+ });
663
+ });
664
+ flush();
665
+ return items;
666
+ }
667
+ function RollupGroup({ members, message }) {
668
+ const [expanded, setExpanded] = useState(false);
669
+ const sentence = rollupSentence(members.flatMap((m) => m.part.kind === "tool_call" ? [m.part.name] : []));
670
+ return /* @__PURE__ */ jsxs("div", {
671
+ className: "py-1.5 text-sm",
672
+ "data-testid": "tool-rollup",
673
+ children: [/* @__PURE__ */ jsxs("button", {
674
+ type: "button",
675
+ onClick: () => setExpanded((v) => !v),
676
+ "aria-expanded": expanded,
677
+ className: "flex min-h-6 items-center gap-2 w-full text-left",
678
+ children: [
679
+ /* @__PURE__ */ jsx("span", {
680
+ className: "text-green-600 leading-none",
681
+ "aria-hidden": "true",
682
+ children: "●"
683
+ }),
684
+ /* @__PURE__ */ jsx("span", {
685
+ className: "font-mono text-[13px] theme-muted-text min-w-0 truncate",
686
+ children: sentence
687
+ }),
688
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: cx("w-3.5 h-3.5 shrink-0 theme-muted-text transition-transform", expanded && "rotate-90") })
689
+ ]
690
+ }), /* @__PURE__ */ jsx("div", {
691
+ className: cx("ml-1.5 mt-0.5 rounded-md", expanded ? "bg-(--theme-muted-panel-bg)/40 px-2" : "hidden"),
692
+ children: members.map((m) => /* @__PURE__ */ jsx(PartDispatch, {
693
+ part: m.part,
694
+ message
695
+ }, m.index))
696
+ })]
697
+ });
698
+ }
699
+ function AgentMessageParts({ message, isStreaming, onApprovalAnswer }) {
700
+ const parts = message.parts ?? [];
701
+ const items = useMemo(() => buildRenderItems(parts), [parts]);
702
+ const lastIndex = parts.length - 1;
703
+ return /* @__PURE__ */ jsx("div", {
704
+ className: "w-full",
705
+ "data-testid": "agent-parts",
706
+ children: items.map((item) => item.kind === "rollup" ? /* @__PURE__ */ jsx(RollupGroup, {
707
+ members: item.members,
708
+ message
709
+ }, item.members[0]?.index ?? 0) : item.kind === "reasoning" ? /* @__PURE__ */ jsx(ReasoningBlock, {
710
+ part: mergeReasoning(item.parts),
711
+ isStreaming: (isStreaming ?? false) && item.index + item.parts.length - 1 === lastIndex
712
+ }, item.index) : /* @__PURE__ */ jsx(PartDispatch, {
713
+ part: item.part,
714
+ message,
715
+ isStreaming: (isStreaming ?? false) && item.index === lastIndex,
716
+ ...onApprovalAnswer ? { onApprovalAnswer } : {}
717
+ }, item.index))
718
+ });
719
+ }
720
+ //#endregion
721
+ export { ApprovalBlock, NoticeBlock, ReasoningBlock, SubagentCard, TodoSnapshotBlock, ToolCallBlock, buildRenderItems, AgentMessageParts as default, mergeReasoning };