@pikku/core 0.12.107 → 0.12.111

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 (588) hide show
  1. package/CHANGELOG.md +344 -0
  2. package/dist/analytics/analytics.d.ts +6 -0
  3. package/dist/analytics/analytics.js +58 -0
  4. package/dist/analytics/analytics.types.d.ts +156 -0
  5. package/dist/analytics/analytics.types.js +1 -0
  6. package/dist/analytics/anonymous-analytics-identity.d.ts +23 -0
  7. package/dist/analytics/anonymous-analytics-identity.js +27 -0
  8. package/dist/analytics/compose-analytics-identity.d.ts +14 -0
  9. package/dist/analytics/compose-analytics-identity.js +33 -0
  10. package/dist/analytics/cookie-analytics-identity.d.ts +24 -0
  11. package/dist/analytics/cookie-analytics-identity.js +37 -0
  12. package/dist/analytics/define-analytics-events.d.ts +22 -0
  13. package/dist/analytics/define-analytics-events.js +9 -0
  14. package/dist/analytics/fan-out-analytics.d.ts +15 -0
  15. package/dist/analytics/fan-out-analytics.js +36 -0
  16. package/dist/analytics/index.d.ts +13 -0
  17. package/dist/analytics/index.js +8 -0
  18. package/dist/analytics/logger-analytics-service.d.ts +14 -0
  19. package/dist/analytics/logger-analytics-service.js +23 -0
  20. package/dist/analytics/mint-cookie.d.ts +44 -0
  21. package/dist/analytics/mint-cookie.js +55 -0
  22. package/dist/errors/errors.d.ts +7 -0
  23. package/dist/errors/errors.js +17 -0
  24. package/dist/function/function-meta.types.d.ts +2 -0
  25. package/dist/function/function-runner.js +29 -0
  26. package/dist/function/functions.types.d.ts +22 -3
  27. package/dist/middleware/auth-apikey.d.ts +1 -1
  28. package/dist/pikku-state.d.ts +1 -1
  29. package/dist/scopes.d.ts +11 -0
  30. package/dist/scopes.js +17 -0
  31. package/dist/services/credential-wire-service.d.ts +1 -1
  32. package/dist/services/feature-flag-service.d.ts +100 -0
  33. package/dist/services/feature-flag-service.js +1 -0
  34. package/dist/services/index.d.ts +1 -0
  35. package/dist/services/meta-service.d.ts +16 -0
  36. package/dist/services/meta-service.js +19 -0
  37. package/dist/services/webhook-service.d.ts +7 -2
  38. package/dist/services/webhook-service.js +11 -6
  39. package/dist/testing/service-tests/agent-run-service-tests.d.ts +2 -2
  40. package/dist/testing/service-tests/agent-storage-service-tests.d.ts +1 -1
  41. package/dist/testing/service-tests/channel-store-tests.d.ts +1 -1
  42. package/dist/testing/service-tests/credential-service-tests.d.ts +1 -1
  43. package/dist/testing/service-tests/deployment-service-tests.d.ts +1 -1
  44. package/dist/testing/service-tests/event-hub-store-tests.d.ts +1 -1
  45. package/dist/testing/service-tests/secret-service-tests.d.ts +1 -1
  46. package/dist/testing/service-tests/session-store-tests.d.ts +1 -1
  47. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +1 -1
  48. package/dist/testing/service-tests/workflow-service-tests.d.ts +1 -1
  49. package/dist/types/core.types.d.ts +23 -0
  50. package/dist/wirings/agent/agent-rpc.d.ts +1 -1
  51. package/dist/wirings/agent/agent-turn.d.ts +1 -1
  52. package/dist/wirings/agent-scorer/agent-scorer-live.d.ts +1 -1
  53. package/dist/wirings/channel/channel-common.d.ts +1 -1
  54. package/dist/wirings/channel/channel-rpc-validators.d.ts +2 -2
  55. package/dist/wirings/channel/channel-runner.d.ts +1 -1
  56. package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
  57. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
  58. package/dist/wirings/cli/channel/cli-approval.d.ts +2 -2
  59. package/dist/wirings/flag/assert-feature-available.d.ts +15 -0
  60. package/dist/wirings/flag/assert-feature-available.js +23 -0
  61. package/dist/wirings/flag/cached-flag-source.d.ts +73 -0
  62. package/dist/wirings/flag/cached-flag-source.js +96 -0
  63. package/dist/wirings/flag/define-feature-flags.d.ts +33 -0
  64. package/dist/wirings/flag/define-feature-flags.js +32 -0
  65. package/dist/wirings/flag/flag.types.d.ts +97 -0
  66. package/dist/wirings/flag/flag.types.js +1 -0
  67. package/dist/wirings/flag/index.d.ts +7 -0
  68. package/dist/wirings/flag/index.js +5 -0
  69. package/dist/wirings/flag/resolve-flag.d.ts +52 -0
  70. package/dist/wirings/flag/resolve-flag.js +90 -0
  71. package/dist/wirings/flag/validate-flag-definitions.d.ts +26 -0
  72. package/dist/wirings/flag/validate-flag-definitions.js +103 -0
  73. package/dist/wirings/virtual-user/virtual-user-scaffold.d.ts +8 -8
  74. package/dist/wirings/virtual-user/virtual-user-schedule.d.ts +1 -1
  75. package/dist/wirings/workflow/workflow-queue-routing.d.ts +1 -1
  76. package/package.json +11 -5
  77. package/run-tests.sh +17 -9
  78. package/src/public-surface.json +26 -0
  79. package/src/agent-naming.test.ts +0 -68
  80. package/src/api-report.test.ts +0 -138
  81. package/src/app-alias-surface.test.ts +0 -179
  82. package/src/app-leaf-surface.test.ts +0 -222
  83. package/src/bootstrap-compat/root.ts +0 -20
  84. package/src/classification/column-form.test.ts +0 -97
  85. package/src/classification/column-form.ts +0 -55
  86. package/src/classification/data-classification.ts +0 -73
  87. package/src/classification/index.ts +0 -40
  88. package/src/classification/key-ids.ts +0 -2
  89. package/src/classification/secret-value.test.ts +0 -204
  90. package/src/classification/secret-value.ts +0 -106
  91. package/src/crypto-utils.test.ts +0 -668
  92. package/src/crypto-utils.ts +0 -460
  93. package/src/dev/hot-reload.test.ts +0 -587
  94. package/src/dev/hot-reload.ts +0 -225
  95. package/src/dev/module-runner.test.ts +0 -235
  96. package/src/dev/module-runner.ts +0 -138
  97. package/src/dev/reload-meta.test.ts +0 -183
  98. package/src/dev/reload-meta.ts +0 -144
  99. package/src/ecosystem-tier-removed.test.ts +0 -72
  100. package/src/env.ts +0 -1
  101. package/src/errors/error-handler.ts +0 -77
  102. package/src/errors/error.test.ts +0 -229
  103. package/src/errors/errors.ts +0 -393
  104. package/src/errors/index.ts +0 -11
  105. package/src/errors/serialized-error.ts +0 -12
  106. package/src/factory-functions.test.ts +0 -111
  107. package/src/function/abort-scope.test.ts +0 -97
  108. package/src/function/abort-scope.ts +0 -80
  109. package/src/function/function-meta.types.ts +0 -151
  110. package/src/function/function-runner.test.ts +0 -1619
  111. package/src/function/function-runner.ts +0 -499
  112. package/src/function/functions.types.ts +0 -319
  113. package/src/function/index.ts +0 -40
  114. package/src/function/list.types.test.ts +0 -100
  115. package/src/function/list.types.ts +0 -69
  116. package/src/function/pikku-request.test.ts +0 -35
  117. package/src/function/pikku-request.ts +0 -17
  118. package/src/gopass-secrets-removed.test.ts +0 -51
  119. package/src/handle-error.test.ts +0 -532
  120. package/src/handle-error.ts +0 -64
  121. package/src/middleware/auth-apikey.test.ts +0 -362
  122. package/src/middleware/auth-apikey.ts +0 -39
  123. package/src/middleware/auth-bearer.test.ts +0 -566
  124. package/src/middleware/auth-bearer.ts +0 -83
  125. package/src/middleware/auth-cookie.test.ts +0 -572
  126. package/src/middleware/auth-cookie.ts +0 -107
  127. package/src/middleware/cors.test.ts +0 -579
  128. package/src/middleware/cors.ts +0 -103
  129. package/src/middleware/index.ts +0 -30
  130. package/src/middleware/middleware-factories.ts +0 -76
  131. package/src/middleware/middleware.types.ts +0 -61
  132. package/src/middleware/remote-auth.test.ts +0 -547
  133. package/src/middleware/remote-auth.ts +0 -95
  134. package/src/middleware/remote-jobs-secret.ts +0 -35
  135. package/src/middleware/require-origin.test.ts +0 -115
  136. package/src/middleware/require-origin.ts +0 -79
  137. package/src/middleware/telemetry.ts +0 -83
  138. package/src/middleware-runner.test.ts +0 -578
  139. package/src/middleware-runner.ts +0 -232
  140. package/src/no-any-casts.test.ts +0 -57
  141. package/src/no-root-barrel.test.ts +0 -122
  142. package/src/permissions.test.ts +0 -256
  143. package/src/permissions.ts +0 -217
  144. package/src/pikku-state.test.ts +0 -198
  145. package/src/pikku-state.ts +0 -206
  146. package/src/production-barrels-stay-lean.test.ts +0 -110
  147. package/src/public-surface.test.ts +0 -133
  148. package/src/remote.test.ts +0 -173
  149. package/src/remote.ts +0 -56
  150. package/src/removed-legacy-exports.test.ts +0 -66
  151. package/src/run-tests-script.test.ts +0 -67
  152. package/src/schema.test.ts +0 -430
  153. package/src/schema.ts +0 -204
  154. package/src/scopes.test.ts +0 -203
  155. package/src/scopes.ts +0 -67
  156. package/src/services/agent-run-state-service.ts +0 -37
  157. package/src/services/agent-runner-service.ts +0 -238
  158. package/src/services/agent-storage-service.ts +0 -39
  159. package/src/services/ai-embedding-service.ts +0 -9
  160. package/src/services/audit-service.test.ts +0 -44
  161. package/src/services/audit-service.ts +0 -280
  162. package/src/services/content-service.ts +0 -65
  163. package/src/services/credential-service.ts +0 -20
  164. package/src/services/credential-wire-service.test.ts +0 -235
  165. package/src/services/credential-wire-service.ts +0 -120
  166. package/src/services/deployment-service.ts +0 -32
  167. package/src/services/email-service.test.ts +0 -100
  168. package/src/services/email-service.ts +0 -60
  169. package/src/services/email-template.test.ts +0 -311
  170. package/src/services/email-template.ts +0 -254
  171. package/src/services/file-scenario-run-store.test.ts +0 -349
  172. package/src/services/file-scenario-run-store.ts +0 -282
  173. package/src/services/gateway-service.ts +0 -5
  174. package/src/services/http-personas-converse.test.ts +0 -274
  175. package/src/services/http-personas.test.ts +0 -379
  176. package/src/services/http-personas.ts +0 -508
  177. package/src/services/in-memory-agent-run-state-service.ts +0 -87
  178. package/src/services/in-memory-queue-service.test.ts +0 -162
  179. package/src/services/in-memory-queue-service.ts +0 -78
  180. package/src/services/in-memory-session-store.test.ts +0 -58
  181. package/src/services/in-memory-session-store.ts +0 -20
  182. package/src/services/in-memory-trigger-service.ts +0 -47
  183. package/src/services/in-memory-workflow-service.test.ts +0 -430
  184. package/src/services/in-memory-workflow-service.ts +0 -595
  185. package/src/services/index.ts +0 -192
  186. package/src/services/istanbul-coverage-service.test.ts +0 -66
  187. package/src/services/istanbul-coverage-service.ts +0 -59
  188. package/src/services/jwt-service.ts +0 -15
  189. package/src/services/local-content-request-handler.test.ts +0 -240
  190. package/src/services/local-content-request-handler.ts +0 -295
  191. package/src/services/local-content.test.ts +0 -186
  192. package/src/services/local-content.ts +0 -242
  193. package/src/services/local-credential-service.ts +0 -63
  194. package/src/services/local-email-service.test.ts +0 -182
  195. package/src/services/local-email-service.ts +0 -43
  196. package/src/services/local-gateway-service.ts +0 -51
  197. package/src/services/local-secrets.test.ts +0 -95
  198. package/src/services/local-secrets.ts +0 -71
  199. package/src/services/local-variables.test.ts +0 -61
  200. package/src/services/local-variables.ts +0 -45
  201. package/src/services/logger-console.test.ts +0 -117
  202. package/src/services/logger-console.ts +0 -174
  203. package/src/services/logger.ts +0 -48
  204. package/src/services/meta-service.test.ts +0 -75
  205. package/src/services/meta-service.ts +0 -767
  206. package/src/services/persona-actor-secret.test.ts +0 -68
  207. package/src/services/persona-actor-secret.ts +0 -70
  208. package/src/services/persona-sign-in.test.ts +0 -219
  209. package/src/services/persona-sign-in.ts +0 -238
  210. package/src/services/personas-service.ts +0 -191
  211. package/src/services/pikku-user-id.test.ts +0 -62
  212. package/src/services/pikku-user-id.ts +0 -13
  213. package/src/services/queue-webhook-service.test.ts +0 -409
  214. package/src/services/queue-webhook-service.ts +0 -150
  215. package/src/services/remote-jobs.test.ts +0 -106
  216. package/src/services/remote-jobs.ts +0 -92
  217. package/src/services/scheduler-service.ts +0 -37
  218. package/src/services/schema-service.ts +0 -10
  219. package/src/services/scope-service.ts +0 -91
  220. package/src/services/scoped-credential-service.test.ts +0 -86
  221. package/src/services/scoped-credential-service.ts +0 -63
  222. package/src/services/scoped-secret-service.test.ts +0 -93
  223. package/src/services/scoped-secret-service.ts +0 -40
  224. package/src/services/secret-host-binding.test.ts +0 -138
  225. package/src/services/secret-host-binding.ts +0 -51
  226. package/src/services/secret-service.ts +0 -25
  227. package/src/services/secretless.test.ts +0 -54
  228. package/src/services/secretless.ts +0 -29
  229. package/src/services/session-store.ts +0 -9
  230. package/src/services/stub-tracker.test.ts +0 -104
  231. package/src/services/stub-tracker.ts +0 -175
  232. package/src/services/system-role-guard.test.ts +0 -96
  233. package/src/services/system-role-guard.ts +0 -71
  234. package/src/services/temporary-file-service.ts +0 -76
  235. package/src/services/trigger-service.ts +0 -5
  236. package/src/services/typed-credential-service.ts +0 -83
  237. package/src/services/typed-secret-service.test.ts +0 -204
  238. package/src/services/typed-secret-service.ts +0 -132
  239. package/src/services/typed-variables-service.test.ts +0 -166
  240. package/src/services/typed-variables-service.ts +0 -166
  241. package/src/services/user-session-service.test.ts +0 -147
  242. package/src/services/user-session-service.ts +0 -85
  243. package/src/services/v8-coverage-service.test.ts +0 -69
  244. package/src/services/v8-coverage-service.ts +0 -163
  245. package/src/services/variables-service.ts +0 -13
  246. package/src/services/webhook-service.ts +0 -147
  247. package/src/services/workflow-service.ts +0 -120
  248. package/src/side-effects-are-declared.test.ts +0 -84
  249. package/src/source-files-stay-composable.test.ts +0 -41
  250. package/src/template-alias-surface.test.ts +0 -240
  251. package/src/test-utils.ts +0 -38
  252. package/src/testing/index.ts +0 -3
  253. package/src/testing/service-tests/agent-run-service-tests.ts +0 -98
  254. package/src/testing/service-tests/agent-storage-service-tests.ts +0 -379
  255. package/src/testing/service-tests/channel-store-tests.ts +0 -98
  256. package/src/testing/service-tests/credential-service-tests.ts +0 -143
  257. package/src/testing/service-tests/deployment-service-tests.ts +0 -33
  258. package/src/testing/service-tests/event-hub-store-tests.ts +0 -48
  259. package/src/testing/service-tests/secret-service-tests.ts +0 -105
  260. package/src/testing/service-tests/session-store-tests.ts +0 -62
  261. package/src/testing/service-tests/workflow-run-service-tests.ts +0 -59
  262. package/src/testing/service-tests/workflow-service-tests.ts +0 -308
  263. package/src/testing/service-tests.ts +0 -95
  264. package/src/time-utils.test.ts +0 -56
  265. package/src/time-utils.ts +0 -89
  266. package/src/types/core.types.ts +0 -446
  267. package/src/types/index.ts +0 -25
  268. package/src/types/state.types.ts +0 -226
  269. package/src/types/typed-credentials.test.ts +0 -72
  270. package/src/utils/hash.test.ts +0 -68
  271. package/src/utils/hash.ts +0 -26
  272. package/src/utils/hmac.ts +0 -21
  273. package/src/utils/node-host-resolver.ts +0 -20
  274. package/src/utils/safe-fetch.test.ts +0 -515
  275. package/src/utils/safe-fetch.ts +0 -347
  276. package/src/utils.test.ts +0 -359
  277. package/src/utils.ts +0 -165
  278. package/src/version.test.ts +0 -80
  279. package/src/version.ts +0 -25
  280. package/src/wirings/actor-flow/actor-flow.types.ts +0 -40
  281. package/src/wirings/actor-flow/index.ts +0 -10
  282. package/src/wirings/actor-flow/run-conversation.test.ts +0 -187
  283. package/src/wirings/actor-flow/run-conversation.ts +0 -280
  284. package/src/wirings/addon/addon-auth-tags.test.ts +0 -219
  285. package/src/wirings/addon/addon-runner.ts +0 -236
  286. package/src/wirings/addon/addon-scopes.test.ts +0 -225
  287. package/src/wirings/addon/addon-secrets.test.ts +0 -391
  288. package/src/wirings/addon/index.ts +0 -12
  289. package/src/wirings/addon/remote-addon-auth.ts +0 -65
  290. package/src/wirings/addon/wire-addon.test.ts +0 -102
  291. package/src/wirings/addon/wire-addon.ts +0 -202
  292. package/src/wirings/addon/wire-remote-addon.ts +0 -41
  293. package/src/wirings/agent/agent-agui.test.ts +0 -1213
  294. package/src/wirings/agent/agent-agui.ts +0 -405
  295. package/src/wirings/agent/agent-authorization.test.ts +0 -208
  296. package/src/wirings/agent/agent-finalize.test.ts +0 -187
  297. package/src/wirings/agent/agent-finalize.ts +0 -197
  298. package/src/wirings/agent/agent-helpers.test.ts +0 -215
  299. package/src/wirings/agent/agent-helpers.ts +0 -96
  300. package/src/wirings/agent/agent-interrupt.test.ts +0 -833
  301. package/src/wirings/agent/agent-interrupt.ts +0 -400
  302. package/src/wirings/agent/agent-memory.test.ts +0 -397
  303. package/src/wirings/agent/agent-memory.ts +0 -496
  304. package/src/wirings/agent/agent-middleware.types.test.ts +0 -41
  305. package/src/wirings/agent/agent-model-config.test.ts +0 -103
  306. package/src/wirings/agent/agent-model-config.ts +0 -59
  307. package/src/wirings/agent/agent-prepare.test.ts +0 -977
  308. package/src/wirings/agent/agent-prepare.ts +0 -1083
  309. package/src/wirings/agent/agent-registry.test.ts +0 -455
  310. package/src/wirings/agent/agent-registry.ts +0 -99
  311. package/src/wirings/agent/agent-resume-authorization.test.ts +0 -206
  312. package/src/wirings/agent/agent-rpc.ts +0 -116
  313. package/src/wirings/agent/agent-runner.test.ts +0 -1229
  314. package/src/wirings/agent/agent-runner.ts +0 -858
  315. package/src/wirings/agent/agent-stream-delegate.test.ts +0 -381
  316. package/src/wirings/agent/agent-stream-output-hooks.test.ts +0 -353
  317. package/src/wirings/agent/agent-stream.test.ts +0 -1800
  318. package/src/wirings/agent/agent-stream.ts +0 -1639
  319. package/src/wirings/agent/agent-thread-ownership.test.ts +0 -297
  320. package/src/wirings/agent/agent-turn.test.ts +0 -65
  321. package/src/wirings/agent/agent-turn.ts +0 -122
  322. package/src/wirings/agent/agent-utils.ts +0 -20
  323. package/src/wirings/agent/agent.types.ts +0 -676
  324. package/src/wirings/agent/index.ts +0 -58
  325. package/src/wirings/agent/voice-input.test.ts +0 -220
  326. package/src/wirings/agent/voice-input.ts +0 -180
  327. package/src/wirings/agent/voice-output.test.ts +0 -510
  328. package/src/wirings/agent/voice-output.ts +0 -311
  329. package/src/wirings/agent-scorer/agent-scorer-grade.test.ts +0 -106
  330. package/src/wirings/agent-scorer/agent-scorer-grade.ts +0 -55
  331. package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +0 -285
  332. package/src/wirings/agent-scorer/agent-scorer-judge.ts +0 -180
  333. package/src/wirings/agent-scorer/agent-scorer-live.test.ts +0 -174
  334. package/src/wirings/agent-scorer/agent-scorer-live.ts +0 -56
  335. package/src/wirings/agent-scorer/agent-scorer-registry.ts +0 -66
  336. package/src/wirings/agent-scorer/agent-scorer-sampling.test.ts +0 -34
  337. package/src/wirings/agent-scorer/agent-scorer-sampling.ts +0 -36
  338. package/src/wirings/agent-scorer/agent-scorer-snapshots.test.ts +0 -49
  339. package/src/wirings/agent-scorer/agent-scorer-snapshots.ts +0 -46
  340. package/src/wirings/agent-scorer/agent-scorer-worker.test.ts +0 -122
  341. package/src/wirings/agent-scorer/agent-scorer-worker.ts +0 -71
  342. package/src/wirings/agent-scorer/agent-scorer.ts +0 -102
  343. package/src/wirings/agent-scorer/agent-scorer.types.ts +0 -128
  344. package/src/wirings/agent-scorer/index.ts +0 -23
  345. package/src/wirings/channel/channel-common.ts +0 -102
  346. package/src/wirings/channel/channel-handler-shapes.test.ts +0 -72
  347. package/src/wirings/channel/channel-handler.test.ts +0 -322
  348. package/src/wirings/channel/channel-handler.ts +0 -259
  349. package/src/wirings/channel/channel-host-rpc.test.ts +0 -150
  350. package/src/wirings/channel/channel-host-rpc.ts +0 -69
  351. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -188
  352. package/src/wirings/channel/channel-middleware-runner.ts +0 -126
  353. package/src/wirings/channel/channel-rpc-registry.ts +0 -116
  354. package/src/wirings/channel/channel-rpc-responder.ts +0 -117
  355. package/src/wirings/channel/channel-rpc-service.ts +0 -132
  356. package/src/wirings/channel/channel-rpc-validators.ts +0 -65
  357. package/src/wirings/channel/channel-rpc.test.ts +0 -841
  358. package/src/wirings/channel/channel-rpc.ts +0 -5
  359. package/src/wirings/channel/channel-rpc.types.ts +0 -160
  360. package/src/wirings/channel/channel-runner.ts +0 -164
  361. package/src/wirings/channel/channel-store.ts +0 -35
  362. package/src/wirings/channel/channel.types.ts +0 -193
  363. package/src/wirings/channel/define-channel-routes.ts +0 -5
  364. package/src/wirings/channel/eventhub-service.ts +0 -16
  365. package/src/wirings/channel/eventhub-store.ts +0 -13
  366. package/src/wirings/channel/index.ts +0 -40
  367. package/src/wirings/channel/local/index.ts +0 -3
  368. package/src/wirings/channel/local/local-channel-handler.ts +0 -98
  369. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -339
  370. package/src/wirings/channel/local/local-channel-runner.ts +0 -271
  371. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -77
  372. package/src/wirings/channel/local/local-eventhub-service.ts +0 -69
  373. package/src/wirings/channel/log-channels.ts +0 -16
  374. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -135
  375. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -60
  376. package/src/wirings/channel/serverless/index.ts +0 -6
  377. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -328
  378. package/src/wirings/cli/channel/cli-approval.test.ts +0 -177
  379. package/src/wirings/cli/channel/cli-approval.ts +0 -135
  380. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -118
  381. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +0 -192
  382. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +0 -148
  383. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +0 -480
  384. package/src/wirings/cli/channel/cli-raw-client-runner.ts +0 -188
  385. package/src/wirings/cli/channel/index.ts +0 -6
  386. package/src/wirings/cli/cli-runner.test.ts +0 -969
  387. package/src/wirings/cli/cli-runner.ts +0 -538
  388. package/src/wirings/cli/cli.types.ts +0 -388
  389. package/src/wirings/cli/command-parser.test.ts +0 -1120
  390. package/src/wirings/cli/command-parser.ts +0 -713
  391. package/src/wirings/cli/define-cli-commands.ts +0 -13
  392. package/src/wirings/cli/format-cli-error.test.ts +0 -91
  393. package/src/wirings/cli/format-cli-error.ts +0 -96
  394. package/src/wirings/cli/index.ts +0 -19
  395. package/src/wirings/credential/credential.types.ts +0 -37
  396. package/src/wirings/credential/define-credential.ts +0 -49
  397. package/src/wirings/credential/index.ts +0 -7
  398. package/src/wirings/credential/validate-credential-definitions.ts +0 -63
  399. package/src/wirings/gateway/gateway-authorization.test.ts +0 -575
  400. package/src/wirings/gateway/gateway-channel-meta.test.ts +0 -44
  401. package/src/wirings/gateway/gateway-runner.test.ts +0 -581
  402. package/src/wirings/gateway/gateway-runner.ts +0 -411
  403. package/src/wirings/gateway/gateway.types.ts +0 -137
  404. package/src/wirings/gateway/index.ts +0 -15
  405. package/src/wirings/http/http-routes.test.ts +0 -318
  406. package/src/wirings/http/http-routes.ts +0 -111
  407. package/src/wirings/http/http-runner-addon-ref.test.ts +0 -238
  408. package/src/wirings/http/http-runner.test.ts +0 -503
  409. package/src/wirings/http/http-runner.ts +0 -462
  410. package/src/wirings/http/http.types.ts +0 -307
  411. package/src/wirings/http/index.ts +0 -27
  412. package/src/wirings/http/log-http-routes.ts +0 -18
  413. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -318
  414. package/src/wirings/http/pikku-fetch-http-request.ts +0 -260
  415. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -123
  416. package/src/wirings/http/pikku-fetch-http-response.ts +0 -149
  417. package/src/wirings/http/routers/http-router.ts +0 -13
  418. package/src/wirings/http/routers/path-to-regex.test.ts +0 -306
  419. package/src/wirings/http/routers/path-to-regex.ts +0 -115
  420. package/src/wirings/http/web-request.test.ts +0 -382
  421. package/src/wirings/http/web-request.ts +0 -162
  422. package/src/wirings/mcp/index.ts +0 -26
  423. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -388
  424. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  425. package/src/wirings/mcp/mcp-runner.test.ts +0 -588
  426. package/src/wirings/mcp/mcp-runner.ts +0 -330
  427. package/src/wirings/mcp/mcp.types.ts +0 -199
  428. package/src/wirings/node/index.ts +0 -2
  429. package/src/wirings/node/node.types.ts +0 -23
  430. package/src/wirings/oauth2/index.ts +0 -1
  431. package/src/wirings/oauth2/oauth2.types.ts +0 -12
  432. package/src/wirings/persona/define-personas.ts +0 -33
  433. package/src/wirings/persona/index.ts +0 -75
  434. package/src/wirings/persona/persona-app-scopes.test.ts +0 -47
  435. package/src/wirings/persona/persona-app-scopes.ts +0 -74
  436. package/src/wirings/persona/persona-email.ts +0 -87
  437. package/src/wirings/persona/persona-environments.test.ts +0 -194
  438. package/src/wirings/persona/persona-environments.ts +0 -138
  439. package/src/wirings/persona/persona-mailbox.ts +0 -156
  440. package/src/wirings/persona/persona.test.ts +0 -230
  441. package/src/wirings/persona/persona.types.ts +0 -156
  442. package/src/wirings/persona/validate-personas.ts +0 -137
  443. package/src/wirings/queue/index.ts +0 -29
  444. package/src/wirings/queue/queue-identity.test.ts +0 -454
  445. package/src/wirings/queue/queue-identity.ts +0 -176
  446. package/src/wirings/queue/queue-runner.test.ts +0 -705
  447. package/src/wirings/queue/queue-runner.ts +0 -181
  448. package/src/wirings/queue/queue.types.ts +0 -161
  449. package/src/wirings/queue/register-queue-helper.ts +0 -46
  450. package/src/wirings/queue/signed-queue-service.ts +0 -60
  451. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  452. package/src/wirings/queue/validate-worker-config.ts +0 -90
  453. package/src/wirings/role/define-system-role.ts +0 -33
  454. package/src/wirings/role/index.ts +0 -13
  455. package/src/wirings/role/role.test.ts +0 -104
  456. package/src/wirings/role/role.types.ts +0 -47
  457. package/src/wirings/role/validate-role-definitions.ts +0 -93
  458. package/src/wirings/rpc/index.ts +0 -8
  459. package/src/wirings/rpc/rpc-runner.test.ts +0 -1130
  460. package/src/wirings/rpc/rpc-runner.ts +0 -569
  461. package/src/wirings/rpc/rpc-types.ts +0 -87
  462. package/src/wirings/scheduler/index.ts +0 -11
  463. package/src/wirings/scheduler/log-schedulers.ts +0 -16
  464. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -835
  465. package/src/wirings/scheduler/scheduler-runner.ts +0 -138
  466. package/src/wirings/scheduler/scheduler.types.ts +0 -42
  467. package/src/wirings/scope/define-scope.ts +0 -33
  468. package/src/wirings/scope/index.ts +0 -15
  469. package/src/wirings/scope/scope.test.ts +0 -159
  470. package/src/wirings/scope/scope.types.ts +0 -42
  471. package/src/wirings/scope/validate-scope-definitions.ts +0 -107
  472. package/src/wirings/secret/index.ts +0 -9
  473. package/src/wirings/secret/secret.types.ts +0 -70
  474. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -232
  475. package/src/wirings/secret/validate-secret-definitions.ts +0 -88
  476. package/src/wirings/trigger/index.ts +0 -9
  477. package/src/wirings/trigger/pikku-trigger-service.ts +0 -107
  478. package/src/wirings/trigger/trigger-runner.test.ts +0 -78
  479. package/src/wirings/trigger/trigger-runner.ts +0 -113
  480. package/src/wirings/trigger/trigger.types.ts +0 -100
  481. package/src/wirings/variable/index.ts +0 -8
  482. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -115
  483. package/src/wirings/variable/validate-variable-definitions.ts +0 -71
  484. package/src/wirings/variable/variable.types.ts +0 -40
  485. package/src/wirings/virtual-user/index.ts +0 -107
  486. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +0 -115
  487. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +0 -95
  488. package/src/wirings/virtual-user/run-virtual-user.test.ts +0 -774
  489. package/src/wirings/virtual-user/run-virtual-user.ts +0 -684
  490. package/src/wirings/virtual-user/virtual-user-agents.test.ts +0 -72
  491. package/src/wirings/virtual-user/virtual-user-agents.ts +0 -62
  492. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +0 -215
  493. package/src/wirings/virtual-user/virtual-user-catalogue.ts +0 -184
  494. package/src/wirings/virtual-user/virtual-user-derive.test.ts +0 -426
  495. package/src/wirings/virtual-user/virtual-user-derive.ts +0 -161
  496. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +0 -68
  497. package/src/wirings/virtual-user/virtual-user-dispositions.ts +0 -210
  498. package/src/wirings/virtual-user/virtual-user-intents.test.ts +0 -218
  499. package/src/wirings/virtual-user/virtual-user-intents.ts +0 -185
  500. package/src/wirings/virtual-user/virtual-user-rng.test.ts +0 -72
  501. package/src/wirings/virtual-user/virtual-user-rng.ts +0 -50
  502. package/src/wirings/virtual-user/virtual-user-run-store.ts +0 -131
  503. package/src/wirings/virtual-user/virtual-user-scaffold.test.ts +0 -854
  504. package/src/wirings/virtual-user/virtual-user-scaffold.ts +0 -664
  505. package/src/wirings/virtual-user/virtual-user-schedule-store.ts +0 -93
  506. package/src/wirings/virtual-user/virtual-user-schedule.test.ts +0 -280
  507. package/src/wirings/virtual-user/virtual-user-schedule.ts +0 -156
  508. package/src/wirings/virtual-user/virtual-user-target.ts +0 -47
  509. package/src/wirings/virtual-user/virtual-user.types.ts +0 -215
  510. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -709
  511. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -25
  512. package/src/wirings/workflow/feature.test.ts +0 -131
  513. package/src/wirings/workflow/feature.ts +0 -59
  514. package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +0 -569
  515. package/src/wirings/workflow/graph/graph-foreach.test.ts +0 -626
  516. package/src/wirings/workflow/graph/graph-node.ts +0 -115
  517. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -1049
  518. package/src/wirings/workflow/graph/graph-runner.ts +0 -1376
  519. package/src/wirings/workflow/graph/graph-validation.test.ts +0 -27
  520. package/src/wirings/workflow/graph/graph-validation.ts +0 -41
  521. package/src/wirings/workflow/graph/template.test.ts +0 -49
  522. package/src/wirings/workflow/graph/template.ts +0 -42
  523. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -39
  524. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -75
  525. package/src/wirings/workflow/index.ts +0 -107
  526. package/src/wirings/workflow/pikku-scenario-service.ts +0 -1013
  527. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -963
  528. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1993
  529. package/src/wirings/workflow/run-timeline.test.ts +0 -199
  530. package/src/wirings/workflow/run-timeline.ts +0 -185
  531. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -107
  532. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -57
  533. package/src/wirings/workflow/scenario-expectations.test.ts +0 -238
  534. package/src/wirings/workflow/scenario-hooks.test.ts +0 -259
  535. package/src/wirings/workflow/scenario-poll.test.ts +0 -64
  536. package/src/wirings/workflow/scenario-poll.ts +0 -27
  537. package/src/wirings/workflow/scenario-prose.test.ts +0 -275
  538. package/src/wirings/workflow/scenario-prose.ts +0 -86
  539. package/src/wirings/workflow/scenario-run.types.ts +0 -193
  540. package/src/wirings/workflow/scenario-service.test.ts +0 -147
  541. package/src/wirings/workflow/scenario-step-guards.ts +0 -23
  542. package/src/wirings/workflow/scenario-step.test.ts +0 -800
  543. package/src/wirings/workflow/scenario-step.types.ts +0 -262
  544. package/src/wirings/workflow/scenario-surface.test.ts +0 -146
  545. package/src/wirings/workflow/scenario-surface.ts +0 -71
  546. package/src/wirings/workflow/scenario.types.ts +0 -63
  547. package/src/wirings/workflow/workflow-approval-audit.ts +0 -47
  548. package/src/wirings/workflow/workflow-approval-policy.test.ts +0 -594
  549. package/src/wirings/workflow/workflow-approval-policy.ts +0 -68
  550. package/src/wirings/workflow/workflow-approval.ts +0 -290
  551. package/src/wirings/workflow/workflow-child-run-session.test.ts +0 -168
  552. package/src/wirings/workflow/workflow-constants.ts +0 -66
  553. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +0 -116
  554. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -55
  555. package/src/wirings/workflow/workflow-dispatch-relay.test.ts +0 -128
  556. package/src/wirings/workflow/workflow-errors.ts +0 -132
  557. package/src/wirings/workflow/workflow-inline-authority.test.ts +0 -175
  558. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -51
  559. package/src/wirings/workflow/workflow-invocation-id.ts +0 -28
  560. package/src/wirings/workflow/workflow-meta-resolver.ts +0 -45
  561. package/src/wirings/workflow/workflow-mirror.test.ts +0 -171
  562. package/src/wirings/workflow/workflow-missing-meta.test.ts +0 -92
  563. package/src/wirings/workflow/workflow-on-error.test.ts +0 -145
  564. package/src/wirings/workflow/workflow-queue-routing.ts +0 -129
  565. package/src/wirings/workflow/workflow-queue-wiring.ts +0 -149
  566. package/src/wirings/workflow/workflow-queue-workers.test.ts +0 -131
  567. package/src/wirings/workflow/workflow-queue-workers.ts +0 -66
  568. package/src/wirings/workflow/workflow-recovery.ts +0 -192
  569. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +0 -140
  570. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -113
  571. package/src/wirings/workflow/workflow-run-authority.test.ts +0 -212
  572. package/src/wirings/workflow/workflow-run-context.test.ts +0 -172
  573. package/src/wirings/workflow/workflow-run-engine.types.ts +0 -92
  574. package/src/wirings/workflow/workflow-run-ownership.ts +0 -37
  575. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -127
  576. package/src/wirings/workflow/workflow-stalled-recovery.test.ts +0 -152
  577. package/src/wirings/workflow/workflow-status-stream.test.ts +0 -354
  578. package/src/wirings/workflow/workflow-status-stream.ts +0 -144
  579. package/src/wirings/workflow/workflow-step-claim.ts +0 -46
  580. package/src/wirings/workflow/workflow-step-ordinal.test.ts +0 -94
  581. package/src/wirings/workflow/workflow-step-session.test.ts +0 -87
  582. package/src/wirings/workflow/workflow-suspend.ts +0 -61
  583. package/src/wirings/workflow/workflow-terminal-run-guard.test.ts +0 -105
  584. package/src/wirings/workflow/workflow.types.ts +0 -268
  585. package/src/wirings-stay-decoupled.test.ts +0 -130
  586. package/tsconfig.json +0 -14
  587. package/tsconfig.tsbuildinfo +0 -1
  588. package/tsconfig.type-tests.json +0 -15
