orcheo-studio 0.21.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 (329) hide show
  1. package/.bumpversion.cfg +14 -0
  2. package/.eslintrc +1 -0
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +60 -0
  5. package/bin/orcheo-studio.js +39 -0
  6. package/components.json +21 -0
  7. package/dist/assets/arc-BbeTokFd.js +1 -0
  8. package/dist/assets/architectureDiagram-VXUJARFQ-CN00R9LC.js +36 -0
  9. package/dist/assets/avatar-01-CIAd4XAq.svg +1 -0
  10. package/dist/assets/avatar-02-BkgLJWQZ.svg +1 -0
  11. package/dist/assets/avatar-03-DVVcnD3b.svg +1 -0
  12. package/dist/assets/avatar-04-ydqFTDdh.svg +1 -0
  13. package/dist/assets/avatar-05-CSIhgJow.svg +1 -0
  14. package/dist/assets/avatar-06-B-h1Nz9Y.svg +1 -0
  15. package/dist/assets/avatar-07-BgkDZuBW.svg +1 -0
  16. package/dist/assets/avatar-08-C5KZjVH6.svg +1 -0
  17. package/dist/assets/avatar-09-2EGeSlPh.svg +1 -0
  18. package/dist/assets/avatar-10-DRf4ZGD2.svg +1 -0
  19. package/dist/assets/avatar-11-CEzBCpib.svg +1 -0
  20. package/dist/assets/avatar-12-COVngNEy.svg +1 -0
  21. package/dist/assets/avatar-13-D1i1tZVO.svg +1 -0
  22. package/dist/assets/avatar-14-B68CNAEs.svg +1 -0
  23. package/dist/assets/avatar-15-B9NsRNUX.svg +1 -0
  24. package/dist/assets/avatar-16-DQ_JJRGR.svg +1 -0
  25. package/dist/assets/avatar-17-DfDJkGv5.svg +1 -0
  26. package/dist/assets/avatar-18-BuxiqOaJ.svg +1 -0
  27. package/dist/assets/avatar-19-C2mJfrwW.svg +1 -0
  28. package/dist/assets/avatar-20-DPE_yE1a.svg +1 -0
  29. package/dist/assets/avatar-21-DbB0Lj6t.svg +1 -0
  30. package/dist/assets/blockDiagram-VD42YOAC-BPpieIRz.js +122 -0
  31. package/dist/assets/c4Diagram-YG6GDRKO-DAhuY1fj.js +10 -0
  32. package/dist/assets/channel-DtVQHWfl.js +1 -0
  33. package/dist/assets/chunk-4BX2VUAB-7RJQCroR.js +1 -0
  34. package/dist/assets/chunk-55IACEB6-CEN5yOA_.js +1 -0
  35. package/dist/assets/chunk-B4BG7PRW-vdlAz_3Q.js +165 -0
  36. package/dist/assets/chunk-DI55MBZ5-BTmKjGVg.js +220 -0
  37. package/dist/assets/chunk-FMBD7UC4-CwWvFfrg.js +15 -0
  38. package/dist/assets/chunk-QN33PNHL-XH90lUUN.js +1 -0
  39. package/dist/assets/chunk-QZHKN3VN-DMoMVES0.js +1 -0
  40. package/dist/assets/chunk-TZMSLE5B-Bx2XTXDY.js +1 -0
  41. package/dist/assets/classDiagram-2ON5EDUG-pw6P8q-u.js +1 -0
  42. package/dist/assets/classDiagram-v2-WZHVMYZB-pw6P8q-u.js +1 -0
  43. package/dist/assets/clone-DJq6GzHg.js +1 -0
  44. package/dist/assets/cose-bilkent-S5V4N54A-DS1MNwZB.js +1 -0
  45. package/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  46. package/dist/assets/dagre-6UL2VRFP-DdklXSXB.js +4 -0
  47. package/dist/assets/defaultLocale-C4B-KCzX.js +1 -0
  48. package/dist/assets/diagram-PSM6KHXK-BKBo8pqg.js +24 -0
  49. package/dist/assets/diagram-QEK2KX5R-DaavZhFO.js +43 -0
  50. package/dist/assets/diagram-S2PKOQOG-DkTwknYd.js +24 -0
  51. package/dist/assets/erDiagram-Q2GNP2WA-ClR5qEsI.js +60 -0
  52. package/dist/assets/flowDiagram-NV44I4VS-Cxt_sJHB.js +162 -0
  53. package/dist/assets/ganttDiagram-JELNMOA3-CIbs3JPJ.js +267 -0
  54. package/dist/assets/gitGraphDiagram-V2S2FVAM-DmqLh_uo.js +65 -0
  55. package/dist/assets/graph-zo28rS-a.js +1 -0
  56. package/dist/assets/index-B0_h2wCA.css +1 -0
  57. package/dist/assets/index-Be29_rJf.js +775 -0
  58. package/dist/assets/infoDiagram-HS3SLOUP-D9_rMkAf.js +2 -0
  59. package/dist/assets/init-Gi6I4Gst.js +1 -0
  60. package/dist/assets/isUndefined-C59bc74c.js +1 -0
  61. package/dist/assets/journeyDiagram-XKPGCS4Q-4ZuggLXE.js +139 -0
  62. package/dist/assets/kanban-definition-3W4ZIXB7-BQDNrhHL.js +89 -0
  63. package/dist/assets/katex-CBSAILhF.js +261 -0
  64. package/dist/assets/layout-CXbNm-Yo.js +1 -0
  65. package/dist/assets/linear-DQWATg1F.js +1 -0
  66. package/dist/assets/min-DJjRzMm8.js +1 -0
  67. package/dist/assets/mindmap-definition-VGOIOE7T-DiZQmsHT.js +68 -0
  68. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  69. package/dist/assets/pieDiagram-ADFJNKIX-Bkju7jCD.js +30 -0
  70. package/dist/assets/quadrantDiagram-AYHSOK5B-CIB47UvU.js +7 -0
  71. package/dist/assets/requirementDiagram-UZGBJVZJ-BSB3uACk.js +64 -0
  72. package/dist/assets/sankeyDiagram-TZEHDZUN-rB8wD2kd.js +10 -0
  73. package/dist/assets/sequenceDiagram-WL72ISMW-Cd9s3Q_1.js +145 -0
  74. package/dist/assets/stateDiagram-FKZM4ZOC-zAxtjcM9.js +1 -0
  75. package/dist/assets/stateDiagram-v2-4FDKWEC3-C4DctH65.js +1 -0
  76. package/dist/assets/timeline-definition-IT6M3QCI-Et89F1F3.js +61 -0
  77. package/dist/assets/treemap-GDKQZRPO-6mZVX2Gv.js +162 -0
  78. package/dist/assets/xychartDiagram-PRI3JC2R-CgyY8dNz.js +7 -0
  79. package/dist/favicon.ico +0 -0
  80. package/dist/index.html +19 -0
  81. package/dist/robots.txt +2 -0
  82. package/eslint.config.js +49 -0
  83. package/index.html +18 -0
  84. package/package.json +183 -0
  85. package/postcss.config.js +6 -0
  86. package/public/favicon.ico +0 -0
  87. package/public/robots.txt +2 -0
  88. package/src/App.tsx +115 -0
  89. package/src/assets/avatars/avatar-01.svg +1 -0
  90. package/src/assets/avatars/avatar-02.svg +1 -0
  91. package/src/assets/avatars/avatar-03.svg +1 -0
  92. package/src/assets/avatars/avatar-04.svg +1 -0
  93. package/src/assets/avatars/avatar-05.svg +1 -0
  94. package/src/assets/avatars/avatar-06.svg +1 -0
  95. package/src/assets/avatars/avatar-07.svg +1 -0
  96. package/src/assets/avatars/avatar-08.svg +1 -0
  97. package/src/assets/avatars/avatar-09.svg +1 -0
  98. package/src/assets/avatars/avatar-10.svg +1 -0
  99. package/src/assets/avatars/avatar-11.svg +1 -0
  100. package/src/assets/avatars/avatar-12.svg +1 -0
  101. package/src/assets/avatars/avatar-13.svg +1 -0
  102. package/src/assets/avatars/avatar-14.svg +1 -0
  103. package/src/assets/avatars/avatar-15.svg +1 -0
  104. package/src/assets/avatars/avatar-16.svg +1 -0
  105. package/src/assets/avatars/avatar-17.svg +1 -0
  106. package/src/assets/avatars/avatar-18.svg +1 -0
  107. package/src/assets/avatars/avatar-19.svg +1 -0
  108. package/src/assets/avatars/avatar-20.svg +1 -0
  109. package/src/assets/avatars/avatar-21.svg +1 -0
  110. package/src/assets/avatars/index.ts +99 -0
  111. package/src/design-system/ui/alert-dialog.tsx +141 -0
  112. package/src/design-system/ui/alert.tsx +59 -0
  113. package/src/design-system/ui/avatar.tsx +51 -0
  114. package/src/design-system/ui/badge.tsx +38 -0
  115. package/src/design-system/ui/button.tsx +59 -0
  116. package/src/design-system/ui/card.tsx +83 -0
  117. package/src/design-system/ui/dialog.tsx +122 -0
  118. package/src/design-system/ui/dropdown-menu.tsx +201 -0
  119. package/src/design-system/ui/input.tsx +22 -0
  120. package/src/design-system/ui/label.tsx +26 -0
  121. package/src/design-system/ui/scroll-area.tsx +48 -0
  122. package/src/design-system/ui/select.tsx +159 -0
  123. package/src/design-system/ui/separator.tsx +31 -0
  124. package/src/design-system/ui/sheet.tsx +141 -0
  125. package/src/design-system/ui/skeleton.tsx +15 -0
  126. package/src/design-system/ui/switch.tsx +29 -0
  127. package/src/design-system/ui/table.tsx +120 -0
  128. package/src/design-system/ui/tabs.tsx +55 -0
  129. package/src/design-system/ui/textarea.tsx +22 -0
  130. package/src/design-system/ui/toast.tsx +132 -0
  131. package/src/design-system/ui/toaster.tsx +35 -0
  132. package/src/design-system/ui/toggle-group.tsx +61 -0
  133. package/src/design-system/ui/toggle.tsx +46 -0
  134. package/src/design-system/ui/tooltip.tsx +32 -0
  135. package/src/features/MODULES.md +199 -0
  136. package/src/features/account/components/settings/appearance-settings-tab.tsx +24 -0
  137. package/src/features/account/components/theme-settings.tsx +70 -0
  138. package/src/features/account/components/use-theme-preferences.ts +106 -0
  139. package/src/features/account/pages/profile/components/profile-general-tab.tsx +89 -0
  140. package/src/features/account/pages/profile/types.ts +7 -0
  141. package/src/features/account/pages/profile.tsx +71 -0
  142. package/src/features/account/pages/service-tokens.tsx +522 -0
  143. package/src/features/account/pages/settings.tsx +42 -0
  144. package/src/features/account/pages/workspace-management.tsx +63 -0
  145. package/src/features/account/pages/workspace-members.tsx +335 -0
  146. package/src/features/auth/components/auto-login.tsx +51 -0
  147. package/src/features/auth/components/require-auth.tsx +56 -0
  148. package/src/features/auth/lib/auth-session.ts +448 -0
  149. package/src/features/auth/lib/oidc-client.ts +565 -0
  150. package/src/features/auth/pages/login.tsx +24 -0
  151. package/src/features/auth/pages/oauth-callback.tsx +63 -0
  152. package/src/features/chatkit/components/chatkit-surface.tsx +60 -0
  153. package/src/features/chatkit/components/public-chat-config.ts +70 -0
  154. package/src/features/chatkit/components/public-chat-error-boundary.tsx +74 -0
  155. package/src/features/chatkit/components/public-chat-widget.tsx +150 -0
  156. package/src/features/chatkit/components/studio-chat-bubble.tsx +451 -0
  157. package/src/features/chatkit/lib/chatkit-attachments.ts +31 -0
  158. package/src/features/chatkit/lib/chatkit-client.ts +195 -0
  159. package/src/features/chatkit/lib/chatkit-theme.ts +20 -0
  160. package/src/features/chatkit/lib/telemetry.ts +29 -0
  161. package/src/features/chatkit/lib/workflow-session.ts +70 -0
  162. package/src/features/chatkit/pages/public-chat.tsx +445 -0
  163. package/src/features/shared/components/chat-interface-options.ts +325 -0
  164. package/src/features/shared/components/chat-interface.types.ts +47 -0
  165. package/src/features/shared/components/top-navigation/account-menu.tsx +172 -0
  166. package/src/features/shared/components/top-navigation/active-workspace-indicator.tsx +280 -0
  167. package/src/features/shared/components/top-navigation/studio-brand.tsx +59 -0
  168. package/src/features/shared/components/top-navigation/top-navigation-types.ts +22 -0
  169. package/src/features/shared/components/top-navigation/version-status.tsx +280 -0
  170. package/src/features/shared/components/top-navigation.tsx +42 -0
  171. package/src/features/shared/components/workspace-bootstrap-gate.tsx +235 -0
  172. package/src/features/workflow/components/dialogs/add-credential-dialog.tsx +245 -0
  173. package/src/features/workflow/components/dialogs/confirm-delete-workflow-dialog.tsx +52 -0
  174. package/src/features/workflow/components/dialogs/credential-access-badge.tsx +34 -0
  175. package/src/features/workflow/components/dialogs/credential-status-badge.tsx +45 -0
  176. package/src/features/workflow/components/dialogs/credentials-table.tsx +453 -0
  177. package/src/features/workflow/components/dialogs/credentials-vault.tsx +85 -0
  178. package/src/features/workflow/components/dialogs/edit-credential-dialog.tsx +264 -0
  179. package/src/features/workflow/components/dialogs/update-workflow-dialog.tsx +214 -0
  180. package/src/features/workflow/components/dialogs/upload-workflow-dialog.tsx +288 -0
  181. package/src/features/workflow/components/forms/schema-config-form.tsx +41 -0
  182. package/src/features/workflow/components/layouts/sidebar-layout.tsx +288 -0
  183. package/src/features/workflow/components/layouts/use-sidebar-resize.ts +164 -0
  184. package/src/features/workflow/components/layouts/workflow-page-layout.tsx +69 -0
  185. package/src/features/workflow/components/panels/json-object-field.tsx +138 -0
  186. package/src/features/workflow/components/panels/rjsf-basic-widgets.tsx +21 -0
  187. package/src/features/workflow/components/panels/rjsf-input-widgets.tsx +105 -0
  188. package/src/features/workflow/components/panels/rjsf-templates.tsx +147 -0
  189. package/src/features/workflow/components/panels/rjsf-text-widgets.tsx +139 -0
  190. package/src/features/workflow/components/panels/rjsf-theme.tsx +10 -0
  191. package/src/features/workflow/components/panels/schema-dnd.ts +79 -0
  192. package/src/features/workflow/components/panels/workflow-diff-dialog.tsx +207 -0
  193. package/src/features/workflow/components/panels/workflow-history-filters.tsx +62 -0
  194. package/src/features/workflow/components/panels/workflow-history-footer.tsx +28 -0
  195. package/src/features/workflow/components/panels/workflow-history-header.tsx +47 -0
  196. package/src/features/workflow/components/panels/workflow-history-table.tsx +148 -0
  197. package/src/features/workflow/components/panels/workflow-history.tsx +150 -0
  198. package/src/features/workflow/components/panels/workflow-tabs.tsx +29 -0
  199. package/src/features/workflow/components/trace/agent-prism/Avatar.tsx +146 -0
  200. package/src/features/workflow/components/trace/agent-prism/Badge.tsx +95 -0
  201. package/src/features/workflow/components/trace/agent-prism/BrandLogo.tsx +102 -0
  202. package/src/features/workflow/components/trace/agent-prism/Button.tsx +124 -0
  203. package/src/features/workflow/components/trace/agent-prism/CollapseAndExpandControls.tsx +45 -0
  204. package/src/features/workflow/components/trace/agent-prism/CollapsibleSection.tsx +124 -0
  205. package/src/features/workflow/components/trace/agent-prism/CopyButton.tsx +63 -0
  206. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsView.tsx +146 -0
  207. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewAttributesTab.tsx +125 -0
  208. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewContentViewer.tsx +51 -0
  209. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewHeader.tsx +100 -0
  210. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewInputOutputTab.tsx +401 -0
  211. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewJsonOutput.tsx +33 -0
  212. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewRawDataTab.tsx +27 -0
  213. package/src/features/workflow/components/trace/agent-prism/IconButton.tsx +75 -0
  214. package/src/features/workflow/components/trace/agent-prism/PriceBadge.tsx +14 -0
  215. package/src/features/workflow/components/trace/agent-prism/SearchInput.tsx +17 -0
  216. package/src/features/workflow/components/trace/agent-prism/SpanBadge.tsx +54 -0
  217. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCard.tsx +480 -0
  218. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardBadges.tsx +23 -0
  219. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardConnector.tsx +36 -0
  220. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardTimeline.tsx +60 -0
  221. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardToggle.tsx +39 -0
  222. package/src/features/workflow/components/trace/agent-prism/SpanStatus.tsx +80 -0
  223. package/src/features/workflow/components/trace/agent-prism/TabSelector.tsx +35 -0
  224. package/src/features/workflow/components/trace/agent-prism/Tabs.tsx +140 -0
  225. package/src/features/workflow/components/trace/agent-prism/TextInput.tsx +143 -0
  226. package/src/features/workflow/components/trace/agent-prism/TimestampBadge.tsx +22 -0
  227. package/src/features/workflow/components/trace/agent-prism/TokensBadge.tsx +27 -0
  228. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceList.tsx +123 -0
  229. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItem.tsx +86 -0
  230. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItemHeader.tsx +37 -0
  231. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewer.tsx +208 -0
  232. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerDesktopLayout.tsx +99 -0
  233. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerMobileLayout.tsx +103 -0
  234. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerPlaceholder.tsx +5 -0
  235. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerSearchAndControls.tsx +30 -0
  236. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerTreeViewContainer.tsx +76 -0
  237. package/src/features/workflow/components/trace/agent-prism/TraceViewer/useTraceSelection.ts +186 -0
  238. package/src/features/workflow/components/trace/agent-prism/TreeView.tsx +73 -0
  239. package/src/features/workflow/components/trace/agent-prism/index.ts +7 -0
  240. package/src/features/workflow/components/trace/agent-prism/shared.ts +170 -0
  241. package/src/features/workflow/components/trace/agent-prism/theme/index.ts +101 -0
  242. package/src/features/workflow/components/trace/agent-prism/theme/theme.css +247 -0
  243. package/src/features/workflow/data/templates/assets/vibe-agent/config.json +5 -0
  244. package/src/features/workflow/data/templates/candidate-badges.ts +138 -0
  245. package/src/features/workflow/data/templates/index.ts +29 -0
  246. package/src/features/workflow/data/templates/template-definition.ts +77 -0
  247. package/src/features/workflow/data/templates/template-owner.ts +7 -0
  248. package/src/features/workflow/data/workflow-data.ts +8 -0
  249. package/src/features/workflow/data/workflow-types.ts +57 -0
  250. package/src/features/workflow/lib/mermaid-renderer.ts +334 -0
  251. package/src/features/workflow/lib/workflow-diff.ts +191 -0
  252. package/src/features/workflow/lib/workflow-execution-builders.ts +103 -0
  253. package/src/features/workflow/lib/workflow-execution-formatters.ts +145 -0
  254. package/src/features/workflow/lib/workflow-execution-storage.ts +63 -0
  255. package/src/features/workflow/lib/workflow-execution.types.ts +80 -0
  256. package/src/features/workflow/lib/workflow-storage-api.ts +581 -0
  257. package/src/features/workflow/lib/workflow-storage-helpers.ts +373 -0
  258. package/src/features/workflow/lib/workflow-storage-versioning.ts +127 -0
  259. package/src/features/workflow/lib/workflow-storage.constants.ts +21 -0
  260. package/src/features/workflow/lib/workflow-storage.ts +482 -0
  261. package/src/features/workflow/lib/workflow-storage.types.ts +261 -0
  262. package/src/features/workflow/pages/workflow/components/settings-tab-content.tsx +428 -0
  263. package/src/features/workflow/pages/workflow/components/trace-tab-content.tsx +183 -0
  264. package/src/features/workflow/pages/workflow/components/workflow-config-sheet.tsx +207 -0
  265. package/src/features/workflow/pages/workflow/components/workflow-config-sheet.utils.ts +275 -0
  266. package/src/features/workflow/pages/workflow/components/workflow-layout.tsx +143 -0
  267. package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +766 -0
  268. package/src/features/workflow/pages/workflow/handlers/credentials.ts +338 -0
  269. package/src/features/workflow/pages/workflow/helpers/execution.ts +39 -0
  270. package/src/features/workflow/pages/workflow/helpers/trace.ts +838 -0
  271. package/src/features/workflow/pages/workflow/helpers/types.ts +28 -0
  272. package/src/features/workflow/pages/workflow/hooks/controller/build-layout-props.ts +171 -0
  273. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-controller.ts +19 -0
  274. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-core.ts +84 -0
  275. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-execution-controller.ts +167 -0
  276. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-lifecycle.ts +37 -0
  277. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-resources.ts +57 -0
  278. package/src/features/workflow/pages/workflow/hooks/execution-log-helpers.ts +75 -0
  279. package/src/features/workflow/pages/workflow/hooks/execution-node-status.ts +46 -0
  280. package/src/features/workflow/pages/workflow/hooks/execution-record-updater.ts +119 -0
  281. package/src/features/workflow/pages/workflow/hooks/execution-record.ts +31 -0
  282. package/src/features/workflow/pages/workflow/hooks/execution-runtime-updates.ts +96 -0
  283. package/src/features/workflow/pages/workflow/hooks/use-execution-trace.ts +512 -0
  284. package/src/features/workflow/pages/workflow/hooks/use-execution-updates.ts +125 -0
  285. package/src/features/workflow/pages/workflow/hooks/use-pause-workflow.ts +70 -0
  286. package/src/features/workflow/pages/workflow/hooks/use-studio-ui-state.ts +10 -0
  287. package/src/features/workflow/pages/workflow/hooks/use-workflow-chat.ts +212 -0
  288. package/src/features/workflow/pages/workflow/hooks/use-workflow-credential-readiness.ts +72 -0
  289. package/src/features/workflow/pages/workflow/hooks/use-workflow-credentials.ts +167 -0
  290. package/src/features/workflow/pages/workflow/hooks/use-workflow-execution-state.ts +20 -0
  291. package/src/features/workflow/pages/workflow/hooks/use-workflow-listeners.ts +182 -0
  292. package/src/features/workflow/pages/workflow/hooks/use-workflow-loader.ts +236 -0
  293. package/src/features/workflow/pages/workflow/hooks/use-workflow-metadata-state.ts +56 -0
  294. package/src/features/workflow/pages/workflow/hooks/use-workflow-saver.ts +191 -0
  295. package/src/features/workflow/pages/workflow/hooks/use-workflow-storage-listener.ts +81 -0
  296. package/src/features/workflow/pages/workflow/hooks/workflow-runner-websocket.ts +150 -0
  297. package/src/features/workflow/pages/workflow-gallery/types.ts +3 -0
  298. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-actions.ts +223 -0
  299. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-state.ts +206 -0
  300. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery.ts +14 -0
  301. package/src/features/workflow/pages/workflow-gallery/workflow-card-size.ts +8 -0
  302. package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +327 -0
  303. package/src/features/workflow/pages/workflow-gallery/workflow-gallery-tabs.tsx +173 -0
  304. package/src/features/workflow/pages/workflow-gallery.tsx +96 -0
  305. package/src/features/workflow/pages/workflow.tsx +119 -0
  306. package/src/features/workflow/types/credential-vault.ts +52 -0
  307. package/src/hooks/browser-context-provider.tsx +19 -0
  308. package/src/hooks/use-browser-context.ts +188 -0
  309. package/src/hooks/use-color-scheme.ts +77 -0
  310. package/src/hooks/use-credential-vault.ts +442 -0
  311. package/src/hooks/use-page-context.ts +39 -0
  312. package/src/hooks/use-toast.ts +182 -0
  313. package/src/hooks/use-uploads-allowed.ts +28 -0
  314. package/src/index.css +95 -0
  315. package/src/lib/api.ts +445 -0
  316. package/src/lib/auth-fetch.ts +35 -0
  317. package/src/lib/config.ts +102 -0
  318. package/src/lib/theme.ts +109 -0
  319. package/src/lib/utils.ts +6 -0
  320. package/src/lib/workspace-routing.ts +67 -0
  321. package/src/lib/workspace-session.ts +66 -0
  322. package/src/lib/workspace-slug.ts +10 -0
  323. package/src/main.tsx +28 -0
  324. package/src/vite-env.d.ts +17 -0
  325. package/tailwind.config.js +153 -0
  326. package/tsconfig.app.json +30 -0
  327. package/tsconfig.json +16 -0
  328. package/tsconfig.node.json +21 -0
  329. package/vite.config.ts +122 -0
