@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
package/README.md CHANGED
@@ -1,8 +1,24 @@
1
1
  # @parallelworks/ui
2
2
 
3
- Shared UI foundation for Parallel Works packages and applications: the unified
4
- theme contract, the icon barrel, and (in later versions) core primitives such
5
- as tables, tooltips, loaders, and modals.
3
+ React components built on one theme contract. Each surface is its own subpath,
4
+ so an application ships only what it imports:
5
+
6
+ | Subpath | Contents |
7
+ | --- | --- |
8
+ | `.` | theme contract, primitives (buttons, inputs, tables, tooltips, modals, dropdowns, settings layouts, page header), `UIProvider` |
9
+ | `./theme` | `deriveTheme`, presets, `applyTheme` |
10
+ | `./icons` | the icon barrel |
11
+ | `./list` | list pages, tables, row menus and list controls |
12
+ | `./form` | `DynamicForm` and its field registry |
13
+ | `./graph` | job dependency graph and tree view |
14
+ | `./editor` | Monaco editor (`monaco-editor` and `monaco-yaml` are optional peers) |
15
+ | `./logviewer` | log viewer with ANSI color and search |
16
+ | `./file-explorer` | object storage explorer over a host-supplied provider |
17
+ | `./ai`, `./ai/openai`, `./ai/mock` | chat interface and adapters |
18
+ | `./theme.css`, `./base.css`, `./fonts.css`, `./styles.css`, `./logviewer.css`, `./ai.css` | stylesheets |
19
+
20
+ Hosts bind notifications, strings, navigation, data hooks and the workflow
21
+ engine through `UIProvider`.
6
22
 
7
23
  ## Theme contract
8
24
 
