@xrkseek/harness 0.4.8 → 0.4.9

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 (242) hide show
  1. package/node_modules/@xrkseek/cordis/LICENSE +21 -0
  2. package/node_modules/@xrkseek/cordis/README.md +14 -0
  3. package/node_modules/@xrkseek/cordis/bin.js +16 -0
  4. package/node_modules/@xrkseek/cordis/lib/index.js +1828 -0
  5. package/node_modules/@xrkseek/cordis/lib/types/context.d.ts +101 -0
  6. package/node_modules/@xrkseek/cordis/lib/types/context.d.ts.map +1 -0
  7. package/node_modules/@xrkseek/cordis/lib/types/events.d.ts +240 -0
  8. package/node_modules/@xrkseek/cordis/lib/types/events.d.ts.map +1 -0
  9. package/node_modules/@xrkseek/cordis/lib/types/fiber.d.ts +202 -0
  10. package/node_modules/@xrkseek/cordis/lib/types/fiber.d.ts.map +1 -0
  11. package/node_modules/@xrkseek/cordis/lib/types/index.d.ts +15 -0
  12. package/node_modules/@xrkseek/cordis/lib/types/index.d.ts.map +1 -0
  13. package/node_modules/@xrkseek/cordis/lib/types/logger.d.ts +105 -0
  14. package/node_modules/@xrkseek/cordis/lib/types/logger.d.ts.map +1 -0
  15. package/node_modules/@xrkseek/cordis/lib/types/reflect.d.ts +186 -0
  16. package/node_modules/@xrkseek/cordis/lib/types/reflect.d.ts.map +1 -0
  17. package/node_modules/@xrkseek/cordis/lib/types/registry.d.ts +201 -0
  18. package/node_modules/@xrkseek/cordis/lib/types/registry.d.ts.map +1 -0
  19. package/node_modules/@xrkseek/cordis/lib/types/service.d.ts +55 -0
  20. package/node_modules/@xrkseek/cordis/lib/types/service.d.ts.map +1 -0
  21. package/node_modules/@xrkseek/cordis/lib/types/utils.d.ts +62 -0
  22. package/node_modules/@xrkseek/cordis/lib/types/utils.d.ts.map +1 -0
  23. package/node_modules/@xrkseek/cordis/package.json +49 -0
  24. package/node_modules/@xrkseek/cordis/src/context.d.ts +101 -0
  25. package/node_modules/@xrkseek/cordis/src/context.d.ts.map +1 -0
  26. package/node_modules/@xrkseek/cordis/src/context.js +99 -0
  27. package/node_modules/@xrkseek/cordis/src/context.js.map +1 -0
  28. package/node_modules/@xrkseek/cordis/src/context.ts +146 -0
  29. package/node_modules/@xrkseek/cordis/src/events.d.ts +240 -0
  30. package/node_modules/@xrkseek/cordis/src/events.d.ts.map +1 -0
  31. package/node_modules/@xrkseek/cordis/src/events.js +199 -0
  32. package/node_modules/@xrkseek/cordis/src/events.js.map +1 -0
  33. package/node_modules/@xrkseek/cordis/src/events.ts +352 -0
  34. package/node_modules/@xrkseek/cordis/src/fiber.d.ts +202 -0
  35. package/node_modules/@xrkseek/cordis/src/fiber.d.ts.map +1 -0
  36. package/node_modules/@xrkseek/cordis/src/fiber.js +677 -0
  37. package/node_modules/@xrkseek/cordis/src/fiber.js.map +1 -0
  38. package/node_modules/@xrkseek/cordis/src/fiber.ts +754 -0
  39. package/node_modules/@xrkseek/cordis/src/index.d.ts +15 -0
  40. package/node_modules/@xrkseek/cordis/src/index.d.ts.map +1 -0
  41. package/node_modules/@xrkseek/cordis/src/index.js +15 -0
  42. package/node_modules/@xrkseek/cordis/src/index.js.map +1 -0
  43. package/node_modules/@xrkseek/cordis/src/index.ts +14 -0
  44. package/node_modules/@xrkseek/cordis/src/logger.d.ts +105 -0
  45. package/node_modules/@xrkseek/cordis/src/logger.d.ts.map +1 -0
  46. package/node_modules/@xrkseek/cordis/src/logger.js +193 -0
  47. package/node_modules/@xrkseek/cordis/src/logger.js.map +1 -0
  48. package/node_modules/@xrkseek/cordis/src/logger.ts +270 -0
  49. package/node_modules/@xrkseek/cordis/src/reflect.d.ts +186 -0
  50. package/node_modules/@xrkseek/cordis/src/reflect.d.ts.map +1 -0
  51. package/node_modules/@xrkseek/cordis/src/reflect.js +311 -0
  52. package/node_modules/@xrkseek/cordis/src/reflect.js.map +1 -0
  53. package/node_modules/@xrkseek/cordis/src/reflect.ts +418 -0
  54. package/node_modules/@xrkseek/cordis/src/registry.d.ts +201 -0
  55. package/node_modules/@xrkseek/cordis/src/registry.d.ts.map +1 -0
  56. package/node_modules/@xrkseek/cordis/src/registry.js +218 -0
  57. package/node_modules/@xrkseek/cordis/src/registry.js.map +1 -0
  58. package/node_modules/@xrkseek/cordis/src/registry.ts +337 -0
  59. package/node_modules/@xrkseek/cordis/src/service.d.ts +55 -0
  60. package/node_modules/@xrkseek/cordis/src/service.d.ts.map +1 -0
  61. package/node_modules/@xrkseek/cordis/src/service.js +113 -0
  62. package/node_modules/@xrkseek/cordis/src/service.js.map +1 -0
  63. package/node_modules/@xrkseek/cordis/src/service.ts +115 -0
  64. package/node_modules/@xrkseek/cordis/src/utils.d.ts +62 -0
  65. package/node_modules/@xrkseek/cordis/src/utils.d.ts.map +1 -0
  66. package/node_modules/@xrkseek/cordis/src/utils.js +271 -0
  67. package/node_modules/@xrkseek/cordis/src/utils.js.map +1 -0
  68. package/node_modules/@xrkseek/cordis/src/utils.ts +287 -0
  69. package/node_modules/@xrkseek/core-agent-loop/dist/index.d.ts.map +1 -1
  70. package/node_modules/@xrkseek/core-agent-loop/dist/index.js +39 -68
  71. package/node_modules/@xrkseek/core-agent-loop/dist/index.js.map +1 -1
  72. package/node_modules/@xrkseek/core-session/dist/compaction.d.ts +4 -3
  73. package/node_modules/@xrkseek/core-session/dist/compaction.d.ts.map +1 -1
  74. package/node_modules/@xrkseek/core-session/dist/compaction.js.map +1 -1
  75. package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.d.ts.map +1 -1
  76. package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.js +2 -1
  77. package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.js.map +1 -1
  78. package/node_modules/@xrkseek/exec-image-gen/README.md +1 -1
  79. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.d.ts +16 -0
  80. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.d.ts.map +1 -0
  81. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.js +152 -0
  82. package/node_modules/@xrkseek/exec-image-gen/dist/catalog.js.map +1 -0
  83. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.d.ts +9 -0
  84. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.d.ts.map +1 -0
  85. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.js +21 -0
  86. package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.js.map +1 -0
  87. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.d.ts +16 -0
  88. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.d.ts.map +1 -0
  89. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.js +189 -0
  90. package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.js.map +1 -0
  91. package/node_modules/@xrkseek/exec-image-gen/dist/index.d.ts +10 -5
  92. package/node_modules/@xrkseek/exec-image-gen/dist/index.d.ts.map +1 -1
  93. package/node_modules/@xrkseek/exec-image-gen/dist/index.js +174 -18
  94. package/node_modules/@xrkseek/exec-image-gen/dist/index.js.map +1 -1
  95. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.d.ts +16 -0
  96. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.d.ts.map +1 -0
  97. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.js +144 -0
  98. package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.js.map +1 -0
  99. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.d.ts +9 -0
  100. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.d.ts.map +1 -0
  101. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.js +21 -0
  102. package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.js.map +1 -0
  103. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.d.ts +4 -1
  104. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.d.ts.map +1 -1
  105. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.js +7 -5
  106. package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.js.map +1 -1
  107. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.d.ts +14 -0
  108. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.d.ts.map +1 -0
  109. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.js +117 -0
  110. package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.js.map +1 -0
  111. package/node_modules/@xrkseek/exec-image-gen/dist/tools.d.ts.map +1 -1
  112. package/node_modules/@xrkseek/exec-image-gen/dist/tools.js +43 -6
  113. package/node_modules/@xrkseek/exec-image-gen/dist/tools.js.map +1 -1
  114. package/node_modules/@xrkseek/exec-image-gen/dist/types.d.ts +1 -1
  115. package/node_modules/@xrkseek/exec-image-gen/dist/types.d.ts.map +1 -1
  116. package/node_modules/@xrkseek/exec-image-gen/dist/types.js.map +1 -1
  117. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.d.ts +16 -0
  118. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.d.ts.map +1 -0
  119. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.js +137 -0
  120. package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.js.map +1 -0
  121. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.d.ts +52 -0
  122. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.d.ts.map +1 -0
  123. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.js +216 -0
  124. package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.js.map +1 -0
  125. package/node_modules/@xrkseek/exec-memory/dist/index.d.ts +1 -0
  126. package/node_modules/@xrkseek/exec-memory/dist/index.d.ts.map +1 -1
  127. package/node_modules/@xrkseek/exec-memory/dist/index.js +1 -0
  128. package/node_modules/@xrkseek/exec-memory/dist/index.js.map +1 -1
  129. package/node_modules/@xrkseek/exec-memory/dist/tools.d.ts.map +1 -1
  130. package/node_modules/@xrkseek/exec-memory/dist/tools.js +20 -7
  131. package/node_modules/@xrkseek/exec-memory/dist/tools.js.map +1 -1
  132. package/node_modules/@xrkseek/exec-video-gen/README.md +1 -1
  133. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.d.ts +14 -1
  134. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.d.ts.map +1 -1
  135. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.js +99 -1
  136. package/node_modules/@xrkseek/exec-video-gen/dist/catalog.js.map +1 -1
  137. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.d.ts +9 -0
  138. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.d.ts.map +1 -0
  139. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.js +17 -0
  140. package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.js.map +1 -0
  141. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.d.ts +14 -0
  142. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.d.ts.map +1 -0
  143. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.js +342 -0
  144. package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.js.map +1 -0
  145. package/node_modules/@xrkseek/exec-video-gen/dist/index.d.ts +8 -6
  146. package/node_modules/@xrkseek/exec-video-gen/dist/index.d.ts.map +1 -1
  147. package/node_modules/@xrkseek/exec-video-gen/dist/index.js +122 -19
  148. package/node_modules/@xrkseek/exec-video-gen/dist/index.js.map +1 -1
  149. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.d.ts +4 -1
  150. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.d.ts.map +1 -1
  151. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.js +21 -15
  152. package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.js.map +1 -1
  153. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.d.ts +9 -0
  154. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.d.ts.map +1 -0
  155. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.js +18 -0
  156. package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.js.map +1 -0
  157. package/node_modules/@xrkseek/exec-video-gen/dist/tools.d.ts.map +1 -1
  158. package/node_modules/@xrkseek/exec-video-gen/dist/tools.js +26 -6
  159. package/node_modules/@xrkseek/exec-video-gen/dist/tools.js.map +1 -1
  160. package/node_modules/@xrkseek/exec-video-gen/dist/types.d.ts +1 -1
  161. package/node_modules/@xrkseek/exec-video-gen/dist/types.d.ts.map +1 -1
  162. package/node_modules/@xrkseek/exec-video-gen/dist/types.js.map +1 -1
  163. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.d.ts +18 -0
  164. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.d.ts.map +1 -0
  165. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.js +263 -0
  166. package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.js.map +1 -0
  167. package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts.map +1 -1
  168. package/node_modules/@xrkseek/preset-harness/dist/preset.js +12 -3
  169. package/node_modules/@xrkseek/preset-harness/dist/preset.js.map +1 -1
  170. package/node_modules/@xrkseek/preset-harness/dist/tsconfig.tsbuildinfo +1 -1
  171. package/node_modules/@xrkseek/preset-minimal/dist/tsconfig.tsbuildinfo +1 -1
  172. package/node_modules/@xrkseek/preset-server/dist/tsconfig.tsbuildinfo +1 -1
  173. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.d.ts +31 -0
  174. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.d.ts.map +1 -1
  175. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.js +125 -1
  176. package/node_modules/@xrkseek/server-face/dist/agent-team-graph.js.map +1 -1
  177. package/node_modules/@xrkseek/server-face/dist/context.d.ts +19 -1
  178. package/node_modules/@xrkseek/server-face/dist/context.d.ts.map +1 -1
  179. package/node_modules/@xrkseek/server-face/dist/index.d.ts +3 -3
  180. package/node_modules/@xrkseek/server-face/dist/index.d.ts.map +1 -1
  181. package/node_modules/@xrkseek/server-face/dist/index.js +1 -1
  182. package/node_modules/@xrkseek/server-face/dist/index.js.map +1 -1
  183. package/node_modules/@xrkseek/server-face/dist/mcp-oauth.d.ts.map +1 -1
  184. package/node_modules/@xrkseek/server-face/dist/mcp-oauth.js +25 -3
  185. package/node_modules/@xrkseek/server-face/dist/mcp-oauth.js.map +1 -1
  186. package/node_modules/@xrkseek/server-face/dist/ralph-tool.d.ts +2 -0
  187. package/node_modules/@xrkseek/server-face/dist/ralph-tool.d.ts.map +1 -1
  188. package/node_modules/@xrkseek/server-face/dist/ralph-tool.js +11 -5
  189. package/node_modules/@xrkseek/server-face/dist/ralph-tool.js.map +1 -1
  190. package/node_modules/@xrkseek/server-face/dist/runtime.d.ts.map +1 -1
  191. package/node_modules/@xrkseek/server-face/dist/runtime.js +1 -0
  192. package/node_modules/@xrkseek/server-face/dist/runtime.js.map +1 -1
  193. package/node_modules/@xrkseek/server-face/dist/session-status.d.ts +16 -0
  194. package/node_modules/@xrkseek/server-face/dist/session-status.d.ts.map +1 -1
  195. package/node_modules/@xrkseek/server-face/dist/session-status.js +44 -5
  196. package/node_modules/@xrkseek/server-face/dist/session-status.js.map +1 -1
  197. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts +9 -0
  198. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts.map +1 -1
  199. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js +50 -0
  200. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js.map +1 -1
  201. package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts.map +1 -1
  202. package/node_modules/@xrkseek/server-face/dist/settings-document.js +40 -0
  203. package/node_modules/@xrkseek/server-face/dist/settings-document.js.map +1 -1
  204. package/node_modules/@xrkseek/server-face/dist/settings-schemas.d.ts.map +1 -1
  205. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js +20 -4
  206. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js.map +1 -1
  207. package/node_modules/@xrkseek/server-face/dist/subagent-tools.d.ts.map +1 -1
  208. package/node_modules/@xrkseek/server-face/dist/subagent-tools.js +191 -0
  209. package/node_modules/@xrkseek/server-face/dist/subagent-tools.js.map +1 -1
  210. package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.d.ts.map +1 -1
  211. package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.js +8 -0
  212. package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.js.map +1 -1
  213. package/node_modules/@xrkseek/server-host/dist/index.d.ts.map +1 -1
  214. package/node_modules/@xrkseek/server-host/dist/index.js +135 -24
  215. package/node_modules/@xrkseek/server-host/dist/index.js.map +1 -1
  216. package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.d.ts.map +1 -1
  217. package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.js +6 -0
  218. package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.js.map +1 -1
  219. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.d.ts +32 -0
  220. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.d.ts.map +1 -0
  221. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.js +134 -0
  222. package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.js.map +1 -0
  223. package/node_modules/@xrkseek/server-host/package.json +2 -0
  224. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.d.ts.map +1 -1
  225. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.js +20 -0
  226. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.js.map +1 -1
  227. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-face-bridge.d.ts +10 -2
  228. package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-face-bridge.d.ts.map +1 -1
  229. package/node_modules/@xrkseek/xrk-workflow/README.i18n.yaml +6 -0
  230. package/node_modules/@xrkseek/xrk-workflow/README.md +73 -0
  231. package/node_modules/@xrkseek/xrk-workflow/README.zh.md +72 -0
  232. package/node_modules/@xrkseek/xrk-workflow/lib/types/index.d.ts +177 -0
  233. package/node_modules/@xrkseek/xrk-workflow/lib/types/index.js +730 -0
  234. package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.d.ts +13 -0
  235. package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.js +118 -0
  236. package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.d.ts +45 -0
  237. package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.js +9 -0
  238. package/node_modules/@xrkseek/xrk-workflow/lib/types/types.d.ts +118 -0
  239. package/node_modules/@xrkseek/xrk-workflow/lib/types/types.js +16 -0
  240. package/node_modules/@xrkseek/xrk-workflow/package.json +53 -0
  241. package/node_modules/@xrkseek/xrk-workflow/src/index.ts +947 -0
  242. package/package.json +5 -1
