@xopcai/xopc 0.0.89 → 0.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/README.md +36 -12
  2. package/README.zh-CN.md +36 -12
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
  6. package/dist/gateway/static/root/assets/agents-bVWUlrlD.js +222 -0
  7. package/dist/gateway/static/root/assets/apps-page-CIC8bmvZ.js +1 -0
  8. package/dist/gateway/static/root/assets/{attachment-preview-renderer-CpyoFbs4.js → attachment-preview-renderer-DBAxQXb-.js} +2 -2
  9. package/dist/gateway/static/root/assets/{attachment-process-heavy-CqVriadb.js → attachment-process-heavy-Csq3TrrP.js} +4 -4
  10. package/dist/gateway/static/root/assets/channels-settings-C8G8RAAP.js +1 -0
  11. package/dist/gateway/static/root/assets/{channels-status-swr-DaHGkRF1.js → channels-status-swr-CYWL5DLD.js} +1 -1
  12. package/dist/gateway/static/root/assets/circle-check-C23XjkUj.js +1 -0
  13. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
  14. package/dist/gateway/static/root/assets/cron-api-TVqLlGAC.js +1 -0
  15. package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +2 -0
  16. package/dist/gateway/static/root/assets/cron-page-BtcFYlvv.js +1 -0
  17. package/dist/gateway/static/root/assets/dist-CUV1uY5f.js +1 -0
  18. package/dist/gateway/static/root/assets/{extension-debug-page-CtuKJ9tE.js → extension-debug-page-mTLHRDp1.js} +1 -1
  19. package/dist/gateway/static/root/assets/{extension-page-ykzjOkR5.js → extension-page-iI8BI7WK.js} +1 -1
  20. package/dist/gateway/static/root/assets/{extension-settings-page-Ce2qrdpO.js → extension-settings-page-ByXcdubM.js} +1 -1
  21. package/dist/gateway/static/root/assets/{fetch-C9FFJjuH.js → fetch-BWtQq_Ys.js} +1 -1
  22. package/dist/gateway/static/root/assets/{field-primitives-BFcrNeTU.js → field-primitives-BsZ-4VT5.js} +1 -1
  23. package/dist/gateway/static/root/assets/{heartbeat-config-api-CEg4Vr9R.js → heartbeat-config-api-WjTsRLCU.js} +1 -1
  24. package/dist/gateway/static/root/assets/{index-CZfy9oxs.js → index-CKkR-v9U.js} +101 -97
  25. package/dist/gateway/static/root/assets/index-VlELBY99.css +1 -0
  26. package/dist/gateway/static/root/assets/logs-page-ClnIpxfd.js +1 -0
  27. package/dist/gateway/static/root/assets/note-detail-page-B91pLkEI.css +1 -0
  28. package/dist/gateway/static/root/assets/note-detail-page-DJ2Mb4x7.js +179 -0
  29. package/dist/gateway/static/root/assets/note-time-JLBPSLzK.js +1 -0
  30. package/dist/gateway/static/root/assets/notes-page-BE-75qz9.js +1 -0
  31. package/dist/gateway/static/root/assets/{pdf-BnEvgIXZ.js → pdf-epILhEOn.js} +1 -1
  32. package/dist/gateway/static/root/assets/preload-helper-zJ_50EbN.js +1 -0
  33. package/dist/gateway/static/root/assets/sessions-page-bJJkWtTl.js +1 -0
  34. package/dist/gateway/static/root/assets/{settings-form-section-BqdzA28u.js → settings-form-section-DSYCknxM.js} +1 -1
  35. package/dist/gateway/static/root/assets/settings-page-WcMXLq2U.js +3 -0
  36. package/dist/gateway/static/root/assets/share-preview-page-awRqs4hV.js +2 -0
  37. package/dist/gateway/static/root/assets/skills-page-Lu-i1JG7.js +2 -0
  38. package/dist/gateway/static/root/assets/{theme-store-CNqbmTNV.js → theme-store-BC-42BoZ.js} +1 -1
  39. package/dist/gateway/static/root/assets/toast-z0toXu32.js +1 -0
  40. package/dist/gateway/static/root/assets/url-CY1RQKTU.js +3 -0
  41. package/dist/gateway/static/root/assets/{utils-BWm2tG2w.js → utils-DX3TQuap.js} +1 -1
  42. package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +45 -0
  43. package/dist/gateway/static/root/assets/voice-api-key-field-B5uKlDqA.js +1 -0
  44. package/dist/gateway/static/root/assets/workflow-page.utils-ClC37yEp.js +1 -0
  45. package/dist/gateway/static/root/assets/workflows-page-C7VhIXtR.js +27 -0
  46. package/dist/gateway/static/root/index.html +11 -7
  47. package/dist/package.js +1 -1
  48. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +20 -18
  49. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
  50. package/dist/src/agent/tools/cronjob-tool.d.ts +6 -0
  51. package/dist/src/agent/tools/cronjob-tool.js +74 -9
  52. package/dist/src/agent/tools/cronjob-tool.js.map +1 -1
  53. package/dist/src/agent/tools/edit.d.ts +5 -1
  54. package/dist/src/agent/tools/edit.js +7 -5
  55. package/dist/src/agent/tools/edit.js.map +1 -1
  56. package/dist/src/agent/tools/factory.js +2 -2
  57. package/dist/src/agent/tools/factory.js.map +1 -1
  58. package/dist/src/agent/tools/write.d.ts +5 -1
  59. package/dist/src/agent/tools/write.js +7 -5
  60. package/dist/src/agent/tools/write.js.map +1 -1
  61. package/dist/src/agent/workflow/agent-progress.js +2 -0
  62. package/dist/src/agent/workflow/agent-progress.js.map +1 -1
  63. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +12 -0
  64. package/dist/src/agent/workflow/builtins/client-proposal.js +155 -0
  65. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -0
  66. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +12 -0
  67. package/dist/src/agent/workflow/builtins/competitor-scan.js +150 -0
  68. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -0
  69. package/dist/src/agent/workflow/builtins/content-draft.d.ts +13 -0
  70. package/dist/src/agent/workflow/builtins/content-draft.js +146 -0
  71. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -0
  72. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +11 -0
  73. package/dist/src/agent/workflow/builtins/content-repurpose.js +137 -0
  74. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -0
  75. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +13 -0
  76. package/dist/src/agent/workflow/builtins/decision-compare.js +173 -0
  77. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -0
  78. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +11 -0
  79. package/dist/src/agent/workflow/builtins/inbox-triage.js +148 -0
  80. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -0
  81. package/dist/src/agent/workflow/builtins/index.d.ts +10 -1
  82. package/dist/src/agent/workflow/builtins/index.js +46 -1
  83. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  84. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +12 -0
  85. package/dist/src/agent/workflow/builtins/meeting-prep.js +144 -0
  86. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -0
  87. package/dist/src/agent/workflow/builtins/offer-design.d.ts +12 -0
  88. package/dist/src/agent/workflow/builtins/offer-design.js +161 -0
  89. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -0
  90. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +12 -0
  91. package/dist/src/agent/workflow/builtins/weekly-review.js +131 -0
  92. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -0
  93. package/dist/src/agent/workflow/step-labels.js +2 -2
  94. package/dist/src/agent/workflow/step-labels.js.map +1 -1
  95. package/dist/src/agent/workflow/subagent-runner.js +3 -1
  96. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  97. package/dist/src/agent/workflow/types.d.ts +4 -0
  98. package/dist/src/chat-commands/agent-edit.d.ts +4 -0
  99. package/dist/src/chat-commands/agent-edit.js +136 -0
  100. package/dist/src/chat-commands/agent-edit.js.map +1 -0
  101. package/dist/src/chat-commands/index.d.ts +1 -0
  102. package/dist/src/chat-commands/index.js +3 -1
  103. package/dist/src/chat-commands/index.js.map +1 -1
  104. package/dist/src/cli/bin.js +2 -0
  105. package/dist/src/cli/bin.js.map +1 -1
  106. package/dist/src/cli/commands/cron.js +42 -3
  107. package/dist/src/cli/commands/cron.js.map +1 -1
  108. package/dist/src/cli/commands/doctor/checks/session-integrity.js +79 -56
  109. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  110. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  111. package/dist/src/cli/commands/update.js +86 -79
  112. package/dist/src/cli/commands/update.js.map +1 -1
  113. package/dist/src/commands/agents.config.d.ts +3 -2
  114. package/dist/src/commands/agents.config.js +5 -2
  115. package/dist/src/commands/agents.config.js.map +1 -1
  116. package/dist/src/config/agent-typed-models.d.ts +2 -7
  117. package/dist/src/config/agent-typed-models.js +3 -14
  118. package/dist/src/config/agent-typed-models.js.map +1 -1
  119. package/dist/src/config/localized-text.d.ts +6 -0
  120. package/dist/src/config/localized-text.js +42 -0
  121. package/dist/src/config/localized-text.js.map +1 -0
  122. package/dist/src/config/models-json.d.ts +6 -6
  123. package/dist/src/config/schema.d.ts +6 -21
  124. package/dist/src/config/schema.js +4 -4
  125. package/dist/src/config/schema.js.map +1 -1
  126. package/dist/src/cron/executor.d.ts +2 -0
  127. package/dist/src/cron/executor.js +111 -1
  128. package/dist/src/cron/executor.js.map +1 -1
  129. package/dist/src/cron/types.d.ts +8 -1
  130. package/dist/src/cron/validation.d.ts +4 -0
  131. package/dist/src/cron/validation.js +4 -3
  132. package/dist/src/cron/validation.js.map +1 -1
  133. package/dist/src/cron/workflow-run-completion.d.ts +23 -0
  134. package/dist/src/cron/workflow-run-completion.js +72 -0
  135. package/dist/src/cron/workflow-run-completion.js.map +1 -0
  136. package/dist/src/extensions/update.d.ts +51 -0
  137. package/dist/src/extensions/update.js +260 -0
  138. package/dist/src/extensions/update.js.map +1 -0
  139. package/dist/src/gateway/agents-admin.d.ts +15 -8
  140. package/dist/src/gateway/agents-admin.js +77 -28
  141. package/dist/src/gateway/agents-admin.js.map +1 -1
  142. package/dist/src/gateway/heartbeat/service.js +1 -1
  143. package/dist/src/gateway/hono/lib/config-payload.d.ts +6 -0
  144. package/dist/src/gateway/hono/lib/config-payload.js +3 -1
  145. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  146. package/dist/src/gateway/hono/middleware/auth.d.ts +2 -0
  147. package/dist/src/gateway/hono/middleware/auth.js +11 -7
  148. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  149. package/dist/src/gateway/hono/routes/agents.js +55 -12
  150. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  151. package/dist/src/gateway/hono/routes/config-patch/agents.js +1 -1
  152. package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +2 -2
  153. package/dist/src/gateway/hono/routes/config-patch/gateway.js +12 -0
  154. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  155. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  156. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  157. package/dist/src/gateway/hono/routes/notes.d.ts +3 -0
  158. package/dist/src/gateway/hono/routes/notes.js +274 -0
  159. package/dist/src/gateway/hono/routes/notes.js.map +1 -0
  160. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  161. package/dist/src/gateway/hono/routes/update.js +55 -107
  162. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  163. package/dist/src/gateway/hono/routes/workflows.js +3 -1
  164. package/dist/src/gateway/hono/routes/workflows.js.map +1 -1
  165. package/dist/src/gateway/server.js +2 -0
  166. package/dist/src/gateway/server.js.map +1 -1
  167. package/dist/src/gateway/service.d.ts +3 -0
  168. package/dist/src/gateway/service.js +12 -1
  169. package/dist/src/gateway/service.js.map +1 -1
  170. package/dist/src/gateway/workspace-ripgrep.d.ts +6 -0
  171. package/dist/src/gateway/workspace-ripgrep.js +62 -11
  172. package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
  173. package/dist/src/heartbeat/index.js +1 -1
  174. package/dist/src/infra/brew.d.ts +4 -0
  175. package/dist/src/infra/brew.js +20 -0
  176. package/dist/src/infra/brew.js.map +1 -0
  177. package/dist/src/infra/package-json.d.ts +2 -0
  178. package/dist/src/infra/package-json.js +23 -0
  179. package/dist/src/infra/package-json.js.map +1 -0
  180. package/dist/src/infra/package-update-steps.d.ts +35 -0
  181. package/dist/src/infra/package-update-steps.js +304 -0
  182. package/dist/src/infra/package-update-steps.js.map +1 -0
  183. package/dist/src/infra/path-env.d.ts +11 -0
  184. package/dist/src/infra/path-env.js +90 -0
  185. package/dist/src/infra/path-env.js.map +1 -0
  186. package/dist/src/infra/path-prepend.d.ts +7 -0
  187. package/dist/src/infra/path-prepend.js +44 -0
  188. package/dist/src/infra/path-prepend.js.map +1 -0
  189. package/dist/src/infra/stable-node-path.d.ts +2 -0
  190. package/dist/src/infra/stable-node-path.js +28 -0
  191. package/dist/src/infra/stable-node-path.js.map +1 -0
  192. package/dist/src/infra/update-global.d.ts +30 -23
  193. package/dist/src/infra/update-global.js +113 -64
  194. package/dist/src/infra/update-global.js.map +1 -1
  195. package/dist/src/infra/update-log.d.ts +1 -0
  196. package/dist/src/infra/update-log.js +12 -0
  197. package/dist/src/infra/update-log.js.map +1 -0
  198. package/dist/src/infra/update-restart.d.ts +20 -0
  199. package/dist/src/infra/update-restart.js +165 -0
  200. package/dist/src/infra/update-restart.js.map +1 -0
  201. package/dist/src/infra/update-runner.d.ts +89 -1
  202. package/dist/src/infra/update-runner.js +604 -173
  203. package/dist/src/infra/update-runner.js.map +1 -1
  204. package/dist/src/infra/update-startup.d.ts +3 -0
  205. package/dist/src/infra/update-startup.js +8 -4
  206. package/dist/src/infra/update-startup.js.map +1 -1
  207. package/dist/src/notes/attachment-ref.d.ts +9 -0
  208. package/dist/src/notes/attachment-ref.js +27 -0
  209. package/dist/src/notes/attachment-ref.js.map +1 -0
  210. package/dist/src/notes/index.d.ts +4 -0
  211. package/dist/src/notes/index.js +4 -0
  212. package/dist/src/notes/note-attachment-sync.d.ts +7 -0
  213. package/dist/src/notes/note-attachment-sync.js +46 -0
  214. package/dist/src/notes/note-attachment-sync.js.map +1 -0
  215. package/dist/src/notes/note-index-meta.d.ts +14 -0
  216. package/dist/src/notes/note-index-meta.js +87 -0
  217. package/dist/src/notes/note-index-meta.js.map +1 -0
  218. package/dist/src/notes/paths.d.ts +5 -0
  219. package/dist/src/notes/paths.js +23 -0
  220. package/dist/src/notes/paths.js.map +1 -0
  221. package/dist/src/notes/service.d.ts +42 -0
  222. package/dist/src/notes/service.js +331 -0
  223. package/dist/src/notes/service.js.map +1 -0
  224. package/dist/src/notes/store.d.ts +33 -0
  225. package/dist/src/notes/store.js +317 -0
  226. package/dist/src/notes/store.js.map +1 -0
  227. package/dist/src/notes/types.d.ts +162 -0
  228. package/dist/src/notes/types.js +1 -0
  229. package/dist/src/routing/resolve-route.d.ts +3 -1
  230. package/dist/src/routing/resolve-route.js.map +1 -1
  231. package/dist/src/session/store.d.ts +5 -3
  232. package/dist/src/session/store.js +66 -20
  233. package/dist/src/session/store.js.map +1 -1
  234. package/dist/src/utils/logger/stats.d.ts +1 -1
  235. package/dist/src/workflows/domain/event.d.ts +3 -0
  236. package/dist/src/workflows/domain/run.d.ts +3 -0
  237. package/dist/src/workflows/domain/run.js.map +1 -1
  238. package/dist/src/workflows/engine/projector.js +17 -0
  239. package/dist/src/workflows/engine/projector.js.map +1 -1
  240. package/dist/src/workflows/engine/workflow-engine.js +127 -0
  241. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  242. package/dist/src/workflows/index.js +1 -1
  243. package/dist/src/workflows/service/run-view-to-snapshot.js +3 -1
  244. package/dist/src/workflows/service/run-view-to-snapshot.js.map +1 -1
  245. package/dist/src/workflows/service/workflow-run-service.d.ts +1 -0
  246. package/dist/src/workflows/service/workflow-run-service.js +4 -1
  247. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  248. package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
  249. package/package.json +1 -1
  250. package/dist/gateway/static/root/assets/agents-B6PJB07W.js +0 -222
  251. package/dist/gateway/static/root/assets/apps-page-BOr0B1wv.js +0 -1
  252. package/dist/gateway/static/root/assets/channels-settings-BelUKggl.js +0 -1
  253. package/dist/gateway/static/root/assets/cron-api-CjOg-BIj.js +0 -1
  254. package/dist/gateway/static/root/assets/cron-dreaming-jobs-DueM3rBz.js +0 -2
  255. package/dist/gateway/static/root/assets/cron-page-DhoZmZXb.js +0 -1
  256. package/dist/gateway/static/root/assets/dist-6LecgDx5.js +0 -1
  257. package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +0 -45
  258. package/dist/gateway/static/root/assets/index-CiN1cQiQ.css +0 -1
  259. package/dist/gateway/static/root/assets/logs-page-BwWLfqvd.js +0 -1
  260. package/dist/gateway/static/root/assets/sessions-page-DV5WN8uk.js +0 -1
  261. package/dist/gateway/static/root/assets/settings-page-CfOBRbPX.js +0 -3
  262. package/dist/gateway/static/root/assets/share-preview-page-Di5Bzh4g.js +0 -2
  263. package/dist/gateway/static/root/assets/skills-page-D0H5Kaxg.js +0 -2
  264. package/dist/gateway/static/root/assets/url-aYn-Rj1C.js +0 -7
  265. package/dist/gateway/static/root/assets/vendor-codemirror-D0yxdRpg.js +0 -58
  266. package/dist/gateway/static/root/assets/voice-api-key-field-X2UfnHeq.js +0 -1
  267. package/dist/gateway/static/root/assets/workflows-page-BOPpO3NG.js +0 -27
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","names":[],"sources":["../../../../src/workflows/domain/run.ts"],"sourcesContent":["import type { WorkflowDefinitionEstimatedAgents } from './definition.js';\nimport type { WorkflowArtifactRef, WorkflowResultEnvelope } from './result.js';\n\nexport type WorkflowRunStatus =\n | 'queued'\n | 'running'\n | 'succeeded'\n | 'failed'\n | 'cancelled'\n | 'timeout';\n\nconst TERMINAL_WORKFLOW_RUN_STATUSES = new Set<WorkflowRunStatus>([\n 'succeeded',\n 'failed',\n 'cancelled',\n 'timeout',\n]);\n\nexport function isTerminalWorkflowRunStatus(status: WorkflowRunStatus): boolean {\n return TERMINAL_WORKFLOW_RUN_STATUSES.has(status);\n}\n\nexport interface WorkflowRun {\n id: string;\n definitionId: string;\n definitionVersion: string;\n title: string;\n goal: string;\n input: unknown;\n status: WorkflowRunStatus;\n source: WorkflowRunSource;\n metadata?: WorkflowRunMetadata;\n result?: WorkflowResultEnvelope;\n error?: WorkflowRunError;\n metrics: WorkflowRunMetrics;\n createdAtMs: number;\n startedAtMs?: number;\n completedAtMs?: number;\n}\n\nexport interface WorkflowRunMetadata {\n sessionKey: string;\n triggerSource: WorkflowRunSource['kind'];\n agentId?: string;\n retryOfRunId?: string;\n definition: WorkflowRunDefinitionSnapshot;\n input?: WorkflowRunInputEnvelope;\n correlation?: WorkflowRunCorrelation;\n origin?: WorkflowRunOrigin;\n schedule?: WorkflowRunScheduleMetadata;\n}\n\nexport interface WorkflowRunInputEnvelope {\n payload: unknown;\n goal?: string;\n variables?: Record<string, unknown>;\n context?: Record<string, unknown>;\n}\n\nexport interface WorkflowRunCorrelation {\n idempotencyKey?: string;\n requestId?: string;\n traceId?: string;\n parentRunId?: string;\n}\n\nexport interface WorkflowRunOrigin {\n channel: string;\n sessionKey?: string;\n chatId?: string;\n messageId?: string;\n scheduleId?: string;\n fireId?: string;\n requestId?: string;\n}\n\nexport interface WorkflowRunScheduleMetadata {\n scheduleId: string;\n fireId?: string;\n scheduledAtMs?: number;\n}\n\nexport interface WorkflowRunDefinitionSnapshot {\n id: string;\n name: string;\n title: string;\n version: string;\n source: 'builtin' | 'user';\n tags: string[];\n phaseCount: number;\n estimatedAgents?: WorkflowDefinitionEstimatedAgents;\n}\n\nexport type WorkflowRunSource =\n | { kind: 'chat'; sessionKey: string; messageId?: string }\n | { kind: 'webui'; sessionKey?: string; requestId?: string }\n | { kind: 'cron'; scheduleId: string; fireId?: string; scheduledAtMs?: number }\n | { kind: 'api'; requestId?: string; idempotencyKey?: string }\n | { kind: 'im'; channel: string; chatId: string; messageId?: string; userId?: string };\n\nexport interface WorkflowRunMetrics {\n agentCount: number;\n doneAgentCount: number;\n errorAgentCount: number;\n skippedAgentCount: number;\n artifactCount: number;\n durationMs?: number;\n}\n\nexport interface WorkflowRunError {\n code: WorkflowRunErrorCode;\n message: string;\n detail?: string;\n recoverable: boolean;\n}\n\nexport type WorkflowRunErrorCode =\n | 'definition_not_found'\n | 'invalid_input'\n | 'runtime_error'\n | 'timeout'\n | 'cancelled'\n | 'result_validation_failed'\n | 'agent_quota_exceeded';\n\nexport interface WorkflowRunControls {\n canCancel: boolean;\n canRetry: boolean;\n canArchive: boolean;\n}\n\nexport interface WorkflowRunSummary {\n id: string;\n definitionId: string;\n title: string;\n status: WorkflowRunStatus;\n source: WorkflowRunSource;\n metadata?: WorkflowRunMetadata;\n createdAtMs: number;\n startedAtMs?: number;\n completedAtMs?: number;\n metrics: WorkflowRunMetrics;\n}\n\nexport interface WorkflowRunView {\n run: WorkflowRun;\n phases: WorkflowPhaseView[];\n agents: WorkflowAgentView[];\n logs: WorkflowLogEntry[];\n artifacts: WorkflowArtifactRef[];\n timeline: WorkflowTimelineItem[];\n controls: WorkflowRunControls;\n}\n\nexport type WorkflowPhaseStatus = 'pending' | 'running' | 'completed' | 'failed';\n\nexport interface WorkflowPhaseView {\n id: string;\n title: string;\n status: WorkflowPhaseStatus;\n startedAtMs?: number;\n completedAtMs?: number;\n agentIds: string[];\n}\n\nexport type WorkflowAgentStatus = 'queued' | 'running' | 'done' | 'error' | 'skipped';\n\nexport interface WorkflowAgentView {\n id: string;\n label: string;\n phaseId?: string;\n status: WorkflowAgentStatus;\n prompt?: string;\n currentStep?: string;\n resultPreview?: string;\n error?: string;\n startedAtMs?: number;\n completedAtMs?: number;\n steps: WorkflowAgentStepView[];\n}\n\nexport type WorkflowAgentStepStatus = 'running' | 'done' | 'error';\n\nexport interface WorkflowAgentStepView {\n id: string;\n label: string;\n kind: 'tool' | 'llm' | 'thinking';\n detail?: string;\n status: WorkflowAgentStepStatus;\n startedAtMs?: number;\n completedAtMs?: number;\n}\n\nexport interface WorkflowLogEntry {\n sequence: number;\n message: string;\n createdAtMs: number;\n}\n\nexport interface WorkflowTimelineItem {\n sequence: number;\n type: string;\n title: string;\n createdAtMs: number;\n}\n"],"mappings":";AAWA,MAAM,iCAAiC,IAAI,IAAuB;CAChE;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,4BAA4B,QAAoC;AAC9E,QAAO,+BAA+B,IAAI,OAAO"}
1
+ {"version":3,"file":"run.js","names":[],"sources":["../../../../src/workflows/domain/run.ts"],"sourcesContent":["import type { WorkflowDefinitionEstimatedAgents } from './definition.js';\nimport type { WorkflowArtifactRef, WorkflowResultEnvelope } from './result.js';\n\nexport type WorkflowRunStatus =\n | 'queued'\n | 'running'\n | 'succeeded'\n | 'failed'\n | 'cancelled'\n | 'timeout';\n\nconst TERMINAL_WORKFLOW_RUN_STATUSES = new Set<WorkflowRunStatus>([\n 'succeeded',\n 'failed',\n 'cancelled',\n 'timeout',\n]);\n\nexport function isTerminalWorkflowRunStatus(status: WorkflowRunStatus): boolean {\n return TERMINAL_WORKFLOW_RUN_STATUSES.has(status);\n}\n\nexport interface WorkflowRun {\n id: string;\n definitionId: string;\n definitionVersion: string;\n title: string;\n goal: string;\n input: unknown;\n status: WorkflowRunStatus;\n source: WorkflowRunSource;\n metadata?: WorkflowRunMetadata;\n result?: WorkflowResultEnvelope;\n error?: WorkflowRunError;\n metrics: WorkflowRunMetrics;\n createdAtMs: number;\n startedAtMs?: number;\n completedAtMs?: number;\n}\n\nexport interface WorkflowRunMetadata {\n sessionKey: string;\n triggerSource: WorkflowRunSource['kind'];\n agentId?: string;\n retryOfRunId?: string;\n definition: WorkflowRunDefinitionSnapshot;\n input?: WorkflowRunInputEnvelope;\n correlation?: WorkflowRunCorrelation;\n origin?: WorkflowRunOrigin;\n schedule?: WorkflowRunScheduleMetadata;\n}\n\nexport interface WorkflowRunInputEnvelope {\n payload: unknown;\n goal?: string;\n variables?: Record<string, unknown>;\n context?: Record<string, unknown>;\n}\n\nexport interface WorkflowRunCorrelation {\n idempotencyKey?: string;\n requestId?: string;\n traceId?: string;\n parentRunId?: string;\n}\n\nexport interface WorkflowRunOrigin {\n channel: string;\n sessionKey?: string;\n chatId?: string;\n messageId?: string;\n scheduleId?: string;\n fireId?: string;\n requestId?: string;\n}\n\nexport interface WorkflowRunScheduleMetadata {\n scheduleId: string;\n fireId?: string;\n scheduledAtMs?: number;\n}\n\nexport interface WorkflowRunDefinitionSnapshot {\n id: string;\n name: string;\n title: string;\n version: string;\n source: 'builtin' | 'user';\n tags: string[];\n phaseCount: number;\n estimatedAgents?: WorkflowDefinitionEstimatedAgents;\n}\n\nexport type WorkflowRunSource =\n | { kind: 'chat'; sessionKey: string; messageId?: string }\n | { kind: 'webui'; sessionKey?: string; requestId?: string }\n | { kind: 'cron'; scheduleId: string; fireId?: string; scheduledAtMs?: number }\n | { kind: 'api'; requestId?: string; idempotencyKey?: string }\n | { kind: 'im'; channel: string; chatId: string; messageId?: string; userId?: string };\n\nexport interface WorkflowRunMetrics {\n agentCount: number;\n doneAgentCount: number;\n errorAgentCount: number;\n skippedAgentCount: number;\n artifactCount: number;\n durationMs?: number;\n}\n\nexport interface WorkflowRunError {\n code: WorkflowRunErrorCode;\n message: string;\n detail?: string;\n recoverable: boolean;\n}\n\nexport type WorkflowRunErrorCode =\n | 'definition_not_found'\n | 'invalid_input'\n | 'runtime_error'\n | 'timeout'\n | 'cancelled'\n | 'result_validation_failed'\n | 'agent_quota_exceeded';\n\nexport interface WorkflowRunControls {\n canCancel: boolean;\n canRetry: boolean;\n canArchive: boolean;\n}\n\nexport interface WorkflowRunSummary {\n id: string;\n definitionId: string;\n title: string;\n status: WorkflowRunStatus;\n source: WorkflowRunSource;\n metadata?: WorkflowRunMetadata;\n createdAtMs: number;\n startedAtMs?: number;\n completedAtMs?: number;\n metrics: WorkflowRunMetrics;\n}\n\nexport interface WorkflowRunView {\n run: WorkflowRun;\n phases: WorkflowPhaseView[];\n agents: WorkflowAgentView[];\n logs: WorkflowLogEntry[];\n artifacts: WorkflowArtifactRef[];\n timeline: WorkflowTimelineItem[];\n controls: WorkflowRunControls;\n}\n\nexport type WorkflowPhaseStatus = 'pending' | 'running' | 'completed' | 'failed';\n\nexport interface WorkflowPhaseView {\n id: string;\n title: string;\n status: WorkflowPhaseStatus;\n startedAtMs?: number;\n completedAtMs?: number;\n agentIds: string[];\n}\n\nexport type WorkflowAgentStatus = 'queued' | 'running' | 'done' | 'error' | 'skipped';\n\nexport interface WorkflowAgentView {\n id: string;\n label: string;\n phaseId?: string;\n status: WorkflowAgentStatus;\n prompt?: string;\n currentStep?: string;\n resultPreview?: string;\n error?: string;\n startedAtMs?: number;\n completedAtMs?: number;\n steps: WorkflowAgentStepView[];\n}\n\nexport type WorkflowAgentStepStatus = 'running' | 'done' | 'error';\n\nexport interface WorkflowAgentStepView {\n id: string;\n label: string;\n kind: 'tool' | 'llm' | 'thinking';\n toolName?: string;\n detail?: string;\n status: WorkflowAgentStepStatus;\n resultPreview?: string;\n error?: string;\n startedAtMs?: number;\n completedAtMs?: number;\n}\n\nexport interface WorkflowLogEntry {\n sequence: number;\n message: string;\n createdAtMs: number;\n}\n\nexport interface WorkflowTimelineItem {\n sequence: number;\n type: string;\n title: string;\n createdAtMs: number;\n}\n"],"mappings":";AAWA,MAAM,iCAAiC,IAAI,IAAuB;CAChE;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,4BAA4B,QAAoC;AAC9E,QAAO,+BAA+B,IAAI,OAAO"}
@@ -102,6 +102,7 @@ function projectWorkflowRunView(events) {
102
102
  id: payload.stepId,
103
103
  label: payload.label,
104
104
  kind: payload.kind,
105
+ toolName: payload.toolName,
105
106
  detail: payload.detail,
106
107
  status: "running",
107
108
  startedAtMs: event.createdAtMs
@@ -117,6 +118,8 @@ function projectWorkflowRunView(events) {
117
118
  steps: existing.steps.map((step) => step.id === payload.stepId ? {
118
119
  ...step,
119
120
  status: payload.status,
121
+ resultPreview: payload.resultPreview,
122
+ error: payload.error,
120
123
  completedAtMs: event.createdAtMs
121
124
  } : step)
122
125
  });
