@pikku/core 0.12.78 → 0.12.80

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 (341) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/dist/dev/hot-reload.js +1 -6
  3. package/dist/ecosystem.d.ts +27 -0
  4. package/dist/ecosystem.js +26 -0
  5. package/dist/errors/error-handler.js +4 -2
  6. package/dist/function/function-runner.js +20 -42
  7. package/dist/function/functions.types.d.ts +9 -5
  8. package/dist/index.d.ts +4 -9
  9. package/dist/index.js +3 -8
  10. package/dist/middleware/auth-cookie.d.ts +0 -4
  11. package/dist/middleware/auth-cookie.js +38 -2
  12. package/dist/middleware/cors.js +1 -0
  13. package/dist/middleware/index.d.ts +1 -1
  14. package/dist/middleware/index.js +1 -1
  15. package/dist/middleware/remote-auth.js +14 -3
  16. package/dist/permissions.d.ts +8 -10
  17. package/dist/permissions.js +0 -11
  18. package/dist/pikku-state.js +12 -5
  19. package/dist/schema.js +35 -1
  20. package/dist/services/ai-run-state-service.d.ts +7 -1
  21. package/dist/services/in-memory-ai-run-state-service.d.ts +1 -1
  22. package/dist/services/in-memory-ai-run-state-service.js +2 -1
  23. package/dist/services/in-memory-workflow-service.d.ts +10 -0
  24. package/dist/services/in-memory-workflow-service.js +25 -0
  25. package/dist/services/local-content-request-handler.d.ts +21 -0
  26. package/dist/services/local-content-request-handler.js +72 -53
  27. package/dist/services/local-content.d.ts +6 -0
  28. package/dist/services/local-content.js +14 -1
  29. package/dist/services/workflow-service.d.ts +4 -2
  30. package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
  31. package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
  32. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
  33. package/dist/testing/service-tests/ai-storage-service-tests.js +226 -0
  34. package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
  35. package/dist/testing/service-tests/channel-store-tests.js +72 -0
  36. package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
  37. package/dist/testing/service-tests/credential-service-tests.js +109 -0
  38. package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
  39. package/dist/testing/service-tests/deployment-service-tests.js +21 -0
  40. package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
  41. package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
  42. package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
  43. package/dist/testing/service-tests/secret-service-tests.js +80 -0
  44. package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
  45. package/dist/testing/service-tests/session-store-tests.js +43 -0
  46. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
  47. package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
  48. package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
  49. package/dist/testing/service-tests/workflow-service-tests.js +150 -0
  50. package/dist/testing/service-tests.d.ts +6 -0
  51. package/dist/testing/service-tests.js +26 -791
  52. package/dist/types/core.types.d.ts +11 -1
  53. package/dist/types/state.types.d.ts +1 -1
  54. package/dist/utils/node-host-resolver.d.ts +12 -0
  55. package/dist/utils/node-host-resolver.js +16 -0
  56. package/dist/utils/safe-fetch.d.ts +18 -0
  57. package/dist/utils/safe-fetch.js +167 -29
  58. package/dist/wirings/actor-flow/run-conversation.js +1 -6
  59. package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
  60. package/dist/wirings/ai-agent/agent-rpc.js +53 -0
  61. package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
  62. package/dist/wirings/ai-agent/ai-agent-memory.js +3 -1
  63. package/dist/wirings/ai-agent/ai-agent-prepare.js +3 -9
  64. package/dist/wirings/ai-agent/ai-agent-runner.js +28 -107
  65. package/dist/wirings/ai-agent/ai-agent-stream.js +20 -61
  66. package/dist/wirings/ai-agent/ai-agent-turn.d.ts +56 -0
  67. package/dist/wirings/ai-agent/ai-agent-turn.js +81 -0
  68. package/dist/wirings/ai-agent/ai-agent.types.d.ts +1 -1
  69. package/dist/wirings/ai-agent/voice-input.js +1 -6
  70. package/dist/wirings/ai-agent/voice-output.js +2 -12
  71. package/dist/wirings/channel/channel-common.js +1 -0
  72. package/dist/wirings/channel/channel-handler.js +3 -5
  73. package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
  74. package/dist/wirings/channel/channel-rpc-service.js +0 -8
  75. package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
  76. package/dist/wirings/channel/channel-rpc.types.js +8 -0
  77. package/dist/wirings/channel/channel-runner.d.ts +1 -3
  78. package/dist/wirings/channel/channel-runner.js +16 -8
  79. package/dist/wirings/channel/channel.types.d.ts +2 -0
  80. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  81. package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
  82. package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
  83. package/dist/wirings/cli/cli-runner.js +4 -2
  84. package/dist/wirings/cli/cli.types.d.ts +0 -8
  85. package/dist/wirings/cli/command-parser.js +13 -0
  86. package/dist/wirings/gateway/gateway-runner.js +41 -5
  87. package/dist/wirings/http/http-routes.js +2 -0
  88. package/dist/wirings/http/http-runner.d.ts +0 -10
  89. package/dist/wirings/http/http-runner.js +6 -13
  90. package/dist/wirings/http/http.types.d.ts +0 -10
  91. package/dist/wirings/http/index.d.ts +1 -1
  92. package/dist/wirings/http/index.js +1 -1
  93. package/dist/wirings/mcp/mcp-runner.d.ts +0 -7
  94. package/dist/wirings/mcp/mcp-runner.js +0 -6
  95. package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
  96. package/dist/wirings/rpc/rpc-runner.js +53 -86
  97. package/dist/wirings/rpc/rpc-types.d.ts +3 -0
  98. package/dist/wirings/secret/validate-secret-definitions.js +2 -0
  99. package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
  100. package/dist/wirings/trigger/trigger-runner.js +1 -0
  101. package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
  102. package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
  103. package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
  104. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +29 -2
  105. package/dist/wirings/workflow/feature.js +7 -4
  106. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
  107. package/dist/wirings/workflow/graph/graph-runner.js +8 -7
  108. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
  109. package/dist/wirings/workflow/index.d.ts +7 -2
  110. package/dist/wirings/workflow/index.js +5 -1
  111. package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
  112. package/dist/wirings/workflow/pikku-scenario-service.js +38 -10
  113. package/dist/wirings/workflow/pikku-workflow-service.d.ts +44 -111
  114. package/dist/wirings/workflow/pikku-workflow-service.js +86 -404
  115. package/dist/wirings/workflow/workflow-approval.d.ts +39 -0
  116. package/dist/wirings/workflow/workflow-approval.js +114 -0
  117. package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
  118. package/dist/wirings/workflow/workflow-constants.js +35 -0
  119. package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
  120. package/dist/wirings/workflow/workflow-errors.js +112 -0
  121. package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
  122. package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
  123. package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
  124. package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
  125. package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
  126. package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
  127. package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
  128. package/dist/wirings/workflow/workflow-recovery.js +101 -0
  129. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
  130. package/dist/wirings/workflow/workflow-run-engine.types.js +1 -0
  131. package/dist/wirings/workflow/workflow-run-ownership.d.ts +16 -0
  132. package/dist/wirings/workflow/workflow-run-ownership.js +29 -0
  133. package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
  134. package/dist/wirings/workflow/workflow-suspend.js +33 -0
  135. package/dist/wirings/workflow/workflow.types.d.ts +7 -0
  136. package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
  137. package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
  138. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
  139. package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
  140. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
  141. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
  142. package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
  143. package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
  144. package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
  145. package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
  146. package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
  147. package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
  148. package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
  149. package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
  150. package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
  151. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
  152. package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
  153. package/knowledge/decisions/internals/index.md +38 -26
  154. package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
  155. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
  156. package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
  157. package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
  158. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
  159. package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
  160. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
  161. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
  162. package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
  163. package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
  164. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
  165. package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
  166. package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
  167. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
  168. package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
  169. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
  170. package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
  171. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
  172. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
  173. package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
  174. package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
  175. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
  176. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
  177. package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +34 -0
  178. package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
  179. package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
  180. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +13 -3
  181. package/knowledge/decisions/security/index.md +7 -0
  182. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
  183. package/knowledge/questions/index.md +2 -1
  184. package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
  185. package/package.json +14 -3
  186. package/scripts/generate-api-report.d.mts +1 -0
  187. package/scripts/generate-api-report.mjs +89 -0
  188. package/scripts/generate-api-report.mts +218 -0
  189. package/src/api-report.test.ts +69 -0
  190. package/src/column-form.ts +1 -4
  191. package/src/crypto-utils.test.ts +15 -2
  192. package/src/dev/hot-reload.ts +2 -7
  193. package/src/ecosystem.ts +40 -0
  194. package/src/errors/error-handler.ts +5 -3
  195. package/src/errors/error.test.ts +4 -1
  196. package/src/function/function-runner.test.ts +1 -1
  197. package/src/function/function-runner.ts +28 -39
  198. package/src/function/functions.types.ts +15 -9
  199. package/src/handle-error.ts +1 -1
  200. package/src/index.ts +3 -22
  201. package/src/middleware/auth-cookie.test.ts +50 -0
  202. package/src/middleware/auth-cookie.ts +38 -2
  203. package/src/middleware/cors.ts +2 -1
  204. package/src/middleware/index.ts +1 -1
  205. package/src/middleware/remote-auth.test.ts +43 -0
  206. package/src/middleware/remote-auth.ts +17 -3
  207. package/src/middleware-runner.ts +4 -2
  208. package/src/no-any-casts.test.ts +57 -0
  209. package/src/permissions.test.ts +3 -1
  210. package/src/permissions.ts +22 -24
  211. package/src/pikku-state.ts +17 -6
  212. package/src/public-surface.json +578 -0
  213. package/src/public-surface.json.README +25 -0
  214. package/src/public-surface.test.ts +105 -0
  215. package/src/removed-legacy-exports.test.ts +62 -0
  216. package/src/schema.test.ts +78 -0
  217. package/src/schema.ts +36 -1
  218. package/src/services/ai-run-state-service.ts +7 -1
  219. package/src/services/audit-service.ts +2 -2
  220. package/src/services/in-memory-ai-run-state-service.ts +3 -2
  221. package/src/services/in-memory-workflow-service.ts +25 -0
  222. package/src/services/index.ts +1 -4
  223. package/src/services/local-content-request-handler.test.ts +43 -5
  224. package/src/services/local-content-request-handler.ts +103 -74
  225. package/src/services/local-content.ts +15 -1
  226. package/src/services/local-email-service.ts +5 -1
  227. package/src/services/system-role-guard.test.ts +4 -1
  228. package/src/services/workflow-service.ts +9 -2
  229. package/src/side-effects-are-declared.test.ts +84 -0
  230. package/src/source-files-stay-composable.test.ts +41 -0
  231. package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
  232. package/src/testing/service-tests/ai-storage-service-tests.ts +286 -0
  233. package/src/testing/service-tests/channel-store-tests.ts +98 -0
  234. package/src/testing/service-tests/credential-service-tests.ts +143 -0
  235. package/src/testing/service-tests/deployment-service-tests.ts +33 -0
  236. package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
  237. package/src/testing/service-tests/secret-service-tests.ts +105 -0
  238. package/src/testing/service-tests/session-store-tests.ts +62 -0
  239. package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
  240. package/src/testing/service-tests/workflow-service-tests.ts +308 -0
  241. package/src/testing/service-tests.ts +31 -1111
  242. package/src/types/core.types.ts +15 -1
  243. package/src/types/state.types.ts +1 -1
  244. package/src/utils/node-host-resolver.ts +20 -0
  245. package/src/utils/safe-fetch.test.ts +143 -1
  246. package/src/utils/safe-fetch.ts +200 -25
  247. package/src/wirings/actor-flow/run-conversation.ts +1 -6
  248. package/src/wirings/ai-agent/agent-rpc.ts +120 -0
  249. package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
  250. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
  251. package/src/wirings/ai-agent/ai-agent-memory.ts +8 -1
  252. package/src/wirings/ai-agent/ai-agent-prepare.ts +10 -12
  253. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
  254. package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
  255. package/src/wirings/ai-agent/ai-agent-runner.ts +49 -120
  256. package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
  257. package/src/wirings/ai-agent/ai-agent-stream.ts +36 -63
  258. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
  259. package/src/wirings/ai-agent/ai-agent-turn.ts +121 -0
  260. package/src/wirings/ai-agent/ai-agent.types.ts +1 -1
  261. package/src/wirings/ai-agent/voice-input.ts +1 -6
  262. package/src/wirings/ai-agent/voice-output.ts +2 -12
  263. package/src/wirings/channel/channel-common.ts +5 -2
  264. package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
  265. package/src/wirings/channel/channel-handler.ts +7 -7
  266. package/src/wirings/channel/channel-rpc-service.ts +0 -14
  267. package/src/wirings/channel/channel-rpc.test.ts +25 -4
  268. package/src/wirings/channel/channel-rpc.types.ts +14 -0
  269. package/src/wirings/channel/channel-runner.ts +33 -20
  270. package/src/wirings/channel/channel.types.ts +2 -0
  271. package/src/wirings/channel/local/local-channel-runner.ts +1 -1
  272. package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
  273. package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
  274. package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
  275. package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
  276. package/src/wirings/cli/cli-runner.ts +7 -4
  277. package/src/wirings/cli/cli.types.ts +0 -39
  278. package/src/wirings/cli/command-parser.test.ts +19 -0
  279. package/src/wirings/cli/command-parser.ts +17 -1
  280. package/src/wirings/gateway/gateway-authorization.test.ts +131 -0
  281. package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
  282. package/src/wirings/gateway/gateway-runner.ts +62 -22
  283. package/src/wirings/http/http-routes.ts +4 -1
  284. package/src/wirings/http/http-runner.ts +11 -26
  285. package/src/wirings/http/http.types.ts +0 -15
  286. package/src/wirings/http/index.ts +1 -7
  287. package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
  288. package/src/wirings/http/web-request.ts +1 -1
  289. package/src/wirings/mcp/mcp-runner.ts +2 -16
  290. package/src/wirings/persona/persona-environments.test.ts +14 -3
  291. package/src/wirings/persona/persona.test.ts +13 -3
  292. package/src/wirings/persona/validate-personas.ts +5 -1
  293. package/src/wirings/queue/queue-runner.ts +1 -1
  294. package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
  295. package/src/wirings/rpc/rpc-runner.ts +58 -136
  296. package/src/wirings/rpc/rpc-types.ts +7 -0
  297. package/src/wirings/rpc/wire-addon.ts +3 -1
  298. package/src/wirings/secret/validate-secret-definitions.test.ts +69 -0
  299. package/src/wirings/secret/validate-secret-definitions.ts +2 -0
  300. package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
  301. package/src/wirings/trigger/trigger-runner.ts +7 -5
  302. package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
  303. package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
  304. package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
  305. package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
  306. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
  307. package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
  308. package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
  309. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +35 -2
  310. package/src/wirings/workflow/feature.ts +7 -4
  311. package/src/wirings/workflow/graph/graph-node.ts +1 -1
  312. package/src/wirings/workflow/graph/graph-runner.test.ts +4 -2
  313. package/src/wirings/workflow/graph/graph-runner.ts +13 -16
  314. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
  315. package/src/wirings/workflow/index.ts +12 -4
  316. package/src/wirings/workflow/pikku-scenario-service.ts +54 -25
  317. package/src/wirings/workflow/pikku-workflow-service.test.ts +2 -2
  318. package/src/wirings/workflow/pikku-workflow-service.ts +208 -630
  319. package/src/wirings/workflow/scenario-hooks.test.ts +51 -0
  320. package/src/wirings/workflow/workflow-approval.ts +185 -0
  321. package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
  322. package/src/wirings/workflow/workflow-constants.ts +47 -0
  323. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
  324. package/src/wirings/workflow/workflow-dispatch-relay.test.ts +128 -0
  325. package/src/wirings/workflow/workflow-errors.ts +128 -0
  326. package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
  327. package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
  328. package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
  329. package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
  330. package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
  331. package/src/wirings/workflow/workflow-recovery.ts +162 -0
  332. package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
  333. package/src/wirings/workflow/workflow-run-authority.test.ts +215 -0
  334. package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
  335. package/src/wirings/workflow/workflow-run-ownership.ts +36 -0
  336. package/src/wirings/workflow/workflow-suspend.ts +61 -0
  337. package/src/wirings/workflow/workflow.types.ts +7 -0
  338. package/src/wirings-stay-decoupled.test.ts +123 -0
  339. package/tsconfig.json +1 -1
  340. package/tsconfig.tsbuildinfo +1 -1
  341. package/src/internal.ts +0 -10