@@ -0,0 +1,947 @@
1
+ /**
2
+ * Service Definition for the workflow capability seam. Service Providers execute orchestration scripts;
3
+ * observe-only lifecycle events never expose run control.
4
+ * @module @xrkseek/xrk-workflow
5
+ */
6
+
7
+ import { Context, Service } from '@xrkseek/cordis'
8
+ import { HarnessError } from '@xrkseek/xrk-llm/src/error.ts'
9
+ import { SessionId } from '@xrkseek/xrk-session/types'
10
+ import {
11
+ WorkflowRunId,
12
+ type WorkflowAgentEndInfo,
13
+ type WorkflowAgentInfo,
14
+ type WorkflowResult,
15
+ type WorkflowResultInfo,
16
+ type WorkflowRunInfo,
17
+ } from './types.ts'
18
+ import type { WorkflowRun, WorkflowStartRequest } from './runtime-types.ts'
19
+
20
+ export { WorkflowRunId } from './types.ts'
21
+ export type {
22
+ WorkflowAgentEndInfo,
23
+ WorkflowAgentInfo,
24
+ WorkflowAgentOutcome,
25
+ WorkflowMeta,
26
+ WorkflowPhase,
27
+ WorkflowResult,
28
+ WorkflowResultInfo,
29
+ WorkflowRunInfo,
30
+ WorkflowStopReason,
31
+ } from './types.ts'
32
+ export type { WorkflowRun, WorkflowStartRequest } from './runtime-types.ts'
33
+
34
+ /**
35
+ * Nested `await tools.name(args)` bridge (Code Mode shape). Host mounts a
36
+ * registry-backed bridge; Isolating posts RPC across the worker boundary.
37
+ */
38
+ export interface WorkflowToolCallResult {
39
+ readonly content: string
40
+ readonly isError?: boolean
41
+ }
42
+
43
+ export interface WorkflowToolBridge {
44
+ /** Names exposed on the `tools` Proxy (exclude recursive orchestrators). */
45
+ readonly listNames: () => readonly string[]
46
+ readonly call: (
47
+ name: string,
48
+ args: unknown,
49
+ signal?: AbortSignal,
50
+ ) => Promise<WorkflowToolCallResult>
51
+ }
52
+
53
+ /** Build the script-facing `tools` Proxy (same contract as Code Mode). */
54
+ export function buildWorkflowToolsProxy(
55
+ bridge: WorkflowToolBridge | undefined,
56
+ signal?: AbortSignal,
57
+ ): Record<string, (args?: unknown) => Promise<string>> {
58
+ const listNames = (): readonly string[] => bridge?.listNames() ?? []
59
+ const callTool = (name: string) => async (args?: unknown): Promise<string> => {
60
+ if (!bridge) throw new Error('tools bridge not mounted')
61
+ if (!listNames().includes(name)) throw new Error(`unknown tool: ${name}`)
62
+ const out = await bridge.call(name, args ?? {}, signal)
63
+ if (out.isError) throw new Error(`tools.${name} failed: ${out.content}`)
64
+ return out.content
65
+ }
66
+ return new Proxy({}, {
67
+ get(_target, prop) {
68
+ if (typeof prop !== 'string' || prop === 'then') return undefined
69
+ return callTool(prop)
70
+ },
71
+ ownKeys() {
72
+ return [...listNames()]
73
+ },
74
+ getOwnPropertyDescriptor(_target, prop) {
75
+ if (typeof prop === 'string' && listNames().includes(prop)) {
76
+ return {
77
+ enumerable: true,
78
+ configurable: true,
79
+ writable: false,
80
+ value: callTool(prop),
81
+ }
82
+ }
83
+ return undefined
84
+ },
85
+ })
86
+ }
87
+
88
+ declare module '@xrkseek/cordis' {
89
+ interface Context {
90
+ workflowEngine: WorkflowEngine
91
+ }
92
+
93
+ interface Events {
94
+ /**
95
+ * A workflow run started — the script's meta block validated, the body
96
+ * about to execute. Paired with {@link Events['workflow/end']}.
97
+ * @param info - the run's identity snapshot (id + meta).
98
+ * @mode emit
99
+ */
100
+ 'workflow/start'(info: WorkflowRunInfo): void
101
+ /**
102
+ * The script entered a phase (a `phase(title)` call) — progress grouping
103
+ * for observers; no execution semantics.
104
+ * @param info - the run's identity snapshot.
105
+ * @param title - the phase title, verbatim.
106
+ * @mode emit
107
+ */
108
+ 'workflow/phase'(info: WorkflowRunInfo, title: string): void
109
+ /**
110
+ * The script emitted a narration line (a `log(message)` call).
111
+ * @param info - the run's identity snapshot.
112
+ * @param message - the logged message, verbatim.
113
+ * @mode emit
114
+ */
115
+ 'workflow/log'(info: WorkflowRunInfo, message: string): void
116
+ /**
117
+ * One `agent()` call established a published child run. Paired with
118
+ * {@link Events['workflow/agent-end']} by `agent.seq`. A call that never
119
+ * receives a published run from the provider emits neither
120
+ * event in this pair.
121
+ * @param info - the run's identity snapshot.
122
+ * @param agent - the call's sequence number, label, phase, and child id.
123
+ * @mode emit
124
+ */
125
+ 'workflow/agent-start'(info: WorkflowRunInfo, agent: WorkflowAgentInfo): void
126
+ /**
127
+ * One `agent()` call settled (clean result, child failure, or run
128
+ * cancellation). Paired with {@link Events['workflow/agent-start']} by
129
+ * `agent.seq`, exactly once per started call on every stop path — on an
130
+ * engine termination path (a worker killed past its grace) the end is
131
+ * engine-synthesized with outcome `'cancelled'`.
132
+ * @param info - the run's identity snapshot.
133
+ * @param agent - the call identity plus its outcome.
134
+ * @mode emit
135
+ */
136
+ 'workflow/agent-end'(info: WorkflowRunInfo, agent: WorkflowAgentEndInfo): void
137
+ /**
138
+ * A workflow run settled (any stop reason). Fired when
139
+ * {@link WorkflowRun.result} resolves. Paired with
140
+ * {@link Events['workflow/start']}.
141
+ * @param info - the run's identity snapshot.
142
+ * @param result - the outcome data (stop reason, error, agent count) —
143
+ * deliberately WITHOUT the result value (see {@link WorkflowResultInfo}).
144
+ * @mode emit
145
+ */
146
+ 'workflow/end'(info: WorkflowRunInfo, result: WorkflowResultInfo): void
147
+ }
148
+ }
149
+
150
+ /** The full set of `workflow/*` event names {@link WorkflowEngine.emitWorkflowEvent} dispatches. */
151
+ export type WorkflowEventName =
152
+ | 'workflow/start'
153
+ | 'workflow/phase'
154
+ | 'workflow/log'
155
+ | 'workflow/agent-start'
156
+ | 'workflow/agent-end'
157
+ | 'workflow/end'
158
+
159
+ /**
160
+ * Machine-routable fatal workflow failures: parse/meta/argument/schema errors,
161
+ * resource caps, subagent infrastructure failures, unserializable boundary
162
+ * values, and cancellation. An ordinary child failure resolves its item to
163
+ * `null` and is not one of these fatal codes.
164
+ */
165
+ export type WorkflowErrorCode =
166
+ | 'SCRIPT_PARSE'
167
+ | 'META_INVALID'
168
+ | 'INVALID_ARGUMENT'
169
+ | 'UNSUPPORTED_OPTION'
170
+ | 'UNSUPPORTED_SCHEMA'
171
+ | 'AGENT_CAP'
172
+ | 'ITEM_CAP'
173
+ | 'AGENT_START'
174
+ | 'AGENT_RESULT'
175
+ | 'RESULT_UNSERIALIZABLE'
176
+ | 'CANCELLED'
177
+ | 'WORKER_EXIT'
178
+
179
+ /**
180
+ * Typed error for workflow-seam failures. Extends {@link HarnessError}, so the
181
+ * `code` is machine-routable taxonomy. `fatal` drives the combinator
182
+ * discipline: `parallel()`/`pipeline()` re-throw a fatal error (a typo'd
183
+ * option or a tripped cap must kill the script loudly), and reserve the
184
+ * per-item `null` for child-run failures and ordinary in-stage script errors.
185
+ * Every {@link WorkflowErrorCode} is fatal; the flag exists so the
186
+ * distinction is explicit at every catch site rather than implied.
187
+ */
188
+ export class WorkflowError extends HarnessError {
189
+ /** Whether combinators must propagate this error instead of nulling the item. */
190
+ readonly fatal: boolean
191
+
192
+ constructor(message: string, code: WorkflowErrorCode, options?: ErrorOptions & { fatal?: boolean }) {
193
+ super(message, code, options)
194
+ this.name = 'WorkflowError'
195
+ this.fatal = options?.fatal ?? true
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Whether combinators must re-throw `error` instead of mapping the item to `null`.
201
+ * @param error - any thrown value; fatality is host `instanceof` (unforgeable from a script realm).
202
+ * @returns true iff `error` is a {@link WorkflowError} whose `fatal` flag is set.
203
+ */
204
+ export function isFatalWorkflowError(error: unknown): boolean {
205
+ return error instanceof WorkflowError && error.fatal
206
+ }
207
+
208
+ /**
209
+ * Workflow Service Definition contract. Invalid requests throw before publication; a live
210
+ * run is holder-owned, its result never rejects, cancellation and disposal are
211
+ * bounded, and disposal waits for child cleanup within that bound. Lifecycle
212
+ * listener failures are contained, and `workflow/end` fires exactly once as the
213
+ * result settles.
214
+ */
215
+ export abstract class WorkflowEngine extends Service {
216
+ constructor(ctx: Context) {
217
+ super(ctx, 'workflowEngine')
218
+ }
219
+
220
+ /**
221
+ * Parse and execute a workflow script.
222
+ * @param request - the script, its `args`, the parent agent, and an
223
+ * optional cancel signal.
224
+ * @returns the live run; its `result` resolves when the script settles.
225
+ */
226
+ abstract start(request: WorkflowStartRequest): WorkflowRun
227
+
228
+ /**
229
+ * Emit a lifecycle event while containing and logging each listener failure.
230
+ * @param name - the `workflow/*` event to dispatch.
231
+ * @param args - the event's payload, matching its declared signature.
232
+ */
233
+ protected emitWorkflowEvent(name: WorkflowEventName, ...args: unknown[]): void {
234
+ for (const callback of this.ctx.events.dispatch('emit', [name, ...args])) {
235
+ try {
236
+ const returned: unknown = (callback as (...payload: unknown[]) => unknown)(...args)
237
+ void Promise.resolve(returned).catch((error: unknown) => {
238
+ this.ctx.logger.warn(`workflow: ${name} listener rejected: ${renderListenerError(error)}`)
239
+ })
240
+ } catch (error: unknown) {
241
+ this.ctx.logger.warn(`workflow: ${name} listener threw: ${renderListenerError(error)}`)
242
+ }
243
+ }
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Render any thrown value without violating listener containment.
249
+ * @param error - any thrown value.
250
+ * @returns `String(error)`, or a fixed label when even coercion throws.
251
+ */
252
+ function renderListenerError(error: unknown): string {
253
+ try {
254
+ return String(error)
255
+ } catch {
256
+ // String coercion itself may throw.
257
+ return '[unrenderable thrown value]'
258
+ }
259
+ }
260
+
261
+ /**
262
+ * In-process Provider: AsyncFunction body with `phase` / `log` / `agent`.
263
+ * `agent()` returns `null` unless `createAgent` is supplied (Cordis compositions
264
+ * that wire subagents). Product Face boot uses the Face-native `ralph` tool;
265
+ * this Provider fills the abstract `ctx.workflowEngine` hole for Cordis mounts.
266
+ */
267
+ export class InProcessWorkflowEngine extends WorkflowEngine {
268
+ private readonly createAgent:
269
+ | ((
270
+ request: WorkflowStartRequest,
271
+ call: { label: string; prompt: string; phase?: string },
272
+ ) => Promise<unknown>)
273
+ | undefined
274
+ private readonly toolBridge: WorkflowToolBridge | undefined
275
+
276
+ constructor(
277
+ ctx: Context,
278
+ options?: {
279
+ readonly createAgent?: InProcessWorkflowEngine['createAgent']
280
+ readonly toolBridge?: WorkflowToolBridge
281
+ },
282
+ ) {
283
+ super(ctx)
284
+ this.createAgent = options?.createAgent
285
+ this.toolBridge = options?.toolBridge
286
+ }
287
+
288
+ start(request: WorkflowStartRequest): WorkflowRun {
289
+ const meta = request.meta
290
+ if (!meta || typeof meta !== 'object') {
291
+ throw new WorkflowError('workflow meta must be an object', 'META_INVALID')
292
+ }
293
+ if (typeof meta.name !== 'string' || !meta.name.trim()) {
294
+ throw new WorkflowError('workflow meta.name is required', 'META_INVALID')
295
+ }
296
+ if (typeof meta.description !== 'string' || !meta.description.trim()) {
297
+ throw new WorkflowError('workflow meta.description is required', 'META_INVALID')
298
+ }
299
+ if (typeof request.script !== 'string' || !request.script.trim()) {
300
+ throw new WorkflowError('workflow script must be a non-empty string', 'SCRIPT_PARSE')
301
+ }
302
+ const id = WorkflowRunId(`wf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`)
303
+ let cancelled = false
304
+ let cancelReason = 'cancelled'
305
+ let agentsStarted = 0
306
+ let currentPhase: string | undefined
307
+ const ac = new AbortController()
308
+ const onAbort = () => {
309
+ cancelled = true
310
+ cancelReason = 'parent signal aborted'
311
+ ac.abort()
312
+ }
313
+ if (request.signal) {
314
+ if (request.signal.aborted) onAbort()
315
+ else request.signal.addEventListener('abort', onAbort, { once: true })
316
+ }
317
+
318
+ const info = { id, meta: request.meta }
319
+ this.emitWorkflowEvent('workflow/start', info)
320
+
321
+ const result = (async (): Promise<WorkflowResult> => {
322
+ try {
323
+ if (cancelled) {
324
+ return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted }
325
+ }
326
+ const phase = (title: string) => {
327
+ currentPhase = String(title ?? '')
328
+ this.emitWorkflowEvent('workflow/phase', info, currentPhase)
329
+ }
330
+ const log = (message: string) => {
331
+ this.emitWorkflowEvent('workflow/log', info, String(message ?? ''))
332
+ }
333
+ const agent = async (opts: {
334
+ label?: string
335
+ prompt?: string
336
+ phase?: string
337
+ } = {}) => {
338
+ if (cancelled || ac.signal.aborted) {
339
+ throw new WorkflowError(cancelReason, 'CANCELLED')
340
+ }
341
+ const cap = request.maxTotalAgents
342
+ if (typeof cap === 'number' && agentsStarted >= cap) {
343
+ throw new WorkflowError(`workflow maxTotalAgents ${cap} reached`, 'AGENT_CAP')
344
+ }
345
+ agentsStarted += 1
346
+ const seq = agentsStarted
347
+ const label = String(opts.label ?? opts.prompt ?? `agent-${seq}`).slice(0, 120)
348
+ const phaseTitle = opts.phase ?? currentPhase
349
+ const childId = SessionId(`wf-child-${String(id)}-${seq}`)
350
+ this.emitWorkflowEvent('workflow/agent-start', info, {
351
+ seq,
352
+ label,
353
+ ...(phaseTitle ? { phase: phaseTitle } : {}),
354
+ childId,
355
+ })
356
+ let outcome: 'completed' | 'failed' | 'cancelled' = 'failed'
357
+ let value: unknown = null
358
+ try {
359
+ if (this.createAgent) {
360
+ value = await this.createAgent(request, {
361
+ label,
362
+ prompt: String(opts.prompt ?? ''),
363
+ ...(phaseTitle ? { phase: phaseTitle } : {}),
364
+ })
365
+ outcome = cancelled ? 'cancelled' : 'completed'
366
+ }
367
+ } catch {
368
+ outcome = cancelled ? 'cancelled' : 'failed'
369
+ value = null
370
+ }
371
+ this.emitWorkflowEvent('workflow/agent-end', info, {
372
+ seq,
373
+ label,
374
+ ...(phaseTitle ? { phase: phaseTitle } : {}),
375
+ childId,
376
+ outcome,
377
+ })
378
+ return value
379
+ }
380
+
381
+ const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor as new (
382
+ ...args: string[]
383
+ ) => (...args: unknown[]) => Promise<unknown>
384
+ const tools = buildWorkflowToolsProxy(this.toolBridge, ac.signal)
385
+ const fn = new AsyncFunction(
386
+ 'args',
387
+ 'phase',
388
+ 'log',
389
+ 'agent',
390
+ 'tools',
391
+ `"use strict";\n${request.script}`,
392
+ )
393
+ const value = await fn(request.args, phase, log, agent, tools)
394
+ if (cancelled || ac.signal.aborted) {
395
+ return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted }
396
+ }
397
+ return {
398
+ value: value === undefined ? null : value,
399
+ stopReason: 'completed',
400
+ agentsStarted,
401
+ }
402
+ } catch (err) {
403
+ if (cancelled || ac.signal.aborted) {
404
+ return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted }
405
+ }
406
+ return {
407
+ value: null,
408
+ stopReason: 'error',
409
+ error: err instanceof Error ? err.message : String(err),
410
+ agentsStarted,
411
+ }
412
+ }
413
+ })().then((settled) => {
414
+ this.emitWorkflowEvent('workflow/end', info, {
415
+ stopReason: settled.stopReason,
416
+ agentsStarted: settled.agentsStarted,
417
+ ...(settled.error ? { error: settled.error } : {}),
418
+ })
419
+ return settled
420
+ })
421
+
422
+ return {
423
+ id,
424
+ meta: request.meta,
425
+ result,
426
+ cancel(reason?: string) {
427
+ cancelled = true
428
+ cancelReason = reason?.trim() || 'cancelled'
429
+ ac.abort()
430
+ },
431
+ async dispose() {
432
+ cancelled = true
433
+ ac.abort()
434
+ await result.catch(() => undefined)
435
+ },
436
+ }
437
+ }
438
+ }
439
+
440
+ /**
441
+ * Worker-thread Provider: script body runs in an isolated `worker_threads`
442
+ * Worker (eval). `agent()` posts an RPC to the parent thread, which may run
443
+ * an optional {@link IsolatingWorkflowEngine} `createAgent` bridge (same
444
+ * contract as {@link InProcessWorkflowEngine}) and return a structured-cloneable
445
+ * value. Without `createAgent`, `agent()` still settles `null`.
446
+ * `await tools.name(args)` uses an optional {@link WorkflowToolBridge}
447
+ * (Code Mode subset — nested Host tools via parentPort RPC). Full sandboxed
448
+ * Node PTC process confinement is not claimed.
449
+ */
450
+ export class IsolatingWorkflowEngine extends WorkflowEngine {
451
+ private readonly createAgent:
452
+ | ((
453
+ request: WorkflowStartRequest,
454
+ call: { label: string; prompt: string; phase?: string },
455
+ ) => Promise<unknown>)
456
+ | undefined
457
+ private readonly toolBridge: WorkflowToolBridge | undefined
458
+
459
+ constructor(
460
+ ctx: Context,
461
+ options?: {
462
+ readonly createAgent?: IsolatingWorkflowEngine['createAgent']
463
+ readonly toolBridge?: WorkflowToolBridge
464
+ },
465
+ ) {
466
+ super(ctx)
467
+ this.createAgent = options?.createAgent
468
+ this.toolBridge = options?.toolBridge
469
+ }
470
+
471
+ start(request: WorkflowStartRequest): WorkflowRun {
472
+ const meta = request.meta
473
+ if (!meta || typeof meta !== 'object') {
474
+ throw new WorkflowError('workflow meta must be an object', 'META_INVALID')
475
+ }
476
+ if (typeof meta.name !== 'string' || !meta.name.trim()) {
477
+ throw new WorkflowError('workflow meta.name is required', 'META_INVALID')
478
+ }
479
+ if (typeof meta.description !== 'string' || !meta.description.trim()) {
480
+ throw new WorkflowError('workflow meta.description is required', 'META_INVALID')
481
+ }
482
+ if (typeof request.script !== 'string' || !request.script.trim()) {
483
+ throw new WorkflowError('workflow script must be a non-empty string', 'SCRIPT_PARSE')
484
+ }
485
+ const id = WorkflowRunId(`wf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`)
486
+ let cancelled = false
487
+ let cancelReason = 'cancelled'
488
+ let agentsStarted = 0
489
+ const ac = new AbortController()
490
+ const onAbort = () => {
491
+ cancelled = true
492
+ cancelReason = 'parent signal aborted'
493
+ ac.abort()
494
+ }
495
+ if (request.signal) {
496
+ if (request.signal.aborted) onAbort()
497
+ else request.signal.addEventListener('abort', onAbort, { once: true })
498
+ }
499
+
500
+ const info = { id, meta: request.meta }
501
+ this.emitWorkflowEvent('workflow/start', info)
502
+
503
+ const result = (async (): Promise<WorkflowResult> => {
504
+ if (cancelled) {
505
+ return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted }
506
+ }
507
+ try {
508
+ const settled = await runIsolatingWorkerScript({
509
+ script: request.script,
510
+ args: request.args,
511
+ signal: ac.signal,
512
+ onPhase: (title) => {
513
+ this.emitWorkflowEvent('workflow/phase', info, title)
514
+ },
515
+ onLog: (message) => {
516
+ this.emitWorkflowEvent('workflow/log', info, message)
517
+ },
518
+ onAgentStart: (agent) => {
519
+ agentsStarted += 1
520
+ this.emitWorkflowEvent('workflow/agent-start', info, agent)
521
+ },
522
+ onAgentEnd: (agent) => {
523
+ this.emitWorkflowEvent('workflow/agent-end', info, agent)
524
+ },
525
+ runId: String(id),
526
+ toolNames: this.toolBridge?.listNames() ?? [],
527
+ ...(typeof request.maxTotalAgents === 'number'
528
+ ? { maxTotalAgents: request.maxTotalAgents }
529
+ : {}),
530
+ ...(this.createAgent
531
+ ? {
532
+ createAgent: async (call: {
533
+ label: string
534
+ prompt: string
535
+ phase?: string
536
+ }) => {
537
+ if (cancelled || ac.signal.aborted) {
538
+ throw new WorkflowError(cancelReason, 'CANCELLED')
539
+ }
540
+ return this.createAgent!(request, call)
541
+ },
542
+ }
543
+ : {}),
544
+ ...(this.toolBridge ? { toolBridge: this.toolBridge } : {}),
545
+ })
546
+ if (cancelled || ac.signal.aborted) {
547
+ return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted }
548
+ }
549
+ agentsStarted = Math.max(agentsStarted, settled.agentsStarted)
550
+ return settled
551
+ } catch (err) {
552
+ if (cancelled || ac.signal.aborted) {
553
+ return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted }
554
+ }
555
+ return {
556
+ value: null,
557
+ stopReason: 'error',
558
+ error: err instanceof Error ? err.message : String(err),
559
+ agentsStarted,
560
+ }
561
+ }
562
+ })().then((settled) => {
563
+ this.emitWorkflowEvent('workflow/end', info, {
564
+ stopReason: settled.stopReason,
565
+ agentsStarted: settled.agentsStarted,
566
+ ...(settled.error ? { error: settled.error } : {}),
567
+ })
568
+ return settled
569
+ })
570
+
571
+ return {
572
+ id,
573
+ meta: request.meta,
574
+ result,
575
+ cancel(reason?: string) {
576
+ cancelled = true
577
+ cancelReason = reason?.trim() || 'cancelled'
578
+ ac.abort()
579
+ },
580
+ async dispose() {
581
+ cancelled = true
582
+ ac.abort()
583
+ await result.catch(() => undefined)
584
+ },
585
+ }
586
+ }
587
+ }
588
+
589
+ /** Best-effort clone so worker_threads can postMessage the agent result. */
590
+ function cloneForWorker(value: unknown): unknown {
591
+ if (value === undefined) return null
592
+ try {
593
+ return structuredClone(value)
594
+ } catch {
595
+ try {
596
+ return JSON.parse(JSON.stringify(value)) as unknown
597
+ } catch {
598
+ return null
599
+ }
600
+ }
601
+ }
602
+
603
+ async function runIsolatingWorkerScript(input: {
604
+ readonly script: string
605
+ readonly args: unknown
606
+ readonly signal?: AbortSignal
607
+ readonly onPhase: (title: string) => void
608
+ readonly onLog: (message: string) => void
609
+ readonly onAgentStart: (agent: WorkflowAgentInfo) => void
610
+ readonly onAgentEnd: (agent: WorkflowAgentEndInfo) => void
611
+ readonly runId: string
612
+ readonly maxTotalAgents?: number
613
+ readonly toolNames?: readonly string[]
614
+ readonly createAgent?: (call: {
615
+ label: string
616
+ prompt: string
617
+ phase?: string
618
+ }) => Promise<unknown>
619
+ readonly toolBridge?: WorkflowToolBridge
620
+ }): Promise<WorkflowResult> {
621
+ const { Worker } = await import('node:worker_threads')
622
+ const workerSource = `
623
+ const { parentPort, workerData } = require('node:worker_threads');
624
+ let agentsStarted = 0;
625
+ let callSeq = 0;
626
+ const pending = new Map();
627
+ parentPort.on('message', (msg) => {
628
+ if (!msg || (msg.type !== 'agent-result' && msg.type !== 'tool-result')) return;
629
+ const wait = pending.get(msg.callId);
630
+ if (!wait) return;
631
+ pending.delete(msg.callId);
632
+ if (msg.ok) wait.resolve(msg.value === undefined ? null : msg.value);
633
+ else wait.reject(new Error(String(msg.error || 'bridge failed')));
634
+ });
635
+ const phase = (title) => {
636
+ parentPort.postMessage({ type: 'phase', title: String(title ?? '') });
637
+ };
638
+ const log = (message) => {
639
+ parentPort.postMessage({ type: 'log', message: String(message ?? '') });
640
+ };
641
+ const agent = async (opts = {}) => {
642
+ const cap = workerData.maxTotalAgents;
643
+ if (typeof cap === 'number' && agentsStarted >= cap) {
644
+ throw new Error('workflow maxTotalAgents ' + cap + ' reached');
645
+ }
646
+ agentsStarted += 1;
647
+ const seq = agentsStarted;
648
+ const label = String(opts.label ?? opts.prompt ?? ('agent-' + seq)).slice(0, 120);
649
+ const phaseTitle = opts.phase;
650
+ const childId = 'wf-child-' + workerData.runId + '-' + seq;
651
+ const callId = 'c' + (++callSeq);
652
+ parentPort.postMessage({
653
+ type: 'agent-start',
654
+ seq, label, phase: phaseTitle || undefined, childId,
655
+ });
656
+ parentPort.postMessage({
657
+ type: 'agent-call',
658
+ callId, seq, label,
659
+ prompt: String(opts.prompt ?? ''),
660
+ phase: phaseTitle || undefined,
661
+ childId,
662
+ });
663
+ let value = null;
664
+ let outcome = 'completed';
665
+ try {
666
+ value = await new Promise((resolve, reject) => {
667
+ pending.set(callId, { resolve, reject });
668
+ });
669
+ } catch (err) {
670
+ outcome = 'failed';
671
+ parentPort.postMessage({
672
+ type: 'agent-end',
673
+ seq, label, phase: phaseTitle || undefined, childId, outcome,
674
+ });
675
+ throw err;
676
+ }
677
+ parentPort.postMessage({
678
+ type: 'agent-end',
679
+ seq, label, phase: phaseTitle || undefined, childId, outcome,
680
+ });
681
+ return value;
682
+ };
683
+ const toolNames = Array.isArray(workerData.toolNames) ? workerData.toolNames : [];
684
+ const callTool = (name) => async (args) => {
685
+ const callId = 't' + (++callSeq);
686
+ parentPort.postMessage({
687
+ type: 'tool-call',
688
+ callId,
689
+ name: String(name),
690
+ args: args === undefined ? {} : args,
691
+ });
692
+ const out = await new Promise((resolve, reject) => {
693
+ pending.set(callId, { resolve, reject });
694
+ });
695
+ if (out && out.isError) {
696
+ throw new Error('tools.' + name + ' failed: ' + String(out.content || ''));
697
+ }
698
+ return out && typeof out.content === 'string' ? out.content : String(out && out.content != null ? out.content : '');
699
+ };
700
+ const tools = new Proxy({}, {
701
+ get(_target, prop) {
702
+ if (typeof prop !== 'string' || prop === 'then') return undefined;
703
+ return callTool(prop);
704
+ },
705
+ ownKeys() { return toolNames.slice(); },
706
+ getOwnPropertyDescriptor(_target, prop) {
707
+ if (typeof prop === 'string' && toolNames.includes(prop)) {
708
+ return { enumerable: true, configurable: true, writable: false, value: callTool(prop) };
709
+ }
710
+ return undefined;
711
+ },
712
+ });
713
+ const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
714
+ try {
715
+ const fn = new AsyncFunction('args', 'phase', 'log', 'agent', 'tools',
716
+ '"use strict";\\n' + workerData.script);
717
+ Promise.resolve(fn(workerData.args, phase, log, agent, tools)).then((value) => {
718
+ parentPort.postMessage({
719
+ type: 'done',
720
+ ok: true,
721
+ value: value === undefined ? null : value,
722
+ agentsStarted,
723
+ });
724
+ }).catch((err) => {
725
+ parentPort.postMessage({
726
+ type: 'done',
727
+ ok: false,
728
+ error: String(err && err.message ? err.message : err),
729
+ agentsStarted,
730
+ });
731
+ });
732
+ } catch (err) {
733
+ parentPort.postMessage({
734
+ type: 'done',
735
+ ok: false,
736
+ error: String(err && err.message ? err.message : err),
737
+ agentsStarted: 0,
738
+ });
739
+ }
740
+ `
741
+
742
+ return new Promise<WorkflowResult>((resolve, reject) => {
743
+ const worker = new Worker(workerSource, {
744
+ eval: true,
745
+ workerData: {
746
+ script: input.script,
747
+ args: input.args ?? null,
748
+ runId: input.runId,
749
+ toolNames: [...(input.toolNames ?? [])],
750
+ ...(typeof input.maxTotalAgents === 'number'
751
+ ? { maxTotalAgents: input.maxTotalAgents }
752
+ : {}),
753
+ },
754
+ resourceLimits: { maxOldGenerationSizeMb: 128 },
755
+ })
756
+ let settled = false
757
+ let agentsStartedSeen = 0
758
+ const finish = (result: WorkflowResult) => {
759
+ if (settled) return
760
+ settled = true
761
+ input.signal?.removeEventListener('abort', onAbort)
762
+ void worker.terminate().catch(() => undefined)
763
+ resolve(result)
764
+ }
765
+ const onAbort = () => {
766
+ void worker.terminate().catch(() => undefined)
767
+ finish({
768
+ value: null,
769
+ stopReason: 'cancelled',
770
+ error: 'parent signal aborted',
771
+ agentsStarted: agentsStartedSeen,
772
+ })
773
+ }
774
+ if (input.signal) {
775
+ if (input.signal.aborted) {
776
+ onAbort()
777
+ return
778
+ }
779
+ input.signal.addEventListener('abort', onAbort, { once: true })
780
+ }
781
+ worker.on('message', (msg: {
782
+ type?: string
783
+ title?: string
784
+ message?: string
785
+ seq?: number
786
+ label?: string
787
+ phase?: string
788
+ childId?: string
789
+ callId?: string
790
+ prompt?: string
791
+ name?: string
792
+ args?: unknown
793
+ outcome?: 'completed' | 'failed' | 'cancelled'
794
+ ok?: boolean
795
+ value?: unknown
796
+ error?: string
797
+ agentsStarted?: number
798
+ }) => {
799
+ if (!msg || typeof msg !== 'object') return
800
+ if (msg.type === 'phase' && typeof msg.title === 'string') {
801
+ input.onPhase(msg.title)
802
+ return
803
+ }
804
+ if (msg.type === 'log' && typeof msg.message === 'string') {
805
+ input.onLog(msg.message)
806
+ return
807
+ }
808
+ if (msg.type === 'agent-start' && typeof msg.seq === 'number') {
809
+ agentsStartedSeen = Math.max(agentsStartedSeen, msg.seq)
810
+ input.onAgentStart({
811
+ seq: msg.seq,
812
+ label: String(msg.label ?? ''),
813
+ ...(msg.phase ? { phase: msg.phase } : {}),
814
+ childId: SessionId(String(msg.childId ?? `wf-child-${msg.seq}`)),
815
+ })
816
+ return
817
+ }
818
+ if (msg.type === 'agent-call' && typeof msg.callId === 'string') {
819
+ const callId = msg.callId
820
+ const label = String(msg.label ?? '')
821
+ const prompt = String(msg.prompt ?? '')
822
+ const phaseTitle = msg.phase
823
+ void (async () => {
824
+ try {
825
+ let value: unknown = null
826
+ if (input.createAgent) {
827
+ value = await input.createAgent({
828
+ label,
829
+ prompt,
830
+ ...(phaseTitle ? { phase: String(phaseTitle) } : {}),
831
+ })
832
+ }
833
+ worker.postMessage({
834
+ type: 'agent-result',
835
+ callId,
836
+ ok: true,
837
+ value: cloneForWorker(value),
838
+ })
839
+ } catch (err) {
840
+ worker.postMessage({
841
+ type: 'agent-result',
842
+ callId,
843
+ ok: false,
844
+ error: err instanceof Error ? err.message : String(err),
845
+ })
846
+ }
847
+ })()
848
+ return
849
+ }
850
+ if (msg.type === 'tool-call' && typeof msg.callId === 'string' && typeof msg.name === 'string') {
851
+ const callId = msg.callId
852
+ const name = msg.name
853
+ void (async () => {
854
+ try {
855
+ if (!input.toolBridge) {
856
+ worker.postMessage({
857
+ type: 'tool-result',
858
+ callId,
859
+ ok: false,
860
+ error: 'tools bridge not mounted',
861
+ })
862
+ return
863
+ }
864
+ const names = input.toolBridge.listNames()
865
+ if (!names.includes(name)) {
866
+ worker.postMessage({
867
+ type: 'tool-result',
868
+ callId,
869
+ ok: false,
870
+ error: `unknown tool: ${name}`,
871
+ })
872
+ return
873
+ }
874
+ const out = await input.toolBridge.call(name, msg.args ?? {}, input.signal)
875
+ worker.postMessage({
876
+ type: 'tool-result',
877
+ callId,
878
+ ok: true,
879
+ value: cloneForWorker({
880
+ content: out.content,
881
+ ...(out.isError ? { isError: true } : {}),
882
+ }),
883
+ })
884
+ } catch (err) {
885
+ worker.postMessage({
886
+ type: 'tool-result',
887
+ callId,
888
+ ok: false,
889
+ error: err instanceof Error ? err.message : String(err),
890
+ })
891
+ }
892
+ })()
893
+ return
894
+ }
895
+ if (msg.type === 'agent-end' && typeof msg.seq === 'number') {
896
+ input.onAgentEnd({
897
+ seq: msg.seq,
898
+ label: String(msg.label ?? ''),
899
+ ...(msg.phase ? { phase: msg.phase } : {}),
900
+ childId: SessionId(String(msg.childId ?? `wf-child-${msg.seq}`)),
901
+ outcome: msg.outcome ?? 'completed',
902
+ })
903
+ return
904
+ }
905
+ if (msg.type === 'done') {
906
+ const agentsStarted =
907
+ typeof msg.agentsStarted === 'number' ? msg.agentsStarted : agentsStartedSeen
908
+ if (msg.ok) {
909
+ finish({
910
+ value: msg.value ?? null,
911
+ stopReason: 'completed',
912
+ agentsStarted,
913
+ })
914
+ } else {
915
+ finish({
916
+ value: null,
917
+ stopReason: 'error',
918
+ error: msg.error || 'worker failed',
919
+ agentsStarted,
920
+ })
921
+ }
922
+ }
923
+ })
924
+ worker.on('error', (err) => {
925
+ finish({
926
+ value: null,
927
+ stopReason: 'error',
928
+ error: err instanceof Error ? err.message : String(err),
929
+ agentsStarted: agentsStartedSeen,
930
+ })
931
+ })
932
+ worker.on('exit', (code) => {
933
+ if (settled) return
934
+ if (code === 0) {
935
+ finish({
936
+ value: null,
937
+ stopReason: 'completed',
938
+ agentsStarted: agentsStartedSeen,
939
+ })
940
+ } else {
941
+ reject(new WorkflowError(`isolating worker exited ${code}`, 'WORKER_EXIT'))
942
+ }
943
+ })
944
+ })
945
+ }
946
+
947
+ export default WorkflowEngine