@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
@@ -41,7 +41,11 @@ const CATALOGUE: ApiCatalogueEntry[] = [
41
41
  ]
42
42
 
43
43
  const INTENTS: IntentSource[] = [
44
- { id: 'onboard', title: 'set up your first project', steps: ['sign in', 'make a project'] },
44
+ {
45
+ id: 'onboard',
46
+ title: 'set up your first project',
47
+ steps: ['sign in', 'make a project'],
48
+ },
45
49
  ]
46
50
 
47
51
  const PERSONA = {
@@ -84,10 +88,7 @@ const scripted = (
84
88
  return { llm, turns: () => turn }
85
89
  }
86
90
 
87
- const respond = <T>(
88
- status: number,
89
- body: T
90
- ): ScenarioHttpResponse<T> => ({
91
+ const respond = <T>(status: number, body: T): ScenarioHttpResponse<T> => ({
91
92
  status,
92
93
  ok: status >= 200 && status < 300,
93
94
  body,
@@ -126,7 +127,12 @@ describe('running a virtual user', () => {
126
127
  { kind: 'complete', summary: 'done' },
127
128
  ])
128
129
 
129
- const result = await runVirtualUser({ ...base, target, llm, budget: { steps: 3 } })
130
+ const result = await runVirtualUser({
131
+ ...base,
132
+ target,
133
+ llm,
134
+ budget: { steps: 3 },
135
+ })
130
136
 
131
137
  // The first attempt cost a step and bought the schema; only the second
132
138
  // reached the server.
@@ -355,7 +361,9 @@ describe('what a virtual user reports', () => {
355
361
  })
356
362
 
357
363
  test('an app-specific oracle can add what the engine cannot know', async () => {
358
- const target = recordingTarget(() => respond(200, { orgId: 'someone-else' }))
364
+ const target = recordingTarget(() =>
365
+ respond(200, { orgId: 'someone-else' })
366
+ )
359
367
  const { llm } = scripted(walkTo('listProjects'))
360
368
 
361
369
  const result = await runVirtualUser({
@@ -595,8 +603,9 @@ describe('goals and persona', () => {
595
603
  test('goals in the user’s own words become intents alongside the derived ones', async () => {
596
604
  const seen: string[] = []
597
605
  const target = recordingTarget(() => respond(200, {}))
598
- const { llm } = scripted([{ kind: 'complete' }, { kind: 'complete' }], (_i, m) =>
599
- seen.push(...m)
606
+ const { llm } = scripted(
607
+ [{ kind: 'complete' }, { kind: 'complete' }],
608
+ (_i, m) => seen.push(...m)
600
609
  )
601
610
 
602
611
  const result = await runVirtualUser({
@@ -143,8 +143,12 @@ const msg = (role: AIMessage['role'], content: string): AIMessage => ({
143
143
  })
144
144
 
145
145
  /** Read a structured result, falling back to parsing JSON out of the text. */
146
- const readObject = <T>(result: { object?: unknown; text?: string }): T | null => {
147
- if (result.object && typeof result.object === 'object') return result.object as T
146
+ const readObject = <T>(result: {
147
+ object?: unknown
148
+ text?: string
149
+ }): T | null => {
150
+ if (result.object && typeof result.object === 'object')
151
+ return result.object as T
148
152
  if (result.text) {
149
153
  try {
150
154
  return JSON.parse(result.text) as T
@@ -201,7 +205,11 @@ export const rememberIds = (
201
205
  return into
202
206
  }
203
207
  for (const [key, value] of Object.entries(body)) {
204
- if (typeof value === 'string' && MEMORABLE.test(key) && value.length < 200) {
208
+ if (
209
+ typeof value === 'string' &&
210
+ MEMORABLE.test(key) &&
211
+ value.length < 200
212
+ ) {
205
213
  into[key] = value
206
214
  } else if (typeof value === 'object') {
207
215
  rememberIds(value, into, depth + 1)
@@ -237,7 +245,10 @@ const personaInstructions = (
237
245
  '',
238
246
  agents.length
239
247
  ? `Assistants you can talk to:\n${agents
240
- .map((agent) => `- ${agent.name}${agent.description ? `: ${agent.description}` : ''}`)
248
+ .map(
249
+ (agent) =>
250
+ `- ${agent.name}${agent.description ? `: ${agent.description}` : ''}`
251
+ )
241
252
  .join('\n')}`
242
253
  : '',
243
254
  fixtures.length ? `Files you have: ${fixtures.join(', ')}` : '',
@@ -351,7 +362,10 @@ export const runVirtualUser = async (
351
362
  stoppedBy = 'budget-duration'
352
363
  break
353
364
  }
354
- if (budget?.mutations !== undefined && tally.mutations >= budget.mutations) {
365
+ if (
366
+ budget?.mutations !== undefined &&
367
+ tally.mutations >= budget.mutations
368
+ ) {
355
369
  stoppedBy = 'budget-mutations'
356
370
  break
357
371
  }
@@ -402,10 +416,7 @@ export const runVirtualUser = async (
402
416
  )
403
417
  )
404
418
  }
405
- // Whether this user trusts its notes this turn or goes and looks again.
406
- // `stale` almost always trusts them, a newcomer has none to trust, and an
407
- // auditor checks nearly everything — which is the whole difference between
408
- // those runs, expressed as one roll rather than as prose.
419
+ // knowledge: decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md
409
420
  if (Object.keys(memory).length && !rng.chance(profile.reReadRate)) {
410
421
  messages.push(
411
422
  msg(
@@ -448,7 +459,9 @@ export const runVirtualUser = async (
448
459
 
449
460
  if (!raw || typeof raw.kind !== 'string') {
450
461
  steps.push(record)
451
- messages.push(msg('user', 'That was not a valid action. Choose one action.'))
462
+ messages.push(
463
+ msg('user', 'That was not a valid action. Choose one action.')
464
+ )
452
465
  continue
453
466
  }
454
467
 
@@ -550,10 +563,7 @@ export const runVirtualUser = async (
550
563
  continue
551
564
  }
552
565
 
553
- // What may be called is decided once, when the catalogue is narrowed: a
554
- // read-only disposition is never offered a mutation and an approval-gated
555
- // endpoint is never offered at all, so `index` is the gate and there is no
556
- // second one here to drift out of step with it.
566
+ // knowledge: decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md
557
567
  const mutating = !isReadOnly(entry)
558
568
 
559
569
  const args = readArgs((action as { args?: unknown }).args)
@@ -566,7 +576,10 @@ export const runVirtualUser = async (
566
576
  try {
567
577
  response = await target.call(entry.name, args)
568
578
  } catch (error) {
569
- record.findingKinds = [...(record.findingKinds ?? []), 'transport-error']
579
+ record.findingKinds = [
580
+ ...(record.findingKinds ?? []),
581
+ 'transport-error',
582
+ ]
570
583
  addFinding({
571
584
  kind: 'transport-error',
572
585
  detail: `${entry.name} threw: ${(error as Error).message}`,
@@ -45,7 +45,10 @@ describe('reachableAgents', () => {
45
45
 
46
46
  test('carries the description through, which is what the model chooses on', () => {
47
47
  const [router] = reachableAgents(AGENTS, ['content:write'])
48
- assert.equal(router!.description, 'Routes requests to the right domain agent')
48
+ assert.equal(
49
+ router!.description,
50
+ 'Routes requests to the right domain agent'
51
+ )
49
52
  })
50
53
 
51
54
  test('omits description rather than passing undefined', () => {
@@ -31,23 +31,9 @@ export const deriveCatalogue = (
31
31
  ): ApiCatalogueEntry[] => {
32
32
  const entries: ApiCatalogueEntry[] = []
33
33
  for (const [name, meta] of Object.entries(functions ?? {})) {
34
- // Scenario bodies and their steps are never network-callable — they are
35
- // held out of every deployed unit — so offering one would only ever waste
36
- // a turn on a 404.
37
- //
38
- // For a platform or addon step this is not an efficiency argument but the
39
- // oracle: a virtual user's findings are worth something only because it
40
- // cannot manufacture the outcomes it is meant to discover. One that could
41
- // invoke "Stripe's webhook arrives" would forge its own payment success,
42
- // and every finding downstream of that is worthless. Same class of argument
43
- // as `allowApprovalRequired` defaulting to false — and enforced here, at
44
- // derivation, rather than by convention.
34
+ // knowledge: decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md
45
35
  if (meta.scenario || meta.scenarioStep || meta.scenarioStepKind) continue
46
- // `expose: true` is what puts a function on the rpc transport, and that is
47
- // what the shipped target calls over. Absent is not permissive: an unexposed
48
- // function 404s, and offering one spends a step to learn nothing about the
49
- // product. Measured on the e2e app, 34 of its 72 functions are in exactly
50
- // that state — nearly half a catalogue that cannot be called.
36
+ // knowledge: decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md
51
37
  if (meta.expose !== true) continue
52
38
 
53
39
  const inputSchema = meta.inputSchemaName
@@ -103,10 +89,7 @@ const scenarioSteps = (meta: {
103
89
  )
104
90
  }
105
91
 
106
- // Insertion order is the order the CLI wrote the nodes in, which is the order
107
- // the scenario declares them. Following `next` instead would buy an ordering
108
- // that is already true and cost a traversal that has to decide what a branch
109
- // means to a reader who will never take one.
92
+ // knowledge: decisions/internals/virtual-user-step-order-comes-from-insertion-order.md
110
93
  return Object.values(meta.nodes ?? {}).flatMap((node) => {
111
94
  const { rpcName, scenarioStepPhase, actor } = (node ?? {}) as {
112
95
  rpcName?: string
@@ -149,11 +132,7 @@ export const deriveIntents = (
149
132
  steps.push(
150
133
  composeStepProse({
151
134
  phase: step.phase,
152
- // The template goes in unfilled, braces and all. A reporter fills its
153
- // placeholders from a run that happened; there is no run yet, and
154
- // "invites {email}" tells a user to pick someone where the filled-in
155
- // form would have told it whom — which is the scenario's answer, not
156
- // the user's own.
135
+ // knowledge: decisions/internals/a-scenario-step-template-is-offered-unfilled.md
157
136
  description: template ?? description ?? '',
158
137
  actor: step.actor,
159
138
  })
@@ -1,6 +1,9 @@
1
1
  import { strict as assert } from 'assert'
2
2
  import { describe, test } from 'node:test'
3
- import { DISPOSITIONS, dispositionProfile } from './virtual-user-dispositions.js'
3
+ import {
4
+ DISPOSITIONS,
5
+ dispositionProfile,
6
+ } from './virtual-user-dispositions.js'
4
7
 
5
8
  describe('resolving a disposition profile', () => {
6
9
  test('an unknown disposition falls back to realistic rather than throwing', () => {
@@ -46,7 +49,9 @@ describe('resolving a disposition profile', () => {
46
49
  const profile = dispositionProfile('careless', {
47
50
  instructions: 'Paste ids from other tabs.',
48
51
  })
49
- assert.ok(profile.instructions.startsWith(DISPOSITIONS.careless.instructions))
52
+ assert.ok(
53
+ profile.instructions.startsWith(DISPOSITIONS.careless.instructions)
54
+ )
50
55
  assert.ok(profile.instructions.endsWith('Paste ids from other tabs.'))
51
56
  })
52
57
 
@@ -154,10 +154,7 @@ export const DISPOSITIONS: Readonly<
154
154
  invertedOracle: true,
155
155
  },
156
156
 
157
- // The only disposition that is not testing anything. It is doing the job, so
158
- // it abandons rarely, runs cool, and is told to stop and say so rather than
159
- // guess — the failure mode here is a wrong action nobody asked for, not a
160
- // missed bug.
157
+ // knowledge: decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md
161
158
  accountable: {
162
159
  ...REALISTIC,
163
160
  instructions: [
@@ -3,7 +3,10 @@ import assert from 'node:assert/strict'
3
3
 
4
4
  import { IntentStack, intentsForPersona } from './virtual-user-intents.js'
5
5
  import { createRng } from './virtual-user-rng.js'
6
- import { DISPOSITIONS, type DispositionProfile } from './virtual-user-dispositions.js'
6
+ import {
7
+ DISPOSITIONS,
8
+ type DispositionProfile,
9
+ } from './virtual-user-dispositions.js'
7
10
  import type { IntentSource } from './virtual-user.types.js'
8
11
 
9
12
  const profileWith = (
@@ -182,7 +185,11 @@ describe('intents for an actor', () => {
182
185
  const catalogue: IntentSource[] = [
183
186
  { id: 'a', title: 'invite a teammate', personas: ['orgAdmin'] },
184
187
  { id: 'b', title: 'read the dashboard' },
185
- { id: 'c', title: 'deploy a stage', personas: ['platformAdmin', 'orgAdmin'] },
188
+ {
189
+ id: 'c',
190
+ title: 'deploy a stage',
191
+ personas: ['platformAdmin', 'orgAdmin'],
192
+ },
186
193
  ]
187
194
 
188
195
  test('an actor gets what names it, plus anything that names nobody', () => {
@@ -201,7 +208,10 @@ describe('intents for an actor', () => {
201
208
 
202
209
  test('an empty actor list means everyone', () => {
203
210
  assert.deepEqual(
204
- intentsForPersona([{ id: 'x', title: 'anything', personas: [] }], 'nobody'),
211
+ intentsForPersona(
212
+ [{ id: 'x', title: 'anything', personas: [] }],
213
+ 'nobody'
214
+ ),
205
215
  [{ id: 'x', title: 'anything', personas: [] }]
206
216
  )
207
217
  })
@@ -311,7 +311,7 @@ export interface ReturnStepMeta {
311
311
  }
312
312
 
313
313
  /**
314
- * Inline step metadata (legacy support)
314
+ * Inline step metadata
315
315
  */
316
316
  export interface InlineStepMeta {
317
317
  /** Inline form - local execution */
@@ -528,7 +528,40 @@ export interface PikkuWorkflowWire {
528
528
  approval: WorkflowWireApproval
529
529
  }
530
530
 
531
- export interface PikkuScenarioWire extends PikkuWorkflowWire {
531
+ /**
532
+ * What a scenario has accumulated so far, shared by its body and its hooks.
533
+ *
534
+ * Typed as a partial of the scenario's own output because a scenario can fail
535
+ * at any step: the shape describes what a *completed* run produces, and the
536
+ * context holds however much of it this run reached. A scenario declaring no
537
+ * object output gets an open record rather than `Partial<never>`.
538
+ *
539
+ * `any` collapses to `any`, not to the union of both branches. `PikkuWire`'s
540
+ * default depends on that: the wire type is also used as a generic *constraint*,
541
+ * and a constraint carrying a concrete context would reject every wire whose
542
+ * scenario output differs from it.
543
+ */
544
+ export type ScenarioContext<Out = unknown> = 0 extends 1 & Out
545
+ ? any
546
+ : Out extends object
547
+ ? Partial<Out>
548
+ : Record<string, unknown>
549
+
550
+ export interface PikkuScenarioWire<Out = unknown> extends PikkuWorkflowWire {
551
+ /**
552
+ * Scratch the body writes and the `before`/`after` hooks read.
553
+ *
554
+ * A hook is a separate function, so it cannot see the body's locals — which
555
+ * is why teardown had nowhere to learn the ids the body minted. Assigning
556
+ * them here (`scenario.context.projectId = project.projectId`) hands them to
557
+ * `after`, which runs in a `finally` and so cleans up on a failed run too.
558
+ *
559
+ * Deliberately *not* a world: it is scoped to one run, and scenario steps
560
+ * cannot reach it. Steps stay pure functions of their declared inputs, so the
561
+ * ladder in the report remains a complete account of what a step saw.
562
+ */
563
+ context: ScenarioContext<Out>
564
+
532
565
  /**
533
566
  * Durable polling step: invoke `rpcName` (as an actor when `options.actor`
534
567
  * is set) until `predicate` passes or `options.within` elapses.
@@ -32,9 +32,11 @@ export const resolveFeatureScenarios = (
32
32
  const scenarios = feature.scenarios ?? []
33
33
  for (let index = 0; index < scenarios.length; index++) {
34
34
  const entry = scenarios[index]!
35
- const paired =
35
+ const pairing =
36
36
  typeof entry === 'object' && entry !== null && 'scenario' in entry
37
- const config = paired ? (entry as any).scenario : entry
37
+ ? (entry as { scenario: unknown; data?: unknown })
38
+ : undefined
39
+ const config = pairing ? pairing.scenario : entry
38
40
  const scenarioName = nameByConfig.get(config)
39
41
  if (!scenarioName) {
40
42
  unresolved.push({ featureId, index })
@@ -44,10 +46,11 @@ export const resolveFeatureScenarios = (
44
46
  featureId,
45
47
  featureName: feature.name ?? featureId,
46
48
  scenarioName,
47
- data: paired ? (entry as any).data : undefined,
49
+ data: pairing?.data,
48
50
  tags: [
49
51
  ...new Set([
50
- ...((registrations.get(scenarioName)?.func as any)?.tags ?? []),
52
+ ...((registrations.get(scenarioName)?.func as { tags?: string[] })
53
+ ?.tags ?? []),
51
54
  ...(feature.tags ?? []),
52
55
  ]),
53
56
  ],
@@ -65,7 +65,7 @@ export function createGraph<RPCMap extends Record<string, RPCHandler>>() {
65
65
  for (const [nodeId, def] of Object.entries(nodes) as [string, any][]) {
66
66
  result[nodeId] = {
67
67
  func: funcMap[nodeId] as string,
68
- input: def?.input as any,
68
+ input: def?.input,
69
69
  next: def?.next,
70
70
  onError: def?.onError,
71
71
  retries: def?.retries,
@@ -10,7 +10,7 @@ import {
10
10
  import type { WorkflowRuntimeMeta } from '../workflow.types.js'
11
11
  import { pikkuState } from '../../../pikku-state.js'
12
12
  import { RPCNotFoundError } from '../../rpc/rpc-runner.js'
13
- import { DEFAULT_STEP_RETRIES } from '../pikku-workflow-service.js'
13
+ import { DEFAULT_STEP_RETRIES } from '../workflow-constants.js'
14
14
 
15
15
  describe('graph-runner bugs', () => {
16
16
  test('continueGraph should NOT mark workflow completed while nodes are still running', async () => {
@@ -828,7 +828,9 @@ describe('graph-runner bugs', () => {
828
828
  name: 'testRetries',
829
829
  pikkuFuncId: 'testRetries',
830
830
  source: 'graph',
831
- entryNodeIds: ['a'],
831
+ // All three are dependency-free, so all three are entry nodes — a
832
+ // `startNode` may only name one the graph declared.
833
+ entryNodeIds: ['a', 'b', 'c'],
832
834
  graphHash: 'retries-hash',
833
835
  nodes: {
834
836
  a: {
@@ -1,9 +1,9 @@
1
+ import type { PikkuWorkflowService } from '../pikku-workflow-service.js'
1
2
  import {
2
- type PikkuWorkflowService,
3
3
  WorkflowAsyncException,
4
4
  WorkflowSuspendedException,
5
- DEFAULT_STEP_RETRIES,
6
- } from '../pikku-workflow-service.js'
5
+ } from '../workflow-errors.js'
6
+ import { DEFAULT_STEP_RETRIES } from '../workflow-constants.js'
7
7
  import type { GraphWireState, PikkuGraphWire } from './workflow-graph.types.js'
8
8
  import { pikkuState, getSingletonServices } from '../../../pikku-state.js'
9
9
  import type { WorkflowRuntimeMeta, WorkflowRunWire } from '../workflow.types.js'
@@ -211,7 +211,7 @@ function isDataRef(value: unknown): value is { $ref: string; path?: string } {
211
211
  typeof value === 'object' &&
212
212
  value !== null &&
213
213
  '$ref' in value &&
214
- typeof (value as any).$ref === 'string'
214
+ typeof (value as { $ref?: unknown }).$ref === 'string'
215
215
  )
216
216
  }
217
217
 
@@ -227,7 +227,7 @@ function isTemplate(value: unknown): value is TemplateValue {
227
227
  typeof value === 'object' &&
228
228
  value !== null &&
229
229
  '$template' in value &&
230
- typeof (value as any).$template === 'object'
230
+ typeof (value as { $template?: unknown }).$template === 'object'
231
231
  )
232
232
  }
233
233
 
@@ -695,14 +695,6 @@ export async function executeGraphStep(
695
695
  }
696
696
  }
697
697
 
698
- export async function onGraphNodeComplete(
699
- workflowService: PikkuWorkflowService,
700
- runId: string,
701
- graphName: string
702
- ): Promise<void> {
703
- await continueGraph(workflowService, runId, graphName)
704
- }
705
-
706
698
  export async function runFromMeta(
707
699
  workflowService: PikkuWorkflowService,
708
700
  runId: string,
@@ -928,9 +920,14 @@ export async function runWorkflowGraph(
928
920
  }
929
921
 
930
922
  const nodes = meta.nodes
931
- const entryNodes: string[] = startNode
932
- ? [startNode]
933
- : (meta.entryNodeIds ?? [])
923
+ const declaredEntryNodes = meta.entryNodeIds ?? []
924
+ // knowledge: decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md
925
+ if (startNode && !declaredEntryNodes.includes(startNode)) {
926
+ throw new Error(
927
+ `Workflow graph '${graphName}': '${startNode}' is not an entry node`
928
+ )
929
+ }
930
+ const entryNodes: string[] = startNode ? [startNode] : declaredEntryNodes
934
931
  validateGraphReferences(graphName, nodes, entryNodes)
935
932
 
936
933
  if (entryNodes.length === 0) {
@@ -16,11 +16,6 @@ export const isRef = (value: unknown): value is RefValue =>
16
16
  '__isRef' in value &&
17
17
  (value as RefValue).__isRef === true
18
18
 
19
- export interface InputRef {
20
- nodeId: string
21
- path?: string
22
- }
23
-
24
19
  export type RefFn<NodeIds extends string = string> = (
25
20
  nodeId: NodeIds,
26
21
  path?: string
@@ -1,20 +1,28 @@
1
+ export { PikkuWorkflowService } from './pikku-workflow-service.js'
1
2
  export {
2
- PikkuWorkflowService,
3
3
  WorkflowCancelledException,
4
4
  WorkflowSuspendedException,
5
5
  WorkflowDispatchException,
6
6
  WorkflowNotFoundError,
7
7
  WorkflowRunNotFoundError,
8
8
  WorkflowApprovalResolvedError,
9
- DEFAULT_STEP_RETRIES,
10
- } from './pikku-workflow-service.js'
9
+ WorkflowStepFunctionMismatchError,
10
+ } from './workflow-errors.js'
11
+ export { DEFAULT_STEP_RETRIES } from './workflow-constants.js'
12
+ export {
13
+ assertWorkflowRunOwner,
14
+ WorkflowRunForbiddenError,
15
+ } from './workflow-run-ownership.js'
11
16
  export type {
12
17
  RunLifecycleContext,
13
18
  WorkflowRunEngine,
14
19
  WorkflowRunExtension,
15
- } from './pikku-workflow-service.js'
20
+ } from './workflow-run-engine.types.js'
16
21
  export { deriveInvocationId, uuidv5 } from './workflow-invocation-id.js'
17
22
 
23
+ export { isRef } from './graph/workflow-graph.types.js'
24
+ export type { RefValue } from './graph/workflow-graph.types.js'
25
+
18
26
  export {
19
27
  buildRunTimeline,
20
28
  reconstructStateAt,