@@ -0,0 +1,45 @@
1
+ import { pikkuState } from '../../pikku-state.js'
2
+ import type { WorkflowRuntimeMeta } from './workflow.types.js'
3
+
4
+ export type ResolvedWorkflowMeta = {
5
+ meta: WorkflowRuntimeMeta
6
+ packageName: string | null
7
+ resolvedName: string
8
+ }
9
+
10
+ /**
11
+ * Resolves a workflow name against the root registry, then — for a
12
+ * `namespace:name` form — against the addon package that claims the namespace.
13
+ */
14
+ export const resolveWorkflowMeta = (
15
+ name: string
16
+ ): ResolvedWorkflowMeta | null => {
17
+ const rootMeta = pikkuState(null, 'workflows', 'meta')
18
+ if (rootMeta[name]) {
19
+ return { meta: rootMeta[name], packageName: null, resolvedName: name }
20
+ }
21
+
22
+ const colonIndex = name.indexOf(':')
23
+ if (colonIndex === -1) {
24
+ return null
25
+ }
26
+
27
+ const namespace = name.substring(0, colonIndex)
28
+ const localName = name.substring(colonIndex + 1)
29
+ const addons = pikkuState(null, 'addons', 'packages')
30
+ const pkgConfig = addons?.get(namespace)
31
+ if (!pkgConfig) {
32
+ return null
33
+ }
34
+
35
+ const addonMeta = pikkuState(pkgConfig.package, 'workflows', 'meta')
36
+ if (!addonMeta?.[localName]) {
37
+ return null
38
+ }
39
+
40
+ return {
41
+ meta: addonMeta[localName],
42
+ packageName: pkgConfig.package,
43
+ resolvedName: localName,
44
+ }
45
+ }
@@ -0,0 +1,92 @@
1
+ import { describe, test } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import { InMemoryWorkflowService } from '../../services/in-memory-workflow-service.js'
5
+ import { pikkuState, resetPikkuState } from '../../pikku-state.js'
6
+ import { PikkuMissingMetaError } from '../../errors/errors.js'
7
+ import { WorkflowNotFoundError } from './workflow-errors.js'
8
+
9
+ const silentLogger = { error() {}, info() {}, warn() {}, debug() {} }
10
+
11
+ const startRun = async (workflowName: string) => {
12
+ pikkuState(null, 'package', 'singletonServices', {
13
+ logger: silentLogger,
14
+ } as any)
15
+ const service = new InMemoryWorkflowService()
16
+ const runId = await service.createRun(workflowName, {}, false, '', {
17
+ type: 'test',
18
+ })
19
+ return { service, runId }
20
+ }
21
+
22
+ describe('a run whose workflow has no generated meta', () => {
23
+ test('reports missing metadata rather than crashing on an undefined meta', async () => {
24
+ resetPikkuState()
25
+ const { service, runId } = await startRun('flowWithoutMeta')
26
+
27
+ // The registration exists, so this is not an unknown workflow — codegen or
28
+ // the generated bootstrap import is what is missing.
29
+ pikkuState(null, 'workflows', 'registrations').set('flowWithoutMeta', {
30
+ name: 'flowWithoutMeta',
31
+ func: async () => undefined,
32
+ } as any)
33
+
34
+ await assert.rejects(
35
+ service.runWorkflowJob(runId, {}),
36
+ (error: unknown) => {
37
+ assert.ok(
38
+ error instanceof PikkuMissingMetaError,
39
+ `expected PikkuMissingMetaError, got ${(error as Error)?.constructor?.name}: ${(error as Error)?.message}`
40
+ )
41
+ assert.match(String((error as Error).message), /flowWithoutMeta/)
42
+ return true
43
+ }
44
+ )
45
+ })
46
+
47
+ test('a workflow with neither meta nor a registration is still missing meta', async () => {
48
+ resetPikkuState()
49
+ const { service, runId } = await startRun('unknownFlow')
50
+
51
+ await assert.rejects(
52
+ service.runWorkflowJob(runId, {}),
53
+ (error: unknown) => {
54
+ assert.ok(
55
+ error instanceof PikkuMissingMetaError,
56
+ `expected PikkuMissingMetaError, got ${(error as Error)?.constructor?.name}`
57
+ )
58
+ return true
59
+ }
60
+ )
61
+ })
62
+
63
+ test('a registered workflow that does have meta gets past both guards', async () => {
64
+ resetPikkuState()
65
+ const { service, runId } = await startRun('flowWithMeta')
66
+
67
+ pikkuState(null, 'workflows', 'meta', {
68
+ flowWithMeta: {
69
+ name: 'flowWithMeta',
70
+ pikkuFuncId: 'flowWithMeta',
71
+ source: 'dsl',
72
+ },
73
+ } as any)
74
+
75
+ // Guards the tests above: without this the assertions would pass for a
76
+ // service that threw PikkuMissingMetaError unconditionally.
77
+ await assert.rejects(
78
+ service.runWorkflowJob(runId, {}),
79
+ (error: unknown) => {
80
+ assert.ok(
81
+ !(error instanceof PikkuMissingMetaError),
82
+ 'meta was present, so the missing-meta guard must not fire'
83
+ )
84
+ assert.ok(
85
+ error instanceof WorkflowNotFoundError,
86
+ `expected WorkflowNotFoundError, got ${(error as Error)?.constructor?.name}`
87
+ )
88
+ return true
89
+ }
90
+ )
91
+ })
92
+ })
@@ -0,0 +1,85 @@
1
+ import { getSingletonServices, pikkuState } from '../../pikku-state.js'
2
+ import { getDurationInMilliseconds } from '../../time-utils.js'
3
+ import type { JobGroup, JobOptions } from '../queue/queue.types.js'
4
+ import type {
5
+ WorkflowServiceConfig,
6
+ WorkflowStepOptions,
7
+ } from './workflow.types.js'
8
+ import { DEFAULT_STEP_RETRIES } from './workflow-constants.js'
9
+
10
+ export type WorkflowQueueStrategy = 'per-workflow' | 'shared-groups'
11
+
12
+ const toKebab = (s: string) =>
13
+ s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
14
+
15
+ export const resolveWorkflowConfig = (): WorkflowServiceConfig => {
16
+ const workflow = getSingletonServices().config?.workflow
17
+ return {
18
+ retries: workflow?.retries ?? DEFAULT_STEP_RETRIES,
19
+ retryDelay: workflow?.retryDelay ?? 0,
20
+ orchestratorQueueName:
21
+ workflow?.orchestratorQueueName ?? 'pikku-workflow-orchestrator',
22
+ stepWorkerQueueName:
23
+ workflow?.stepWorkerQueueName ?? 'pikku-workflow-step-worker',
24
+ sleeperRPCName: workflow?.sleeperRPCName ?? 'pikkuWorkflowSleeper',
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Falls back to the shared queue whenever the dedicated one was not generated
30
+ * into queue meta, so a workflow added without a rebuild still runs.
31
+ */
32
+ const dedicatedQueueName = (
33
+ prefix: string,
34
+ name: string | undefined,
35
+ strategy: WorkflowQueueStrategy,
36
+ fallback: string
37
+ ): string => {
38
+ if (!name || strategy === 'shared-groups') {
39
+ return fallback
40
+ }
41
+ const dedicated = `${prefix}${toKebab(name)}`
42
+ return pikkuState(null, 'queue', 'meta')[dedicated] ? dedicated : fallback
43
+ }
44
+
45
+ export const orchestratorQueueName = (
46
+ strategy: WorkflowQueueStrategy,
47
+ workflowName?: string
48
+ ): string =>
49
+ dedicatedQueueName(
50
+ 'wf-orchestrator-',
51
+ workflowName,
52
+ strategy,
53
+ resolveWorkflowConfig().orchestratorQueueName
54
+ )
55
+
56
+ export const stepWorkerQueueName = (
57
+ strategy: WorkflowQueueStrategy,
58
+ rpcName?: string
59
+ ): string =>
60
+ dedicatedQueueName(
61
+ 'wf-step-',
62
+ rpcName,
63
+ strategy,
64
+ resolveWorkflowConfig().stepWorkerQueueName
65
+ )
66
+
67
+ export const jobGroupFor = (
68
+ strategy: WorkflowQueueStrategy,
69
+ id?: string
70
+ ): JobGroup | undefined =>
71
+ id && strategy === 'shared-groups' ? { id, tier: id } : undefined
72
+
73
+ export const stepJobOptions = (
74
+ stepOptions?: WorkflowStepOptions
75
+ ): JobOptions => {
76
+ const retries = stepOptions?.retries ?? DEFAULT_STEP_RETRIES
77
+ const retryDelay = stepOptions?.retryDelay
78
+ const backoff =
79
+ retryDelay !== undefined && retryDelay !== 'exponential'
80
+ ? { type: 'fixed', delay: getDurationInMilliseconds(retryDelay) }
81
+ : retries > 0 || retryDelay === 'exponential'
82
+ ? 'exponential'
83
+ : undefined
84
+ return { attempts: retries + 1, ...(backoff ? { backoff } : {}) }
85
+ }
@@ -0,0 +1,149 @@
1
+ import { addFunction } from '../../function/function-runner.js'
2
+ import { pikkuState } from '../../pikku-state.js'
3
+ import { wireQueueWorker } from '../queue/queue-runner.js'
4
+ import type {
5
+ GroupConcurrencyConfig,
6
+ PikkuWorkerConfig,
7
+ } from '../queue/queue.types.js'
8
+ import type { Logger } from '../../services/logger.js'
9
+ import {
10
+ pikkuWorkflowOrchestratorFunc,
11
+ pikkuWorkflowSleeperFunc,
12
+ pikkuWorkflowWorkerFunc,
13
+ } from './workflow-queue-workers.js'
14
+ import type { WorkflowQueueStrategy } from './workflow-queue-routing.js'
15
+
16
+ const ORCHESTRATOR_QUEUE_PREFIX = 'wf-orchestrator-'
17
+ const STEP_QUEUE_PREFIX = 'wf-step-'
18
+
19
+ const helperFunctionMeta = (funcId: string) => ({
20
+ pikkuFuncId: funcId,
21
+ sessionless: true,
22
+ functionType: 'helper' as const,
23
+ inputSchemaName: null,
24
+ outputSchemaName: null,
25
+ })
26
+
27
+ export type WorkflowQueueWiringOptions = {
28
+ strategy: WorkflowQueueStrategy
29
+ concurrency: number
30
+ groupConcurrency: number | GroupConcurrencyConfig
31
+ /**
32
+ * Resolved only when there is something to warn about: reading the logger
33
+ * throws while singleton services are uninitialized, and wiring queues before
34
+ * that point is legitimate.
35
+ */
36
+ getLogger: () => Logger | undefined
37
+ }
38
+
39
+ /**
40
+ * Registers the orchestrator, step-worker and sleeper functions and binds them
41
+ * to their queues. Idempotent: a queue already carrying a registered function
42
+ * is left alone.
43
+ */
44
+ export const wireWorkflowQueueWorkers = ({
45
+ strategy,
46
+ concurrency,
47
+ groupConcurrency,
48
+ getLogger,
49
+ }: WorkflowQueueWiringOptions): void => {
50
+ const functions = pikkuState(null, 'function', 'functions')
51
+ const functionsMeta = pikkuState(null, 'function', 'meta')
52
+ const queueMeta = pikkuState(null, 'queue', 'meta')
53
+
54
+ const registerWorkflowFunc = (
55
+ funcId: string,
56
+ func: { func: unknown },
57
+ queueName: string,
58
+ config?: PikkuWorkerConfig
59
+ ) => {
60
+ if (functions.has(funcId)) return
61
+ addFunction(funcId, func as never)
62
+ if (!queueMeta[queueName]) {
63
+ queueMeta[queueName] = { pikkuFuncId: funcId, name: queueName }
64
+ }
65
+ wireQueueWorker({ name: queueName, func, config } as never)
66
+ if (!functionsMeta[funcId]) {
67
+ functionsMeta[funcId] = helperFunctionMeta(funcId)
68
+ }
69
+ }
70
+
71
+ const sharedGroups = strategy === 'shared-groups'
72
+ const sharedQueueConfig: PikkuWorkerConfig | undefined = sharedGroups
73
+ ? { batchSize: concurrency, groupConcurrency }
74
+ : undefined
75
+
76
+ registerWorkflowFunc(
77
+ 'pikkuWorkflowOrchestrator',
78
+ { func: pikkuWorkflowOrchestratorFunc },
79
+ 'pikku-workflow-orchestrator',
80
+ sharedQueueConfig
81
+ )
82
+ registerWorkflowFunc(
83
+ 'pikkuWorkflowStepWorker',
84
+ { func: pikkuWorkflowWorkerFunc },
85
+ 'pikku-workflow-step-worker',
86
+ sharedQueueConfig
87
+ )
88
+
89
+ const registerDedicatedQueues = (meta: Record<string, any>) => {
90
+ for (const [queueName, entry] of Object.entries(meta)) {
91
+ if (functions.has(entry.pikkuFuncId)) continue
92
+ if (queueName.startsWith(ORCHESTRATOR_QUEUE_PREFIX)) {
93
+ registerWorkflowFunc(
94
+ entry.pikkuFuncId,
95
+ { func: pikkuWorkflowOrchestratorFunc },
96
+ queueName
97
+ )
98
+ } else if (queueName.startsWith(STEP_QUEUE_PREFIX)) {
99
+ registerWorkflowFunc(
100
+ entry.pikkuFuncId,
101
+ { func: pikkuWorkflowWorkerFunc },
102
+ queueName
103
+ )
104
+ }
105
+ }
106
+ }
107
+
108
+ if (!sharedGroups) {
109
+ registerDedicatedQueues(pikkuState(null, 'queue', 'meta'))
110
+
111
+ const addons = pikkuState(null, 'addons', 'packages')
112
+ for (const [, addon] of addons ?? []) {
113
+ const addonQueueMeta = pikkuState(addon.package, 'queue', 'meta')
114
+ if (addonQueueMeta) {
115
+ registerDedicatedQueues(addonQueueMeta)
116
+ }
117
+ }
118
+ }
119
+
120
+ warnOnMissingDedicatedQueues(queueMeta, getLogger)
121
+
122
+ if (!functions.has('pikkuWorkflowSleeper')) {
123
+ addFunction('pikkuWorkflowSleeper', { func: pikkuWorkflowSleeperFunc })
124
+ }
125
+ if (!functionsMeta.pikkuWorkflowSleeper) {
126
+ functionsMeta.pikkuWorkflowSleeper = helperFunctionMeta(
127
+ 'pikkuWorkflowSleeper'
128
+ )
129
+ }
130
+ }
131
+
132
+ const warnOnMissingDedicatedQueues = (
133
+ queueMeta: Record<string, unknown>,
134
+ getLogger: () => Logger | undefined
135
+ ) => {
136
+ const workflowCount = Object.keys(
137
+ pikkuState(null, 'workflows', 'meta') ?? {}
138
+ ).length
139
+ const dedicatedQueues = Object.keys(queueMeta).filter((name) =>
140
+ name.startsWith(ORCHESTRATOR_QUEUE_PREFIX)
141
+ ).length
142
+ if (workflowCount > 0 && dedicatedQueues === 0) {
143
+ getLogger()?.warn?.(
144
+ `[pikku] ${workflowCount} workflow(s) registered but no per-workflow orchestrator queues were found in queue meta. ` +
145
+ `All workflows will share a single orchestrator queue, where one slow step blocks every other workflow behind it. ` +
146
+ `Check that the generated bootstrap imports the queue-workers meta (pikku-queue-workers-wirings-meta.gen.js).`
147
+ )
148
+ }
149
+ }
@@ -0,0 +1,162 @@
1
+ import type { Logger } from '../../services/logger.js'
2
+ import {
3
+ DEFAULT_STALLED_RUN_LIMIT,
4
+ DEFAULT_STALLED_RUN_MS,
5
+ DEFAULT_UNDISPATCHED_STEP_LIMIT,
6
+ DEFAULT_UNDISPATCHED_STEP_MS,
7
+ REDISPATCH_BACKOFF_MAX_ENTRIES,
8
+ REDISPATCH_BACKOFF_MAX_MS,
9
+ REDISPATCH_BACKOFF_MS,
10
+ } from './workflow-constants.js'
11
+
12
+ /**
13
+ * Per-process, advisory record of when a run may next be re-dispatched.
14
+ *
15
+ * Keyed by run rather than by step because the run is the unit of re-drive:
16
+ * `resumeWorkflow` replays the whole run and re-dispatches every step still
17
+ * owed a job, so holding off a single step while resuming its run would
18
+ * suppress nothing.
19
+ *
20
+ * Losing this on restart costs extra dispatches, never correctness.
21
+ */
22
+ export class RedispatchBackoff {
23
+ private readonly eligibleAt = new Map<string, number>()
24
+ private readonly delays = new Map<string, number>()
25
+
26
+ public isEligible(runId: string, now: number): boolean {
27
+ const at = this.eligibleAt.get(runId)
28
+ return at === undefined || at <= now
29
+ }
30
+
31
+ public note(runId: string, now: number): void {
32
+ const previous = this.delays.get(runId)
33
+ const delay = Math.min(
34
+ previous === undefined ? REDISPATCH_BACKOFF_MS : previous * 2,
35
+ REDISPATCH_BACKOFF_MAX_MS
36
+ )
37
+ // A run that settles is never returned again, so entries are only evicted
38
+ // by this bound — oldest first, which is also least recently re-dispatched.
39
+ if (this.eligibleAt.size >= REDISPATCH_BACKOFF_MAX_ENTRIES) {
40
+ const oldest = this.eligibleAt.keys().next()
41
+ if (!oldest.done) {
42
+ this.eligibleAt.delete(oldest.value)
43
+ this.delays.delete(oldest.value)
44
+ }
45
+ }
46
+ this.delays.set(runId, delay)
47
+ this.eligibleAt.set(runId, now + delay)
48
+ }
49
+ }
50
+
51
+ type SweepDeps = {
52
+ resume: (runId: string) => Promise<void>
53
+ logger?: Logger
54
+ }
55
+
56
+ const resumeEach = async (
57
+ runIds: Iterable<string>,
58
+ { resume, logger }: SweepDeps,
59
+ failure: (runId: string, detail: string) => string
60
+ ): Promise<string[]> => {
61
+ const succeeded: string[] = []
62
+ for (const runId of runIds) {
63
+ try {
64
+ await resume(runId)
65
+ succeeded.push(runId)
66
+ } catch (err) {
67
+ // One unresumable run must not stop the sweep from recovering the rest.
68
+ logger?.error(
69
+ failure(runId, err instanceof Error ? err.message : String(err))
70
+ )
71
+ }
72
+ }
73
+ return succeeded
74
+ }
75
+
76
+ /**
77
+ * Re-drive runs whose next move was lost, and report which were resumed.
78
+ *
79
+ * Arming a step is two writes to two systems — the step row, then the queue or
80
+ * scheduler job — so a process that dies between them leaves a run that is
81
+ * `running` with nothing in flight. Nothing notices: the run parks on a step
82
+ * that will never complete and never error, so it neither finishes nor fails.
83
+ * (Seen on a `workflow.sleep()`: a deploy restart landed between the sleep
84
+ * step's insert and its timer, parking the run permanently.)
85
+ *
86
+ * Replay is the recovery — `resumeWorkflow` re-orchestrates from persisted step
87
+ * state, and every settled step is memoized, so resuming a run that was not
88
+ * actually stuck costs an orchestration pass and changes nothing. That
89
+ * idempotence is what makes an idle-time heuristic safe here; a run that is
90
+ * legitimately mid-sleep is excluded anyway, since its step is `scheduled`.
91
+ */
92
+ export const sweepStalledRuns = async (
93
+ findStalledRunIds: (before: Date, limit: number) => Promise<string[]>,
94
+ options: { stalledAfterMs?: number; limit?: number } | undefined,
95
+ deps: SweepDeps
96
+ ): Promise<{ resumed: string[] }> => {
97
+ const before = new Date(
98
+ Date.now() - (options?.stalledAfterMs ?? DEFAULT_STALLED_RUN_MS)
99
+ )
100
+ const runIds = await findStalledRunIds(
101
+ before,
102
+ options?.limit ?? DEFAULT_STALLED_RUN_LIMIT
103
+ )
104
+ return {
105
+ resumed: await resumeEach(
106
+ runIds,
107
+ deps,
108
+ (runId, detail) =>
109
+ `Failed to resume stalled workflow run ${runId}: ${detail}`
110
+ ),
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Re-drive steps whose dispatch was lost, and report which runs were nudged.
116
+ *
117
+ * The step row is the outbox record and this is the relay. Age is the only
118
+ * signal available — a step `pending` because its dispatch was lost is
119
+ * indistinguishable from one whose job is merely still queued — so a step past
120
+ * `undispatchedAfterMs` is re-dispatched regardless, and correctness rests on
121
+ * the claim in `executeWorkflowStepInner` rather than on the guess being right.
122
+ * A redundant dispatch costs one queue message: the loser reads `running` and
123
+ * returns without invoking anything.
124
+ *
125
+ * Re-dispatches back off per run (doubling from 30s, capped at 10m) so a
126
+ * genuine queue backlog is not amplified by a tick that keeps firing at the
127
+ * steps the backlog is already delaying.
128
+ */
129
+ export const sweepUndispatchedSteps = async (
130
+ findUndispatchedSteps: (
131
+ before: Date,
132
+ limit: number
133
+ ) => Promise<Array<{ runId: string; stepId: string }>>,
134
+ backoff: RedispatchBackoff,
135
+ options: { undispatchedAfterMs?: number; limit?: number } | undefined,
136
+ deps: SweepDeps
137
+ ): Promise<{ redispatched: string[] }> => {
138
+ const before = new Date(
139
+ Date.now() - (options?.undispatchedAfterMs ?? DEFAULT_UNDISPATCHED_STEP_MS)
140
+ )
141
+ const steps = await findUndispatchedSteps(
142
+ before,
143
+ options?.limit ?? DEFAULT_UNDISPATCHED_STEP_LIMIT
144
+ )
145
+
146
+ const now = Date.now()
147
+ const runIds = new Set<string>()
148
+ for (const { runId } of steps) {
149
+ if (!backoff.isEligible(runId, now)) continue
150
+ backoff.note(runId, now)
151
+ runIds.add(runId)
152
+ }
153
+
154
+ return {
155
+ redispatched: await resumeEach(
156
+ runIds,
157
+ deps,
158
+ (runId, detail) =>
159
+ `Failed to re-dispatch workflow run ${runId}: ${detail}`
160
+ ),
161
+ }
162
+ }
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict'
3
3
 
4
4
  import { InMemoryWorkflowService } from '../../services/in-memory-workflow-service.js'
5
5
  import { pikkuState } from '../../pikku-state.js'
6
- import { DEFAULT_STEP_RETRIES } from './pikku-workflow-service.js'
6
+ import { DEFAULT_STEP_RETRIES } from './workflow-constants.js'
7
7
  import type { PikkuWorkflowService } from './pikku-workflow-service.js'
8
8
  import { deriveInvocationId } from './workflow-invocation-id.js'
9
9
  import type { WorkflowStepOptions } from './workflow.types.js'