@@ -1,1376 +0,0 @@
1
- import type { PikkuWorkflowService } from '../pikku-workflow-service.js'
2
- import {
3
- WorkflowAsyncException,
4
- WorkflowSuspendedException,
5
- } from '../workflow-errors.js'
6
- import { DEFAULT_STEP_RETRIES } from '../workflow-constants.js'
7
- import type { GraphWireState, PikkuGraphWire } from './workflow-graph.types.js'
8
- import { pikkuState, getSingletonServices } from '../../../pikku-state.js'
9
- import type { WorkflowRuntimeMeta, WorkflowRunWire } from '../workflow.types.js'
10
- import { RPCNotFoundError } from '../../rpc/rpc-runner.js'
11
-
12
- export class ChildWorkflowStartedException extends Error {
13
- name = 'ChildWorkflowStartedException'
14
- constructor(
15
- public parentRunId: string,
16
- public stepId: string,
17
- public childRunId: string
18
- ) {
19
- super(`Child workflow started: ${childRunId}`)
20
- }
21
- }
22
-
23
- function buildTemplateRegex(nodeId: string): RegExp | null {
24
- if (!nodeId.includes('${')) return null
25
- const escaped = nodeId
26
- .split(/\$\{[^}]+\}/)
27
- .map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
28
- .join('.+')
29
- return new RegExp(`^${escaped}$`)
30
- }
31
-
32
- const FANOUT_INSTANCE = /^(.+)\[(\d+)\]$/
33
-
34
- function fanoutInstanceKey(base: string, index: number): string {
35
- return `${base}[${index}]`
36
- }
37
-
38
- function splitFanoutInstance(
39
- name: string
40
- ): { base: string; index: number } | null {
41
- const match = FANOUT_INSTANCE.exec(name)
42
- if (!match) return null
43
- return { base: match[1]!, index: Number(match[2]!) }
44
- }
45
-
46
- export function stripInstanceOrdinal(name: string): string {
47
- const fanout = splitFanoutInstance(name)
48
- const withoutItem = fanout ? fanout.base : name
49
- const hash = withoutItem.lastIndexOf('#')
50
- if (hash <= 0) return withoutItem
51
- return /^\d+$/.test(withoutItem.slice(hash + 1))
52
- ? withoutItem.slice(0, hash)
53
- : withoutItem
54
- }
55
-
56
- function remapStepNamesToNodeIds(
57
- stepNames: string[],
58
- nodes: Record<string, any>,
59
- graphName: string
60
- ): string[] {
61
- const templatePatterns = new Map<string, RegExp>()
62
- for (const nodeId of Object.keys(nodes)) {
63
- const regex = buildTemplateRegex(nodeId)
64
- if (regex) templatePatterns.set(nodeId, regex)
65
- }
66
- return stepNames.map((name) => {
67
- if (nodes[name]) return name
68
- const base = stripInstanceOrdinal(name)
69
- if (base !== name && nodes[base]) return base
70
- const matches: string[] = []
71
- for (const [nodeId, regex] of templatePatterns) {
72
- if (regex.test(base)) matches.push(nodeId)
73
- }
74
- if (matches.length > 1) {
75
- throw new Error(
76
- `Workflow graph '${graphName}': ambiguous template node match for '${name}' (${matches.join(', ')})`
77
- )
78
- }
79
- if (matches.length === 1) {
80
- return matches[0]!
81
- }
82
- return name
83
- })
84
- }
85
-
86
- const ENTRY_FROM = '__entry__'
87
-
88
- function closesCycle(
89
- source: string,
90
- target: string,
91
- nodes: Record<string, any>
92
- ): boolean {
93
- const seen = new Set<string>()
94
- const stack = [target]
95
- while (stack.length) {
96
- const cur = stack.pop()!
97
- if (cur === source) return true
98
- if (seen.has(cur)) continue
99
- seen.add(cur)
100
- for (const next of normalizeNodeTargets(nodes[cur]?.next)) stack.push(next)
101
- }
102
- return false
103
- }
104
-
105
- interface GraphFireInstruction {
106
- logical: string
107
- instanceKey: string
108
- fromStepName?: string
109
- itemIndex?: number
110
- }
111
-
112
- function planGraphTransitions(
113
- nodes: Record<string, any>,
114
- instances: Array<{ stepName: string; status: string; fromStepName?: string }>,
115
- branchByStep: Record<string, string>,
116
- entryNodeIds: string[],
117
- graphName: string,
118
- fanoutWidths: Record<string, number> = {}
119
- ): {
120
- toFire: GraphFireInstruction[]
121
- hasInFlight: boolean
122
- blockedWaiting: boolean
123
- } {
124
- const toLogical = (name: string) =>
125
- remapStepNamesToNodeIds([name], nodes, graphName)[0]!
126
-
127
- const countByLogical: Record<string, number> = {}
128
- const instancesByLogical: Record<
129
- string,
130
- Array<{ stepName: string; status: string }>
131
- > = {}
132
- const consumed = new Set<string>()
133
- for (const inst of instances) {
134
- const logical = toLogical(inst.stepName)
135
- countByLogical[logical] = (countByLogical[logical] ?? 0) + 1
136
- ;(instancesByLogical[logical] ??= []).push(inst)
137
- consumed.add(`${inst.fromStepName ?? ENTRY_FROM}->${logical}`)
138
- }
139
-
140
- const isFanned = (nodeId: string) => Boolean(nodes[nodeId]?.forEach)
141
- const fanoutComplete = (nodeId: string) => {
142
- const width = fanoutWidths[nodeId]
143
- if (width === undefined) return false
144
- const succeeded = (instancesByLogical[nodeId] ?? []).filter(
145
- (i) => i.status === 'succeeded'
146
- ).length
147
- return succeeded >= width
148
- }
149
-
150
- const completed = instances.filter((i) => i.status === 'succeeded')
151
- const completedLogical = new Set<string>()
152
- for (const inst of completed) {
153
- const logical = toLogical(inst.stepName)
154
- if (!isFanned(logical)) completedLogical.add(logical)
155
- }
156
- for (const nodeId of Object.keys(fanoutWidths)) {
157
- if (isFanned(nodeId) && fanoutComplete(nodeId)) completedLogical.add(nodeId)
158
- }
159
-
160
- const edges: Array<{
161
- from?: string
162
- fromKey: string
163
- fromLogical?: string
164
- target: string
165
- }> = []
166
- for (const entryId of entryNodeIds) {
167
- edges.push({ fromKey: ENTRY_FROM, target: entryId })
168
- }
169
- const fannedEdgesEmitted = new Set<string>()
170
- for (const inst of completed) {
171
- const fromLogical = toLogical(inst.stepName)
172
- const node = nodes[fromLogical]
173
- if (!node?.next) continue
174
- let from = inst.stepName
175
- let branchKey = branchByStep[inst.stepName]
176
- if (isFanned(fromLogical)) {
177
- if (!completedLogical.has(fromLogical)) continue
178
- if (fannedEdgesEmitted.has(fromLogical)) continue
179
- fannedEdgesEmitted.add(fromLogical)
180
- from = fromLogical
181
- branchKey = branchByStep[fromLogical] ?? branchByStep[inst.stepName]
182
- }
183
- for (const target of resolveNextFromConfig(node.next, branchKey)) {
184
- edges.push({ from, fromKey: from, fromLogical, target })
185
- }
186
- }
187
- // A zero-width fanout produces no instances at all, so its outgoing edges
188
- // have no completed instance to hang off — emit them from the logical node.
189
- for (const [nodeId, width] of Object.entries(fanoutWidths)) {
190
- if (width !== 0 || fannedEdgesEmitted.has(nodeId)) continue
191
- const node = nodes[nodeId]
192
- if (!node?.next) continue
193
- fannedEdgesEmitted.add(nodeId)
194
- for (const target of resolveNextFromConfig(
195
- node.next,
196
- branchByStep[nodeId]
197
- )) {
198
- edges.push({ from: nodeId, fromKey: nodeId, fromLogical: nodeId, target })
199
- }
200
- }
201
-
202
- const toFire: GraphFireInstruction[] = []
203
- const plannedFanout = new Set<string>()
204
- let blockedWaiting = false
205
- for (const edge of edges) {
206
- const target = edge.target
207
- const edgeKey = `${edge.fromKey}->${target}`
208
-
209
- if (isFanned(target)) {
210
- if (plannedFanout.has(target)) continue
211
- plannedFanout.add(target)
212
- if (!areDependenciesSatisfied(nodes[target] ?? {}, completedLogical)) {
213
- blockedWaiting = true
214
- continue
215
- }
216
- const width = fanoutWidths[target]
217
- if (width === undefined) {
218
- blockedWaiting = true
219
- continue
220
- }
221
- const existing = instancesByLogical[target] ?? []
222
- const existingIndexes = new Set(
223
- existing
224
- .map((i) => splitFanoutInstance(i.stepName)?.index)
225
- .filter((index): index is number => index !== undefined)
226
- )
227
- const pending: number[] = []
228
- for (let index = 0; index < width; index++) {
229
- if (!existingIndexes.has(index)) pending.push(index)
230
- }
231
- if (pending.length === 0) continue
232
- const sequential = nodes[target]?.mode === 'sequential'
233
- const anyInFlight = existing.some((i) => i.status !== 'succeeded')
234
- const emit = sequential
235
- ? anyInFlight
236
- ? []
237
- : pending.slice(0, 1)
238
- : pending
239
- for (const index of emit) {
240
- toFire.push({
241
- logical: target,
242
- instanceKey: fanoutInstanceKey(target, index),
243
- fromStepName: edge.from,
244
- itemIndex: index,
245
- })
246
- }
247
- if (emit.length === 0) blockedWaiting = true
248
- continue
249
- }
250
-
251
- if (consumed.has(edgeKey)) continue
252
- const visits = countByLogical[target] ?? 0
253
- const isBackEdge =
254
- edge.fromLogical !== undefined &&
255
- closesCycle(edge.fromLogical, target, nodes)
256
- if (!isBackEdge && visits > 0) {
257
- consumed.add(edgeKey)
258
- continue
259
- }
260
- if (!areDependenciesSatisfied(nodes[target] ?? {}, completedLogical)) {
261
- blockedWaiting = true
262
- continue
263
- }
264
- toFire.push({
265
- logical: target,
266
- instanceKey: visits === 0 ? target : `${target}#${visits}`,
267
- fromStepName: edge.from,
268
- })
269
- countByLogical[target] = visits + 1
270
- consumed.add(edgeKey)
271
- }
272
-
273
- return {
274
- toFire,
275
- hasInFlight: instances.some((i) => i.status !== 'succeeded'),
276
- blockedWaiting,
277
- }
278
- }
279
-
280
- function remapBranchKeys(
281
- branchKeys: Record<string, string>,
282
- nodes: Record<string, any>,
283
- graphName: string
284
- ): Record<string, string> {
285
- const templatePatterns = new Map<string, RegExp>()
286
- for (const nodeId of Object.keys(nodes)) {
287
- const regex = buildTemplateRegex(nodeId)
288
- if (regex) templatePatterns.set(nodeId, regex)
289
- }
290
- if (templatePatterns.size === 0) return branchKeys
291
- const remapped: Record<string, string> = {}
292
- for (const [key, value] of Object.entries(branchKeys)) {
293
- let mappedKey = key
294
- if (!nodes[key]) {
295
- const matches: string[] = []
296
- for (const [nodeId, regex] of templatePatterns) {
297
- if (regex.test(key)) matches.push(nodeId)
298
- }
299
- if (matches.length > 1) {
300
- throw new Error(
301
- `Workflow graph '${graphName}': ambiguous template branch key match for '${key}' (${matches.join(', ')})`
302
- )
303
- }
304
- if (matches.length === 1) {
305
- mappedKey = matches[0]!
306
- }
307
- }
308
- remapped[mappedKey] = value
309
- }
310
- return remapped
311
- }
312
-
313
- function isDataRef(value: unknown): value is { $ref: string; path?: string } {
314
- return (
315
- typeof value === 'object' &&
316
- value !== null &&
317
- '$ref' in value &&
318
- typeof (value as { $ref?: unknown }).$ref === 'string'
319
- )
320
- }
321
-
322
- interface TemplateValue {
323
- $template: {
324
- parts: string[]
325
- expressions: Array<{ $ref: string; path?: string }>
326
- }
327
- }
328
-
329
- function isTemplate(value: unknown): value is TemplateValue {
330
- return (
331
- typeof value === 'object' &&
332
- value !== null &&
333
- '$template' in value &&
334
- typeof (value as { $template?: unknown }).$template === 'object'
335
- )
336
- }
337
-
338
- function getWorkflowMeta(name: string): WorkflowRuntimeMeta | undefined {
339
- const rootMeta = pikkuState(null, 'workflows', 'meta')
340
- if (rootMeta[name]) return rootMeta[name]
341
-
342
- const colonIndex = name.indexOf(':')
343
- if (colonIndex !== -1) {
344
- const namespace = name.substring(0, colonIndex)
345
- const localName = name.substring(colonIndex + 1)
346
- const addons = pikkuState(null, 'addons', 'packages')
347
- const pkgConfig = addons?.get(namespace)
348
- if (pkgConfig) {
349
- const addonMeta = pikkuState(pkgConfig.package, 'workflows', 'meta')
350
- if (addonMeta?.[localName]) return addonMeta[localName]
351
- }
352
- }
353
-
354
- return undefined
355
- }
356
-
357
- function resolveNextFromConfig(next: unknown, branchKey?: string): string[] {
358
- if (!next) return []
359
-
360
- if (typeof next === 'string') return [next]
361
- if (Array.isArray(next)) return next
362
-
363
- if (typeof next === 'object' && next !== null) {
364
- if (!branchKey || !(branchKey in next)) return []
365
- const branchNext = (next as Record<string, string | string[]>)[branchKey]!
366
- return Array.isArray(branchNext) ? branchNext : [branchNext]
367
- }
368
-
369
- return []
370
- }
371
-
372
- function getValueAtPath(obj: any, path: string): any {
373
- if (!path) return obj
374
- const parts = path.split('.')
375
- let current = obj
376
- for (const part of parts) {
377
- if (current == null) return undefined
378
- current = current[part]
379
- }
380
- return current
381
- }
382
-
383
- function resolveTemplate(
384
- template: TemplateValue,
385
- nodeResults: Record<string, any>
386
- ): string {
387
- const { parts, expressions } = template.$template
388
- let result = ''
389
- for (let i = 0; i < parts.length; i++) {
390
- result += parts[i]
391
- if (i < expressions.length) {
392
- const expr = expressions[i]!
393
- const nodeResult = nodeResults[expr.$ref]
394
- const value = expr.path
395
- ? getValueAtPath(nodeResult, expr.path)
396
- : nodeResult
397
- result += String(value ?? '')
398
- }
399
- }
400
- return result
401
- }
402
-
403
- function resolveValue(value: unknown, nodeResults: Record<string, any>): any {
404
- if (isDataRef(value)) {
405
- if (value.$ref === '$item' && !('$item' in nodeResults)) {
406
- return value
407
- }
408
- const source = nodeResults[value.$ref]
409
- return value.path ? getValueAtPath(source, value.path) : source
410
- }
411
- if (isTemplate(value)) {
412
- return resolveTemplate(value, nodeResults)
413
- }
414
- if (Array.isArray(value)) {
415
- return value.map((item) => resolveValue(item, nodeResults))
416
- }
417
- if (typeof value === 'object' && value !== null) {
418
- const resolved: Record<string, any> = {}
419
- for (const [k, v] of Object.entries(value)) {
420
- resolved[k] = resolveValue(v, nodeResults)
421
- }
422
- return resolved
423
- }
424
- return value
425
- }
426
-
427
- function resolveSerializedInput(
428
- input: Record<string, unknown> | undefined,
429
- nodeResults: Record<string, any>
430
- ): Record<string, any> {
431
- if (!input || Object.keys(input).length === 0) return {}
432
-
433
- const resolved: Record<string, any> = {}
434
- for (const [key, value] of Object.entries(input)) {
435
- resolved[key] = resolveValue(value, nodeResults)
436
- }
437
- return resolved
438
- }
439
-
440
- function collectReferencedNodeIds(value: unknown, nodeIds: string[]): void {
441
- if (isDataRef(value)) {
442
- nodeIds.push(value.$ref)
443
- } else if (isTemplate(value)) {
444
- for (const expr of value.$template.expressions) {
445
- nodeIds.push(expr.$ref)
446
- }
447
- } else if (Array.isArray(value)) {
448
- for (const item of value) {
449
- collectReferencedNodeIds(item, nodeIds)
450
- }
451
- } else if (typeof value === 'object' && value !== null) {
452
- for (const v of Object.values(value)) {
453
- collectReferencedNodeIds(v, nodeIds)
454
- }
455
- }
456
- }
457
-
458
- function extractReferencedNodeIds(
459
- input: Record<string, unknown> | undefined
460
- ): string[] {
461
- if (!input) return []
462
- const nodeIds: string[] = []
463
- for (const value of Object.values(input)) {
464
- collectReferencedNodeIds(value, nodeIds)
465
- }
466
- return [...new Set(nodeIds)]
467
- }
468
-
469
- const IGNORED_REFS = new Set(['trigger', '$item', 'unknown'])
470
-
471
- const FOREACH_MODES = new Set(['parallel', 'sequential'])
472
-
473
- function normalizeNodeTargets(value: unknown): string[] {
474
- if (!value) return []
475
- if (typeof value === 'string') return [value]
476
- if (Array.isArray(value)) return value.filter((v) => typeof v === 'string')
477
- if (typeof value === 'object') {
478
- const targets: string[] = []
479
- for (const branchTarget of Object.values(
480
- value as Record<string, unknown>
481
- )) {
482
- targets.push(...normalizeNodeTargets(branchTarget))
483
- }
484
- return targets
485
- }
486
- return []
487
- }
488
-
489
- function validateGraphReferences(
490
- graphName: string,
491
- nodes: Record<string, any>,
492
- entryNodes: string[]
493
- ): void {
494
- const nodeIds = new Set(Object.keys(nodes))
495
-
496
- for (const entryId of entryNodes) {
497
- if (!nodeIds.has(entryId)) {
498
- throw new Error(
499
- `Workflow graph '${graphName}': entry node '${entryId}' is not defined`
500
- )
501
- }
502
- }
503
-
504
- for (const [nodeId, node] of Object.entries(nodes)) {
505
- const inputRefs = extractReferencedNodeIds(node.input).filter(
506
- (id) => !IGNORED_REFS.has(id)
507
- )
508
- for (const refId of inputRefs) {
509
- if (!nodeIds.has(refId)) {
510
- throw new Error(
511
- `Workflow graph '${graphName}': node '${nodeId}' references unknown node '${refId}' in input`
512
- )
513
- }
514
- }
515
-
516
- if (node.forEach !== undefined) {
517
- const source = forEachSource(node)
518
- if (!source) {
519
- throw new Error(
520
- `Workflow graph '${graphName}': node '${nodeId}' forEach must reference a node`
521
- )
522
- }
523
- if (!IGNORED_REFS.has(source.$ref) && !nodeIds.has(source.$ref)) {
524
- throw new Error(
525
- `Workflow graph '${graphName}': node '${nodeId}' references unknown node '${source.$ref}' in forEach`
526
- )
527
- }
528
- if (node.mode !== undefined && !FOREACH_MODES.has(node.mode)) {
529
- throw new Error(
530
- `Workflow graph '${graphName}': node '${nodeId}' has an unknown forEach mode '${node.mode}'`
531
- )
532
- }
533
- } else if (node.mode !== undefined) {
534
- throw new Error(
535
- `Workflow graph '${graphName}': node '${nodeId}' sets mode '${node.mode}' without a forEach`
536
- )
537
- }
538
-
539
- const nextTargets = normalizeNodeTargets(node.next)
540
- for (const nextId of nextTargets) {
541
- if (!nodeIds.has(nextId)) {
542
- throw new Error(
543
- `Workflow graph '${graphName}': node '${nodeId}' routes to unknown node '${nextId}'`
544
- )
545
- }
546
- }
547
-
548
- const errorTargets = normalizeNodeTargets(node.onError)
549
- for (const errorId of errorTargets) {
550
- if (!nodeIds.has(errorId)) {
551
- throw new Error(
552
- `Workflow graph '${graphName}': node '${nodeId}' onError targets unknown node '${errorId}'`
553
- )
554
- }
555
- }
556
- }
557
- }
558
-
559
- function forEachSource(node: {
560
- forEach?: unknown
561
- }): { $ref: string; path?: string } | undefined {
562
- return isDataRef(node.forEach) ? node.forEach : undefined
563
- }
564
-
565
- function nodeDependencies(node: {
566
- input?: Record<string, unknown>
567
- forEach?: unknown
568
- }): string[] {
569
- const deps = extractReferencedNodeIds(node.input)
570
- const source = forEachSource(node)
571
- if (source) deps.push(source.$ref)
572
- return [...new Set(deps)].filter((id) => !IGNORED_REFS.has(id))
573
- }
574
-
575
- function describeValue(value: unknown): string {
576
- if (value === null) return 'null'
577
- if (value === undefined) return 'undefined'
578
- return typeof value
579
- }
580
-
581
- function resolveForEachItems(
582
- graphName: string,
583
- nodeId: string,
584
- node: { forEach?: unknown },
585
- nodeResults: Record<string, any>
586
- ): unknown[] {
587
- const source = forEachSource(node)
588
- if (!source) {
589
- throw new Error(
590
- `Workflow graph '${graphName}': node '${nodeId}' has an unusable forEach configuration`
591
- )
592
- }
593
- const raw = nodeResults[source.$ref]
594
- const value = source.path ? getValueAtPath(raw, source.path) : raw
595
- if (!Array.isArray(value)) {
596
- const label = source.path ? `${source.$ref}.${source.path}` : source.$ref
597
- throw new Error(
598
- `Workflow graph '${graphName}': node '${nodeId}' forEach source '${label}' resolved to ${describeValue(
599
- value
600
- )}, expected an array`
601
- )
602
- }
603
- return value
604
- }
605
-
606
- function areDependenciesSatisfied(
607
- node: { input?: Record<string, unknown>; forEach?: unknown },
608
- completedNodeIds: Set<string>
609
- ): boolean {
610
- return nodeDependencies(node).every((dep) => completedNodeIds.has(dep))
611
- }
612
-
613
- interface GraphResultReader {
614
- /** Per-item source arrays, keyed by fanned node id, for every ready fanout. */
615
- fanoutItems: Record<string, unknown[]>
616
- fanoutWidths: Record<string, number>
617
- /** Reads node results, aggregating a fanned node into its ordered item array. */
618
- read: (nodeIds: string[]) => Promise<Record<string, any>>
619
- }
620
-
621
- async function createGraphResultReader(
622
- workflowService: PikkuWorkflowService,
623
- runId: string,
624
- graphName: string,
625
- nodes: Record<string, any>,
626
- triggerInput: any,
627
- instances: Array<{ stepName: string; status: string }>
628
- ): Promise<GraphResultReader> {
629
- const succeeded = new Set(
630
- instances.filter((i) => i.status === 'succeeded').map((i) => i.stepName)
631
- )
632
- const fanoutItems: Record<string, unknown[]> = {}
633
- const fanoutWidths: Record<string, number> = {}
634
- const resultCache = new Map<string, any>()
635
- const resolving = new Set<string>()
636
-
637
- const readResult = async (nodeId: string): Promise<any> => {
638
- if (nodeId === 'trigger') return triggerInput
639
- if (resultCache.has(nodeId)) return resultCache.get(nodeId)
640
- if (resolving.has(nodeId)) return undefined
641
- resolving.add(nodeId)
642
- try {
643
- let value: any
644
- if (nodes[nodeId]?.forEach) {
645
- const items = await readFanoutItems(nodeId)
646
- if (items === undefined) return undefined
647
- const keys = items.map((_, index) => fanoutInstanceKey(nodeId, index))
648
- if (keys.some((key) => !succeeded.has(key))) return undefined
649
- const fetched = keys.length
650
- ? await workflowService.getNodeResults(runId, keys)
651
- : {}
652
- value = keys.map((key) => fetched[key])
653
- } else {
654
- if (!succeeded.has(nodeId)) return undefined
655
- const fetched = await workflowService.getNodeResults(runId, [nodeId])
656
- value = fetched[nodeId]
657
- }
658
- resultCache.set(nodeId, value)
659
- return value
660
- } finally {
661
- resolving.delete(nodeId)
662
- }
663
- }
664
-
665
- const readFanoutItems = async (
666
- nodeId: string
667
- ): Promise<unknown[] | undefined> => {
668
- if (fanoutItems[nodeId]) return fanoutItems[nodeId]
669
- const node = nodes[nodeId]
670
- const source = forEachSource(node)
671
- if (!source) return undefined
672
- const sourceValue = await readResult(source.$ref)
673
- if (sourceValue === undefined) return undefined
674
- const items = resolveForEachItems(graphName, nodeId, node, {
675
- [source.$ref]: sourceValue,
676
- })
677
- fanoutItems[nodeId] = items
678
- fanoutWidths[nodeId] = items.length
679
- return items
680
- }
681
-
682
- for (const nodeId of Object.keys(nodes)) {
683
- if (nodes[nodeId]?.forEach) await readFanoutItems(nodeId)
684
- }
685
-
686
- return {
687
- fanoutItems,
688
- fanoutWidths,
689
- read: async (nodeIds: string[]) => {
690
- const results: Record<string, any> = {}
691
- for (const nodeId of nodeIds) {
692
- const value = await readResult(nodeId)
693
- if (value !== undefined) results[nodeId] = value
694
- }
695
- return results
696
- },
697
- }
698
- }
699
-
700
- async function queueGraphNode(
701
- workflowService: PikkuWorkflowService,
702
- runId: string,
703
- _graphName: string,
704
- nodeId: string,
705
- rpcName: string,
706
- input: any,
707
- nodeConfig?: { retries?: number; retryDelay?: string | number },
708
- fromStepName?: string
709
- ): Promise<void> {
710
- const stepOptions = {
711
- retries: nodeConfig?.retries ?? DEFAULT_STEP_RETRIES,
712
- retryDelay: nodeConfig?.retryDelay,
713
- }
714
- await workflowService.insertStepState(
715
- runId,
716
- nodeId,
717
- rpcName,
718
- input,
719
- stepOptions,
720
- fromStepName
721
- )
722
- await workflowService.queueStepWorker(
723
- runId,
724
- nodeId,
725
- rpcName,
726
- input,
727
- stepOptions,
728
- fromStepName
729
- )
730
- }
731
-
732
- export async function continueGraph(
733
- workflowService: PikkuWorkflowService,
734
- runId: string,
735
- graphName: string,
736
- overrideMeta?: WorkflowRuntimeMeta
737
- ): Promise<void> {
738
- const meta = overrideMeta ?? getWorkflowMeta(graphName)
739
- if (!meta?.nodes) {
740
- throw new Error(`Workflow graph meta '${graphName}' not found`)
741
- }
742
-
743
- const nodes = meta.nodes
744
- validateGraphReferences(graphName, nodes, meta.entryNodeIds ?? [])
745
-
746
- const {
747
- completedNodeIds: rawCompleted,
748
- failedNodeIds: rawFailed,
749
- branchKeys: branchByStep,
750
- } = await workflowService.getCompletedGraphState(runId)
751
- remapStepNamesToNodeIds(rawCompleted, nodes, graphName)
752
- remapBranchKeys(branchByStep, nodes, graphName)
753
- const failedNodeIds = remapStepNamesToNodeIds(rawFailed, nodes, graphName)
754
-
755
- if (failedNodeIds.length > 0) {
756
- const failedNode = failedNodeIds[0]!
757
- await workflowService.updateRunStatus(runId, 'failed', undefined, {
758
- message: `Graph node '${failedNode}' failed after exhausting retries`,
759
- stack: '',
760
- code: 'GRAPH_NODE_FAILED',
761
- })
762
- return
763
- }
764
-
765
- const currentRun = await workflowService.getRun(runId)
766
- if (currentRun?.status === 'suspended') {
767
- return
768
- }
769
-
770
- const instances = await workflowService.getStepInstances(runId)
771
- const triggerInput = currentRun?.input
772
- const reader = await createGraphResultReader(
773
- workflowService,
774
- runId,
775
- graphName,
776
- nodes,
777
- triggerInput,
778
- instances
779
- )
780
- const plan = planGraphTransitions(
781
- nodes,
782
- instances,
783
- branchByStep,
784
- meta.entryNodeIds ?? [],
785
- graphName,
786
- reader.fanoutWidths
787
- )
788
-
789
- if (plan.toFire.length === 0) {
790
- if (!plan.hasInFlight && !plan.blockedWaiting) {
791
- await workflowService.updateRunStatus(runId, 'completed')
792
- }
793
- return
794
- }
795
-
796
- for (const fire of plan.toFire) {
797
- const node = nodes[fire.logical]
798
- if (!node?.rpcName) continue
799
-
800
- const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
801
- (id) => !IGNORED_REFS.has(id)
802
- )
803
- const fetchedResults = await reader.read(referencedNodeIds)
804
- const nodeResults: Record<string, any> = {
805
- trigger: triggerInput,
806
- ...fetchedResults,
807
- }
808
- if (fire.itemIndex !== undefined) {
809
- nodeResults['$item'] = reader.fanoutItems[fire.logical]?.[fire.itemIndex]
810
- }
811
- const resolvedInput = resolveSerializedInput(node.input, nodeResults)
812
-
813
- await queueGraphNode(
814
- workflowService,
815
- runId,
816
- graphName,
817
- fire.instanceKey,
818
- node.rpcName,
819
- resolvedInput,
820
- node,
821
- fire.fromStepName
822
- )
823
- }
824
- }
825
-
826
- async function invokeGraphNodeRpc(
827
- workflowService: PikkuWorkflowService,
828
- rpcService: any,
829
- runId: string,
830
- stepId: string,
831
- nodeId: string,
832
- rpcName: string,
833
- input: any,
834
- graphName: string
835
- ): Promise<any> {
836
- const wireState: GraphWireState = {}
837
- const graphWire: PikkuGraphWire = {
838
- runId,
839
- graphName,
840
- nodeId,
841
- branch: (key: string) => {
842
- wireState.branchKey = key
843
- },
844
- setState: (name: string, value: unknown) =>
845
- workflowService.updateRunState(runId, name, value),
846
- getState: () => workflowService.getRunState(runId),
847
- }
848
-
849
- const result = await rpcService.rpcWithWire(rpcName, input, {
850
- graph: graphWire,
851
- workflow: workflowService.createWorkflowWire(graphName, runId, rpcService),
852
- })
853
-
854
- if (wireState.branchKey) {
855
- await workflowService.setBranchTaken(stepId, wireState.branchKey)
856
- }
857
-
858
- return result
859
- }
860
-
861
- export async function executeGraphStep(
862
- workflowService: PikkuWorkflowService,
863
- rpcService: any,
864
- runId: string,
865
- stepId: string,
866
- nodeId: string,
867
- rpcName: string,
868
- data: any,
869
- graphName: string
870
- ): Promise<any> {
871
- try {
872
- let result: any
873
-
874
- const subWorkflowMeta = pikkuState(null, 'workflows', 'meta')[rpcName]
875
- const agentMeta = subWorkflowMeta
876
- ? undefined
877
- : pikkuState(null, 'agent', 'agentsMeta')[rpcName]
878
- if (subWorkflowMeta) {
879
- const childWire: WorkflowRunWire = {
880
- type: 'workflow',
881
- id: rpcName,
882
- parentRunId: runId,
883
- parentStepId: stepId,
884
- }
885
- const shouldInline = !getSingletonServices()?.queueService
886
- const { runId: childRunId } = await workflowService.startWorkflow(
887
- rpcName,
888
- data,
889
- childWire,
890
- rpcService,
891
- { inline: shouldInline }
892
- )
893
- await workflowService.setStepChildRunId(stepId, childRunId)
894
-
895
- if (shouldInline) {
896
- const childRun = await workflowService.getRun(childRunId)
897
- if (childRun?.status === 'failed') {
898
- throw new Error(childRun.error?.message || 'Sub-workflow failed')
899
- }
900
- if (childRun?.status === 'cancelled') {
901
- throw new Error('Sub-workflow was cancelled')
902
- }
903
- result = childRun?.output
904
- } else {
905
- throw new ChildWorkflowStartedException(runId, stepId, childRunId)
906
- }
907
- } else if (agentMeta) {
908
- const agentRun = await rpcService.agent.run(rpcName, data)
909
- result = agentRun.result
910
- } else {
911
- result = await invokeGraphNodeRpc(
912
- workflowService,
913
- rpcService,
914
- runId,
915
- stepId,
916
- nodeId,
917
- rpcName,
918
- data,
919
- graphName
920
- )
921
- }
922
-
923
- return result
924
- } catch (error) {
925
- if (
926
- error instanceof WorkflowAsyncException ||
927
- error instanceof WorkflowSuspendedException
928
- ) {
929
- throw error
930
- }
931
- if (error instanceof ChildWorkflowStartedException) {
932
- throw error
933
- }
934
- if (error instanceof RPCNotFoundError) {
935
- await workflowService.updateRunStatus(runId, 'suspended', undefined, {
936
- message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
937
- code: 'RPC_NOT_FOUND',
938
- })
939
- throw error
940
- }
941
- const meta = getWorkflowMeta(graphName)
942
- if (meta?.nodes) {
943
- const node = meta.nodes[nodeId]
944
- if (node?.onError) {
945
- const errorNodes = Array.isArray(node.onError)
946
- ? node.onError
947
- : [node.onError]
948
- for (const errorNodeId of errorNodes) {
949
- const errorNode = meta.nodes[errorNodeId]
950
- if (errorNode) {
951
- await queueGraphNode(
952
- workflowService,
953
- runId,
954
- graphName,
955
- errorNodeId,
956
- errorNode.rpcName,
957
- { error: { message: (error as Error).message } },
958
- errorNode
959
- )
960
- }
961
- }
962
- throw error
963
- }
964
- }
965
- throw error
966
- }
967
- }
968
-
969
- export async function runFromMeta(
970
- workflowService: PikkuWorkflowService,
971
- runId: string,
972
- meta: WorkflowRuntimeMeta,
973
- _rpcService: any
974
- ): Promise<void> {
975
- await continueGraph(workflowService, runId, meta.name, meta)
976
- }
977
-
978
- async function executeGraphNodeInline(
979
- workflowService: PikkuWorkflowService,
980
- rpcService: any,
981
- runId: string,
982
- graphName: string,
983
- nodeId: string,
984
- instanceKey: string,
985
- input: any,
986
- nodes: Record<string, any>,
987
- fromStepName?: string
988
- ): Promise<void> {
989
- const node = nodes[nodeId]
990
- if (!node) return
991
-
992
- const rpcName = node.rpcName
993
-
994
- const stepState = await workflowService.insertStepState(
995
- runId,
996
- instanceKey,
997
- rpcName,
998
- input,
999
- { retries: node.retries ?? 0, retryDelay: node.retryDelay },
1000
- fromStepName
1001
- )
1002
-
1003
- await workflowService.setStepRunning(stepState.stepId)
1004
-
1005
- try {
1006
- let result: any
1007
-
1008
- const subWorkflowMeta = pikkuState(null, 'workflows', 'meta')[rpcName]
1009
- const agentMeta = subWorkflowMeta
1010
- ? undefined
1011
- : pikkuState(null, 'agent', 'agentsMeta')[rpcName]
1012
- if (subWorkflowMeta) {
1013
- const childWire: WorkflowRunWire = {
1014
- type: 'workflow',
1015
- id: rpcName,
1016
- parentRunId: runId,
1017
- parentStepId: stepState.stepId,
1018
- }
1019
- const { runId: childRunId } = await workflowService.startWorkflow(
1020
- rpcName,
1021
- input,
1022
- childWire,
1023
- rpcService,
1024
- { inline: true }
1025
- )
1026
- await workflowService.setStepChildRunId(stepState.stepId, childRunId)
1027
- const childRun = await workflowService.getRun(childRunId)
1028
- if (childRun?.status === 'failed') {
1029
- throw new Error(childRun.error?.message || 'Sub-workflow failed')
1030
- }
1031
- if (childRun?.status === 'cancelled') {
1032
- throw new Error('Sub-workflow was cancelled')
1033
- }
1034
- result = childRun?.output
1035
- } else if (agentMeta) {
1036
- const agentRun = await rpcService.agent.run(rpcName, input)
1037
- result = agentRun.result
1038
- } else {
1039
- result = await invokeGraphNodeRpc(
1040
- workflowService,
1041
- rpcService,
1042
- runId,
1043
- stepState.stepId,
1044
- nodeId,
1045
- rpcName,
1046
- input,
1047
- graphName
1048
- )
1049
- }
1050
-
1051
- await workflowService.setStepResult(stepState.stepId, result)
1052
- } catch (error) {
1053
- if (
1054
- error instanceof WorkflowAsyncException ||
1055
- error instanceof WorkflowSuspendedException
1056
- ) {
1057
- throw error
1058
- }
1059
- if (error instanceof RPCNotFoundError) {
1060
- await workflowService.setStepError(stepState.stepId, error as Error)
1061
- await workflowService.updateRunStatus(runId, 'suspended', undefined, {
1062
- message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
1063
- code: 'RPC_NOT_FOUND',
1064
- })
1065
- throw new WorkflowSuspendedException(runId, 'RPC_NOT_FOUND')
1066
- }
1067
- await workflowService.setStepError(stepState.stepId, error as Error)
1068
-
1069
- if (node?.onError) {
1070
- const errorNodes = Array.isArray(node.onError)
1071
- ? node.onError
1072
- : [node.onError]
1073
- await Promise.all(
1074
- errorNodes.map((errorNodeId: string) =>
1075
- executeGraphNodeInline(
1076
- workflowService,
1077
- rpcService,
1078
- runId,
1079
- graphName,
1080
- errorNodeId,
1081
- errorNodeId,
1082
- { error: { message: (error as Error).message } },
1083
- nodes,
1084
- nodeId
1085
- )
1086
- )
1087
- )
1088
- return
1089
- }
1090
- throw error
1091
- }
1092
- }
1093
-
1094
- async function continueGraphInline(
1095
- workflowService: PikkuWorkflowService,
1096
- rpcService: any,
1097
- runId: string,
1098
- graphName: string,
1099
- nodes: Record<string, any>,
1100
- triggerInput: any,
1101
- entryNodeIds: string[]
1102
- ): Promise<void> {
1103
- while (true) {
1104
- const {
1105
- failedNodeIds: rawFailed,
1106
- branchKeys: branchByStep,
1107
- completedNodeIds: rawCompleted,
1108
- } = await workflowService.getCompletedGraphState(runId)
1109
- remapStepNamesToNodeIds(rawCompleted, nodes, graphName)
1110
- remapBranchKeys(branchByStep, nodes, graphName)
1111
- const failedNodeIds = remapStepNamesToNodeIds(rawFailed, nodes, graphName)
1112
-
1113
- if (failedNodeIds.length > 0) {
1114
- const failedNode = failedNodeIds[0]!
1115
- await workflowService.updateRunStatus(runId, 'failed', undefined, {
1116
- message: `Graph node '${failedNode}' failed after exhausting retries`,
1117
- stack: '',
1118
- code: 'GRAPH_NODE_FAILED',
1119
- })
1120
- return
1121
- }
1122
-
1123
- const run = await workflowService.getRun(runId)
1124
- if (run?.status === 'suspended') {
1125
- return
1126
- }
1127
-
1128
- const instances = await workflowService.getStepInstances(runId)
1129
- const reader = await createGraphResultReader(
1130
- workflowService,
1131
- runId,
1132
- graphName,
1133
- nodes,
1134
- triggerInput,
1135
- instances
1136
- )
1137
- const plan = planGraphTransitions(
1138
- nodes,
1139
- instances,
1140
- branchByStep,
1141
- entryNodeIds,
1142
- graphName,
1143
- reader.fanoutWidths
1144
- )
1145
-
1146
- if (plan.toFire.length === 0) {
1147
- if (!plan.hasInFlight && !plan.blockedWaiting) {
1148
- await workflowService.updateRunStatus(runId, 'completed')
1149
- }
1150
- return
1151
- }
1152
-
1153
- let executed = 0
1154
- await Promise.all(
1155
- plan.toFire.map(async (fire) => {
1156
- const node = nodes[fire.logical]
1157
- if (!node?.rpcName) return
1158
-
1159
- const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
1160
- (id) => !IGNORED_REFS.has(id)
1161
- )
1162
- const fetchedResults = await reader.read(referencedNodeIds)
1163
- const nodeResults: Record<string, any> = {
1164
- trigger: triggerInput,
1165
- ...fetchedResults,
1166
- }
1167
- if (fire.itemIndex !== undefined) {
1168
- nodeResults['$item'] =
1169
- reader.fanoutItems[fire.logical]?.[fire.itemIndex]
1170
- }
1171
- const resolvedInput = resolveSerializedInput(node.input, nodeResults)
1172
-
1173
- executed++
1174
- await executeGraphNodeInline(
1175
- workflowService,
1176
- rpcService,
1177
- runId,
1178
- graphName,
1179
- fire.logical,
1180
- fire.instanceKey,
1181
- resolvedInput,
1182
- nodes,
1183
- fire.fromStepName
1184
- )
1185
- })
1186
- )
1187
- if (executed === 0) return
1188
- }
1189
- }
1190
-
1191
- function planEntryFirings(
1192
- graphName: string,
1193
- nodeId: string,
1194
- node: Record<string, any>,
1195
- triggerNodeResults: Record<string, any>,
1196
- triggerInput: any
1197
- ): Array<{ instanceKey: string; input: any }> {
1198
- if (!node.forEach) {
1199
- const input =
1200
- node.input && Object.keys(node.input).length > 0
1201
- ? resolveSerializedInput(node.input, triggerNodeResults)
1202
- : triggerInput
1203
- return [{ instanceKey: nodeId, input }]
1204
- }
1205
-
1206
- const items = resolveForEachItems(graphName, nodeId, node, triggerNodeResults)
1207
- const width = node.mode === 'sequential' ? Math.min(items.length, 1) : items.length
1208
- const firings: Array<{ instanceKey: string; input: any }> = []
1209
- for (let index = 0; index < width; index++) {
1210
- firings.push({
1211
- instanceKey: fanoutInstanceKey(nodeId, index),
1212
- input: resolveSerializedInput(node.input, {
1213
- ...triggerNodeResults,
1214
- $item: items[index],
1215
- }),
1216
- })
1217
- }
1218
- return firings
1219
- }
1220
-
1221
- export async function runWorkflowGraph(
1222
- workflowService: PikkuWorkflowService,
1223
- graphName: string,
1224
- triggerInput: any,
1225
- rpcService?: any,
1226
- inline?: boolean,
1227
- startNode?: string,
1228
- wire?: WorkflowRunWire,
1229
- overrideMeta?: WorkflowRuntimeMeta
1230
- ): Promise<{ runId: string }> {
1231
- const meta = overrideMeta ?? getWorkflowMeta(graphName)
1232
- if (!meta?.nodes) {
1233
- throw new Error(`Workflow graph '${graphName}' not found`)
1234
- }
1235
-
1236
- const nodes = meta.nodes
1237
- const declaredEntryNodes = meta.entryNodeIds ?? []
1238
- // knowledge: decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md
1239
- if (startNode && !declaredEntryNodes.includes(startNode)) {
1240
- throw new Error(
1241
- `Workflow graph '${graphName}': '${startNode}' is not an entry node`
1242
- )
1243
- }
1244
- const entryNodes: string[] = startNode ? [startNode] : declaredEntryNodes
1245
- validateGraphReferences(graphName, nodes, entryNodes)
1246
-
1247
- if (entryNodes.length === 0) {
1248
- throw new Error(
1249
- `Workflow graph '${graphName}': no entry nodes found in meta or startNode`
1250
- )
1251
- }
1252
-
1253
- const readyEntryNodes = entryNodes.filter((nodeId) => {
1254
- const node = nodes[nodeId]
1255
- return node && areDependenciesSatisfied(node, new Set())
1256
- })
1257
-
1258
- if (readyEntryNodes.length === 0) {
1259
- throw new Error(
1260
- `Workflow graph '${graphName}': no entry nodes have satisfied dependencies`
1261
- )
1262
- }
1263
-
1264
- if (!meta.graphHash) {
1265
- throw new Error(`Workflow graph '${graphName}': missing graphHash in meta`)
1266
- }
1267
-
1268
- const runId = await workflowService.createRun(
1269
- graphName,
1270
- triggerInput,
1271
- inline ?? false,
1272
- meta.graphHash,
1273
- wire ?? { type: 'unknown' },
1274
- {
1275
- deterministic: meta.deterministic,
1276
- plannedSteps: meta.plannedSteps,
1277
- }
1278
- )
1279
-
1280
- if (inline) {
1281
- workflowService.registerInlineRun(runId)
1282
- }
1283
-
1284
- const triggerNodeResults = { trigger: triggerInput }
1285
-
1286
- if (inline && rpcService) {
1287
- const executeInline = async () => {
1288
- try {
1289
- await Promise.all(
1290
- readyEntryNodes.map(async (nodeId) => {
1291
- const node = nodes[nodeId]
1292
- if (!node?.rpcName) return
1293
-
1294
- const firings = planEntryFirings(
1295
- graphName,
1296
- nodeId,
1297
- node,
1298
- triggerNodeResults,
1299
- triggerInput
1300
- )
1301
-
1302
- await Promise.all(
1303
- firings.map((firing) =>
1304
- executeGraphNodeInline(
1305
- workflowService,
1306
- rpcService,
1307
- runId,
1308
- graphName,
1309
- nodeId,
1310
- firing.instanceKey,
1311
- firing.input,
1312
- nodes
1313
- )
1314
- )
1315
- )
1316
- })
1317
- )
1318
-
1319
- await continueGraphInline(
1320
- workflowService,
1321
- rpcService,
1322
- runId,
1323
- graphName,
1324
- nodes,
1325
- triggerInput,
1326
- entryNodes
1327
- )
1328
- } catch (error) {
1329
- if (
1330
- error instanceof WorkflowAsyncException ||
1331
- error instanceof WorkflowSuspendedException
1332
- ) {
1333
- return
1334
- }
1335
- await workflowService.updateRunStatus(runId, 'failed', undefined, {
1336
- message: (error as Error).message,
1337
- stack: (error as Error).stack || '',
1338
- code: 'GRAPH_NODE_FAILED',
1339
- })
1340
- } finally {
1341
- workflowService.unregisterInlineRun(runId)
1342
- }
1343
- }
1344
- await executeInline()
1345
- } else {
1346
- for (const nodeId of readyEntryNodes) {
1347
- const node = nodes[nodeId]
1348
- if (!node?.rpcName) continue
1349
-
1350
- const firings = planEntryFirings(
1351
- graphName,
1352
- nodeId,
1353
- node,
1354
- triggerNodeResults,
1355
- triggerInput
1356
- )
1357
-
1358
- for (const firing of firings) {
1359
- await queueGraphNode(
1360
- workflowService,
1361
- runId,
1362
- graphName,
1363
- firing.instanceKey,
1364
- node.rpcName,
1365
- firing.input,
1366
- node
1367
- )
1368
- }
1369
- }
1370
- if (inline) {
1371
- workflowService.unregisterInlineRun(runId)
1372
- }
1373
- }
1374
-
1375
- return { runId }
1376
- }