@@ -167,6 +170,20 @@ function projectWorkflowRunView(events) {
167
170
  case "run_cancelled":
168
171
  run.status = "cancelled";
169
172
  run.completedAtMs = event.createdAtMs;
173
+ for (const [agentId, agent] of agentIdToAgent) {
174
+ if (agent.status !== "queued" && agent.status !== "running") continue;
175
+ agentIdToAgent.set(agentId, {
176
+ ...agent,
177
+ status: "skipped",
178
+ currentStep: void 0,
179
+ completedAtMs: event.createdAtMs,
180
+ steps: agent.steps.map((step) => step.status === "running" ? {
181
+ ...step,
182
+ status: "error",
183
+ completedAtMs: event.createdAtMs
184
+ } : step)
185
+ });
186
+ }
170
187
  break;
171
188
  default: break;
172
189
  }
@@ -1 +1 @@
1
- {"version":3,"file":"projector.js","names":[],"sources":["../../../../src/workflows/engine/projector.ts"],"sourcesContent":["import type { WorkflowEventEnvelope } from '../domain/event.js';\nimport type {\n WorkflowAgentStatus,\n WorkflowAgentView,\n WorkflowLogEntry,\n WorkflowPhaseStatus,\n WorkflowPhaseView,\n WorkflowRun,\n WorkflowRunView,\n WorkflowTimelineItem,\n} from '../domain/run.js';\nimport { isTerminalWorkflowRunStatus } from '../domain/run.js';\nimport type { WorkflowArtifactRef } from '../domain/result.js';\n\nfunction terminalRunStatus(status: WorkflowRun['status']): boolean {\n return isTerminalWorkflowRunStatus(status);\n}\n\nfunction phaseStatusAfterAgentStatus(agentStatuses: WorkflowAgentStatus[]): WorkflowPhaseStatus {\n if (agentStatuses.some((status) => status === 'running')) {\n return 'running';\n }\n if (agentStatuses.some((status) => status === 'error')) {\n return 'failed';\n }\n if (agentStatuses.length > 0 && agentStatuses.every((status) => status === 'done' || status === 'skipped')) {\n return 'completed';\n }\n return 'pending';\n}\n\nfunction buildTimelineItem(event: WorkflowEventEnvelope): WorkflowTimelineItem {\n return {\n sequence: event.sequence,\n type: event.type,\n title: event.type.replaceAll('_', ' '),\n createdAtMs: event.createdAtMs,\n };\n}\n\nexport function projectWorkflowRunView(events: WorkflowEventEnvelope[]): WorkflowRunView | null {\n if (events.length === 0) {\n return null;\n }\n\n const orderedEvents = [...events].sort((left, right) => left.sequence - right.sequence);\n const firstEvent = orderedEvents[0];\n if (firstEvent.type !== 'run_queued') {\n return null;\n }\n\n const firstPayload = firstEvent.payload as { run?: WorkflowRun };\n if (!firstPayload.run) {\n return null;\n }\n\n const run: WorkflowRun = {\n ...firstPayload.run,\n metrics: { ...firstPayload.run.metrics },\n };\n const phaseIdToPhase = new Map<string, WorkflowPhaseView>();\n const agentIdToAgent = new Map<string, WorkflowAgentView>();\n const logs: WorkflowLogEntry[] = [];\n const artifacts: WorkflowArtifactRef[] = [];\n const timeline: WorkflowTimelineItem[] = [];\n\n for (const event of orderedEvents) {\n timeline.push(buildTimelineItem(event));\n\n switch (event.type) {\n case 'run_started': {\n const payload = event.payload as { startedAtMs: number };\n run.status = 'running';\n run.startedAtMs = payload.startedAtMs;\n break;\n }\n case 'phase_started': {\n const payload = event.payload as { phaseId: string; title: string };\n phaseIdToPhase.set(payload.phaseId, {\n id: payload.phaseId,\n title: payload.title,\n status: 'running',\n startedAtMs: event.createdAtMs,\n agentIds: phaseIdToPhase.get(payload.phaseId)?.agentIds ?? [],\n });\n break;\n }\n case 'phase_completed': {\n const payload = event.payload as { phaseId: string };\n const existing = phaseIdToPhase.get(payload.phaseId);\n if (existing) {\n phaseIdToPhase.set(payload.phaseId, {\n ...existing,\n status: 'completed',\n completedAtMs: event.createdAtMs,\n });\n }\n break;\n }\n case 'agent_queued': {\n const payload = event.payload as { agentId: string; label: string; phaseId?: string; prompt?: string };\n agentIdToAgent.set(payload.agentId, {\n id: payload.agentId,\n label: payload.label,\n phaseId: payload.phaseId,\n status: 'queued',\n prompt: payload.prompt,\n steps: [],\n });\n if (payload.phaseId) {\n const existingPhase = phaseIdToPhase.get(payload.phaseId);\n if (existingPhase && !existingPhase.agentIds.includes(payload.agentId)) {\n phaseIdToPhase.set(payload.phaseId, {\n ...existingPhase,\n agentIds: [...existingPhase.agentIds, payload.agentId],\n });\n }\n }\n break;\n }\n case 'agent_started': {\n const payload = event.payload as { agentId: string };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n status: 'running',\n startedAtMs: event.createdAtMs,\n });\n }\n break;\n }\n case 'agent_step_started': {\n const payload = event.payload as {\n agentId: string;\n stepId: string;\n label: string;\n kind: 'tool' | 'llm' | 'thinking';\n detail?: string;\n };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n currentStep: payload.label,\n steps: [\n ...existing.steps,\n {\n id: payload.stepId,\n label: payload.label,\n kind: payload.kind,\n detail: payload.detail,\n status: 'running',\n startedAtMs: event.createdAtMs,\n },\n ],\n });\n }\n break;\n }\n case 'agent_step_completed': {\n const payload = event.payload as { agentId: string; stepId: string; status: 'done' | 'error' };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n steps: existing.steps.map((step) =>\n step.id === payload.stepId\n ? {\n ...step,\n status: payload.status,\n completedAtMs: event.createdAtMs,\n }\n : step,\n ),\n });\n }\n break;\n }\n case 'agent_completed': {\n const payload = event.payload as {\n agentId: string;\n status: WorkflowAgentStatus;\n resultPreview?: string;\n error?: string;\n };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n status: payload.status,\n currentStep: undefined,\n resultPreview: payload.resultPreview,\n error: payload.error,\n completedAtMs: event.createdAtMs,\n });\n }\n break;\n }\n case 'log_appended': {\n const payload = event.payload as { message: string };\n logs.push({ sequence: event.sequence, message: payload.message, createdAtMs: event.createdAtMs });\n break;\n }\n case 'artifact_created': {\n const payload = event.payload as { artifact: WorkflowArtifactRef };\n artifacts.push(payload.artifact);\n run.metrics.artifactCount = artifacts.length;\n break;\n }\n case 'run_completed': {\n const payload = event.payload as { result: WorkflowRun['result'] };\n run.status = 'succeeded';\n run.result = payload.result;\n run.completedAtMs = event.createdAtMs;\n break;\n }\n case 'run_failed': {\n const payload = event.payload as { error: WorkflowRun['error'] };\n run.status = payload.error?.code === 'timeout' ? 'timeout' : 'failed';\n run.error = payload.error;\n run.completedAtMs = event.createdAtMs;\n break;\n }\n case 'run_cancelled': {\n run.status = 'cancelled';\n run.completedAtMs = event.createdAtMs;\n break;\n }\n case 'run_queued':\n default:\n break;\n }\n }\n\n const agents = [...agentIdToAgent.values()];\n run.metrics.agentCount = agents.length;\n run.metrics.doneAgentCount = agents.filter((agent) => agent.status === 'done').length;\n run.metrics.errorAgentCount = agents.filter((agent) => agent.status === 'error').length;\n run.metrics.skippedAgentCount = agents.filter((agent) => agent.status === 'skipped').length;\n run.metrics.artifactCount = artifacts.length;\n if (run.startedAtMs && run.completedAtMs) {\n run.metrics.durationMs = run.completedAtMs - run.startedAtMs;\n }\n\n const phases = [...phaseIdToPhase.values()].map((phase) => {\n if (phase.status === 'completed' || phase.status === 'failed') {\n return phase;\n }\n const phaseAgents = phase.agentIds\n .map((agentId) => agentIdToAgent.get(agentId)?.status)\n .filter((status): status is WorkflowAgentStatus => Boolean(status));\n return { ...phase, status: phaseStatusAfterAgentStatus(phaseAgents) };\n });\n\n return {\n run,\n phases,\n agents,\n logs,\n artifacts,\n timeline,\n controls: {\n canCancel: !terminalRunStatus(run.status),\n canRetry: terminalRunStatus(run.status),\n canArchive: terminalRunStatus(run.status),\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"projector.js","names":[],"sources":["../../../../src/workflows/engine/projector.ts"],"sourcesContent":["import type { WorkflowEventEnvelope } from '../domain/event.js';\nimport type {\n WorkflowAgentStatus,\n WorkflowAgentView,\n WorkflowLogEntry,\n WorkflowPhaseStatus,\n WorkflowPhaseView,\n WorkflowRun,\n WorkflowRunView,\n WorkflowTimelineItem,\n} from '../domain/run.js';\nimport { isTerminalWorkflowRunStatus } from '../domain/run.js';\nimport type { WorkflowArtifactRef } from '../domain/result.js';\n\nfunction terminalRunStatus(status: WorkflowRun['status']): boolean {\n return isTerminalWorkflowRunStatus(status);\n}\n\nfunction phaseStatusAfterAgentStatus(agentStatuses: WorkflowAgentStatus[]): WorkflowPhaseStatus {\n if (agentStatuses.some((status) => status === 'running')) {\n return 'running';\n }\n if (agentStatuses.some((status) => status === 'error')) {\n return 'failed';\n }\n if (agentStatuses.length > 0 && agentStatuses.every((status) => status === 'done' || status === 'skipped')) {\n return 'completed';\n }\n return 'pending';\n}\n\nfunction buildTimelineItem(event: WorkflowEventEnvelope): WorkflowTimelineItem {\n return {\n sequence: event.sequence,\n type: event.type,\n title: event.type.replaceAll('_', ' '),\n createdAtMs: event.createdAtMs,\n };\n}\n\nexport function projectWorkflowRunView(events: WorkflowEventEnvelope[]): WorkflowRunView | null {\n if (events.length === 0) {\n return null;\n }\n\n const orderedEvents = [...events].sort((left, right) => left.sequence - right.sequence);\n const firstEvent = orderedEvents[0];\n if (firstEvent.type !== 'run_queued') {\n return null;\n }\n\n const firstPayload = firstEvent.payload as { run?: WorkflowRun };\n if (!firstPayload.run) {\n return null;\n }\n\n const run: WorkflowRun = {\n ...firstPayload.run,\n metrics: { ...firstPayload.run.metrics },\n };\n const phaseIdToPhase = new Map<string, WorkflowPhaseView>();\n const agentIdToAgent = new Map<string, WorkflowAgentView>();\n const logs: WorkflowLogEntry[] = [];\n const artifacts: WorkflowArtifactRef[] = [];\n const timeline: WorkflowTimelineItem[] = [];\n\n for (const event of orderedEvents) {\n timeline.push(buildTimelineItem(event));\n\n switch (event.type) {\n case 'run_started': {\n const payload = event.payload as { startedAtMs: number };\n run.status = 'running';\n run.startedAtMs = payload.startedAtMs;\n break;\n }\n case 'phase_started': {\n const payload = event.payload as { phaseId: string; title: string };\n phaseIdToPhase.set(payload.phaseId, {\n id: payload.phaseId,\n title: payload.title,\n status: 'running',\n startedAtMs: event.createdAtMs,\n agentIds: phaseIdToPhase.get(payload.phaseId)?.agentIds ?? [],\n });\n break;\n }\n case 'phase_completed': {\n const payload = event.payload as { phaseId: string };\n const existing = phaseIdToPhase.get(payload.phaseId);\n if (existing) {\n phaseIdToPhase.set(payload.phaseId, {\n ...existing,\n status: 'completed',\n completedAtMs: event.createdAtMs,\n });\n }\n break;\n }\n case 'agent_queued': {\n const payload = event.payload as { agentId: string; label: string; phaseId?: string; prompt?: string };\n agentIdToAgent.set(payload.agentId, {\n id: payload.agentId,\n label: payload.label,\n phaseId: payload.phaseId,\n status: 'queued',\n prompt: payload.prompt,\n steps: [],\n });\n if (payload.phaseId) {\n const existingPhase = phaseIdToPhase.get(payload.phaseId);\n if (existingPhase && !existingPhase.agentIds.includes(payload.agentId)) {\n phaseIdToPhase.set(payload.phaseId, {\n ...existingPhase,\n agentIds: [...existingPhase.agentIds, payload.agentId],\n });\n }\n }\n break;\n }\n case 'agent_started': {\n const payload = event.payload as { agentId: string };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n status: 'running',\n startedAtMs: event.createdAtMs,\n });\n }\n break;\n }\n case 'agent_step_started': {\n const payload = event.payload as {\n agentId: string;\n stepId: string;\n label: string;\n kind: 'tool' | 'llm' | 'thinking';\n toolName?: string;\n detail?: string;\n };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n currentStep: payload.label,\n steps: [\n ...existing.steps,\n {\n id: payload.stepId,\n label: payload.label,\n kind: payload.kind,\n toolName: payload.toolName,\n detail: payload.detail,\n status: 'running',\n startedAtMs: event.createdAtMs,\n },\n ],\n });\n }\n break;\n }\n case 'agent_step_completed': {\n const payload = event.payload as {\n agentId: string;\n stepId: string;\n status: 'done' | 'error';\n resultPreview?: string;\n error?: string;\n };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n steps: existing.steps.map((step) =>\n step.id === payload.stepId\n ? {\n ...step,\n status: payload.status,\n resultPreview: payload.resultPreview,\n error: payload.error,\n completedAtMs: event.createdAtMs,\n }\n : step,\n ),\n });\n }\n break;\n }\n case 'agent_completed': {\n const payload = event.payload as {\n agentId: string;\n status: WorkflowAgentStatus;\n resultPreview?: string;\n error?: string;\n };\n const existing = agentIdToAgent.get(payload.agentId);\n if (existing) {\n agentIdToAgent.set(payload.agentId, {\n ...existing,\n status: payload.status,\n currentStep: undefined,\n resultPreview: payload.resultPreview,\n error: payload.error,\n completedAtMs: event.createdAtMs,\n });\n }\n break;\n }\n case 'log_appended': {\n const payload = event.payload as { message: string };\n logs.push({ sequence: event.sequence, message: payload.message, createdAtMs: event.createdAtMs });\n break;\n }\n case 'artifact_created': {\n const payload = event.payload as { artifact: WorkflowArtifactRef };\n artifacts.push(payload.artifact);\n run.metrics.artifactCount = artifacts.length;\n break;\n }\n case 'run_completed': {\n const payload = event.payload as { result: WorkflowRun['result'] };\n run.status = 'succeeded';\n run.result = payload.result;\n run.completedAtMs = event.createdAtMs;\n break;\n }\n case 'run_failed': {\n const payload = event.payload as { error: WorkflowRun['error'] };\n run.status = payload.error?.code === 'timeout' ? 'timeout' : 'failed';\n run.error = payload.error;\n run.completedAtMs = event.createdAtMs;\n break;\n }\n case 'run_cancelled': {\n run.status = 'cancelled';\n run.completedAtMs = event.createdAtMs;\n for (const [agentId, agent] of agentIdToAgent) {\n if (agent.status !== 'queued' && agent.status !== 'running') {\n continue;\n }\n agentIdToAgent.set(agentId, {\n ...agent,\n status: 'skipped',\n currentStep: undefined,\n completedAtMs: event.createdAtMs,\n steps: agent.steps.map((step) =>\n step.status === 'running'\n ? { ...step, status: 'error', completedAtMs: event.createdAtMs }\n : step,\n ),\n });\n }\n break;\n }\n case 'run_queued':\n default:\n break;\n }\n }\n\n const agents = [...agentIdToAgent.values()];\n run.metrics.agentCount = agents.length;\n run.metrics.doneAgentCount = agents.filter((agent) => agent.status === 'done').length;\n run.metrics.errorAgentCount = agents.filter((agent) => agent.status === 'error').length;\n run.metrics.skippedAgentCount = agents.filter((agent) => agent.status === 'skipped').length;\n run.metrics.artifactCount = artifacts.length;\n if (run.startedAtMs && run.completedAtMs) {\n run.metrics.durationMs = run.completedAtMs - run.startedAtMs;\n }\n\n const phases = [...phaseIdToPhase.values()].map((phase) => {\n if (phase.status === 'completed' || phase.status === 'failed') {\n return phase;\n }\n const phaseAgents = phase.agentIds\n .map((agentId) => agentIdToAgent.get(agentId)?.status)\n .filter((status): status is WorkflowAgentStatus => Boolean(status));\n return { ...phase, status: phaseStatusAfterAgentStatus(phaseAgents) };\n });\n\n return {\n run,\n phases,\n agents,\n logs,\n artifacts,\n timeline,\n controls: {\n canCancel: !terminalRunStatus(run.status),\n canRetry: terminalRunStatus(run.status),\n canArchive: terminalRunStatus(run.status),\n },\n };\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { workflowStepLabel } from "../../agent/workflow/step-labels.js";
1
2
  import { runWorkflow } from "../../agent/workflow/runtime.js";