@@ -35,9 +51,9 @@ import '@parallelworks/ui/styles.css'
35
51
  ```
36
52
 
37
53
  The prebuilt stylesheet nests all of its rules in the `pw-ui` cascade layer,
38
- so loading it alongside other Parallel Works package stylesheets (for example
39
- `@parallelworks/ai-chat/styles.css`, which uses the `pw-ai-chat` layer) is
40
- order-independent.
54
+ so its precedence does not depend on where it loads. It includes Tailwind's
55
+ preflight reset; a host with its own Tailwind build should use the `@source`
56
+ route instead to avoid a double preflight.
41
57
 
42
58
  ## Icons
43
59
 
@@ -47,3 +63,67 @@ import { AddIcon, LoaderIcon, TrashIcon } from '@parallelworks/ui/icons'
47
63
 
48
64
  The barrel re-exports a curated, stable set of icon names over `react-icons`
49
65
  so applications never depend on a specific icon pack directly.
66
+
67
+ ## Workflow engine
68
+
69
+ The workflow surfaces (`/form`'s `DynamicForm`, `/graph`'s `DependencyGraph`,
70
+ the editor's workflow completions, and the log viewer's workflow commands) do
71
+ not implement a workflow format themselves. They call a `WorkflowEngine` that
72
+ the host passes once:
73
+
74
+ ```tsx
75
+ import { UIProvider } from '@parallelworks/ui'
76
+
77
+ <UIProvider engine={engine}>{app}</UIProvider>
78
+ ```
79
+
80
+ The engine converts input definitions into the form's field tree, resolves
81
+ `${{ }}` expressions, and supplies the job graph's dependencies, matrix
82
+ grouping, step labels and log paths. The form and graph throw without one; the
83
+ editor and log viewer fall back to plain behavior.
84
+
85
+ ## AI chat
86
+
87
+ `@parallelworks/ui/ai` is a chat interface (thread, composer, streaming,
88
+ sidebar, model selector, attachments, sharing, branching) decoupled from any
89
+ backend through a `ChatAdapter`. State lives in `ChatProvider` and is read
90
+ with `useChat`:
91
+
92
+ ```tsx
93
+ import { ChatProvider, ChatLayout, ChatThread } from '@parallelworks/ui/ai'
94
+ import { createMockChatAdapter } from '@parallelworks/ui/ai/mock'
95
+
96
+ export function Chat() {
97
+ return (
98
+ <ChatProvider
99
+ adapter={createMockChatAdapter()}
100
+ currentUser={{ id: 'u1', username: 'you', name: 'You' }}
101
+ navigation={{ toConversation: id => {}, toNewChat: () => {}, toAttachments: () => {} }}
102
+ notify={{ success: console.log, error: console.error, info: console.log }}
103
+ >
104
+ <ChatLayout>
105
+ <ChatThread />
106
+ </ChatLayout>
107
+ </ChatProvider>
108
+ )
109
+ }
110
+ ```
111
+
112
+ Swap the mock for `createOpenAIChatAdapter({ baseUrl, apiKey })` from
113
+ `@parallelworks/ui/ai/openai`, or implement `ChatAdapter` against your own
114
+ backend. It requires `conversations`, `models` and `streamCompletion`; the
115
+ optional capability groups (`providers`, `attachments`, `sharing`,
116
+ `allocations`) hide their UI when absent. Adapter methods throw
117
+ `ChatAdapterError` with a user-facing `message`. Model entries and wire
118
+ messages keep OpenAI-compatible snake_case field names.
119
+
120
+ Tailwind v4 consumers add the chat rules (markdown rendering, streaming
121
+ animations) and streamdown's classes next to the theme contract:
122
+
123
+ ```css
124
+ @import 'streamdown/styles.css';
125
+ @import '@parallelworks/ui/ai.css';
126
+ @source '../node_modules/streamdown/dist/*.js';
127
+ ```
128
+
129
+ The prebuilt `@parallelworks/ui/styles.css` already includes both.
@@ -0,0 +1,8 @@
1
+ import { type ConversationsAdapter, type StreamCompletion } from './types.js';
2
+ export interface MemoryConversationStore {
3
+ conversations: ConversationsAdapter;
4
+ recordingStream(inner: StreamCompletion): StreamCompletion;
5
+ }
6
+ export declare function createMemoryConversationStore(options?: {
7
+ storageKey?: string;
8
+ }): MemoryConversationStore;
@@ -0,0 +1,152 @@
1
+ import { ChatAdapterError } from "./types.js";
2
+ //#region src/ai/adapter/memoryStore.ts
3
+ function newId() {
4
+ return crypto.randomUUID();
5
+ }
6
+ function createMemoryConversationStore(options) {
7
+ const storageKey = options?.storageKey;
8
+ let conversations = [];
9
+ if (storageKey) try {
10
+ const raw = globalThis.localStorage?.getItem(storageKey);
11
+ if (raw) conversations = JSON.parse(raw);
12
+ } catch {
13
+ conversations = [];
14
+ }
15
+ const persist = () => {
16
+ if (storageKey) try {
17
+ globalThis.localStorage?.setItem(storageKey, JSON.stringify(conversations));
18
+ } catch {}
19
+ };
20
+ const find = (id) => {
21
+ const conversation = conversations.find((c) => c.id === id);
22
+ if (!conversation) throw new ChatAdapterError("Conversation not found", { status: 404 });
23
+ return conversation;
24
+ };
25
+ const toSummary = (c) => ({
26
+ id: c.id,
27
+ ...c.title !== null ? { title: c.title } : {},
28
+ messageCount: c.messages.length,
29
+ createdAt: c.createdAt,
30
+ updatedAt: c.updatedAt,
31
+ isOwner: true,
32
+ canCollaborate: true
33
+ });
34
+ const recordUser = (req) => {
35
+ const conversation = conversations.find((c) => c.id === req.conversationId);
36
+ if (!conversation) return;
37
+ const last = req.messages[req.messages.length - 1];
38
+ const userContent = typeof last?.content === "string" ? last.content : "";
39
+ conversation.messages.push({
40
+ id: req.userMessageId,
41
+ role: "user",
42
+ content: userContent,
43
+ parentId: req.parentMessageId ?? null,
44
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
45
+ });
46
+ conversation.activeBranchId = req.userMessageId;
47
+ conversation.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
48
+ persist();
49
+ };
50
+ const recordAssistant = (req, assistant) => {
51
+ const conversation = conversations.find((c) => c.id === req.conversationId);
52
+ if (!conversation) return;
53
+ conversation.messages.push({
54
+ ...assistant,
55
+ role: "assistant"
56
+ });
57
+ conversation.activeBranchId = assistant.id;
58
+ conversation.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
59
+ persist();
60
+ };
61
+ return {
62
+ conversations: {
63
+ async list() {
64
+ return [...conversations].sort((a, b) => b.createdAt.localeCompare(a.createdAt)).map(toSummary);
65
+ },
66
+ async get(id) {
67
+ const c = find(id);
68
+ return {
69
+ id: c.id,
70
+ title: c.title,
71
+ messages: [...c.messages],
72
+ activeBranchId: c.activeBranchId,
73
+ createdAt: c.createdAt,
74
+ updatedAt: c.updatedAt,
75
+ isOwner: true,
76
+ canCollaborate: true
77
+ };
78
+ },
79
+ async create(title) {
80
+ const now = (/* @__PURE__ */ new Date()).toISOString();
81
+ const conversation = {
82
+ id: newId(),
83
+ title: title ?? null,
84
+ createdAt: now,
85
+ updatedAt: now,
86
+ activeBranchId: null,
87
+ messages: []
88
+ };
89
+ conversations.push(conversation);
90
+ persist();
91
+ return toSummary(conversation);
92
+ },
93
+ async rename(id, title) {
94
+ find(id).title = title;
95
+ persist();
96
+ },
97
+ async remove(id) {
98
+ conversations = conversations.filter((c) => c.id !== id);
99
+ persist();
100
+ }
101
+ },
102
+ recordingStream(inner) {
103
+ return async (req, handlers, signal) => {
104
+ let partialContent = "";
105
+ let partialReasoning = "";
106
+ const wrappedHandlers = {
107
+ ...handlers,
108
+ onContent: (chunk) => {
109
+ partialContent += chunk;
110
+ handlers.onContent(chunk);
111
+ },
112
+ onReasoning: (chunk) => {
113
+ partialReasoning += chunk;
114
+ handlers.onReasoning?.(chunk);
115
+ }
116
+ };
117
+ recordUser(req);
118
+ try {
119
+ const result = await inner(req, wrappedHandlers, signal);
120
+ const assistantId = result.messageId || newId();
121
+ recordAssistant(req, {
122
+ id: assistantId,
123
+ content: result.content || null,
124
+ parentId: req.userMessageId,
125
+ model: result.model ?? req.model,
126
+ ...result.reasoning ? { reasoning: result.reasoning } : {},
127
+ ...result.responsesOutput.length ? { responsesOutput: result.responsesOutput } : {},
128
+ ...result.toolCalls.length ? { toolCalls: result.toolCalls } : {},
129
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
130
+ });
131
+ return {
132
+ ...result,
133
+ messageId: assistantId
134
+ };
135
+ } catch (error) {
136
+ if (error instanceof DOMException && error.name === "AbortError" && (partialContent || partialReasoning)) recordAssistant(req, {
137
+ id: newId(),
138
+ content: partialContent || null,
139
+ parentId: req.userMessageId,
140
+ model: req.model,
141
+ ...partialReasoning ? { reasoning: partialReasoning } : {},
142
+ stopped: true,
143
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
144
+ });
145
+ throw error;
146
+ }
147
+ };
148
+ }
149
+ };
150
+ }
151
+ //#endregion
152
+ export { createMemoryConversationStore };
@@ -0,0 +1,2 @@
1
+ export { createMemoryConversationStore, type MemoryConversationStore, } from '../memoryStore.js';
2
+ export { createMockChatAdapter } from './mockAdapter.js';
@@ -0,0 +1,3 @@
1
+ import { createMemoryConversationStore } from "../memoryStore.js";
2
+ import { createMockChatAdapter } from "./mockAdapter.js";
3
+ export { createMemoryConversationStore, createMockChatAdapter };
@@ -0,0 +1,4 @@
1
+ import type { ChatAdapter } from '../types.js';
2
+ export declare function createMockChatAdapter(options?: {
3
+ storageKey?: string;
4
+ }): ChatAdapter;
@@ -0,0 +1,81 @@
1
+ import { createMemoryConversationStore } from "../memoryStore.js";
2
+ //#region src/ai/adapter/mock/mockAdapter.ts
3
+ var CANNED_REPLIES = [
4
+ "Here's a canned reply from the mock adapter. It streams word by word so the typewriter animation, cancel behavior, and background streams all exercise the same code paths as a real backend.\n\n- No network requests are made\n- Conversations persist in localStorage\n- Try cancelling mid-stream: the partial reply is kept",
5
+ "Everything you see is generated locally. The mock adapter implements the same `ChatAdapter` interface as the OpenAI-compatible adapter and any backend's own, so the UI can't tell the difference.\n\n```ts\nconst adapter = createMockChatAdapter()\n```\n\nMarkdown, `inline code`, and code blocks render through the same pipeline.",
6
+ "Branching works too: edit one of your earlier messages or hit regenerate on a reply, then use the arrows to flip between branches."
7
+ ];
8
+ var THINKING_PREAMBLE = "Thinking about the question, weighing a few canned options, and picking the next reply in the rotation...";
9
+ function sleep(ms, signal) {
10
+ return new Promise((resolve, reject) => {
11
+ if (signal?.aborted) {
12
+ reject(new DOMException("The operation was aborted.", "AbortError"));
13
+ return;
14
+ }
15
+ const onAbort = () => {
16
+ clearTimeout(timer);
17
+ reject(new DOMException("The operation was aborted.", "AbortError"));
18
+ };
19
+ const timer = setTimeout(() => {
20
+ signal?.removeEventListener("abort", onAbort);
21
+ resolve();
22
+ }, ms);
23
+ signal?.addEventListener("abort", onAbort, { once: true });
24
+ });
25
+ }
26
+ function createMockChatAdapter(options) {
27
+ const store = createMemoryConversationStore({ storageKey: options?.storageKey ?? "ai-chat-mock-conversations" });
28
+ let replyIndex = 0;
29
+ return {
30
+ conversations: store.conversations,
31
+ models: { async list() {
32
+ return {
33
+ models: [{
34
+ id: "mock:local/canned-small",
35
+ object: "model",
36
+ created: 0,
37
+ owned_by: "mock",
38
+ provider: "Mock Provider",
39
+ tool_calling_mode: "none"
40
+ }, {
41
+ id: "mock:local/canned-thinking",
42
+ object: "model",
43
+ created: 0,
44
+ owned_by: "mock",
45
+ provider: "Mock Provider",
46
+ tool_calling_mode: "none"
47
+ }],
48
+ unreachableSessions: []
49
+ };
50
+ } },
51
+ streamCompletion: store.recordingStream(async (req, handlers, signal) => {
52
+ if (signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
53
+ let reasoning = "";
54
+ if (req.model.includes("thinking")) for (const word of THINKING_PREAMBLE.split(/(?<= )/)) {
55
+ await sleep(40, signal);
56
+ reasoning += word;
57
+ handlers.onReasoning?.(word);
58
+ }
59
+ const reply = CANNED_REPLIES[replyIndex % CANNED_REPLIES.length] ?? "";
60
+ replyIndex++;
61
+ await sleep(250, signal);
62
+ let content = "";
63
+ for (const word of reply.split(/(?<= )/)) {
64
+ await sleep(25, signal);
65
+ content += word;
66
+ handlers.onContent(word);
67
+ }
68
+ return {
69
+ content,
70
+ messageId: "",
71
+ toolCalls: [],
72
+ finishReason: "stop",
73
+ model: req.model,
74
+ reasoning,
75
+ responsesOutput: []
76
+ };
77
+ })
78
+ };
79
+ }
80
+ //#endregion
81
+ export { createMockChatAdapter };
@@ -0,0 +1,9 @@
1
+ import { type StreamCompletion, type StreamRequest } from '../types.js';
2
+ export interface OpenAIStreamConfig {
3
+ completionsUrl: string;
4
+ responsesUrl?: string;
5
+ buildHeaders?: (req: StreamRequest) => Record<string, string>;
6
+ credentials?: RequestCredentials;
7
+ fetch?: typeof globalThis.fetch;
8
+ }
9
+ export declare function createOpenAICompatibleStream(config: OpenAIStreamConfig): StreamCompletion;
@@ -0,0 +1,33 @@
1
+ import { ChatAdapterError } from "../types.js";
2
+ import { errorMessageFromResponse } from "./errors.js";
3
+ import { buildResponsesRequestBody, parseResponsesSSELine } from "./responses.js";
4
+ import { processSSEStream } from "./sse.js";
5
+ //#region src/ai/adapter/openai/createOpenAIStream.ts
6
+ function createOpenAICompatibleStream(config) {
7
+ return async (req, handlers, signal) => {
8
+ const useResponses = req.useResponses === true && !!config.responsesUrl;
9
+ const url = useResponses ? config.responsesUrl : config.completionsUrl;
10
+ const body = useResponses ? buildResponsesRequestBody(req.model, req.messages) : {
11
+ model: req.model,
12
+ messages: req.messages,
13
+ stream: true
14
+ };
15
+ const res = await (config.fetch ?? globalThis.fetch.bind(globalThis))(url, {
16
+ method: "POST",
17
+ headers: {
18
+ "Content-Type": "application/json",
19
+ Accept: "text/event-stream",
20
+ ...config.buildHeaders?.(req)
21
+ },
22
+ ...config.credentials ? { credentials: config.credentials } : {},
23
+ body: JSON.stringify(body),
24
+ ...signal ? { signal } : {}
25
+ });
26
+ if (!res.ok) throw new ChatAdapterError(await errorMessageFromResponse(res), { status: res.status });
27
+ const reader = res.body?.getReader();
28
+ if (!reader) throw new ChatAdapterError("No response body");
29
+ return processSSEStream(reader, handlers.onContent, void 0, void 0, handlers.onReasoning, handlers.onMessageId, useResponses ? parseResponsesSSELine : void 0);
30
+ };
31
+ }
32
+ //#endregion
33
+ export { createOpenAICompatibleStream };
@@ -0,0 +1,3 @@
1
+ export declare function apiErrorMessage(errorData: unknown, fallback: string): string;
2
+ export declare function statusFallbackMessage(status: number): string;
3
+ export declare function errorMessageFromResponse(res: Response): Promise<string>;
@@ -0,0 +1,37 @@
1
+ //#region src/ai/adapter/openai/errors.ts
2
+ function apiErrorMessage(errorData, fallback) {
3
+ if (typeof errorData !== "object" || errorData === null) return fallback;
4
+ const data = errorData;
5
+ const candidate = data["message"] ?? data["error"] ?? data["detail"];
6
+ if (typeof candidate === "string" && candidate.trim()) return candidate;
7
+ if (candidate && typeof candidate === "object") {
8
+ const nested = candidate["message"];
9
+ if (typeof nested === "string" && nested.trim()) return nested;
10
+ try {
11
+ return JSON.stringify(candidate);
12
+ } catch {
13
+ return fallback;
14
+ }
15
+ }
16
+ return fallback;
17
+ }
18
+ function statusFallbackMessage(status) {
19
+ if (status === 401) return "Your session has expired. Please refresh the page and try again.";
20
+ if (status === 403) return "You do not have permission to use this AI provider.";
21
+ if (status === 404) return "The AI provider or model was not found. Please select a different provider.";
22
+ if (status === 429) return "Too many requests. Please wait a moment and try again.";
23
+ if (status >= 500) return "The AI service is temporarily unavailable. Please try again later.";
24
+ return "Failed to send message";
25
+ }
26
+ async function errorMessageFromResponse(res) {
27
+ let message = statusFallbackMessage(res.status);
28
+ try {
29
+ const contentType = res.headers.get("content-type");
30
+ const text = await res.text();
31
+ if (contentType?.includes("application/json") && text) message = apiErrorMessage(JSON.parse(text), message);
32
+ else if (text && res.status < 500) message = text.substring(0, 200);
33
+ } catch {}
34
+ return message;
35
+ }
36
+ //#endregion
37
+ export { apiErrorMessage, errorMessageFromResponse, statusFallbackMessage };
@@ -0,0 +1,6 @@
1
+ export { createOpenAICompatibleStream, type OpenAIStreamConfig, } from './createOpenAIStream.js';
2
+ export { apiErrorMessage, errorMessageFromResponse, statusFallbackMessage, } from './errors.js';
3
+ export { createOpenAIChatAdapter, type OpenAIChatAdapterOptions, } from './openaiAdapter.js';
4
+ export { buildResponsesRequestBody, parseResponsesSSELine, } from './responses.js';
5
+ export { type ParsedSSELine, parseSSELine, processSSEStream, type SSELineParser, } from './sse.js';
6
+ export type { CompletionChunk, CompletionChunkChoice, CompletionMessage, CompletionRequest, ModelsWireResponse, } from './wire.js';
@@ -0,0 +1,6 @@
1
+ import { apiErrorMessage, errorMessageFromResponse, statusFallbackMessage } from "./errors.js";
2
+ import { buildResponsesRequestBody, parseResponsesSSELine } from "./responses.js";
3
+ import { parseSSELine, processSSEStream } from "./sse.js";
4
+ import { createOpenAICompatibleStream } from "./createOpenAIStream.js";
5
+ import { createOpenAIChatAdapter } from "./openaiAdapter.js";
6
+ export { apiErrorMessage, buildResponsesRequestBody, createOpenAIChatAdapter, createOpenAICompatibleStream, errorMessageFromResponse, parseResponsesSSELine, parseSSELine, processSSEStream, statusFallbackMessage };
@@ -0,0 +1,9 @@
1
+ import { type ChatAdapter } from '../types.js';
2
+ export interface OpenAIChatAdapterOptions {
3
+ baseUrl: string;
4
+ apiKey?: string;
5
+ models?: string[];
6
+ storageKey?: string;
7
+ fetch?: typeof globalThis.fetch;
8
+ }
9
+ export declare function createOpenAIChatAdapter(options: OpenAIChatAdapterOptions): ChatAdapter;
@@ -0,0 +1,54 @@
1
+ import { ChatAdapterError } from "../types.js";
2
+ import { errorMessageFromResponse } from "./errors.js";
3
+ import { createOpenAICompatibleStream } from "./createOpenAIStream.js";
4
+ import { createMemoryConversationStore } from "../memoryStore.js";
5
+ //#region src/ai/adapter/openai/openaiAdapter.ts
6
+ function providerLabelFor(baseUrl) {
7
+ try {
8
+ return new URL(baseUrl).host;
9
+ } catch {
10
+ return "OpenAI compatible";
11
+ }
12
+ }
13
+ function staticModel(id, provider) {
14
+ return {
15
+ id,
16
+ object: "model",
17
+ created: 0,
18
+ owned_by: "openai-compatible",
19
+ provider,
20
+ tool_calling_mode: "none"
21
+ };
22
+ }
23
+ function createOpenAIChatAdapter(options) {
24
+ const baseUrl = options.baseUrl.replace(/\/$/, "");
25
+ const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
26
+ const headers = options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {};
27
+ const store = createMemoryConversationStore({ storageKey: options.storageKey ?? "ai-chat-openai-conversations" });
28
+ return {
29
+ conversations: store.conversations,
30
+ models: { async list() {
31
+ const providerLabel = providerLabelFor(baseUrl);
32
+ if (options.models?.length) return {
33
+ models: options.models.map((id) => staticModel(id, providerLabel)),
34
+ unreachableSessions: []
35
+ };
36
+ const res = await doFetch(`${baseUrl}/models`, { headers });
37
+ if (!res.ok) throw new ChatAdapterError(await errorMessageFromResponse(res), { status: res.status });
38
+ return {
39
+ models: ((await res.json()).data ?? []).map((m) => ({
40
+ ...staticModel(m.id, providerLabel),
41
+ ...m
42
+ })),
43
+ unreachableSessions: []
44
+ };
45
+ } },
46
+ streamCompletion: store.recordingStream(createOpenAICompatibleStream({
47
+ completionsUrl: `${baseUrl}/chat/completions`,
48
+ buildHeaders: () => headers,
49
+ ...options.fetch ? { fetch: options.fetch } : {}
50
+ }))
51
+ };
52
+ }
53
+ //#endregion
54
+ export { createOpenAIChatAdapter };
@@ -0,0 +1,4 @@
1
+ import type { ParsedSSELine } from './sse.js';
2
+ import type { CompletionMessage } from './wire.js';
3
+ export declare function buildResponsesRequestBody(model: string, messages: CompletionMessage[]): Record<string, unknown>;
4
+ export declare function parseResponsesSSELine(line: string): ParsedSSELine;
@@ -0,0 +1,108 @@
1
+ //#region src/ai/adapter/openai/responses.ts
2
+ function contentString(content) {
3
+ return typeof content === "string" ? content : "";
4
+ }
5
+ function buildResponsesRequestBody(model, messages) {
6
+ const input = [];
7
+ let attachmentIds;
8
+ for (const m of messages) switch (m.role) {
9
+ case "system":
10
+ input.push({
11
+ type: "message",
12
+ role: "system",
13
+ content: contentString(m.content)
14
+ });
15
+ break;
16
+ case "user":
17
+ if (m.attachment_ids?.length) attachmentIds = m.attachment_ids;
18
+ input.push({
19
+ type: "message",
20
+ role: "user",
21
+ content: contentString(m.content)
22
+ });
23
+ break;
24
+ case "assistant": {
25
+ const replayed = Array.isArray(m.responses_output) ? replayableOutput(m.responses_output) : [];
26
+ if (replayed.length > 0) {
27
+ for (const item of replayed) input.push(item);
28
+ break;
29
+ }
30
+ const text = contentString(m.content);
31
+ const toolCalls = m.tool_calls ?? [];
32
+ if (text || toolCalls.length === 0) input.push({
33
+ type: "message",
34
+ role: "assistant",
35
+ content: text
36
+ });
37
+ for (const tc of toolCalls) input.push({
38
+ type: "function_call",
39
+ call_id: tc.id ?? "",
40
+ name: tc.function.name,
41
+ arguments: tc.function.arguments
42
+ });
43
+ break;
44
+ }
45
+ case "tool": input.push({
46
+ type: "function_call_output",
47
+ call_id: m.tool_call_id ?? "",
48
+ output: contentString(m.content)
49
+ });
50
+ }
51
+ const body = {
52
+ model,
53
+ input,
54
+ stream: true,
55
+ store: false,
56
+ include: ["reasoning.encrypted_content"]
57
+ };
58
+ if (attachmentIds?.length) body["attachment_ids"] = attachmentIds;
59
+ return body;
60
+ }
61
+ var REPLAYABLE_ITEM_TYPES = /* @__PURE__ */ new Set([
62
+ "reasoning",
63
+ "message",
64
+ "function_call"
65
+ ]);
66
+ function replayableOutput(output) {
67
+ if (!output?.length) return [];
68
+ return output.filter((item) => {
69
+ if (typeof item !== "object" || item === null) return false;
70
+ const itemType = item.type;
71
+ return typeof itemType === "string" && REPLAYABLE_ITEM_TYPES.has(itemType);
72
+ });
73
+ }
74
+ function parseResponsesSSELine(line) {
75
+ if (!line.startsWith("data: ")) return null;
76
+ const data = line.slice(6);
77
+ if (data === "[DONE]" || data === "\"[DONE]\"") return null;
78
+ let event;
79
+ try {
80
+ event = JSON.parse(data);
81
+ } catch {
82
+ return null;
83
+ }
84
+ if (event.error) return { error: event.error.message || "Unknown error" };
85
+ const model = event.response?.model;
86
+ switch (event.type) {
87
+ case "pw.message_id": return event.messageId ? { messageId: event.messageId } : null;
88
+ case "response.output_text.delta":
89
+ case "response.refusal.delta": return typeof event.delta === "string" ? { content: event.delta } : null;
90
+ case "response.reasoning_summary_text.delta": return typeof event.delta === "string" ? { reasoningContent: event.delta } : null;
91
+ case "response.created": return model ? { model } : null;
92
+ case "response.completed": return {
93
+ ...model && { model },
94
+ finishReason: "stop",
95
+ responsesOutput: replayableOutput(event.response?.output)
96
+ };
97
+ case "response.incomplete": return {
98
+ ...model && { model },
99
+ finishReason: "length",
100
+ responsesOutput: replayableOutput(event.response?.output)
101
+ };
102
+ case "response.failed": return { error: event.response?.error?.message || "Response failed" };
103
+ case "error": return { error: event.message || "Stream error" };
104
+ default: return null;
105
+ }
106
+ }
107
+ //#endregion
108
+ export { buildResponsesRequestBody, parseResponsesSSELine };
@@ -0,0 +1,24 @@
1
+ import type { ToolCall, ToolCallDelta } from '../../types.js';
2
+ export type ParsedSSELine = {
3
+ id?: string | undefined;
4
+ messageId?: string | undefined;
5
+ content?: string | undefined;
6
+ reasoningContent?: string | undefined;
7
+ toolCalls?: ToolCallDelta[] | undefined;
8
+ finishReason?: string | null | undefined;
9
+ model?: string | undefined;
10
+ error?: string | undefined;
11
+ responsesOutput?: unknown[] | undefined;
12
+ } | null;
13
+ export type SSELineParser = (line: string) => ParsedSSELine;
14
+ export declare function parseSSELine(line: string): ParsedSSELine;
15
+ /** Process an SSE stream from a ReadableStream reader */
16
+ export declare function processSSEStream(reader: ReadableStreamDefaultReader<Uint8Array>, onContent: (content: string) => void, onToolCall?: (toolCalls: ToolCall[]) => void, onError?: (error: string) => void, onReasoning?: (reasoning: string) => void, onMessageId?: (messageId: string) => void, parseLine?: SSELineParser): Promise<{
17
+ content: string;
18
+ messageId: string;
19
+ toolCalls: ToolCall[];
20
+ finishReason: string | null;
21
+ model: string | null;
22
+ reasoning: string;
23
+ responsesOutput: unknown[];
24
+ }>;