@@ -0,0 +1,183 @@
1
+ import "@features/workflow/components/trace/agent-prism/theme/theme.css";
2
+
3
+ import { RefreshCw } from "lucide-react";
4
+ import { useEffect, useMemo, useState } from "react";
5
+ import type { TraceSpan } from "@evilmartians/agent-prism-types";
6
+
7
+ import { Alert, AlertDescription, AlertTitle } from "@/design-system/ui/alert";
8
+ import { Button } from "@/design-system/ui/button";
9
+ import type { TraceViewerData } from "@features/workflow/components/trace/agent-prism";
10
+ import { TraceViewer } from "@features/workflow/components/trace/agent-prism";
11
+ import { deriveThreadStitchedViewerDataList } from "@features/workflow/pages/workflow/helpers/trace";
12
+ import type { TraceSpanMetadata } from "@features/workflow/pages/workflow/helpers/trace";
13
+
14
+ export interface TraceTabContentProps {
15
+ error?: string;
16
+ viewerData: TraceViewerData[];
17
+ activeViewer?: TraceViewerData;
18
+ onRefresh: () => void;
19
+ isRefreshing: boolean;
20
+ onSelectTrace?: (traceId: string) => void;
21
+ }
22
+
23
+ const renderArtifactActions = (span: TraceSpan) => {
24
+ const metadata = span.metadata as
25
+ | (TraceSpanMetadata & {
26
+ artifacts?: Array<{ id: string; downloadUrl?: string }>;
27
+ })
28
+ | undefined;
29
+ const artifacts = metadata?.artifacts ?? [];
30
+ if (artifacts.length === 0) {
31
+ return null;
32
+ }
33
+ return (
34
+ <div className="flex flex-wrap items-center gap-2">
35
+ {artifacts.map((artifact) => (
36
+ <Button
37
+ key={artifact.id}
38
+ size="sm"
39
+ variant="outline"
40
+ onClick={() => {
41
+ if (artifact.downloadUrl) {
42
+ window.open(
43
+ artifact.downloadUrl,
44
+ "_blank",
45
+ "noopener,noreferrer",
46
+ );
47
+ }
48
+ }}
49
+ >
50
+ Download {artifact.id}
51
+ </Button>
52
+ ))}
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export function TraceTabContent({
58
+ error,
59
+ viewerData,
60
+ activeViewer,
61
+ onRefresh,
62
+ isRefreshing,
63
+ onSelectTrace,
64
+ }: TraceTabContentProps) {
65
+ const [isStitchedTimeline, setIsStitchedTimeline] = useState(false);
66
+ const canStitchByThread = useMemo(
67
+ () => viewerData.some((trace) => Boolean(trace.threadId)),
68
+ [viewerData],
69
+ );
70
+
71
+ useEffect(() => {
72
+ if (!canStitchByThread && isStitchedTimeline) {
73
+ setIsStitchedTimeline(false);
74
+ }
75
+ }, [canStitchByThread, isStitchedTimeline]);
76
+
77
+ const displayedViewerData = useMemo(() => {
78
+ if (!isStitchedTimeline) {
79
+ return viewerData;
80
+ }
81
+ return deriveThreadStitchedViewerDataList(
82
+ viewerData,
83
+ activeViewer?.traceRecord.id,
84
+ );
85
+ }, [activeViewer?.traceRecord.id, isStitchedTimeline, viewerData]);
86
+
87
+ const displayedActiveTraceId = useMemo(() => {
88
+ if (!isStitchedTimeline) {
89
+ return activeViewer?.traceRecord.id;
90
+ }
91
+
92
+ const activeTraceId = activeViewer?.traceRecord.id;
93
+ if (
94
+ activeTraceId &&
95
+ displayedViewerData.some(
96
+ (trace) => trace.traceRecord.id === activeTraceId,
97
+ )
98
+ ) {
99
+ return activeTraceId;
100
+ }
101
+
102
+ const activeThreadId = activeViewer?.threadId;
103
+ if (activeThreadId) {
104
+ const stitchedGroup = displayedViewerData.find(
105
+ (trace) => trace.threadId === activeThreadId,
106
+ );
107
+ if (stitchedGroup) {
108
+ return stitchedGroup.traceRecord.id;
109
+ }
110
+ }
111
+
112
+ return displayedViewerData[0]?.traceRecord.id;
113
+ }, [activeViewer, displayedViewerData, isStitchedTimeline]);
114
+
115
+ const hasData = displayedViewerData.length > 0;
116
+
117
+ return (
118
+ <div className="flex h-full w-full min-w-0 flex-col gap-4">
119
+ <div className="flex flex-wrap items-center justify-between gap-3">
120
+ <div>
121
+ <h2 className="text-lg font-semibold">Execution trace</h2>
122
+ <p className="text-sm text-muted-foreground">
123
+ Inspect span hierarchy, metrics, and artifacts for the selected run.
124
+ </p>
125
+ </div>
126
+ <div className="flex items-center gap-2">
127
+ <Button
128
+ size="sm"
129
+ variant={isStitchedTimeline ? "default" : "outline"}
130
+ disabled={!canStitchByThread}
131
+ onClick={() => {
132
+ setIsStitchedTimeline((current) => !current);
133
+ }}
134
+ >
135
+ {isStitchedTimeline ? "Stitched: On" : "Stitched: Off"}
136
+ </Button>
137
+ <Button
138
+ size="sm"
139
+ variant="outline"
140
+ disabled={isRefreshing}
141
+ onClick={() => {
142
+ void onRefresh();
143
+ }}
144
+ >
145
+ <RefreshCw className="mr-2 size-4" />
146
+ {isRefreshing ? "Refreshing..." : "Refresh"}
147
+ </Button>
148
+ </div>
149
+ </div>
150
+
151
+ {error && (
152
+ <Alert variant="destructive">
153
+ <AlertTitle>Unable to load trace</AlertTitle>
154
+ <AlertDescription>{error}</AlertDescription>
155
+ </Alert>
156
+ )}
157
+
158
+ {!hasData && !error && (
159
+ <div
160
+ data-testid="trace-empty-state"
161
+ className="flex flex-1 items-center justify-center rounded-md border border-dashed border-border text-sm text-muted-foreground"
162
+ >
163
+ No trace spans recorded yet for this execution.
164
+ </div>
165
+ )}
166
+
167
+ {hasData && (
168
+ <div className="min-h-0 w-full min-w-0 flex-1 overflow-hidden rounded-lg border border-border bg-background">
169
+ <TraceViewer
170
+ data={displayedViewerData}
171
+ activeTraceId={displayedActiveTraceId}
172
+ onTraceSelect={(trace) => {
173
+ onSelectTrace?.(trace.id);
174
+ }}
175
+ detailsViewProps={{
176
+ headerActions: renderArtifactActions,
177
+ }}
178
+ />
179
+ </div>
180
+ )}
181
+ </div>
182
+ );
183
+ }
@@ -0,0 +1,207 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import type { RJSFSchema, UiSchema } from "@rjsf/utils";
3
+
4
+ import { Button } from "@/design-system/ui/button";
5
+ import { ScrollArea } from "@/design-system/ui/scroll-area";
6
+ import {
7
+ Sheet,
8
+ SheetContent,
9
+ SheetDescription,
10
+ SheetFooter,
11
+ SheetHeader,
12
+ SheetTitle,
13
+ } from "@/design-system/ui/sheet";
14
+ import { SchemaConfigForm } from "@features/workflow/components/forms/schema-config-form";
15
+ import { JsonObjectField } from "@features/workflow/components/panels/json-object-field";
16
+ import type { WorkflowRunnableConfig } from "@features/workflow/lib/workflow-storage.types";
17
+ import {
18
+ buildConfigurableSchema,
19
+ toFormData,
20
+ toWorkflowConfig,
21
+ } from "@features/workflow/pages/workflow/components/workflow-config-sheet.utils";
22
+
23
+ const baseWorkflowConfigSchema: RJSFSchema = {
24
+ type: "object",
25
+ properties: {
26
+ configurable: {
27
+ type: "object",
28
+ title: "Configurable",
29
+ additionalProperties: true,
30
+ default: {},
31
+ },
32
+ run_name: {
33
+ type: "string",
34
+ title: "Run name",
35
+ },
36
+ tags: {
37
+ type: "array",
38
+ title: "Tags",
39
+ items: {
40
+ type: "string",
41
+ },
42
+ },
43
+ metadata: {
44
+ type: "object",
45
+ title: "Metadata",
46
+ additionalProperties: true,
47
+ default: {},
48
+ },
49
+ callbacks: {
50
+ type: "array",
51
+ title: "Callbacks",
52
+ items: {
53
+ type: ["object", "array", "string", "number", "integer", "boolean"],
54
+ },
55
+ },
56
+ recursion_limit: {
57
+ type: "integer",
58
+ title: "Recursion limit",
59
+ minimum: 1,
60
+ },
61
+ max_concurrency: {
62
+ type: "integer",
63
+ title: "Max concurrency",
64
+ minimum: 1,
65
+ },
66
+ prompts: {
67
+ type: "object",
68
+ title: "Prompts",
69
+ additionalProperties: {
70
+ type: "object",
71
+ properties: {
72
+ template: {
73
+ type: "string",
74
+ title: "Template",
75
+ },
76
+ input_variables: {
77
+ type: "array",
78
+ title: "Input variables",
79
+ items: {
80
+ type: "string",
81
+ },
82
+ },
83
+ optional_variables: {
84
+ type: "array",
85
+ title: "Optional variables",
86
+ items: {
87
+ type: "string",
88
+ },
89
+ },
90
+ partial_variables: {
91
+ type: "object",
92
+ title: "Partial variables",
93
+ additionalProperties: true,
94
+ },
95
+ },
96
+ required: ["template", "input_variables"],
97
+ },
98
+ default: {},
99
+ },
100
+ },
101
+ };
102
+
103
+ const workflowConfigUiSchema: UiSchema = {
104
+ configurable: {
105
+ fields: {
106
+ "ui:field": "jsonObject",
107
+ },
108
+ },
109
+ run_name: {
110
+ "ui:placeholder": "Optional run label",
111
+ },
112
+ tags: {
113
+ "ui:options": {
114
+ orderable: false,
115
+ },
116
+ },
117
+ };
118
+
119
+ interface WorkflowConfigSheetProps {
120
+ open: boolean;
121
+ onOpenChange: (open: boolean) => void;
122
+ initialConfig: WorkflowRunnableConfig | null;
123
+ onSave: (nextConfig: WorkflowRunnableConfig | null) => Promise<void>;
124
+ configurableSchemas?: Record<string, RJSFSchema>;
125
+ }
126
+
127
+ export function WorkflowConfigSheet({
128
+ open,
129
+ onOpenChange,
130
+ initialConfig,
131
+ onSave,
132
+ configurableSchemas,
133
+ }: WorkflowConfigSheetProps) {
134
+ const [formData, setFormData] = useState<Record<string, unknown>>(
135
+ toFormData(initialConfig),
136
+ );
137
+ const [isSaving, setIsSaving] = useState(false);
138
+
139
+ const workflowConfigSchema = useMemo<RJSFSchema>(() => {
140
+ const configurableSchema =
141
+ baseWorkflowConfigSchema.properties?.configurable;
142
+
143
+ return {
144
+ ...baseWorkflowConfigSchema,
145
+ properties: {
146
+ ...baseWorkflowConfigSchema.properties,
147
+ configurable: {
148
+ ...configurableSchema,
149
+ properties: buildConfigurableSchema(
150
+ formData.configurable,
151
+ configurableSchemas,
152
+ ),
153
+ },
154
+ },
155
+ };
156
+ }, [formData.configurable, configurableSchemas]);
157
+
158
+ useEffect(() => {
159
+ if (open) {
160
+ setFormData(toFormData(initialConfig));
161
+ }
162
+ }, [initialConfig, open]);
163
+
164
+ const handleSave = async () => {
165
+ setIsSaving(true);
166
+ try {
167
+ await onSave(toWorkflowConfig(formData));
168
+ onOpenChange(false);
169
+ } finally {
170
+ setIsSaving(false);
171
+ }
172
+ };
173
+
174
+ return (
175
+ <Sheet open={open} onOpenChange={onOpenChange}>
176
+ <SheetContent side="right" className="w-full p-0 sm:max-w-2xl">
177
+ <SheetHeader className="border-b px-6 py-4">
178
+ <SheetTitle>Workflow config</SheetTitle>
179
+ <SheetDescription>
180
+ Configure runnable options saved with this workflow version.
181
+ </SheetDescription>
182
+ </SheetHeader>
183
+
184
+ <ScrollArea className="h-[calc(100vh-9.5rem)]">
185
+ <div className="p-6">
186
+ <SchemaConfigForm
187
+ schema={workflowConfigSchema}
188
+ uiSchema={workflowConfigUiSchema}
189
+ formData={formData}
190
+ onChange={setFormData}
191
+ fields={{ jsonObject: JsonObjectField }}
192
+ />
193
+ </div>
194
+ </ScrollArea>
195
+
196
+ <SheetFooter className="border-t px-6 py-4">
197
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
198
+ Cancel
199
+ </Button>
200
+ <Button onClick={() => void handleSave()} disabled={isSaving}>
201
+ {isSaving ? "Saving..." : "Save config"}
202
+ </Button>
203
+ </SheetFooter>
204
+ </SheetContent>
205
+ </Sheet>
206
+ );
207
+ }
@@ -0,0 +1,275 @@
1
+ import type { RJSFSchema } from "@rjsf/utils";
2
+
3
+ import type { WorkflowRunnableConfig } from "@features/workflow/lib/workflow-storage.types";
4
+
5
+ const isRecord = (value: unknown): value is Record<string, unknown> =>
6
+ typeof value === "object" && value !== null && !Array.isArray(value);
7
+
8
+ /**
9
+ * Validates if an unknown value is a valid RJSFSchema object.
10
+ * @param schema - The value to validate
11
+ * @returns True if the value is a valid schema object
12
+ */
13
+ const isValidSchema = (schema: unknown): schema is RJSFSchema => {
14
+ return (
15
+ typeof schema === "object" && schema !== null && !Array.isArray(schema)
16
+ );
17
+ };
18
+
19
+ const toPositiveInteger = (value: unknown): number | undefined => {
20
+ if (typeof value !== "number" || !Number.isFinite(value)) {
21
+ return undefined;
22
+ }
23
+ const integer = Math.floor(value);
24
+ return integer > 0 ? integer : undefined;
25
+ };
26
+
27
+ /**
28
+ * Infers schema for array items, handling both homogeneous and heterogeneous arrays.
29
+ * @param value - The array to analyze
30
+ * @returns Schema for array items
31
+ */
32
+ const inferArrayItemsSchema = (value: unknown[]): RJSFSchema => {
33
+ if (value.length === 0) {
34
+ return { type: "string" };
35
+ }
36
+
37
+ const itemSchemas = value.map((item) => inferSchemaFromValue(item));
38
+ const firstSchema = JSON.stringify(itemSchemas[0]);
39
+ const hasSingleItemShape = itemSchemas.every(
40
+ (itemSchema) => JSON.stringify(itemSchema) === firstSchema,
41
+ );
42
+
43
+ if (hasSingleItemShape) {
44
+ return itemSchemas[0];
45
+ }
46
+
47
+ // For heterogeneous arrays, create a union type of all observed schemas
48
+ const uniqueSchemas = itemSchemas.filter((schema, index, array) => {
49
+ const schemaStr = JSON.stringify(schema);
50
+ return array.findIndex((s) => JSON.stringify(s) === schemaStr) === index;
51
+ });
52
+
53
+ // If we have multiple types, use oneOf for better widget support
54
+ return uniqueSchemas.length > 1
55
+ ? { oneOf: uniqueSchemas }
56
+ : uniqueSchemas[0] || {};
57
+ };
58
+
59
+ /**
60
+ * Infers a JSON Schema from a given value.
61
+ * @param value - The value to analyze
62
+ * @returns RJSFSchema representing the inferred type and structure
63
+ */
64
+ export const inferSchemaFromValue = (value: unknown): RJSFSchema => {
65
+ if (Array.isArray(value)) {
66
+ return {
67
+ type: "array",
68
+ items: inferArrayItemsSchema(value),
69
+ };
70
+ }
71
+
72
+ if (isRecord(value)) {
73
+ return {
74
+ type: "object",
75
+ properties: Object.fromEntries(
76
+ Object.entries(value).map(([key, itemValue]) => [
77
+ key,
78
+ inferSchemaFromValue(itemValue),
79
+ ]),
80
+ ),
81
+ additionalProperties: true,
82
+ default: {},
83
+ };
84
+ }
85
+
86
+ if (typeof value === "string") {
87
+ return { type: "string" };
88
+ }
89
+
90
+ if (typeof value === "number") {
91
+ return { type: Number.isInteger(value) ? "integer" : "number" };
92
+ }
93
+
94
+ if (typeof value === "boolean") {
95
+ return { type: "boolean" };
96
+ }
97
+
98
+ if (value === null) {
99
+ return { type: "null" };
100
+ }
101
+
102
+ return {};
103
+ };
104
+
105
+ /**
106
+ * Merges an inferred schema with a declared schema, prioritizing declared properties.
107
+ * @param inferredSchema - Schema derived from the actual data
108
+ * @param declaredSchema - Explicitly declared schema from definitions
109
+ * @returns Merged schema with declared properties taking precedence
110
+ */
111
+ const mergeSchemas = (
112
+ inferredSchema: RJSFSchema,
113
+ declaredSchema: RJSFSchema,
114
+ ): RJSFSchema => {
115
+ // Declared schema takes priority over inferred schema
116
+ const merged = { ...inferredSchema, ...declaredSchema };
117
+
118
+ // For objects, merge properties recursively
119
+ if (
120
+ inferredSchema.type === "object" &&
121
+ declaredSchema.type === "object" &&
122
+ inferredSchema.properties &&
123
+ declaredSchema.properties
124
+ ) {
125
+ merged.properties = {
126
+ ...inferredSchema.properties,
127
+ ...declaredSchema.properties,
128
+ };
129
+ }
130
+
131
+ return merged;
132
+ };
133
+
134
+ /**
135
+ * Builds a complete schema for configurable properties by combining inferred and declared schemas.
136
+ * @param configurable - The configurable data object
137
+ * @param schemaDefinitions - Optional declared schema definitions
138
+ * @returns Schema properties for the configurable object
139
+ * @throws Error if schemaDefinitions contains invalid schema objects
140
+ */
141
+ export const buildConfigurableSchema = (
142
+ configurable: unknown,
143
+ schemaDefinitions?: Record<string, RJSFSchema>,
144
+ ): RJSFSchema["properties"] => {
145
+ if (!isRecord(configurable)) {
146
+ if (!schemaDefinitions) {
147
+ return {};
148
+ }
149
+ return Object.fromEntries(
150
+ Object.entries(schemaDefinitions).map(([key, schema]) => [key, schema]),
151
+ );
152
+ }
153
+
154
+ // Validate schema definitions if provided
155
+ if (schemaDefinitions) {
156
+ for (const [key, schema] of Object.entries(schemaDefinitions)) {
157
+ if (!isValidSchema(schema)) {
158
+ throw new Error(
159
+ `Invalid schema definition for key "${key}": expected object, got ${typeof schema}`,
160
+ );
161
+ }
162
+ }
163
+ }
164
+
165
+ const keys = new Set([
166
+ ...Object.keys(configurable),
167
+ ...Object.keys(schemaDefinitions ?? {}),
168
+ ]);
169
+
170
+ return Object.fromEntries(
171
+ Array.from(keys).map((key) => {
172
+ const value = configurable[key];
173
+ try {
174
+ const inferredSchema = inferSchemaFromValue(value);
175
+ const declaredSchema = schemaDefinitions?.[key];
176
+
177
+ return [
178
+ key,
179
+ declaredSchema
180
+ ? mergeSchemas(inferredSchema, declaredSchema)
181
+ : inferredSchema,
182
+ ];
183
+ } catch (error) {
184
+ // If schema inference fails, fall back to a basic string schema
185
+ console.warn(
186
+ `Failed to infer schema for key "${key}": ${error instanceof Error ? error.message : String(error)}`,
187
+ );
188
+ return [key, { type: "string" }];
189
+ }
190
+ }),
191
+ );
192
+ };
193
+
194
+ /**
195
+ * Converts form data to a WorkflowRunnableConfig object.
196
+ * @param formData - Form data from the UI
197
+ * @returns Validated workflow configuration or null if empty
198
+ */
199
+ export const toWorkflowConfig = (
200
+ formData: Record<string, unknown>,
201
+ ): WorkflowRunnableConfig | null => {
202
+ const next: WorkflowRunnableConfig = {};
203
+
204
+ if (
205
+ isRecord(formData.configurable) &&
206
+ Object.keys(formData.configurable).length > 0
207
+ ) {
208
+ next.configurable = formData.configurable;
209
+ }
210
+
211
+ if (typeof formData.run_name === "string") {
212
+ const runName = formData.run_name.trim();
213
+ if (runName.length > 0) {
214
+ next.run_name = runName;
215
+ }
216
+ }
217
+
218
+ if (Array.isArray(formData.tags)) {
219
+ const tags = formData.tags
220
+ .filter((item): item is string => typeof item === "string")
221
+ .map((item) => item.trim())
222
+ .filter(
223
+ (item, index, array) =>
224
+ item.length > 0 && array.indexOf(item) === index,
225
+ );
226
+ if (tags.length > 0) {
227
+ next.tags = tags;
228
+ }
229
+ }
230
+
231
+ if (
232
+ isRecord(formData.metadata) &&
233
+ Object.keys(formData.metadata).length > 0
234
+ ) {
235
+ next.metadata = formData.metadata;
236
+ }
237
+
238
+ if (Array.isArray(formData.callbacks) && formData.callbacks.length > 0) {
239
+ next.callbacks = formData.callbacks;
240
+ }
241
+
242
+ const recursionLimit = toPositiveInteger(formData.recursion_limit);
243
+ if (recursionLimit) {
244
+ next.recursion_limit = recursionLimit;
245
+ }
246
+
247
+ const maxConcurrency = toPositiveInteger(formData.max_concurrency);
248
+ if (maxConcurrency) {
249
+ next.max_concurrency = maxConcurrency;
250
+ }
251
+
252
+ if (isRecord(formData.prompts) && Object.keys(formData.prompts).length > 0) {
253
+ next.prompts = formData.prompts;
254
+ }
255
+
256
+ return Object.keys(next).length > 0 ? next : null;
257
+ };
258
+
259
+ /**
260
+ * Converts a WorkflowRunnableConfig to form data for the UI.
261
+ * @param config - Workflow configuration object or null
262
+ * @returns Form data object with default values
263
+ */
264
+ export const toFormData = (
265
+ config: WorkflowRunnableConfig | null,
266
+ ): Record<string, unknown> => ({
267
+ configurable: config?.configurable ?? {},
268
+ run_name: config?.run_name ?? "",
269
+ tags: config?.tags ?? [],
270
+ metadata: config?.metadata ?? {},
271
+ callbacks: config?.callbacks ?? [],
272
+ recursion_limit: config?.recursion_limit,
273
+ max_concurrency: config?.max_concurrency,
274
+ prompts: config?.prompts ?? {},
275
+ });