2
3
  import "../runtime/script-runtime.js";
3
4
  import { randomUUID } from "node:crypto";
@@ -12,6 +13,7 @@ var WorkflowEngine = class {
12
13
  const phaseTitleToId = buildPhaseTitleToId(definition);
13
14
  let currentPhaseId;
14
15
  let eventQueue = Promise.resolve();
16
+ const progressRecorders = /* @__PURE__ */ new Map();
15
17
  const run = {
16
18
  id: runId,
17
19
  definitionId: definition.id,
@@ -83,12 +85,22 @@ var WorkflowEngine = class {
83
85
  },
84
86
  onAgentEnd: (event) => {
85
87
  const completedStatus = normalizeCompletedAgentStatus(event.status);
88
+ progressRecorders.get(event.id)?.completeOpenSteps(completedStatus === "done" ? "done" : "error");
89
+ progressRecorders.delete(event.id);
86
90
  appendEvent("agent_completed", {
87
91
  agentId: formatRuntimeAgentId(event.id),
88
92
  status: completedStatus,
89
93
  resultPreview: previewWorkflowValue(event.result),
90
94
  error: completedStatus === "error" ? "Subagent failed" : void 0
91
95
  });
96
+ },
97
+ enhanceSubagentRun: (ctx) => {
98
+ const recorder = new AgentProgressRecorder({
99
+ agentId: formatRuntimeAgentId(ctx.id),
100
+ appendEvent
101
+ });
102
+ progressRecorders.set(ctx.id, recorder);
103
+ return { onProgress: (event) => recorder.onProgress(event) };
92
104
  }
93
105
  });
94
106
  await eventQueue;
@@ -105,6 +117,121 @@ var WorkflowEngine = class {
105
117
  return view;
106
118
  }
107
119
  };
120
+ var AgentProgressRecorder = class {
121
+ activeToolStepIds = /* @__PURE__ */ new Map();
122
+ activeIterationStepId = null;
123
+ activeThinkingStepId = null;
124
+ activeLlmStepId = null;
125
+ sequence = 0;
126
+ constructor(options) {
127
+ this.options = options;
128
+ }
129
+ onProgress(event) {
130
+ switch (event.type) {
131
+ case "tool_start":
132
+ this.startToolStep(event);
133
+ return;
134
+ case "tool_end":
135
+ this.completeToolStep(event);
136
+ return;
137
+ case "iteration":
138
+ this.replaceSingletonStep("iteration", this.buildIterationLabel(event.count, event.max), "llm");
139
+ return;
140
+ case "thinking_delta":
141
+ this.ensureSingletonStep("thinking", "Thinking", "thinking");
142
+ return;
143
+ case "text_delta":
144
+ this.ensureSingletonStep("llm", "Writing response", "llm");
145
+ return;
146
+ default: return;
147
+ }
148
+ }
149
+ completeOpenSteps(status) {
150
+ for (const stepId of this.activeToolStepIds.values()) this.options.appendEvent("agent_step_completed", {
151
+ agentId: this.options.agentId,
152
+ stepId,
153
+ status
154
+ });
155
+ this.activeToolStepIds.clear();
156
+ this.completeSingletonStep("iteration", status);
157
+ this.completeSingletonStep("thinking", status);
158
+ this.completeSingletonStep("llm", status);
159
+ }
160
+ startToolStep(event) {
161
+ const stepId = this.nextStepId("tool");
162
+ const { label, detail } = workflowStepLabel(event.toolName, event.args);
163
+ this.activeToolStepIds.set(event.toolCallId, stepId);
164
+ this.options.appendEvent("agent_step_started", {
165
+ agentId: this.options.agentId,
166
+ stepId,
167
+ label,
168
+ kind: "tool",
169
+ toolName: event.toolName,
170
+ detail: detail ?? previewWorkflowValue(event.args)
171
+ });
172
+ }
173
+ completeToolStep(event) {
174
+ const stepId = this.activeToolStepIds.get(event.toolCallId);
175
+ if (!stepId) return;
176
+ this.activeToolStepIds.delete(event.toolCallId);
177
+ this.options.appendEvent("agent_step_completed", {
178
+ agentId: this.options.agentId,
179
+ stepId,
180
+ status: event.isError ? "error" : "done",
181
+ resultPreview: event.resultPreview,
182
+ error: event.error
183
+ });
184
+ }
185
+ replaceSingletonStep(slot, label, kind) {
186
+ this.completeSingletonStep(slot, "done");
187
+ this.ensureSingletonStep(slot, label, kind);
188
+ }
189
+ ensureSingletonStep(slot, label, kind) {
190
+ if (this.getSingletonStepId(slot)) return;
191
+ const stepId = this.nextStepId(slot);
192
+ this.setSingletonStepId(slot, stepId);
193
+ this.options.appendEvent("agent_step_started", {
194
+ agentId: this.options.agentId,
195
+ stepId,
196
+ label,
197
+ kind
198
+ });
199
+ }
200
+ completeSingletonStep(slot, status) {
201
+ const stepId = this.getSingletonStepId(slot);
202
+ if (!stepId) return;
203
+ this.setSingletonStepId(slot, null);
204
+ this.options.appendEvent("agent_step_completed", {
205
+ agentId: this.options.agentId,
206
+ stepId,
207
+ status
208
+ });
209
+ }
210
+ getSingletonStepId(slot) {
211
+ if (slot === "iteration") return this.activeIterationStepId;
212
+ if (slot === "thinking") return this.activeThinkingStepId;
213
+ return this.activeLlmStepId;
214
+ }
215
+ setSingletonStepId(slot, stepId) {
216
+ if (slot === "iteration") {
217
+ this.activeIterationStepId = stepId;
218
+ return;
219
+ }
220
+ if (slot === "thinking") {
221
+ this.activeThinkingStepId = stepId;
222
+ return;
223
+ }
224
+ this.activeLlmStepId = stepId;
225
+ }
226
+ buildIterationLabel(count, max) {
227
+ if (max > 0) return `Iteration ${count}/${max}`;
228
+ return `Iteration ${count}`;
229
+ }
230
+ nextStepId(kind) {
231
+ this.sequence += 1;
232
+ return `${this.options.agentId}-${kind}-${this.sequence}`;
233
+ }
234
+ };
108
235
  function buildPhaseTitleToId(definition) {
109
236
  const phaseTitleToId = /* @__PURE__ */ new Map();
110
237
  for (const phase of definition.phases) phaseTitleToId.set(phase.title, phase.id);
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-engine.js","names":["runWorkflowScript"],"sources":["../../../../src/workflows/engine/workflow-engine.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { WorkflowDefinition } from '../domain/definition.js';\nimport type { WorkflowEventEnvelope, WorkflowEventPayload, WorkflowEventType } from '../domain/event.js';\nimport type { WorkflowRun, WorkflowRunError, WorkflowRunMetadata, WorkflowRunSource, WorkflowRunView } from '../domain/run.js';\nimport type { WorkflowResultEnvelope } from '../domain/result.js';\nimport { WorkflowEventStore } from '../store/event-store.js';\nimport { WorkflowRunStore } from '../store/run-store.js';\nimport { runWorkflowScript } from '../runtime/script-runtime.js';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { WorkflowScriptSubagentRunner } from '../runtime/script-runtime.js';\n\nexport interface WorkflowEngineOptions {\n cwd: string;\n eventStore: WorkflowEventStore;\n runStore: WorkflowRunStore;\n runner: WorkflowScriptSubagentRunner;\n onEventAppended?: (event: WorkflowEventEnvelope) => void;\n onRunViewUpdated?: (view: WorkflowRunView) => void;\n resolveModelId?: (modelId: string) => Model<Api>;\n}\n\nexport interface StartWorkflowRunOptions {\n input?: unknown;\n source: WorkflowRunSource;\n metadata?: WorkflowRunMetadata;\n goal?: string;\n runId?: string;\n signal?: AbortSignal;\n concurrency?: number;\n maxSubagents?: number;\n tokenBudget?: number | null;\n}\n\nexport class WorkflowEngine {\n constructor(private readonly options: WorkflowEngineOptions) {}\n\n async startRun(definition: WorkflowDefinition, options: StartWorkflowRunOptions): Promise<WorkflowRunView> {\n const runId = options.runId ?? randomUUID();\n const createdAtMs = Date.now();\n const phaseTitleToId = buildPhaseTitleToId(definition);\n let currentPhaseId: string | undefined;\n let eventQueue = Promise.resolve();\n\n const run: WorkflowRun = {\n id: runId,\n definitionId: definition.id,\n definitionVersion: definition.version,\n title: definition.title,\n goal: options.goal ?? definition.description,\n input: options.input ?? {},\n status: 'queued',\n source: options.source,\n metadata: options.metadata,\n metrics: {\n agentCount: 0,\n doneAgentCount: 0,\n errorAgentCount: 0,\n skippedAgentCount: 0,\n artifactCount: 0,\n },\n createdAtMs,\n };\n\n const appendEvent = (type: WorkflowEventType, payload: WorkflowEventPayload, createdAtMsOverride?: number) => {\n eventQueue = eventQueue\n .then(() =>\n this.options.eventStore.append({\n runId,\n type,\n payload,\n createdAtMs: createdAtMsOverride,\n }),\n )\n .then(async (event) => {\n this.options.onEventAppended?.(event);\n const view = await this.options.runStore.rebuildRunView(runId);\n if (view) {\n this.options.onRunViewUpdated?.(view);\n }\n });\n return eventQueue;\n };\n\n await appendEvent('run_queued', { run }, createdAtMs);\n await appendEvent('run_started', { startedAtMs: Date.now() });\n\n try {\n const runtimeResult = await runWorkflowScript<unknown>(\n definition.runtime.source,\n {\n runner: this.options.runner,\n resolveModelId: this.options.resolveModelId,\n },\n {\n cwd: this.options.cwd,\n args: options.input,\n signal: options.signal,\n concurrency: options.concurrency ?? definition.defaults.concurrency,\n maxSubagents: options.maxSubagents ?? definition.defaults.maxSubagents,\n tokenBudget: options.tokenBudget,\n onPhase: (title) => {\n const nextPhaseId = phaseTitleToId.get(title) ?? normalizePhaseId(title);\n if (currentPhaseId && currentPhaseId !== nextPhaseId) {\n void appendEvent('phase_completed', { phaseId: currentPhaseId });\n }\n currentPhaseId = nextPhaseId;\n void appendEvent('phase_started', { phaseId: nextPhaseId, title });\n },\n onLog: (message) => {\n void appendEvent('log_appended', { message });\n },\n onAgentQueued: (event) => {\n const phaseId = event.phase ? (phaseTitleToId.get(event.phase) ?? normalizePhaseId(event.phase)) : currentPhaseId;\n void appendEvent('agent_queued', {\n agentId: formatRuntimeAgentId(event.id),\n label: event.label,\n phaseId,\n prompt: event.prompt,\n });\n },\n onAgentStart: (event) => {\n void appendEvent('agent_started', { agentId: formatRuntimeAgentId(event.id) });\n },\n onAgentEnd: (event) => {\n const completedStatus = normalizeCompletedAgentStatus(event.status);\n void appendEvent('agent_completed', {\n agentId: formatRuntimeAgentId(event.id),\n status: completedStatus,\n resultPreview: previewWorkflowValue(event.result),\n error: completedStatus === 'error' ? 'Subagent failed' : undefined,\n });\n },\n },\n );\n\n await eventQueue;\n if (currentPhaseId) {\n await appendEvent('phase_completed', { phaseId: currentPhaseId });\n }\n await appendEvent('run_completed', { result: toWorkflowResultEnvelope(runtimeResult.result) });\n } catch (err) {\n await eventQueue;\n const error = toWorkflowRunError(err, options.signal?.aborted === true);\n if (error.code === 'cancelled') {\n await appendEvent('run_cancelled', { reason: error.message });\n } else {\n await appendEvent('run_failed', { error });\n }\n }\n\n const view = await this.options.runStore.readRunView(runId);\n if (!view) {\n throw new Error(`workflow run view was not created for ${runId}`);\n }\n return view;\n }\n}\n\nfunction buildPhaseTitleToId(definition: WorkflowDefinition): Map<string, string> {\n const phaseTitleToId = new Map<string, string>();\n for (const phase of definition.phases) {\n phaseTitleToId.set(phase.title, phase.id);\n }\n return phaseTitleToId;\n}\n\nfunction normalizePhaseId(title: string): string {\n const normalized = title\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return normalized || 'phase';\n}\n\nfunction formatRuntimeAgentId(id: number): string {\n return `agent-${id}`;\n}\n\nfunction normalizeCompletedAgentStatus(status: string): 'done' | 'error' | 'skipped' {\n if (status === 'done' || status === 'error' || status === 'skipped') {\n return status;\n }\n return 'error';\n}\n\nfunction previewWorkflowValue(value: unknown): string | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n if (typeof value === 'string') {\n return truncate(value, 300);\n }\n try {\n return truncate(JSON.stringify(value), 300);\n } catch {\n return truncate(String(value), 300);\n }\n}\n\nfunction truncate(value: string, maxLength: number): string {\n const trimmed = value.trim();\n if (trimmed.length <= maxLength) {\n return trimmed;\n }\n return `${trimmed.slice(0, maxLength - 1)}…`;\n}\n\nfunction toWorkflowResultEnvelope(value: unknown): WorkflowResultEnvelope {\n if (isWorkflowResultEnvelope(value)) {\n return value;\n }\n if (typeof value === 'string') {\n return {\n summary: truncate(value, 800),\n sections: [{ kind: 'text', title: 'Result', content: value }],\n raw: value,\n };\n }\n return {\n summary: 'Workflow completed.',\n sections: [{ kind: 'json', title: 'Result', value }],\n raw: value,\n };\n}\n\nfunction isWorkflowResultEnvelope(value: unknown): value is WorkflowResultEnvelope {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n const record = value as Partial<WorkflowResultEnvelope>;\n return typeof record.summary === 'string' && Array.isArray(record.sections);\n}\n\nfunction toWorkflowRunError(err: unknown, wasAborted: boolean): WorkflowRunError {\n const message = err instanceof Error ? err.message : String(err);\n if (wasAborted || /aborted|cancelled/i.test(message)) {\n return {\n code: 'cancelled',\n message: message || 'Workflow run cancelled',\n recoverable: true,\n };\n }\n if (/timeout/i.test(message)) {\n return {\n code: 'timeout',\n message,\n recoverable: true,\n };\n }\n if (/quota/i.test(message)) {\n return {\n code: 'agent_quota_exceeded',\n message,\n recoverable: true,\n };\n }\n return {\n code: 'runtime_error',\n message,\n recoverable: false,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"workflow-engine.js","names":["runWorkflowScript"],"sources":["../../../../src/workflows/engine/workflow-engine.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { WorkflowDefinition } from '../domain/definition.js';\nimport type { WorkflowEventEnvelope, WorkflowEventPayload, WorkflowEventType } from '../domain/event.js';\nimport type { WorkflowRun, WorkflowRunError, WorkflowRunMetadata, WorkflowRunSource, WorkflowRunView } from '../domain/run.js';\nimport type { WorkflowResultEnvelope } from '../domain/result.js';\nimport { WorkflowEventStore } from '../store/event-store.js';\nimport { WorkflowRunStore } from '../store/run-store.js';\nimport { runWorkflowScript } from '../runtime/script-runtime.js';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport { workflowStepLabel } from '../../agent/workflow/step-labels.js';\nimport type { SubagentProgressEvent } from '../../agent/workflow/types.js';\nimport type { WorkflowScriptSubagentRunner } from '../runtime/script-runtime.js';\n\nexport interface WorkflowEngineOptions {\n cwd: string;\n eventStore: WorkflowEventStore;\n runStore: WorkflowRunStore;\n runner: WorkflowScriptSubagentRunner;\n onEventAppended?: (event: WorkflowEventEnvelope) => void;\n onRunViewUpdated?: (view: WorkflowRunView) => void;\n resolveModelId?: (modelId: string) => Model<Api>;\n}\n\nexport interface StartWorkflowRunOptions {\n input?: unknown;\n source: WorkflowRunSource;\n metadata?: WorkflowRunMetadata;\n goal?: string;\n runId?: string;\n signal?: AbortSignal;\n concurrency?: number;\n maxSubagents?: number;\n tokenBudget?: number | null;\n}\n\nexport class WorkflowEngine {\n constructor(private readonly options: WorkflowEngineOptions) {}\n\n async startRun(definition: WorkflowDefinition, options: StartWorkflowRunOptions): Promise<WorkflowRunView> {\n const runId = options.runId ?? randomUUID();\n const createdAtMs = Date.now();\n const phaseTitleToId = buildPhaseTitleToId(definition);\n let currentPhaseId: string | undefined;\n let eventQueue = Promise.resolve();\n const progressRecorders = new Map<number, AgentProgressRecorder>();\n\n const run: WorkflowRun = {\n id: runId,\n definitionId: definition.id,\n definitionVersion: definition.version,\n title: definition.title,\n goal: options.goal ?? definition.description,\n input: options.input ?? {},\n status: 'queued',\n source: options.source,\n metadata: options.metadata,\n metrics: {\n agentCount: 0,\n doneAgentCount: 0,\n errorAgentCount: 0,\n skippedAgentCount: 0,\n artifactCount: 0,\n },\n createdAtMs,\n };\n\n const appendEvent = (type: WorkflowEventType, payload: WorkflowEventPayload, createdAtMsOverride?: number) => {\n eventQueue = eventQueue\n .then(() =>\n this.options.eventStore.append({\n runId,\n type,\n payload,\n createdAtMs: createdAtMsOverride,\n }),\n )\n .then(async (event) => {\n this.options.onEventAppended?.(event);\n const view = await this.options.runStore.rebuildRunView(runId);\n if (view) {\n this.options.onRunViewUpdated?.(view);\n }\n });\n return eventQueue;\n };\n\n await appendEvent('run_queued', { run }, createdAtMs);\n await appendEvent('run_started', { startedAtMs: Date.now() });\n\n try {\n const runtimeResult = await runWorkflowScript<unknown>(\n definition.runtime.source,\n {\n runner: this.options.runner,\n resolveModelId: this.options.resolveModelId,\n },\n {\n cwd: this.options.cwd,\n args: options.input,\n signal: options.signal,\n concurrency: options.concurrency ?? definition.defaults.concurrency,\n maxSubagents: options.maxSubagents ?? definition.defaults.maxSubagents,\n tokenBudget: options.tokenBudget,\n onPhase: (title) => {\n const nextPhaseId = phaseTitleToId.get(title) ?? normalizePhaseId(title);\n if (currentPhaseId && currentPhaseId !== nextPhaseId) {\n void appendEvent('phase_completed', { phaseId: currentPhaseId });\n }\n currentPhaseId = nextPhaseId;\n void appendEvent('phase_started', { phaseId: nextPhaseId, title });\n },\n onLog: (message) => {\n void appendEvent('log_appended', { message });\n },\n onAgentQueued: (event) => {\n const phaseId = event.phase ? (phaseTitleToId.get(event.phase) ?? normalizePhaseId(event.phase)) : currentPhaseId;\n void appendEvent('agent_queued', {\n agentId: formatRuntimeAgentId(event.id),\n label: event.label,\n phaseId,\n prompt: event.prompt,\n });\n },\n onAgentStart: (event) => {\n void appendEvent('agent_started', { agentId: formatRuntimeAgentId(event.id) });\n },\n onAgentEnd: (event) => {\n const completedStatus = normalizeCompletedAgentStatus(event.status);\n progressRecorders.get(event.id)?.completeOpenSteps(completedStatus === 'done' ? 'done' : 'error');\n progressRecorders.delete(event.id);\n void appendEvent('agent_completed', {\n agentId: formatRuntimeAgentId(event.id),\n status: completedStatus,\n resultPreview: previewWorkflowValue(event.result),\n error: completedStatus === 'error' ? 'Subagent failed' : undefined,\n });\n },\n enhanceSubagentRun: (ctx) => {\n const recorder = new AgentProgressRecorder({\n agentId: formatRuntimeAgentId(ctx.id),\n appendEvent,\n });\n progressRecorders.set(ctx.id, recorder);\n return { onProgress: (event) => recorder.onProgress(event) };\n },\n },\n );\n\n await eventQueue;\n if (currentPhaseId) {\n await appendEvent('phase_completed', { phaseId: currentPhaseId });\n }\n await appendEvent('run_completed', { result: toWorkflowResultEnvelope(runtimeResult.result) });\n } catch (err) {\n await eventQueue;\n const error = toWorkflowRunError(err, options.signal?.aborted === true);\n if (error.code === 'cancelled') {\n await appendEvent('run_cancelled', { reason: error.message });\n } else {\n await appendEvent('run_failed', { error });\n }\n }\n\n const view = await this.options.runStore.readRunView(runId);\n if (!view) {\n throw new Error(`workflow run view was not created for ${runId}`);\n }\n return view;\n }\n}\n\ntype AppendWorkflowEvent = (\n type: WorkflowEventType,\n payload: WorkflowEventPayload,\n createdAtMsOverride?: number,\n) => Promise<void>;\n\nclass AgentProgressRecorder {\n private readonly activeToolStepIds = new Map<string, string>();\n private activeIterationStepId: string | null = null;\n private activeThinkingStepId: string | null = null;\n private activeLlmStepId: string | null = null;\n private sequence = 0;\n\n constructor(\n private readonly options: {\n agentId: string;\n appendEvent: AppendWorkflowEvent;\n },\n ) {}\n\n onProgress(event: SubagentProgressEvent): void {\n switch (event.type) {\n case 'tool_start':\n this.startToolStep(event);\n return;\n case 'tool_end':\n this.completeToolStep(event);\n return;\n case 'iteration':\n this.replaceSingletonStep('iteration', this.buildIterationLabel(event.count, event.max), 'llm');\n return;\n case 'thinking_delta':\n this.ensureSingletonStep('thinking', 'Thinking', 'thinking');\n return;\n case 'text_delta':\n this.ensureSingletonStep('llm', 'Writing response', 'llm');\n return;\n default:\n return;\n }\n }\n\n completeOpenSteps(status: 'done' | 'error'): void {\n for (const stepId of this.activeToolStepIds.values()) {\n void this.options.appendEvent('agent_step_completed', {\n agentId: this.options.agentId,\n stepId,\n status,\n });\n }\n this.activeToolStepIds.clear();\n this.completeSingletonStep('iteration', status);\n this.completeSingletonStep('thinking', status);\n this.completeSingletonStep('llm', status);\n }\n\n private startToolStep(event: Extract<SubagentProgressEvent, { type: 'tool_start' }>): void {\n const stepId = this.nextStepId('tool');\n const { label, detail } = workflowStepLabel(event.toolName, event.args);\n this.activeToolStepIds.set(event.toolCallId, stepId);\n void this.options.appendEvent('agent_step_started', {\n agentId: this.options.agentId,\n stepId,\n label,\n kind: 'tool',\n toolName: event.toolName,\n detail: detail ?? previewWorkflowValue(event.args),\n });\n }\n\n private completeToolStep(event: Extract<SubagentProgressEvent, { type: 'tool_end' }>): void {\n const stepId = this.activeToolStepIds.get(event.toolCallId);\n if (!stepId) return;\n this.activeToolStepIds.delete(event.toolCallId);\n void this.options.appendEvent('agent_step_completed', {\n agentId: this.options.agentId,\n stepId,\n status: event.isError ? 'error' : 'done',\n resultPreview: event.resultPreview,\n error: event.error,\n });\n }\n\n private replaceSingletonStep(\n slot: 'iteration' | 'thinking' | 'llm',\n label: string,\n kind: 'tool' | 'llm' | 'thinking',\n ): void {\n this.completeSingletonStep(slot, 'done');\n this.ensureSingletonStep(slot, label, kind);\n }\n\n private ensureSingletonStep(\n slot: 'iteration' | 'thinking' | 'llm',\n label: string,\n kind: 'tool' | 'llm' | 'thinking',\n ): void {\n if (this.getSingletonStepId(slot)) return;\n const stepId = this.nextStepId(slot);\n this.setSingletonStepId(slot, stepId);\n void this.options.appendEvent('agent_step_started', {\n agentId: this.options.agentId,\n stepId,\n label,\n kind,\n });\n }\n\n private completeSingletonStep(slot: 'iteration' | 'thinking' | 'llm', status: 'done' | 'error'): void {\n const stepId = this.getSingletonStepId(slot);\n if (!stepId) return;\n this.setSingletonStepId(slot, null);\n void this.options.appendEvent('agent_step_completed', {\n agentId: this.options.agentId,\n stepId,\n status,\n });\n }\n\n private getSingletonStepId(slot: 'iteration' | 'thinking' | 'llm'): string | null {\n if (slot === 'iteration') return this.activeIterationStepId;\n if (slot === 'thinking') return this.activeThinkingStepId;\n return this.activeLlmStepId;\n }\n\n private setSingletonStepId(slot: 'iteration' | 'thinking' | 'llm', stepId: string | null): void {\n if (slot === 'iteration') {\n this.activeIterationStepId = stepId;\n return;\n }\n if (slot === 'thinking') {\n this.activeThinkingStepId = stepId;\n return;\n }\n this.activeLlmStepId = stepId;\n }\n\n private buildIterationLabel(count: number, max: number): string {\n if (max > 0) return `Iteration ${count}/${max}`;\n return `Iteration ${count}`;\n }\n\n private nextStepId(kind: string): string {\n this.sequence += 1;\n return `${this.options.agentId}-${kind}-${this.sequence}`;\n }\n}\n\nfunction buildPhaseTitleToId(definition: WorkflowDefinition): Map<string, string> {\n const phaseTitleToId = new Map<string, string>();\n for (const phase of definition.phases) {\n phaseTitleToId.set(phase.title, phase.id);\n }\n return phaseTitleToId;\n}\n\nfunction normalizePhaseId(title: string): string {\n const normalized = title\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return normalized || 'phase';\n}\n\nfunction formatRuntimeAgentId(id: number): string {\n return `agent-${id}`;\n}\n\nfunction normalizeCompletedAgentStatus(status: string): 'done' | 'error' | 'skipped' {\n if (status === 'done' || status === 'error' || status === 'skipped') {\n return status;\n }\n return 'error';\n}\n\nfunction previewWorkflowValue(value: unknown): string | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n if (typeof value === 'string') {\n return truncate(value, 300);\n }\n try {\n return truncate(JSON.stringify(value), 300);\n } catch {\n return truncate(String(value), 300);\n }\n}\n\nfunction truncate(value: string, maxLength: number): string {\n const trimmed = value.trim();\n if (trimmed.length <= maxLength) {\n return trimmed;\n }\n return `${trimmed.slice(0, maxLength - 1)}…`;\n}\n\nfunction toWorkflowResultEnvelope(value: unknown): WorkflowResultEnvelope {\n if (isWorkflowResultEnvelope(value)) {\n return value;\n }\n if (typeof value === 'string') {\n return {\n summary: truncate(value, 800),\n sections: [{ kind: 'text', title: 'Result', content: value }],\n raw: value,\n };\n }\n return {\n summary: 'Workflow completed.',\n sections: [{ kind: 'json', title: 'Result', value }],\n raw: value,\n };\n}\n\nfunction isWorkflowResultEnvelope(value: unknown): value is WorkflowResultEnvelope {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n const record = value as Partial<WorkflowResultEnvelope>;\n return typeof record.summary === 'string' && Array.isArray(record.sections);\n}\n\nfunction toWorkflowRunError(err: unknown, wasAborted: boolean): WorkflowRunError {\n const message = err instanceof Error ? err.message : String(err);\n if (wasAborted || /aborted|cancelled/i.test(message)) {\n return {\n code: 'cancelled',\n message: message || 'Workflow run cancelled',\n recoverable: true,\n };\n }\n if (/timeout/i.test(message)) {\n return {\n code: 'timeout',\n message,\n recoverable: true,\n };\n }\n if (/quota/i.test(message)) {\n return {\n code: 'agent_quota_exceeded',\n message,\n recoverable: true,\n };\n }\n return {\n code: 'runtime_error',\n message,\n recoverable: false,\n };\n}\n"],"mappings":";;;;;AAqCA,IAAa,iBAAb,MAA4B;CAC1B,YAAY,SAAiD;AAAhC,OAAA,UAAA;;CAE7B,MAAM,SAAS,YAAgC,SAA4D;EACzG,MAAM,QAAQ,QAAQ,SAAS,YAAY;EAC3C,MAAM,cAAc,KAAK,KAAK;EAC9B,MAAM,iBAAiB,oBAAoB,WAAW;EACtD,IAAI;EACJ,IAAI,aAAa,QAAQ,SAAS;EAClC,MAAM,oCAAoB,IAAI,KAAoC;EAElE,MAAM,MAAmB;GACvB,IAAI;GACJ,cAAc,WAAW;GACzB,mBAAmB,WAAW;GAC9B,OAAO,WAAW;GAClB,MAAM,QAAQ,QAAQ,WAAW;GACjC,OAAO,QAAQ,SAAS,EAAE;GAC1B,QAAQ;GACR,QAAQ,QAAQ;GAChB,UAAU,QAAQ;GAClB,SAAS;IACP,YAAY;IACZ,gBAAgB;IAChB,iBAAiB;IACjB,mBAAmB;IACnB,eAAe;IAChB;GACD;GACD;EAED,MAAM,eAAe,MAAyB,SAA+B,wBAAiC;AAC5G,gBAAa,WACV,WACC,KAAK,QAAQ,WAAW,OAAO;IAC7B;IACA;IACA;IACA,aAAa;IACd,CAAC,CACH,CACA,KAAK,OAAO,UAAU;AACrB,SAAK,QAAQ,kBAAkB,MAAM;IACrC,MAAM,OAAO,MAAM,KAAK,QAAQ,SAAS,eAAe,MAAM;AAC9D,QAAI,KACF,MAAK,QAAQ,mBAAmB,KAAK;KAEvC;AACJ,UAAO;;AAGT,QAAM,YAAY,cAAc,EAAE,KAAK,EAAE,YAAY;AACrD,QAAM,YAAY,eAAe,EAAE,aAAa,KAAK,KAAK,EAAE,CAAC;AAE7D,MAAI;GACF,MAAM,gBAAgB,MAAMA,YAC1B,WAAW,QAAQ,QACnB;IACE,QAAQ,KAAK,QAAQ;IACrB,gBAAgB,KAAK,QAAQ;IAC9B,EACD;IACE,KAAK,KAAK,QAAQ;IAClB,MAAM,QAAQ;IACd,QAAQ,QAAQ;IAChB,aAAa,QAAQ,eAAe,WAAW,SAAS;IACxD,cAAc,QAAQ,gBAAgB,WAAW,SAAS;IAC1D,aAAa,QAAQ;IACrB,UAAU,UAAU;KAClB,MAAM,cAAc,eAAe,IAAI,MAAM,IAAI,iBAAiB,MAAM;AACxE,SAAI,kBAAkB,mBAAmB,YAClC,aAAY,mBAAmB,EAAE,SAAS,gBAAgB,CAAC;AAElE,sBAAiB;AACZ,iBAAY,iBAAiB;MAAE,SAAS;MAAa;MAAO,CAAC;;IAEpE,QAAQ,YAAY;AACb,iBAAY,gBAAgB,EAAE,SAAS,CAAC;;IAE/C,gBAAgB,UAAU;KACxB,MAAM,UAAU,MAAM,QAAS,eAAe,IAAI,MAAM,MAAM,IAAI,iBAAiB,MAAM,MAAM,GAAI;AAC9F,iBAAY,gBAAgB;MAC/B,SAAS,qBAAqB,MAAM,GAAG;MACvC,OAAO,MAAM;MACb;MACA,QAAQ,MAAM;MACf,CAAC;;IAEJ,eAAe,UAAU;AAClB,iBAAY,iBAAiB,EAAE,SAAS,qBAAqB,MAAM,GAAG,EAAE,CAAC;;IAEhF,aAAa,UAAU;KACrB,MAAM,kBAAkB,8BAA8B,MAAM,OAAO;AACnE,uBAAkB,IAAI,MAAM,GAAG,EAAE,kBAAkB,oBAAoB,SAAS,SAAS,QAAQ;AACjG,uBAAkB,OAAO,MAAM,GAAG;AAC7B,iBAAY,mBAAmB;MAClC,SAAS,qBAAqB,MAAM,GAAG;MACvC,QAAQ;MACR,eAAe,qBAAqB,MAAM,OAAO;MACjD,OAAO,oBAAoB,UAAU,oBAAoB,KAAA;MAC1D,CAAC;;IAEJ,qBAAqB,QAAQ;KAC3B,MAAM,WAAW,IAAI,sBAAsB;MACzC,SAAS,qBAAqB,IAAI,GAAG;MACrC;MACD,CAAC;AACF,uBAAkB,IAAI,IAAI,IAAI,SAAS;AACvC,YAAO,EAAE,aAAa,UAAU,SAAS,WAAW,MAAM,EAAE;;IAE/D,CACF;AAED,SAAM;AACN,OAAI,eACF,OAAM,YAAY,mBAAmB,EAAE,SAAS,gBAAgB,CAAC;AAEnE,SAAM,YAAY,iBAAiB,EAAE,QAAQ,yBAAyB,cAAc,OAAO,EAAE,CAAC;WACvF,KAAK;AACZ,SAAM;GACN,MAAM,QAAQ,mBAAmB,KAAK,QAAQ,QAAQ,YAAY,KAAK;AACvE,OAAI,MAAM,SAAS,YACjB,OAAM,YAAY,iBAAiB,EAAE,QAAQ,MAAM,SAAS,CAAC;OAE7D,OAAM,YAAY,cAAc,EAAE,OAAO,CAAC;;EAI9C,MAAM,OAAO,MAAM,KAAK,QAAQ,SAAS,YAAY,MAAM;AAC3D,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,yCAAyC,QAAQ;AAEnE,SAAO;;;AAUX,IAAM,wBAAN,MAA4B;CAC1B,oCAAqC,IAAI,KAAqB;CAC9D,wBAA+C;CAC/C,uBAA8C;CAC9C,kBAAyC;CACzC,WAAmB;CAEnB,YACE,SAIA;AAJiB,OAAA,UAAA;;CAMnB,WAAW,OAAoC;AAC7C,UAAQ,MAAM,MAAd;GACE,KAAK;AACH,SAAK,cAAc,MAAM;AACzB;GACF,KAAK;AACH,SAAK,iBAAiB,MAAM;AAC5B;GACF,KAAK;AACH,SAAK,qBAAqB,aAAa,KAAK,oBAAoB,MAAM,OAAO,MAAM,IAAI,EAAE,MAAM;AAC/F;GACF,KAAK;AACH,SAAK,oBAAoB,YAAY,YAAY,WAAW;AAC5D;GACF,KAAK;AACH,SAAK,oBAAoB,OAAO,oBAAoB,MAAM;AAC1D;GACF,QACE;;;CAIN,kBAAkB,QAAgC;AAChD,OAAK,MAAM,UAAU,KAAK,kBAAkB,QAAQ,CAC7C,MAAK,QAAQ,YAAY,wBAAwB;GACpD,SAAS,KAAK,QAAQ;GACtB;GACA;GACD,CAAC;AAEJ,OAAK,kBAAkB,OAAO;AAC9B,OAAK,sBAAsB,aAAa,OAAO;AAC/C,OAAK,sBAAsB,YAAY,OAAO;AAC9C,OAAK,sBAAsB,OAAO,OAAO;;CAG3C,cAAsB,OAAqE;EACzF,MAAM,SAAS,KAAK,WAAW,OAAO;EACtC,MAAM,EAAE,OAAO,WAAW,kBAAkB,MAAM,UAAU,MAAM,KAAK;AACvE,OAAK,kBAAkB,IAAI,MAAM,YAAY,OAAO;AAC/C,OAAK,QAAQ,YAAY,sBAAsB;GAClD,SAAS,KAAK,QAAQ;GACtB;GACA;GACA,MAAM;GACN,UAAU,MAAM;GAChB,QAAQ,UAAU,qBAAqB,MAAM,KAAK;GACnD,CAAC;;CAGJ,iBAAyB,OAAmE;EAC1F,MAAM,SAAS,KAAK,kBAAkB,IAAI,MAAM,WAAW;AAC3D,MAAI,CAAC,OAAQ;AACb,OAAK,kBAAkB,OAAO,MAAM,WAAW;AAC1C,OAAK,QAAQ,YAAY,wBAAwB;GACpD,SAAS,KAAK,QAAQ;GACtB;GACA,QAAQ,MAAM,UAAU,UAAU;GAClC,eAAe,MAAM;GACrB,OAAO,MAAM;GACd,CAAC;;CAGJ,qBACE,MACA,OACA,MACM;AACN,OAAK,sBAAsB,MAAM,OAAO;AACxC,OAAK,oBAAoB,MAAM,OAAO,KAAK;;CAG7C,oBACE,MACA,OACA,MACM;AACN,MAAI,KAAK,mBAAmB,KAAK,CAAE;EACnC,MAAM,SAAS,KAAK,WAAW,KAAK;AACpC,OAAK,mBAAmB,MAAM,OAAO;AAChC,OAAK,QAAQ,YAAY,sBAAsB;GAClD,SAAS,KAAK,QAAQ;GACtB;GACA;GACA;GACD,CAAC;;CAGJ,sBAA8B,MAAwC,QAAgC;EACpG,MAAM,SAAS,KAAK,mBAAmB,KAAK;AAC5C,MAAI,CAAC,OAAQ;AACb,OAAK,mBAAmB,MAAM,KAAK;AAC9B,OAAK,QAAQ,YAAY,wBAAwB;GACpD,SAAS,KAAK,QAAQ;GACtB;GACA;GACD,CAAC;;CAGJ,mBAA2B,MAAuD;AAChF,MAAI,SAAS,YAAa,QAAO,KAAK;AACtC,MAAI,SAAS,WAAY,QAAO,KAAK;AACrC,SAAO,KAAK;;CAGd,mBAA2B,MAAwC,QAA6B;AAC9F,MAAI,SAAS,aAAa;AACxB,QAAK,wBAAwB;AAC7B;;AAEF,MAAI,SAAS,YAAY;AACvB,QAAK,uBAAuB;AAC5B;;AAEF,OAAK,kBAAkB;;CAGzB,oBAA4B,OAAe,KAAqB;AAC9D,MAAI,MAAM,EAAG,QAAO,aAAa,MAAM,GAAG;AAC1C,SAAO,aAAa;;CAGtB,WAAmB,MAAsB;AACvC,OAAK,YAAY;AACjB,SAAO,GAAG,KAAK,QAAQ,QAAQ,GAAG,KAAK,GAAG,KAAK;;;AAInD,SAAS,oBAAoB,YAAqD;CAChF,MAAM,iCAAiB,IAAI,KAAqB;AAChD,MAAK,MAAM,SAAS,WAAW,OAC7B,gBAAe,IAAI,MAAM,OAAO,MAAM,GAAG;AAE3C,QAAO;;AAGT,SAAS,iBAAiB,OAAuB;AAM/C,QALmB,MAChB,MAAM,CACN,aAAa,CACb,QAAQ,eAAe,IAAI,CAC3B,QAAQ,YAAY,GACN,IAAI;;AAGvB,SAAS,qBAAqB,IAAoB;AAChD,QAAO,SAAS;;AAGlB,SAAS,8BAA8B,QAA8C;AACnF,KAAI,WAAW,UAAU,WAAW,WAAW,WAAW,UACxD,QAAO;AAET,QAAO;;AAGT,SAAS,qBAAqB,OAAoC;AAChE,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B;AAEF,KAAI,OAAO,UAAU,SACnB,QAAO,SAAS,OAAO,IAAI;AAE7B,KAAI;AACF,SAAO,SAAS,KAAK,UAAU,MAAM,EAAE,IAAI;SACrC;AACN,SAAO,SAAS,OAAO,MAAM,EAAE,IAAI;;;AAIvC,SAAS,SAAS,OAAe,WAA2B;CAC1D,MAAM,UAAU,MAAM,MAAM;AAC5B,KAAI,QAAQ,UAAU,UACpB,QAAO;AAET,QAAO,GAAG,QAAQ,MAAM,GAAG,YAAY,EAAE,CAAC;;AAG5C,SAAS,yBAAyB,OAAwC;AACxE,KAAI,yBAAyB,MAAM,CACjC,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO;EACL,SAAS,SAAS,OAAO,IAAI;EAC7B,UAAU,CAAC;GAAE,MAAM;GAAQ,OAAO;GAAU,SAAS;GAAO,CAAC;EAC7D,KAAK;EACN;AAEH,QAAO;EACL,SAAS;EACT,UAAU,CAAC;GAAE,MAAM;GAAQ,OAAO;GAAU;GAAO,CAAC;EACpD,KAAK;EACN;;AAGH,SAAS,yBAAyB,OAAiD;AACjF,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,MAAM,CAC7D,QAAO;CAET,MAAM,SAAS;AACf,QAAO,OAAO,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,SAAS;;AAG7E,SAAS,mBAAmB,KAAc,YAAuC;CAC/E,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,KAAI,cAAc,qBAAqB,KAAK,QAAQ,CAClD,QAAO;EACL,MAAM;EACN,SAAS,WAAW;EACpB,aAAa;EACd;AAEH,KAAI,WAAW,KAAK,QAAQ,CAC1B,QAAO;EACL,MAAM;EACN;EACA,aAAa;EACd;AAEH,KAAI,SAAS,KAAK,QAAQ,CACxB,QAAO;EACL,MAAM;EACN;EACA,aAAa;EACd;AAEH,QAAO;EACL,MAAM;EACN;EACA,aAAa;EACd"}
@@ -4,6 +4,7 @@ import { DEFAULT_WORKFLOW_CONCURRENCY, DEFAULT_WORKFLOW_MAX_SUBAGENTS, DEFAULT_W
4
4
  import { isTerminalWorkflowRunStatus } from "./domain/run.js";
5
5
  import { validateWorkflowDefinitionInput } from "./domain/validation.js";
6
6
  import "./domain/index.js";
7
+ import { runViewToSnapshot } from "./service/run-view-to-snapshot.js";
7
8
  import { projectWorkflowRunView } from "./engine/projector.js";
8
9
  import { WorkflowEngine } from "./engine/workflow-engine.js";
9
10
  import "./engine/index.js";
@@ -11,7 +12,6 @@ import { resolveWorkflowRootDir, resolveWorkflowRunArtifactsDir, resolveWorkflow
11
12
  import { WorkflowEventStore, createWorkflowEventStore } from "./store/event-store.js";
12
13
  import { WorkflowRunStore, createWorkflowRunStore } from "./store/run-store.js";
13
14
  import { WorkflowRunService, buildWorkflowRunDefinitionSnapshot, buildWorkflowRunInputEnvelope, buildWorkflowRunMetadata, extractWorkflowRunSessionKey } from "./service/workflow-run-service.js";
14
- import { runViewToSnapshot } from "./service/run-view-to-snapshot.js";
15
15
  import { buildWorkflowRunSessionKey, readWorkflowRunIdFromSessionCustomData } from "./service/workflow-session-key.js";
16
16
  import { WORKFLOW_RUN_LINK_CONTEXT_KIND, WORKFLOW_SESSION_TYPE, WorkflowSessionBridge, formatParentRunLinkText } from "./service/workflow-session-bridge.js";
17
17
  import "./runtime/index.js";
@@ -30,10 +30,12 @@ function runViewToSnapshot(view) {
30
30
  steps: agent.steps?.map((step) => ({
31
31
  id: step.id,
32
32
  kind: step.kind,
33
- toolName: step.kind === "tool" ? step.label : void 0,
33
+ toolName: step.toolName,
34
34
  label: step.label,
35
35
  detail: step.detail,
36
36
  status: step.status,
37
+ resultPreview: step.resultPreview,
38
+ error: step.error,
37
39
  startedAtMs: step.startedAtMs,
38
40
  durationMs: step.startedAtMs != null && step.completedAtMs != null ? step.completedAtMs - step.startedAtMs : void 0
39
41
  }))
@@ -1 +1 @@
1
- {"version":3,"file":"run-view-to-snapshot.js","names":[],"sources":["../../../../src/workflows/service/run-view-to-snapshot.ts"],"sourcesContent":["import type { WorkflowSnapshot } from '../../agent/workflow/types.js';\nimport type { WorkflowRunView } from '../domain/index.js';\n\nfunction agentNumericId(id: string, index: number): number {\n const parsed = Number.parseInt(id, 10);\n if (Number.isFinite(parsed)) return parsed;\n return index + 1;\n}\n\nfunction resolveResultPayload(result: WorkflowRunView['run']['result']): unknown {\n if (result == null) return undefined;\n if (typeof result === 'object' && result !== null && 'raw' in result) {\n const raw = (result as { raw?: unknown }).raw;\n return raw !== undefined ? raw : result;\n }\n return result;\n}\n\n/** Map persisted {@link WorkflowRunView} into chat {@link WorkflowSnapshot}. */\nexport function runViewToSnapshot(view: WorkflowRunView): WorkflowSnapshot {\n const phaseTitleById = new Map(view.phases.map((phase) => [phase.id, phase.title]));\n const runningPhase = view.phases.find((phase) => phase.status === 'running');\n\n const agents = view.agents.map((agent, index) => ({\n id: agentNumericId(agent.id, index),\n label: agent.label,\n phase: agent.phaseId ? phaseTitleById.get(agent.phaseId) : undefined,\n prompt: agent.prompt ?? '',\n status: agent.status,\n resultPreview: agent.resultPreview,\n error: agent.error,\n startedAtMs: agent.startedAtMs,\n durationMs:\n agent.startedAtMs != null && agent.completedAtMs != null\n ? agent.completedAtMs - agent.startedAtMs\n : undefined,\n currentStep: agent.currentStep,\n steps: agent.steps?.map((step) => ({\n id: step.id,\n kind: step.kind,\n toolName: step.kind === 'tool' ? step.label : undefined,\n label: step.label,\n detail: step.detail,\n status: step.status,\n startedAtMs: step.startedAtMs,\n durationMs:\n step.startedAtMs != null && step.completedAtMs != null\n ? step.completedAtMs - step.startedAtMs\n : undefined,\n })),\n }));\n\n const { metrics } = view.run;\n return {\n name: view.run.definitionId,\n description: view.run.goal || view.run.title,\n phases: view.phases.map((phase) => phase.title),\n currentPhase: runningPhase?.title,\n logs: view.logs.map((entry) => entry.message),\n agents,\n agentCount: metrics.agentCount,\n runningCount: Math.max(\n 0,\n metrics.agentCount - metrics.doneAgentCount - metrics.errorAgentCount - metrics.skippedAgentCount,\n ),\n doneCount: metrics.doneAgentCount,\n errorCount: metrics.errorAgentCount,\n skippedCount: metrics.skippedAgentCount,\n durationMs: metrics.durationMs,\n result: resolveResultPayload(view.run.result),\n };\n}\n"],"mappings":";AAGA,SAAS,eAAe,IAAY,OAAuB;CACzD,MAAM,SAAS,OAAO,SAAS,IAAI,GAAG;AACtC,KAAI,OAAO,SAAS,OAAO,CAAE,QAAO;AACpC,QAAO,QAAQ;;AAGjB,SAAS,qBAAqB,QAAmD;AAC/E,KAAI,UAAU,KAAM,QAAO,KAAA;AAC3B,KAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,SAAS,QAAQ;EACpE,MAAM,MAAO,OAA6B;AAC1C,SAAO,QAAQ,KAAA,IAAY,MAAM;;AAEnC,QAAO;;;AAIT,SAAgB,kBAAkB,MAAyC;CACzE,MAAM,iBAAiB,IAAI,IAAI,KAAK,OAAO,KAAK,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;CACnF,MAAM,eAAe,KAAK,OAAO,MAAM,UAAU,MAAM,WAAW,UAAU;CAE5E,MAAM,SAAS,KAAK,OAAO,KAAK,OAAO,WAAW;EAChD,IAAI,eAAe,MAAM,IAAI,MAAM;EACnC,OAAO,MAAM;EACb,OAAO,MAAM,UAAU,eAAe,IAAI,MAAM,QAAQ,GAAG,KAAA;EAC3D,QAAQ,MAAM,UAAU;EACxB,QAAQ,MAAM;EACd,eAAe,MAAM;EACrB,OAAO,MAAM;EACb,aAAa,MAAM;EACnB,YACE,MAAM,eAAe,QAAQ,MAAM,iBAAiB,OAChD,MAAM,gBAAgB,MAAM,cAC5B,KAAA;EACN,aAAa,MAAM;EACnB,OAAO,MAAM,OAAO,KAAK,UAAU;GACjC,IAAI,KAAK;GACT,MAAM,KAAK;GACX,UAAU,KAAK,SAAS,SAAS,KAAK,QAAQ,KAAA;GAC9C,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,QAAQ,KAAK;GACb,aAAa,KAAK;GAClB,YACE,KAAK,eAAe,QAAQ,KAAK,iBAAiB,OAC9C,KAAK,gBAAgB,KAAK,cAC1B,KAAA;GACP,EAAE;EACJ,EAAE;CAEH,MAAM,EAAE,YAAY,KAAK;AACzB,QAAO;EACL,MAAM,KAAK,IAAI;EACf,aAAa,KAAK,IAAI,QAAQ,KAAK,IAAI;EACvC,QAAQ,KAAK,OAAO,KAAK,UAAU,MAAM,MAAM;EAC/C,cAAc,cAAc;EAC5B,MAAM,KAAK,KAAK,KAAK,UAAU,MAAM,QAAQ;EAC7C;EACA,YAAY,QAAQ;EACpB,cAAc,KAAK,IACjB,GACA,QAAQ,aAAa,QAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,kBACjF;EACD,WAAW,QAAQ;EACnB,YAAY,QAAQ;EACpB,cAAc,QAAQ;EACtB,YAAY,QAAQ;EACpB,QAAQ,qBAAqB,KAAK,IAAI,OAAO;EAC9C"}
1
+ {"version":3,"file":"run-view-to-snapshot.js","names":[],"sources":["../../../../src/workflows/service/run-view-to-snapshot.ts"],"sourcesContent":["import type { WorkflowSnapshot } from '../../agent/workflow/types.js';\nimport type { WorkflowRunView } from '../domain/index.js';\n\nfunction agentNumericId(id: string, index: number): number {\n const parsed = Number.parseInt(id, 10);\n if (Number.isFinite(parsed)) return parsed;\n return index + 1;\n}\n\nfunction resolveResultPayload(result: WorkflowRunView['run']['result']): unknown {\n if (result == null) return undefined;\n if (typeof result === 'object' && result !== null && 'raw' in result) {\n const raw = (result as { raw?: unknown }).raw;\n return raw !== undefined ? raw : result;\n }\n return result;\n}\n\n/** Map persisted {@link WorkflowRunView} into chat {@link WorkflowSnapshot}. */\nexport function runViewToSnapshot(view: WorkflowRunView): WorkflowSnapshot {\n const phaseTitleById = new Map(view.phases.map((phase) => [phase.id, phase.title]));\n const runningPhase = view.phases.find((phase) => phase.status === 'running');\n\n const agents = view.agents.map((agent, index) => ({\n id: agentNumericId(agent.id, index),\n label: agent.label,\n phase: agent.phaseId ? phaseTitleById.get(agent.phaseId) : undefined,\n prompt: agent.prompt ?? '',\n status: agent.status,\n resultPreview: agent.resultPreview,\n error: agent.error,\n startedAtMs: agent.startedAtMs,\n durationMs:\n agent.startedAtMs != null && agent.completedAtMs != null\n ? agent.completedAtMs - agent.startedAtMs\n : undefined,\n currentStep: agent.currentStep,\n steps: agent.steps?.map((step) => ({\n id: step.id,\n kind: step.kind,\n toolName: step.toolName,\n label: step.label,\n detail: step.detail,\n status: step.status,\n resultPreview: step.resultPreview,\n error: step.error,\n startedAtMs: step.startedAtMs,\n durationMs:\n step.startedAtMs != null && step.completedAtMs != null\n ? step.completedAtMs - step.startedAtMs\n : undefined,\n })),\n }));\n\n const { metrics } = view.run;\n return {\n name: view.run.definitionId,\n description: view.run.goal || view.run.title,\n phases: view.phases.map((phase) => phase.title),\n currentPhase: runningPhase?.title,\n logs: view.logs.map((entry) => entry.message),\n agents,\n agentCount: metrics.agentCount,\n runningCount: Math.max(\n 0,\n metrics.agentCount - metrics.doneAgentCount - metrics.errorAgentCount - metrics.skippedAgentCount,\n ),\n doneCount: metrics.doneAgentCount,\n errorCount: metrics.errorAgentCount,\n skippedCount: metrics.skippedAgentCount,\n durationMs: metrics.durationMs,\n result: resolveResultPayload(view.run.result),\n };\n}\n"],"mappings":";AAGA,SAAS,eAAe,IAAY,OAAuB;CACzD,MAAM,SAAS,OAAO,SAAS,IAAI,GAAG;AACtC,KAAI,OAAO,SAAS,OAAO,CAAE,QAAO;AACpC,QAAO,QAAQ;;AAGjB,SAAS,qBAAqB,QAAmD;AAC/E,KAAI,UAAU,KAAM,QAAO,KAAA;AAC3B,KAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,SAAS,QAAQ;EACpE,MAAM,MAAO,OAA6B;AAC1C,SAAO,QAAQ,KAAA,IAAY,MAAM;;AAEnC,QAAO;;;AAIT,SAAgB,kBAAkB,MAAyC;CACzE,MAAM,iBAAiB,IAAI,IAAI,KAAK,OAAO,KAAK,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;CACnF,MAAM,eAAe,KAAK,OAAO,MAAM,UAAU,MAAM,WAAW,UAAU;CAE5E,MAAM,SAAS,KAAK,OAAO,KAAK,OAAO,WAAW;EAChD,IAAI,eAAe,MAAM,IAAI,MAAM;EACnC,OAAO,MAAM;EACb,OAAO,MAAM,UAAU,eAAe,IAAI,MAAM,QAAQ,GAAG,KAAA;EAC3D,QAAQ,MAAM,UAAU;EACxB,QAAQ,MAAM;EACd,eAAe,MAAM;EACrB,OAAO,MAAM;EACb,aAAa,MAAM;EACnB,YACE,MAAM,eAAe,QAAQ,MAAM,iBAAiB,OAChD,MAAM,gBAAgB,MAAM,cAC5B,KAAA;EACN,aAAa,MAAM;EACnB,OAAO,MAAM,OAAO,KAAK,UAAU;GACjC,IAAI,KAAK;GACT,MAAM,KAAK;GACX,UAAU,KAAK;GACf,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,QAAQ,KAAK;GACb,eAAe,KAAK;GACpB,OAAO,KAAK;GACZ,aAAa,KAAK;GAClB,YACE,KAAK,eAAe,QAAQ,KAAK,iBAAiB,OAC9C,KAAK,gBAAgB,KAAK,cAC1B,KAAA;GACP,EAAE;EACJ,EAAE;CAEH,MAAM,EAAE,YAAY,KAAK;AACzB,QAAO;EACL,MAAM,KAAK,IAAI;EACf,aAAa,KAAK,IAAI,QAAQ,KAAK,IAAI;EACvC,QAAQ,KAAK,OAAO,KAAK,UAAU,MAAM,MAAM;EAC/C,cAAc,cAAc;EAC5B,MAAM,KAAK,KAAK,KAAK,UAAU,MAAM,QAAQ;EAC7C;EACA,YAAY,QAAQ;EACpB,cAAc,KAAK,IACjB,GACA,QAAQ,aAAa,QAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,kBACjF;EACD,WAAW,QAAQ;EACnB,YAAY,QAAQ;EACpB,cAAc,QAAQ;EACtB,YAAY,QAAQ;EACpB,QAAQ,qBAAqB,KAAK,IAAI,OAAO;EAC9C"}
@@ -19,6 +19,7 @@ export declare class WorkflowRunService {
19
19
  retryWorkflowRun(params: RetryWorkflowRunServiceParams): Promise<WorkflowRunServiceResult>;
20
20
  cancelWorkflowRun(params: CancelWorkflowRunServiceParams): Promise<CancelWorkflowRunResult>;
21
21
  createRunStore(agentId: string): WorkflowRunStore;
22
+ readWorkflowRunView(agentId: string, runId: string): Promise<import("../index.js").WorkflowRunView>;
22
23
  private loadDefinition;
23
24
  private createWorkflowEngine;
24
25
  }
@@ -2,10 +2,10 @@ import { extractProfileAgentId } from "../../config/agent-profile.js";
2
2
  import { init_providers, resolveModel } from "../../providers/index.js";
3
3
  import { createWorkflowCatalog } from "../../agent/workflow/catalog.js";
4
4
  import { DelegateSubagentRunner } from "../../agent/workflow/subagent-runner.js";
5
- import { resolveModelRef } from "../../config/agent-typed-models.js";
6
5
  import { buildWorkflowDefinition } from "../domain/definition-utils.js";
7
6
  import { isTerminalWorkflowRunStatus } from "../domain/run.js";
8
7
  import "../domain/index.js";
8
+ import { resolveModelRef } from "../../config/agent-typed-models.js";
9
9
  import { WorkflowEngine } from "../engine/workflow-engine.js";
10
10
  import "../engine/index.js";
11
11
  import { WorkflowEventStore } from "../store/event-store.js";
@@ -143,6 +143,9 @@ var WorkflowRunService = class {
143
143
  const eventStore = new WorkflowEventStore(this.options.service.currentConfig, agentId);
144
144
  return new WorkflowRunStore(this.options.service.currentConfig, agentId, eventStore);
145
145
  }
146
+ async readWorkflowRunView(agentId, runId) {
147
+ return this.createRunStore(agentId).readRunView(runId);
148
+ }
146
149
  loadDefinition(definitionId) {
147
150
  const catalog = createWorkflowCatalog();
148
151
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run-service.js","names":["resolveModelById"],"sources":["../../../../src/workflows/service/workflow-run-service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\n\nimport type { BuildChildToolsOptions } from '../../agent/child-agent-factory.js';\nimport { extractProfileAgentId } from '../../config/agent-profile.js';\nimport { resolveModelRef } from '../../config/agent-typed-models.js';\nimport type { GatewayWorkflowHost } from '../../gateway/gateway-workflow-host.types.js';\nimport { resolveModel as resolveModelById } from '../../providers/index.js';\nimport { createWorkflowCatalog } from '../../agent/workflow/catalog.js';\nimport { DelegateSubagentRunner } from '../../agent/workflow/subagent-runner.js';\nimport type {\n WorkflowDefinition,\n WorkflowRunDefinitionSnapshot,\n WorkflowRunInputEnvelope,\n WorkflowRunMetadata,\n WorkflowRunSource,\n} from '../domain/index.js';\nimport { buildWorkflowDefinition, isTerminalWorkflowRunStatus } from '../domain/index.js';\nimport { WorkflowEngine } from '../engine/index.js';\nimport { WorkflowEventStore } from '../store/event-store.js';\nimport { WorkflowRunStore } from '../store/run-store.js';\nimport type { WorkflowSessionBridge } from './workflow-session-bridge.js';\nexport type {\n CancelWorkflowRunResult,\n CancelWorkflowRunServiceParams,\n CancelWorkflowRunServiceResult,\n RetryWorkflowRunServiceParams,\n StartWorkflowRunServiceParams,\n StartWorkflowRunServiceResult,\n WorkflowRunServiceErrorCode,\n WorkflowRunServiceErrorResult,\n WorkflowRunServiceResult,\n} from './workflow-run-service.types.js';\n\nimport type {\n CancelWorkflowRunResult,\n CancelWorkflowRunServiceParams,\n RetryWorkflowRunServiceParams,\n StartWorkflowRunServiceParams,\n WorkflowRunServiceResult,\n} from './workflow-run-service.types.js';\n\nexport interface WorkflowRunServiceOptions {\n service: GatewayWorkflowHost;\n sessionBridge: WorkflowSessionBridge;\n buildChildTools: (childOptions: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class WorkflowRunService {\n private readonly activeRuns = new Map<string, AbortController>();\n\n constructor(private readonly options: WorkflowRunServiceOptions) {}\n\n async startWorkflowRun(params: StartWorkflowRunServiceParams): Promise<WorkflowRunServiceResult> {\n const definition = this.loadDefinition(params.definitionId);\n if (!definition) {\n return {\n ok: false,\n code: 'definition_not_found',\n message: 'Workflow definition not found',\n httpStatus: 404,\n };\n }\n\n const runId = randomUUID();\n const goal = params.goal ?? '';\n const { sessionKey } = await this.options.sessionBridge.prepareRunSession({\n runId,\n agentId: params.agentId,\n definitionId: params.definitionId,\n definitionTitle: definition.title,\n goal,\n parentSessionKey: params.parentSessionKey,\n });\n const source = normalizeWorkflowRunSourceForSession(params.source, sessionKey, params.parentSessionKey);\n const abortController = new AbortController();\n const eventStore = new WorkflowEventStore(this.options.service.currentConfig, params.agentId);\n const runStore = new WorkflowRunStore(this.options.service.currentConfig, params.agentId, eventStore);\n const engine = this.createWorkflowEngine({\n eventStore,\n runStore,\n sessionKey,\n });\n const inputEnvelope = params.inputEnvelope ?? buildWorkflowRunInputEnvelope(params.input, params.goal);\n\n this.activeRuns.set(runId, abortController);\n void engine.startRun(definition, {\n runId,\n input: inputEnvelope.payload,\n goal: inputEnvelope.goal ?? params.goal,\n source,\n metadata: buildWorkflowRunMetadata({\n definition,\n agentId: params.agentId,\n sessionKey,\n source,\n input: inputEnvelope,\n retryOfRunId: params.retryOfRunId,\n idempotencyKey: params.idempotencyKey,\n }),\n signal: abortController.signal,\n concurrency: params.concurrency,\n maxSubagents: params.maxSubagents,\n tokenBudget: params.tokenBudget,\n }).catch((err) => {\n this.options.service.emit('workflow.run.error', {\n runId,\n error: err instanceof Error ? err.message : String(err),\n });\n }).finally(() => {\n this.activeRuns.delete(runId);\n });\n\n return { ok: true, runId, sessionKey };\n }\n\n async retryWorkflowRun(params: RetryWorkflowRunServiceParams): Promise<WorkflowRunServiceResult> {\n const runStore = this.createRunStore(params.agentId);\n const existing = await runStore.readRunView(params.runId);\n if (!existing) {\n return {\n ok: false,\n code: 'run_not_found',\n message: 'Workflow run not found',\n httpStatus: 404,\n };\n }\n\n const parentSessionKey =\n existing.run.source.kind === 'chat' ? existing.run.source.sessionKey : undefined;\n\n return this.startWorkflowRun({\n agentId: params.agentId,\n definitionId: existing.run.definitionId,\n input: existing.run.input,\n goal: existing.run.goal,\n source: existing.run.source,\n parentSessionKey,\n retryOfRunId: existing.run.id,\n });\n }\n\n async cancelWorkflowRun(params: CancelWorkflowRunServiceParams): Promise<CancelWorkflowRunResult> {\n const controller = this.activeRuns.get(params.runId);\n if (controller) {\n controller.abort();\n this.activeRuns.delete(params.runId);\n return { ok: true, cancelled: true };\n }\n\n const runStore = this.createRunStore(params.agentId);\n const view = await runStore.readRunView(params.runId);\n if (!view) {\n return {\n ok: false,\n code: 'run_not_found',\n message: 'Workflow run not found',\n httpStatus: 404,\n };\n }\n\n if (isTerminalWorkflowRunStatus(view.run.status)) {\n return { ok: true, cancelled: true, alreadyFinished: true };\n }\n\n const eventStore = new WorkflowEventStore(this.options.service.currentConfig, params.agentId);\n await eventStore.append({\n runId: params.runId,\n type: 'run_cancelled',\n payload: { reason: params.reason ?? 'Cancelled by user' },\n });\n const updated = await runStore.rebuildRunView(params.runId);\n if (updated) {\n this.options.service.emit('workflow.run.updated', { runId: params.runId, view: updated });\n void this.options.sessionBridge.handleRunViewUpdated(updated);\n }\n return { ok: true, cancelled: true };\n }\n\n createRunStore(agentId: string): WorkflowRunStore {\n const eventStore = new WorkflowEventStore(this.options.service.currentConfig, agentId);\n return new WorkflowRunStore(this.options.service.currentConfig, agentId, eventStore);\n }\n\n private loadDefinition(definitionId: string): WorkflowDefinition | null {\n const catalog = createWorkflowCatalog();\n try {\n const loaded = catalog.load(definitionId);\n return buildWorkflowDefinition({\n name: loaded.name,\n source: loaded.source,\n script: loaded.script,\n meta: loaded.meta,\n });\n } catch {\n return null;\n }\n }\n\n private createWorkflowEngine(params: {\n eventStore: WorkflowEventStore;\n runStore: WorkflowRunStore;\n sessionKey: string;\n }): WorkflowEngine {\n const gatewayService = this.options.service;\n const runner = new DelegateSubagentRunner({\n workspace: gatewayService.currentWorkspacePath,\n bus: gatewayService.messageBusInstance,\n getDefaultModel: () => resolveModelById(gatewayService.agentService.getModelForSession(params.sessionKey)),\n getConfig: () => gatewayService.currentConfig,\n buildChildTools: (childOptions) => this.options.buildChildTools(childOptions),\n });\n\n return new WorkflowEngine({\n cwd: gatewayService.currentWorkspacePath,\n eventStore: params.eventStore,\n runStore: params.runStore,\n runner,\n resolveModelId: (modelId) => {\n const agentId = extractProfileAgentId(params.sessionKey, gatewayService.currentConfig);\n return resolveModelById(resolveModelRef(gatewayService.currentConfig, agentId, modelId));\n },\n onEventAppended: (event) => {\n gatewayService.emit('workflow.event.appended', { runId: event.runId, event });\n },\n onRunViewUpdated: (view) => {\n gatewayService.emit('workflow.run.updated', { runId: view.run.id, view });\n void this.options.sessionBridge.handleRunViewUpdated(view);\n },\n });\n }\n}\n\nfunction normalizeWorkflowRunSourceForSession(\n source: WorkflowRunSource,\n workflowSessionKey: string,\n parentSessionKey?: string,\n): WorkflowRunSource {\n if (parentSessionKey?.trim()) {\n return { kind: 'chat', sessionKey: parentSessionKey.trim() };\n }\n if (source.kind === 'webui') {\n return { ...source, sessionKey: workflowSessionKey };\n }\n if (source.kind === 'chat') {\n return source;\n }\n return source;\n}\n\nexport function buildWorkflowRunInputEnvelope(input: unknown, goal?: string): WorkflowRunInputEnvelope {\n if (isWorkflowRunInputEnvelope(input)) {\n return input;\n }\n return {\n payload: input ?? {},\n goal,\n };\n}\n\nexport function buildWorkflowRunMetadata(params: {\n definition: WorkflowDefinition;\n agentId: string;\n sessionKey: string;\n source: WorkflowRunSource;\n input: WorkflowRunInputEnvelope;\n retryOfRunId?: string;\n idempotencyKey?: string;\n}): WorkflowRunMetadata {\n return {\n sessionKey: params.sessionKey,\n triggerSource: params.source.kind,\n agentId: params.agentId,\n retryOfRunId: params.retryOfRunId,\n definition: buildWorkflowRunDefinitionSnapshot(params.definition),\n input: params.input,\n correlation: {\n idempotencyKey: params.idempotencyKey,\n },\n origin: buildWorkflowRunOrigin(params.source),\n schedule: params.source.kind === 'cron'\n ? { scheduleId: params.source.scheduleId, fireId: params.source.fireId }\n : undefined,\n };\n}\n\nexport function buildWorkflowRunDefinitionSnapshot(definition: WorkflowDefinition): WorkflowRunDefinitionSnapshot {\n return {\n id: definition.id,\n name: definition.name,\n title: definition.title,\n version: definition.version,\n source: definition.metadata.source,\n tags: [...definition.metadata.tags],\n phaseCount: definition.phases.length,\n estimatedAgents: definition.metadata.estimatedAgents,\n };\n}\n\nexport function extractWorkflowRunSessionKey(source: WorkflowRunSource): string | null {\n if ('sessionKey' in source && typeof source.sessionKey === 'string' && source.sessionKey.trim()) {\n return source.sessionKey.trim();\n }\n return null;\n}\n\nfunction buildWorkflowRunOrigin(source: WorkflowRunSource): WorkflowRunMetadata['origin'] {\n switch (source.kind) {\n case 'chat':\n return { channel: 'chat', sessionKey: source.sessionKey, messageId: source.messageId };\n case 'webui':\n return { channel: 'webui', sessionKey: source.sessionKey };\n case 'cron':\n return { channel: 'cron', scheduleId: source.scheduleId, fireId: source.fireId };\n case 'api':\n return { channel: 'api', requestId: source.requestId };\n case 'im':\n return { channel: source.channel, chatId: source.chatId, messageId: source.messageId };\n }\n}\n\nfunction isWorkflowRunInputEnvelope(input: unknown): input is WorkflowRunInputEnvelope {\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n return false;\n }\n return 'payload' in input || 'variables' in input || 'context' in input;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"workflow-run-service.js","names":["resolveModelById"],"sources":["../../../../src/workflows/service/workflow-run-service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\n\nimport type { BuildChildToolsOptions } from '../../agent/child-agent-factory.js';\nimport { extractProfileAgentId } from '../../config/agent-profile.js';\nimport { resolveModelRef } from '../../config/agent-typed-models.js';\nimport type { GatewayWorkflowHost } from '../../gateway/gateway-workflow-host.types.js';\nimport { resolveModel as resolveModelById } from '../../providers/index.js';\nimport { createWorkflowCatalog } from '../../agent/workflow/catalog.js';\nimport { DelegateSubagentRunner } from '../../agent/workflow/subagent-runner.js';\nimport type {\n WorkflowDefinition,\n WorkflowRunDefinitionSnapshot,\n WorkflowRunInputEnvelope,\n WorkflowRunMetadata,\n WorkflowRunSource,\n} from '../domain/index.js';\nimport { buildWorkflowDefinition, isTerminalWorkflowRunStatus } from '../domain/index.js';\nimport { WorkflowEngine } from '../engine/index.js';\nimport { WorkflowEventStore } from '../store/event-store.js';\nimport { WorkflowRunStore } from '../store/run-store.js';\nimport type { WorkflowSessionBridge } from './workflow-session-bridge.js';\nexport type {\n CancelWorkflowRunResult,\n CancelWorkflowRunServiceParams,\n CancelWorkflowRunServiceResult,\n RetryWorkflowRunServiceParams,\n StartWorkflowRunServiceParams,\n StartWorkflowRunServiceResult,\n WorkflowRunServiceErrorCode,\n WorkflowRunServiceErrorResult,\n WorkflowRunServiceResult,\n} from './workflow-run-service.types.js';\n\nimport type {\n CancelWorkflowRunResult,\n CancelWorkflowRunServiceParams,\n RetryWorkflowRunServiceParams,\n StartWorkflowRunServiceParams,\n WorkflowRunServiceResult,\n} from './workflow-run-service.types.js';\n\nexport interface WorkflowRunServiceOptions {\n service: GatewayWorkflowHost;\n sessionBridge: WorkflowSessionBridge;\n buildChildTools: (childOptions: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class WorkflowRunService {\n private readonly activeRuns = new Map<string, AbortController>();\n\n constructor(private readonly options: WorkflowRunServiceOptions) {}\n\n async startWorkflowRun(params: StartWorkflowRunServiceParams): Promise<WorkflowRunServiceResult> {\n const definition = this.loadDefinition(params.definitionId);\n if (!definition) {\n return {\n ok: false,\n code: 'definition_not_found',\n message: 'Workflow definition not found',\n httpStatus: 404,\n };\n }\n\n const runId = randomUUID();\n const goal = params.goal ?? '';\n const { sessionKey } = await this.options.sessionBridge.prepareRunSession({\n runId,\n agentId: params.agentId,\n definitionId: params.definitionId,\n definitionTitle: definition.title,\n goal,\n parentSessionKey: params.parentSessionKey,\n });\n const source = normalizeWorkflowRunSourceForSession(params.source, sessionKey, params.parentSessionKey);\n const abortController = new AbortController();\n const eventStore = new WorkflowEventStore(this.options.service.currentConfig, params.agentId);\n const runStore = new WorkflowRunStore(this.options.service.currentConfig, params.agentId, eventStore);\n const engine = this.createWorkflowEngine({\n eventStore,\n runStore,\n sessionKey,\n });\n const inputEnvelope = params.inputEnvelope ?? buildWorkflowRunInputEnvelope(params.input, params.goal);\n\n this.activeRuns.set(runId, abortController);\n void engine.startRun(definition, {\n runId,\n input: inputEnvelope.payload,\n goal: inputEnvelope.goal ?? params.goal,\n source,\n metadata: buildWorkflowRunMetadata({\n definition,\n agentId: params.agentId,\n sessionKey,\n source,\n input: inputEnvelope,\n retryOfRunId: params.retryOfRunId,\n idempotencyKey: params.idempotencyKey,\n }),\n signal: abortController.signal,\n concurrency: params.concurrency,\n maxSubagents: params.maxSubagents,\n tokenBudget: params.tokenBudget,\n }).catch((err) => {\n this.options.service.emit('workflow.run.error', {\n runId,\n error: err instanceof Error ? err.message : String(err),\n });\n }).finally(() => {\n this.activeRuns.delete(runId);\n });\n\n return { ok: true, runId, sessionKey };\n }\n\n async retryWorkflowRun(params: RetryWorkflowRunServiceParams): Promise<WorkflowRunServiceResult> {\n const runStore = this.createRunStore(params.agentId);\n const existing = await runStore.readRunView(params.runId);\n if (!existing) {\n return {\n ok: false,\n code: 'run_not_found',\n message: 'Workflow run not found',\n httpStatus: 404,\n };\n }\n\n const parentSessionKey =\n existing.run.source.kind === 'chat' ? existing.run.source.sessionKey : undefined;\n\n return this.startWorkflowRun({\n agentId: params.agentId,\n definitionId: existing.run.definitionId,\n input: existing.run.input,\n goal: existing.run.goal,\n source: existing.run.source,\n parentSessionKey,\n retryOfRunId: existing.run.id,\n });\n }\n\n async cancelWorkflowRun(params: CancelWorkflowRunServiceParams): Promise<CancelWorkflowRunResult> {\n const controller = this.activeRuns.get(params.runId);\n if (controller) {\n controller.abort();\n this.activeRuns.delete(params.runId);\n return { ok: true, cancelled: true };\n }\n\n const runStore = this.createRunStore(params.agentId);\n const view = await runStore.readRunView(params.runId);\n if (!view) {\n return {\n ok: false,\n code: 'run_not_found',\n message: 'Workflow run not found',\n httpStatus: 404,\n };\n }\n\n if (isTerminalWorkflowRunStatus(view.run.status)) {\n return { ok: true, cancelled: true, alreadyFinished: true };\n }\n\n const eventStore = new WorkflowEventStore(this.options.service.currentConfig, params.agentId);\n await eventStore.append({\n runId: params.runId,\n type: 'run_cancelled',\n payload: { reason: params.reason ?? 'Cancelled by user' },\n });\n const updated = await runStore.rebuildRunView(params.runId);\n if (updated) {\n this.options.service.emit('workflow.run.updated', { runId: params.runId, view: updated });\n void this.options.sessionBridge.handleRunViewUpdated(updated);\n }\n return { ok: true, cancelled: true };\n }\n\n createRunStore(agentId: string): WorkflowRunStore {\n const eventStore = new WorkflowEventStore(this.options.service.currentConfig, agentId);\n return new WorkflowRunStore(this.options.service.currentConfig, agentId, eventStore);\n }\n\n async readWorkflowRunView(agentId: string, runId: string) {\n return this.createRunStore(agentId).readRunView(runId);\n }\n\n private loadDefinition(definitionId: string): WorkflowDefinition | null {\n const catalog = createWorkflowCatalog();\n try {\n const loaded = catalog.load(definitionId);\n return buildWorkflowDefinition({\n name: loaded.name,\n source: loaded.source,\n script: loaded.script,\n meta: loaded.meta,\n });\n } catch {\n return null;\n }\n }\n\n private createWorkflowEngine(params: {\n eventStore: WorkflowEventStore;\n runStore: WorkflowRunStore;\n sessionKey: string;\n }): WorkflowEngine {\n const gatewayService = this.options.service;\n const runner = new DelegateSubagentRunner({\n workspace: gatewayService.currentWorkspacePath,\n bus: gatewayService.messageBusInstance,\n getDefaultModel: () => resolveModelById(gatewayService.agentService.getModelForSession(params.sessionKey)),\n getConfig: () => gatewayService.currentConfig,\n buildChildTools: (childOptions) => this.options.buildChildTools(childOptions),\n });\n\n return new WorkflowEngine({\n cwd: gatewayService.currentWorkspacePath,\n eventStore: params.eventStore,\n runStore: params.runStore,\n runner,\n resolveModelId: (modelId) => {\n const agentId = extractProfileAgentId(params.sessionKey, gatewayService.currentConfig);\n return resolveModelById(resolveModelRef(gatewayService.currentConfig, agentId, modelId));\n },\n onEventAppended: (event) => {\n gatewayService.emit('workflow.event.appended', { runId: event.runId, event });\n },\n onRunViewUpdated: (view) => {\n gatewayService.emit('workflow.run.updated', { runId: view.run.id, view });\n void this.options.sessionBridge.handleRunViewUpdated(view);\n },\n });\n }\n}\n\nfunction normalizeWorkflowRunSourceForSession(\n source: WorkflowRunSource,\n workflowSessionKey: string,\n parentSessionKey?: string,\n): WorkflowRunSource {\n if (parentSessionKey?.trim()) {\n return { kind: 'chat', sessionKey: parentSessionKey.trim() };\n }\n if (source.kind === 'webui') {\n return { ...source, sessionKey: workflowSessionKey };\n }\n if (source.kind === 'chat') {\n return source;\n }\n return source;\n}\n\nexport function buildWorkflowRunInputEnvelope(input: unknown, goal?: string): WorkflowRunInputEnvelope {\n if (isWorkflowRunInputEnvelope(input)) {\n return input;\n }\n return {\n payload: input ?? {},\n goal,\n };\n}\n\nexport function buildWorkflowRunMetadata(params: {\n definition: WorkflowDefinition;\n agentId: string;\n sessionKey: string;\n source: WorkflowRunSource;\n input: WorkflowRunInputEnvelope;\n retryOfRunId?: string;\n idempotencyKey?: string;\n}): WorkflowRunMetadata {\n return {\n sessionKey: params.sessionKey,\n triggerSource: params.source.kind,\n agentId: params.agentId,\n retryOfRunId: params.retryOfRunId,\n definition: buildWorkflowRunDefinitionSnapshot(params.definition),\n input: params.input,\n correlation: {\n idempotencyKey: params.idempotencyKey,\n },\n origin: buildWorkflowRunOrigin(params.source),\n schedule: params.source.kind === 'cron'\n ? { scheduleId: params.source.scheduleId, fireId: params.source.fireId }\n : undefined,\n };\n}\n\nexport function buildWorkflowRunDefinitionSnapshot(definition: WorkflowDefinition): WorkflowRunDefinitionSnapshot {\n return {\n id: definition.id,\n name: definition.name,\n title: definition.title,\n version: definition.version,\n source: definition.metadata.source,\n tags: [...definition.metadata.tags],\n phaseCount: definition.phases.length,\n estimatedAgents: definition.metadata.estimatedAgents,\n };\n}\n\nexport function extractWorkflowRunSessionKey(source: WorkflowRunSource): string | null {\n if ('sessionKey' in source && typeof source.sessionKey === 'string' && source.sessionKey.trim()) {\n return source.sessionKey.trim();\n }\n return null;\n}\n\nfunction buildWorkflowRunOrigin(source: WorkflowRunSource): WorkflowRunMetadata['origin'] {\n switch (source.kind) {\n case 'chat':\n return { channel: 'chat', sessionKey: source.sessionKey, messageId: source.messageId };\n case 'webui':\n return { channel: 'webui', sessionKey: source.sessionKey };\n case 'cron':\n return { channel: 'cron', scheduleId: source.scheduleId, fireId: source.fireId };\n case 'api':\n return { channel: 'api', requestId: source.requestId };\n case 'im':\n return { channel: source.channel, chatId: source.chatId, messageId: source.messageId };\n }\n}\n\nfunction isWorkflowRunInputEnvelope(input: unknown): input is WorkflowRunInputEnvelope {\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n return false;\n }\n return 'payload' in input || 'variables' in input || 'context' in input;\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { appendPiTranscriptContextEntry, appendPiTranscriptMessage } from "../../session/parity/jsonl-transcript-io.js";
2
2
  import { renderWorkflowText } from "../../agent/workflow/snapshot.js";
3
- import "../../session/types.js";
4
3
  import { isTerminalWorkflowRunStatus } from "../domain/run.js";
5
4
  import "../domain/index.js";
6
5
  import { runViewToSnapshot } from "./run-view-to-snapshot.js";
6
+ import "../../session/types.js";
7
7
  import { buildWorkflowRunSessionKey } from "./workflow-session-key.js";
8
8
  import { randomUUID } from "node:crypto";
9
9
  //#region src/workflows/service/workflow-session-bridge.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.89",
3
+ "version": "0.0.91",
4
4
  "description": "The OPC workstation that grows with you: AI assistant for One Person Companies — CLI, gateway, multi-channel (Telegram/WeChat), 20+ LLM providers via pi-ai, extensions and skills.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",