@pikku/core 0.12.83 → 0.12.86

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 (661) hide show
  1. package/CHANGELOG.md +492 -0
  2. package/README.md +1 -1
  3. package/dist/bootstrap-compat/root.d.ts +20 -0
  4. package/dist/classification/column-form.d.ts +32 -0
  5. package/dist/classification/column-form.js +42 -0
  6. package/dist/classification/data-classification.d.ts +64 -0
  7. package/dist/classification/index.d.ts +13 -0
  8. package/dist/classification/index.js +2 -0
  9. package/dist/classification/secret-value.d.ts +56 -0
  10. package/dist/classification/secret-value.js +46 -0
  11. package/dist/crypto-utils.d.ts +1 -1
  12. package/dist/ecosystem/agent-scorer.d.ts +12 -0
  13. package/dist/ecosystem/agent-scorer.js +5 -0
  14. package/dist/ecosystem/agent.d.ts +21 -0
  15. package/dist/ecosystem/agent.js +6 -0
  16. package/dist/ecosystem/channel/local.d.ts +3 -0
  17. package/dist/ecosystem/channel/local.js +3 -0
  18. package/dist/ecosystem/channel/serverless.d.ts +9 -0
  19. package/dist/ecosystem/channel/serverless.js +1 -0
  20. package/dist/ecosystem/channel.d.ts +15 -0
  21. package/dist/ecosystem/channel.js +5 -0
  22. package/dist/ecosystem/cli/channel.d.ts +16 -0
  23. package/dist/ecosystem/cli/channel.js +2 -0
  24. package/dist/ecosystem/cli.d.ts +9 -0
  25. package/dist/ecosystem/cli.js +2 -0
  26. package/dist/ecosystem/credential.d.ts +10 -0
  27. package/dist/ecosystem/credential.js +1 -0
  28. package/dist/ecosystem/crypto-utils.d.ts +8 -0
  29. package/dist/ecosystem/crypto-utils.js +1 -0
  30. package/dist/ecosystem/dev.d.ts +9 -0
  31. package/dist/ecosystem/dev.js +2 -0
  32. package/dist/ecosystem/errors.d.ts +8 -0
  33. package/dist/ecosystem/errors.js +2 -0
  34. package/dist/ecosystem/function.d.ts +13 -0
  35. package/dist/ecosystem/function.js +2 -0
  36. package/dist/ecosystem/gateway.d.ts +1 -0
  37. package/dist/ecosystem/hmac.d.ts +1 -0
  38. package/dist/ecosystem/hmac.js +1 -0
  39. package/dist/ecosystem/http.d.ts +13 -0
  40. package/dist/ecosystem/http.js +5 -0
  41. package/dist/ecosystem/mcp.d.ts +3 -0
  42. package/dist/ecosystem/mcp.js +2 -0
  43. package/dist/ecosystem/middleware.d.ts +18 -0
  44. package/dist/ecosystem/middleware.js +7 -0
  45. package/dist/ecosystem/node-host-resolver.d.ts +1 -0
  46. package/dist/ecosystem/node-host-resolver.js +1 -0
  47. package/dist/ecosystem/node.d.ts +1 -0
  48. package/dist/ecosystem/oauth2.d.ts +1 -0
  49. package/dist/ecosystem/oauth2.js +1 -0
  50. package/dist/ecosystem/persona.d.ts +17 -0
  51. package/dist/ecosystem/persona.js +5 -0
  52. package/dist/ecosystem/queue.d.ts +13 -0
  53. package/dist/ecosystem/queue.js +4 -0
  54. package/dist/ecosystem/remote.d.ts +8 -0
  55. package/dist/ecosystem/remote.js +1 -0
  56. package/dist/ecosystem/role.d.ts +4 -0
  57. package/dist/ecosystem/role.js +2 -0
  58. package/dist/ecosystem/rpc.d.ts +6 -0
  59. package/dist/ecosystem/rpc.js +3 -0
  60. package/dist/ecosystem/safe-fetch.d.ts +7 -0
  61. package/dist/ecosystem/safe-fetch.js +1 -0
  62. package/dist/ecosystem/scenario.d.ts +21 -0
  63. package/dist/ecosystem/scenario.js +8 -0
  64. package/dist/ecosystem/scheduler.d.ts +3 -0
  65. package/dist/ecosystem/scheduler.js +2 -0
  66. package/dist/ecosystem/schema.d.ts +2 -0
  67. package/dist/ecosystem/schema.js +1 -0
  68. package/dist/ecosystem/scope.d.ts +5 -0
  69. package/dist/ecosystem/scope.js +3 -0
  70. package/dist/ecosystem/secret.d.ts +11 -0
  71. package/dist/ecosystem/secret.js +2 -0
  72. package/dist/ecosystem/services/istanbul-coverage.d.ts +1 -0
  73. package/dist/ecosystem/services/istanbul-coverage.js +1 -0
  74. package/dist/ecosystem/services/local-content-request-handler.d.ts +9 -0
  75. package/dist/ecosystem/services/local-content-request-handler.js +1 -0
  76. package/dist/ecosystem/services/local-content.d.ts +2 -0
  77. package/dist/ecosystem/services/local-content.js +1 -0
  78. package/dist/ecosystem/services/local-meta.d.ts +1 -0
  79. package/dist/ecosystem/services/local-meta.js +1 -0
  80. package/dist/ecosystem/services/v8-coverage.d.ts +1 -0
  81. package/dist/ecosystem/services/v8-coverage.js +1 -0
  82. package/dist/ecosystem/services.d.ts +36 -0
  83. package/dist/ecosystem/services.js +12 -0
  84. package/dist/ecosystem/testing.d.ts +7 -0
  85. package/dist/ecosystem/testing.js +1 -0
  86. package/dist/ecosystem/trigger.d.ts +2 -0
  87. package/dist/ecosystem/trigger.js +1 -0
  88. package/dist/ecosystem/types.d.ts +12 -0
  89. package/dist/ecosystem/types.js +6 -0
  90. package/dist/ecosystem/variable.d.ts +9 -0
  91. package/dist/ecosystem/variable.js +1 -0
  92. package/dist/ecosystem/virtual-user.d.ts +24 -0
  93. package/dist/ecosystem/virtual-user.js +8 -0
  94. package/dist/ecosystem/workflow.d.ts +20 -0
  95. package/dist/ecosystem/workflow.js +6 -0
  96. package/dist/errors/index.d.ts +8 -0
  97. package/dist/errors/index.js +1 -0
  98. package/dist/errors/serialized-error.d.ts +7 -0
  99. package/dist/errors/serialized-error.js +1 -0
  100. package/dist/function/function-meta.types.d.ts +139 -0
  101. package/dist/function/function-meta.types.js +1 -0
  102. package/dist/function/function-runner.d.ts +3 -2
  103. package/dist/function/function-runner.js +31 -11
  104. package/dist/function/functions.types.d.ts +10 -2
  105. package/dist/function/index.d.ts +8 -2
  106. package/dist/function/index.js +4 -1
  107. package/dist/function/pikku-request.d.ts +8 -0
  108. package/dist/function/pikku-request.js +15 -0
  109. package/dist/index.d.ts +8 -8
  110. package/dist/index.js +3 -3
  111. package/dist/middleware/auth-apikey.d.ts +2 -10
  112. package/dist/middleware/auth-apikey.js +1 -1
  113. package/dist/middleware/auth-bearer.d.ts +2 -10
  114. package/dist/middleware/auth-bearer.js +1 -1
  115. package/dist/middleware/auth-cookie.d.ts +2 -10
  116. package/dist/middleware/auth-cookie.js +1 -1
  117. package/dist/middleware/cors.d.ts +5 -11
  118. package/dist/middleware/cors.js +13 -6
  119. package/dist/middleware/index.d.ts +3 -0
  120. package/dist/middleware/index.js +1 -0
  121. package/dist/middleware/middleware-factories.d.ts +9 -0
  122. package/dist/middleware/middleware-factories.js +19 -0
  123. package/dist/middleware/middleware.types.d.ts +27 -0
  124. package/dist/middleware/middleware.types.js +1 -0
  125. package/dist/middleware/remote-auth.d.ts +1 -1
  126. package/dist/middleware/remote-auth.js +1 -1
  127. package/dist/middleware/telemetry.d.ts +4 -20
  128. package/dist/middleware/telemetry.js +1 -1
  129. package/dist/middleware-runner.d.ts +2 -1
  130. package/dist/pikku-state.d.ts +2 -1
  131. package/dist/services/{ai-run-state-service.d.ts → agent-run-state-service.d.ts} +5 -5
  132. package/dist/services/agent-run-state-service.js +1 -0
  133. package/dist/services/{ai-agent-runner-service.d.ts → agent-runner-service.d.ts} +12 -12
  134. package/dist/services/agent-runner-service.js +1 -0
  135. package/dist/services/{ai-storage-service.d.ts → agent-storage-service.d.ts} +7 -7
  136. package/dist/services/agent-storage-service.js +1 -0
  137. package/dist/services/audit-service.d.ts +1 -1
  138. package/dist/services/credential-wire-service.js +1 -1
  139. package/dist/services/email-service.d.ts +1 -1
  140. package/dist/services/file-scenario-run-store.d.ts +58 -0
  141. package/dist/services/file-scenario-run-store.js +214 -0
  142. package/dist/services/http-personas.d.ts +1 -1
  143. package/dist/services/http-personas.js +3 -3
  144. package/dist/services/{in-memory-ai-run-state-service.d.ts → in-memory-agent-run-state-service.d.ts} +5 -5
  145. package/dist/services/{in-memory-ai-run-state-service.js → in-memory-agent-run-state-service.js} +1 -1
  146. package/dist/services/in-memory-workflow-service.d.ts +1 -1
  147. package/dist/services/index.d.ts +9 -5
  148. package/dist/services/index.js +4 -1
  149. package/dist/services/local-secrets.d.ts +1 -1
  150. package/dist/services/local-secrets.js +1 -1
  151. package/dist/services/logger.d.ts +7 -7
  152. package/dist/services/meta-service.d.ts +5 -4
  153. package/dist/services/scoped-secret-service.d.ts +1 -1
  154. package/dist/services/secret-service.d.ts +1 -1
  155. package/dist/services/typed-secret-service.d.ts +16 -2
  156. package/dist/services/typed-secret-service.js +5 -0
  157. package/dist/services/webhook-service.d.ts +1 -1
  158. package/dist/services/workflow-service.d.ts +2 -1
  159. package/dist/testing/index.d.ts +1 -0
  160. package/dist/testing/index.js +1 -0
  161. package/dist/testing/service-tests/agent-run-service-tests.d.ts +1 -1
  162. package/dist/testing/service-tests/agent-run-service-tests.js +3 -3
  163. package/dist/testing/service-tests/agent-storage-service-tests.d.ts +3 -0
  164. package/dist/testing/service-tests/{ai-storage-service-tests.js → agent-storage-service-tests.js} +4 -4
  165. package/dist/testing/service-tests.d.ts +4 -4
  166. package/dist/testing/service-tests.js +4 -4
  167. package/dist/types/core.types.d.ts +37 -187
  168. package/dist/types/core.types.js +1 -19
  169. package/dist/types/index.d.ts +2 -0
  170. package/dist/types/index.js +1 -0
  171. package/dist/types/state.types.d.ts +8 -6
  172. package/dist/utils.d.ts +13 -0
  173. package/dist/utils.js +2 -0
  174. package/dist/wirings/actor-flow/run-conversation.d.ts +2 -2
  175. package/dist/wirings/addon/addon-runner.d.ts +17 -0
  176. package/dist/wirings/addon/addon-runner.js +150 -0
  177. package/dist/wirings/addon/index.d.ts +6 -0
  178. package/dist/wirings/addon/index.js +3 -0
  179. package/dist/wirings/addon/remote-addon-auth.d.ts +16 -0
  180. package/dist/wirings/addon/remote-addon-auth.js +39 -0
  181. package/dist/wirings/addon/wire-addon.d.ts +80 -0
  182. package/dist/wirings/addon/wire-addon.js +120 -0
  183. package/dist/wirings/addon/wire-remote-addon.d.ts +22 -0
  184. package/dist/wirings/addon/wire-remote-addon.js +11 -0
  185. package/dist/wirings/{ai-agent/ai-agent-agui.d.ts → agent/agent-agui.d.ts} +2 -2
  186. package/dist/wirings/{ai-agent/ai-agent-agui.js → agent/agent-agui.js} +1 -1
  187. package/dist/wirings/{ai-agent/ai-agent-finalize.d.ts → agent/agent-finalize.d.ts} +10 -10
  188. package/dist/wirings/{ai-agent/ai-agent-finalize.js → agent/agent-finalize.js} +7 -7
  189. package/dist/wirings/{ai-agent/ai-agent-helpers.d.ts → agent/agent-helpers.d.ts} +1 -1
  190. package/dist/wirings/{ai-agent/ai-agent-interrupt.d.ts → agent/agent-interrupt.d.ts} +4 -4
  191. package/dist/wirings/{ai-agent/ai-agent-interrupt.js → agent/agent-interrupt.js} +2 -2
  192. package/dist/wirings/{ai-agent/ai-agent-memory.d.ts → agent/agent-memory.d.ts} +14 -14
  193. package/dist/wirings/{ai-agent/ai-agent-memory.js → agent/agent-memory.js} +1 -1
  194. package/dist/wirings/{ai-agent/ai-agent-model-config.js → agent/agent-model-config.js} +1 -1
  195. package/dist/wirings/{ai-agent/ai-agent-prepare.d.ts → agent/agent-prepare.d.ts} +24 -24
  196. package/dist/wirings/{ai-agent/ai-agent-prepare.js → agent/agent-prepare.js} +17 -17
  197. package/dist/wirings/agent/agent-registry.d.ts +16 -0
  198. package/dist/wirings/{ai-agent/ai-agent-registry.js → agent/agent-registry.js} +9 -9
  199. package/dist/wirings/{ai-agent → agent}/agent-rpc.js +8 -8
  200. package/dist/wirings/agent/agent-runner.d.ts +7 -0
  201. package/dist/wirings/{ai-agent/ai-agent-runner.js → agent/agent-runner.js} +49 -50
  202. package/dist/wirings/{ai-agent/ai-agent-stream.d.ts → agent/agent-stream.d.ts} +15 -15
  203. package/dist/wirings/{ai-agent/ai-agent-stream.js → agent/agent-stream.js} +78 -78
  204. package/dist/wirings/{ai-agent/ai-agent-turn.d.ts → agent/agent-turn.d.ts} +5 -5
  205. package/dist/wirings/{ai-agent/ai-agent-turn.js → agent/agent-turn.js} +4 -4
  206. package/dist/wirings/agent/agent-utils.d.ts +14 -0
  207. package/dist/wirings/agent/agent-utils.js +17 -0
  208. package/dist/wirings/{ai-agent/ai-agent.types.d.ts → agent/agent.types.d.ts} +47 -46
  209. package/dist/wirings/agent/agent.types.js +1 -0
  210. package/dist/wirings/agent/index.d.ts +12 -0
  211. package/dist/wirings/agent/index.js +10 -0
  212. package/dist/wirings/{ai-agent → agent}/voice-input.d.ts +1 -1
  213. package/dist/wirings/{ai-agent → agent}/voice-input.js +5 -5
  214. package/dist/wirings/{ai-agent → agent}/voice-output.d.ts +2 -3
  215. package/dist/wirings/{ai-agent → agent}/voice-output.js +8 -8
  216. package/dist/wirings/{ai-scorer/ai-scorer-grade.d.ts → agent-scorer/agent-scorer-grade.d.ts} +3 -3
  217. package/dist/wirings/{ai-scorer/ai-scorer-grade.js → agent-scorer/agent-scorer-grade.js} +6 -6
  218. package/dist/wirings/agent-scorer/agent-scorer-judge.d.ts +30 -0
  219. package/dist/wirings/{ai-scorer/ai-scorer-judge.js → agent-scorer/agent-scorer-judge.js} +57 -5
  220. package/dist/wirings/{ai-scorer/ai-scorer-live.d.ts → agent-scorer/agent-scorer-live.d.ts} +1 -1
  221. package/dist/wirings/{ai-scorer/ai-scorer-live.js → agent-scorer/agent-scorer-live.js} +3 -3
  222. package/dist/wirings/{ai-scorer/ai-scorer-registry.d.ts → agent-scorer/agent-scorer-registry.d.ts} +6 -6
  223. package/dist/wirings/{ai-scorer/ai-scorer-registry.js → agent-scorer/agent-scorer-registry.js} +4 -4
  224. package/dist/wirings/{ai-scorer/ai-scorer-snapshots.d.ts → agent-scorer/agent-scorer-snapshots.d.ts} +1 -1
  225. package/dist/wirings/{ai-scorer/ai-scorer-worker.d.ts → agent-scorer/agent-scorer-worker.d.ts} +3 -3
  226. package/dist/wirings/{ai-scorer/ai-scorer-worker.js → agent-scorer/agent-scorer-worker.js} +9 -7
  227. package/dist/wirings/{ai-scorer/ai-scorer.d.ts → agent-scorer/agent-scorer.d.ts} +12 -6
  228. package/dist/wirings/{ai-scorer/ai-scorer.js → agent-scorer/agent-scorer.js} +4 -3
  229. package/dist/wirings/{ai-scorer/ai-scorer.types.d.ts → agent-scorer/agent-scorer.types.d.ts} +24 -4
  230. package/dist/wirings/agent-scorer/agent-scorer.types.js +4 -0
  231. package/dist/wirings/agent-scorer/index.d.ts +6 -0
  232. package/dist/wirings/agent-scorer/index.js +5 -0
  233. package/dist/wirings/channel/channel-common.d.ts +2 -1
  234. package/dist/wirings/channel/channel-middleware-runner.d.ts +2 -1
  235. package/dist/wirings/channel/channel-rpc.types.d.ts +2 -2
  236. package/dist/wirings/channel/channel.types.d.ts +1 -1
  237. package/dist/wirings/channel/serverless/index.d.ts +1 -0
  238. package/dist/wirings/cli/channel/index.d.ts +1 -1
  239. package/dist/wirings/cli/cli-runner.d.ts +2 -1
  240. package/dist/wirings/cli/cli-runner.js +4 -1
  241. package/dist/wirings/cli/cli.types.d.ts +21 -2
  242. package/dist/wirings/cli/command-parser.js +157 -23
  243. package/dist/wirings/gateway/gateway.types.d.ts +2 -1
  244. package/dist/wirings/http/http-runner.d.ts +1 -1
  245. package/dist/wirings/http/http-runner.js +1 -1
  246. package/dist/wirings/http/http.types.d.ts +2 -2
  247. package/dist/wirings/http/index.d.ts +1 -0
  248. package/dist/wirings/http/index.js +1 -0
  249. package/dist/wirings/http/pikku-fetch-http-request.js +1 -1
  250. package/dist/wirings/http/pikku-fetch-http-response.js +2 -2
  251. package/dist/wirings/mcp/mcp.types.d.ts +1 -1
  252. package/dist/wirings/persona/index.d.ts +1 -1
  253. package/dist/wirings/persona/index.js +1 -1
  254. package/dist/wirings/persona/persona.types.d.ts +14 -0
  255. package/dist/wirings/queue/queue.types.d.ts +1 -1
  256. package/dist/wirings/queue/signed-queue-service.d.ts +1 -1
  257. package/dist/wirings/rpc/index.d.ts +0 -6
  258. package/dist/wirings/rpc/index.js +0 -3
  259. package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -1
  260. package/dist/wirings/rpc/remote-addon-auth.js +1 -1
  261. package/dist/wirings/rpc/rpc-runner.d.ts +1 -1
  262. package/dist/wirings/rpc/rpc-runner.js +4 -4
  263. package/dist/wirings/rpc/rpc-types.d.ts +1 -1
  264. package/dist/wirings/rpc/wire-addon.d.ts +1 -1
  265. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -1
  266. package/dist/wirings/scope/index.d.ts +1 -0
  267. package/dist/wirings/scope/index.js +1 -0
  268. package/dist/wirings/secret/secret.types.d.ts +10 -0
  269. package/dist/wirings/secret/validate-secret-definitions.js +2 -0
  270. package/dist/wirings/variable/validate-variable-definitions.js +2 -0
  271. package/dist/wirings/variable/variable.types.d.ts +9 -0
  272. package/dist/wirings/virtual-user/index.d.ts +1 -1
  273. package/dist/wirings/virtual-user/index.js +1 -1
  274. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +1 -1
  275. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +1 -1
  276. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +1 -1
  277. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +1 -1
  278. package/dist/wirings/workflow/graph/graph-node.d.ts +9 -2
  279. package/dist/wirings/workflow/graph/graph-node.js +2 -0
  280. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -0
  281. package/dist/wirings/workflow/graph/graph-runner.js +283 -31
  282. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +16 -1
  283. package/dist/wirings/workflow/index.d.ts +2 -0
  284. package/dist/wirings/workflow/index.js +1 -0
  285. package/dist/wirings/workflow/pikku-scenario-service.d.ts +14 -4
  286. package/dist/wirings/workflow/pikku-scenario-service.js +44 -16
  287. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -1
  288. package/dist/wirings/workflow/pikku-workflow-service.js +3 -4
  289. package/dist/wirings/workflow/run-timeline.d.ts +2 -3
  290. package/dist/wirings/workflow/scenario-run.types.d.ts +171 -0
  291. package/dist/wirings/workflow/scenario-run.types.js +1 -0
  292. package/dist/wirings/workflow/scenario-step-guards.d.ts +1 -2
  293. package/dist/wirings/workflow/scenario-step-guards.js +0 -8
  294. package/dist/wirings/workflow/scenario-step.types.d.ts +27 -12
  295. package/dist/wirings/workflow/workflow-approval.js +2 -1
  296. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +2 -1
  297. package/dist/wirings/workflow/workflow.types.d.ts +2 -1
  298. package/knowledge/decisions/index.md +2 -0
  299. package/knowledge/decisions/internals/{a-non-streaming-agent-run-registers-with-airunstate-too.md → a-non-streaming-agent-run-registers-with-agentrunstate-too.md} +6 -6
  300. package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +1 -1
  301. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +1 -1
  302. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +1 -1
  303. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +2 -2
  304. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +6 -6
  305. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +1 -1
  306. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +1 -1
  307. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +1 -1
  308. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +1 -1
  309. package/knowledge/decisions/internals/{ai-agent-agui-bridge-obeys-the-client-ordering-contract.md → agent-agui-bridge-obeys-the-client-ordering-contract.md} +5 -5
  310. package/knowledge/decisions/internals/{ai-agent-audio-chunks-carry-the-format-the-provider-returned.md → agent-audio-chunks-carry-the-format-the-provider-returned.md} +2 -2
  311. package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +1 -1
  312. package/knowledge/decisions/internals/{ai-agent-credential-suspensions-hide-the-tool-result.md → agent-credential-suspensions-hide-the-tool-result.md} +2 -2
  313. package/knowledge/decisions/internals/{ai-agent-delegate-and-supervise-hide-different-text.md → agent-delegate-and-supervise-hide-different-text.md} +4 -4
  314. package/knowledge/decisions/internals/{ai-agent-llm-tool-arguments-have-nulls-stripped.md → agent-llm-tool-arguments-have-nulls-stripped.md} +3 -3
  315. package/knowledge/decisions/internals/{ai-agent-model-config-stays-a-single-resolution-seam.md → agent-model-config-stays-a-single-resolution-seam.md} +3 -3
  316. package/knowledge/decisions/internals/{ai-agent-onerror-hooks-cannot-change-the-failure.md → agent-onerror-hooks-cannot-change-the-failure.md} +6 -6
  317. package/knowledge/decisions/internals/{ai-agent-runner-methods-must-keep-their-receiver.md → agent-runner-methods-must-keep-their-receiver.md} +4 -4
  318. package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +1 -1
  319. package/knowledge/decisions/internals/{ai-agent-stream-persistence-is-best-effort.md → agent-stream-persistence-is-best-effort.md} +4 -4
  320. package/knowledge/decisions/internals/{ai-agent-sub-agents-inherit-the-parent-context-block.md → agent-sub-agents-inherit-the-parent-context-block.md} +3 -3
  321. package/knowledge/decisions/internals/{ai-agent-tool-execute-failures-are-logged-unconditionally.md → agent-tool-execute-failures-are-logged-unconditionally.md} +3 -3
  322. package/knowledge/decisions/internals/{ai-agent-voice-input-transcribes-audio-parts-in-place.md → agent-voice-input-transcribes-audio-parts-in-place.md} +2 -2
  323. package/knowledge/decisions/internals/{ai-agent-working-memory-is-persisted-only-when-valid.md → agent-working-memory-is-persisted-only-when-valid.md} +2 -2
  324. package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +1 -1
  325. package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +2 -2
  326. package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +3 -3
  327. package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +2 -2
  328. package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +1 -1
  329. package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +1 -1
  330. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +1 -1
  331. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +1 -1
  332. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +1 -1
  333. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +1 -1
  334. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +1 -1
  335. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +1 -1
  336. package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +4 -4
  337. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +1 -1
  338. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +3 -3
  339. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +2 -2
  340. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +2 -2
  341. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +1 -1
  342. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +1 -1
  343. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +3 -3
  344. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +1 -1
  345. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +4 -4
  346. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +1 -1
  347. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +1 -1
  348. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +1 -1
  349. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +1 -1
  350. package/knowledge/decisions/internals/index.md +4 -2
  351. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +1 -1
  352. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +1 -1
  353. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +1 -1
  354. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +1 -1
  355. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +1 -1
  356. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +2 -2
  357. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +5 -5
  358. package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +1 -1
  359. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +1 -1
  360. package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +1 -1
  361. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +1 -1
  362. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +43 -19
  363. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +1 -1
  364. package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +5 -5
  365. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +1 -1
  366. package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +2 -2
  367. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +1 -1
  368. package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +2 -2
  369. package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +3 -3
  370. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +1 -1
  371. package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +1 -1
  372. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +1 -1
  373. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +1 -1
  374. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +1 -1
  375. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +1 -1
  376. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +1 -1
  377. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +1 -1
  378. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +1 -1
  379. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +1 -1
  380. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +9 -5
  381. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
  382. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +2 -2
  383. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +1 -1
  384. package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +1 -1
  385. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +1 -1
  386. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +2 -3
  387. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +1 -1
  388. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +1 -1
  389. package/knowledge/decisions/security/{ai-agent-approval-forwarding-requires-a-symbol-brand.md → agent-approval-forwarding-requires-a-symbol-brand.md} +3 -3
  390. package/knowledge/decisions/security/{ai-agent-credential-requests-are-symbol-branded.md → agent-credential-requests-are-symbol-branded.md} +4 -4
  391. package/knowledge/decisions/security/{ai-agent-gate-requires-a-session-only-when-auth-is-true.md → agent-gate-requires-a-session-only-when-auth-is-true.md} +4 -4
  392. package/knowledge/decisions/security/{ai-agent-ownership-failures-never-echo-the-resource.md → agent-ownership-failures-never-echo-the-resource.md} +2 -2
  393. package/knowledge/decisions/security/{ai-agent-resume-re-runs-the-authorization-gate.md → agent-resume-re-runs-the-authorization-gate.md} +4 -4
  394. package/knowledge/decisions/security/{ai-agent-sessionless-deployments-have-no-thread-ownership.md → agent-sessionless-deployments-have-no-thread-ownership.md} +5 -5
  395. package/knowledge/decisions/security/{ai-agent-thread-ownership-composes-the-session-principal.md → agent-thread-ownership-composes-the-session-principal.md} +2 -2
  396. package/knowledge/decisions/security/{ai-agent-tool-filtering-reads-the-live-function-config.md → agent-tool-filtering-reads-the-live-function-config.md} +2 -2
  397. package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +3 -3
  398. package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +3 -3
  399. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +3 -3
  400. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +21 -13
  401. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +1 -1
  402. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +2 -2
  403. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +1 -1
  404. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +2 -2
  405. package/knowledge/decisions/security/index.md +3 -2
  406. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +1 -1
  407. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +3 -3
  408. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +1 -1
  409. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +2 -2
  410. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +1 -1
  411. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +2 -2
  412. package/knowledge/index.md +3 -1
  413. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +1 -1
  414. package/knowledge/questions/index.md +2 -0
  415. package/package.json +16 -14
  416. package/run-tests.sh +0 -0
  417. package/scripts/generate-api-report.d.mts +1 -1
  418. package/scripts/generate-api-report.mjs +67 -60
  419. package/scripts/generate-api-report.mts +37 -47
  420. package/src/agent-naming.test.ts +68 -0
  421. package/src/api-report.test.ts +70 -1
  422. package/src/app-alias-surface.test.ts +179 -0
  423. package/src/app-leaf-surface.test.ts +217 -0
  424. package/src/bootstrap-compat/root.ts +20 -0
  425. package/src/{column-form.test.ts → classification/column-form.test.ts} +2 -2
  426. package/src/{data-classification.ts → classification/data-classification.ts} +1 -5
  427. package/src/classification/index.ts +38 -0
  428. package/src/{secret-value.test.ts → classification/secret-value.test.ts} +2 -2
  429. package/src/{secret-value.ts → classification/secret-value.ts} +1 -6
  430. package/src/crypto-utils.ts +1 -1
  431. package/src/dev/reload-meta.test.ts +1 -1
  432. package/src/errors/index.ts +9 -0
  433. package/src/errors/serialized-error.ts +9 -0
  434. package/src/factory-functions.test.ts +4 -2
  435. package/src/function/function-meta.types.ts +151 -0
  436. package/src/function/function-runner.test.ts +4 -2
  437. package/src/function/function-runner.ts +47 -14
  438. package/src/function/functions.types.ts +11 -7
  439. package/src/function/index.ts +24 -5
  440. package/src/function/list.types.ts +1 -3
  441. package/src/middleware/auth-apikey.ts +4 -2
  442. package/src/middleware/auth-bearer.test.ts +1 -1
  443. package/src/middleware/auth-bearer.ts +4 -2
  444. package/src/middleware/auth-cookie.ts +4 -1
  445. package/src/middleware/cors.test.ts +126 -5
  446. package/src/middleware/cors.ts +19 -8
  447. package/src/middleware/index.ts +16 -0
  448. package/src/middleware/middleware-factories.ts +62 -0
  449. package/src/middleware/middleware.types.ts +61 -0
  450. package/src/middleware/remote-auth.test.ts +1 -1
  451. package/src/middleware/remote-auth.ts +1 -1
  452. package/src/middleware/telemetry.ts +4 -2
  453. package/src/middleware-runner.test.ts +2 -3
  454. package/src/middleware-runner.ts +2 -2
  455. package/src/no-root-barrel.test.ts +114 -0
  456. package/src/permissions.ts +2 -4
  457. package/src/pikku-state.ts +6 -4
  458. package/src/public-surface.json +90 -170
  459. package/src/public-surface.json.README +20 -2
  460. package/src/public-surface.test.ts +31 -3
  461. package/src/remote.test.ts +1 -1
  462. package/src/removed-legacy-exports.test.ts +5 -1
  463. package/src/services/{ai-run-state-service.ts → agent-run-state-service.ts} +5 -5
  464. package/src/services/{ai-agent-runner-service.ts → agent-runner-service.ts} +18 -18
  465. package/src/services/{ai-storage-service.ts → agent-storage-service.ts} +7 -7
  466. package/src/services/audit-service.ts +1 -1
  467. package/src/services/credential-wire-service.ts +1 -1
  468. package/src/services/email-service.ts +2 -4
  469. package/src/services/file-scenario-run-store.test.ts +349 -0
  470. package/src/services/file-scenario-run-store.ts +282 -0
  471. package/src/services/http-personas-converse.test.ts +3 -3
  472. package/src/services/http-personas.ts +4 -4
  473. package/src/services/{in-memory-ai-run-state-service.ts → in-memory-agent-run-state-service.ts} +7 -7
  474. package/src/services/in-memory-workflow-service.ts +1 -1
  475. package/src/services/index.ts +22 -10
  476. package/src/services/local-content-request-handler.ts +1 -2
  477. package/src/services/local-secrets.ts +1 -1
  478. package/src/services/logger.ts +7 -7
  479. package/src/services/meta-service.ts +5 -5
  480. package/src/services/queue-webhook-service.test.ts +1 -1
  481. package/src/services/scoped-secret-service.ts +1 -1
  482. package/src/services/secret-service.ts +1 -1
  483. package/src/services/typed-secret-service.test.ts +52 -0
  484. package/src/services/typed-secret-service.ts +26 -2
  485. package/src/services/webhook-service.ts +1 -1
  486. package/src/services/workflow-service.ts +2 -1
  487. package/src/template-alias-surface.test.ts +240 -0
  488. package/src/testing/index.ts +1 -0
  489. package/src/testing/service-tests/agent-run-service-tests.ts +4 -4
  490. package/src/testing/service-tests/{ai-storage-service-tests.ts → agent-storage-service-tests.ts} +8 -8
  491. package/src/testing/service-tests.ts +10 -8
  492. package/src/types/core.types.ts +40 -292
  493. package/src/types/index.ts +2 -0
  494. package/src/types/state.types.ts +12 -14
  495. package/src/types/typed-credentials.test.ts +72 -0
  496. package/src/utils.ts +34 -0
  497. package/src/wirings/actor-flow/run-conversation.test.ts +2 -2
  498. package/src/wirings/actor-flow/run-conversation.ts +7 -9
  499. package/src/wirings/{rpc → addon}/addon-scopes.test.ts +1 -1
  500. package/src/wirings/addon/index.ts +12 -0
  501. package/src/wirings/{rpc → addon}/remote-addon-auth.ts +4 -1
  502. package/src/wirings/{rpc → addon}/wire-addon.ts +37 -2
  503. package/src/wirings/{ai-agent/ai-agent-agui.test.ts → agent/agent-agui.test.ts} +126 -105
  504. package/src/wirings/{ai-agent/ai-agent-agui.ts → agent/agent-agui.ts} +7 -7
  505. package/src/wirings/{ai-agent/ai-agent-authorization.test.ts → agent/agent-authorization.test.ts} +6 -6
  506. package/src/wirings/{ai-agent/ai-agent-finalize.test.ts → agent/agent-finalize.test.ts} +17 -16
  507. package/src/wirings/{ai-agent/ai-agent-finalize.ts → agent/agent-finalize.ts} +22 -22
  508. package/src/wirings/{ai-agent/ai-agent-helpers.test.ts → agent/agent-helpers.test.ts} +1 -1
  509. package/src/wirings/{ai-agent/ai-agent-helpers.ts → agent/agent-helpers.ts} +1 -1
  510. package/src/wirings/{ai-agent/ai-agent-interrupt.test.ts → agent/agent-interrupt.test.ts} +67 -77
  511. package/src/wirings/{ai-agent/ai-agent-interrupt.ts → agent/agent-interrupt.ts} +5 -5
  512. package/src/wirings/{ai-agent/ai-agent-memory.test.ts → agent/agent-memory.test.ts} +12 -12
  513. package/src/wirings/{ai-agent/ai-agent-memory.ts → agent/agent-memory.ts} +36 -36
  514. package/src/wirings/{ai-agent/ai-agent-model-config.test.ts → agent/agent-model-config.test.ts} +2 -5
  515. package/src/wirings/{ai-agent/ai-agent-model-config.ts → agent/agent-model-config.ts} +1 -1
  516. package/src/wirings/{ai-agent/ai-agent-prepare.test.ts → agent/agent-prepare.test.ts} +18 -18
  517. package/src/wirings/{ai-agent/ai-agent-prepare.ts → agent/agent-prepare.ts} +60 -56
  518. package/src/wirings/{ai-agent/ai-agent-registry.test.ts → agent/agent-registry.test.ts} +49 -43
  519. package/src/wirings/{ai-agent/ai-agent-registry.ts → agent/agent-registry.ts} +14 -14
  520. package/src/wirings/{ai-agent/ai-agent-resume-authorization.test.ts → agent/agent-resume-authorization.test.ts} +18 -18
  521. package/src/wirings/{ai-agent → agent}/agent-rpc.ts +16 -20
  522. package/src/wirings/{ai-agent/ai-agent-runner.test.ts → agent/agent-runner.test.ts} +105 -106
  523. package/src/wirings/{ai-agent/ai-agent-runner.ts → agent/agent-runner.ts} +91 -82
  524. package/src/wirings/{ai-agent/ai-agent-stream-output-hooks.test.ts → agent/agent-stream-output-hooks.test.ts} +25 -25
  525. package/src/wirings/{ai-agent/ai-agent-stream.test.ts → agent/agent-stream.test.ts} +147 -143
  526. package/src/wirings/{ai-agent/ai-agent-stream.ts → agent/agent-stream.ts} +148 -148
  527. package/src/wirings/{ai-agent/ai-agent-thread-ownership.test.ts → agent/agent-thread-ownership.test.ts} +24 -28
  528. package/src/wirings/{ai-agent/ai-agent-turn.test.ts → agent/agent-turn.test.ts} +3 -5
  529. package/src/wirings/{ai-agent/ai-agent-turn.ts → agent/agent-turn.ts} +7 -7
  530. package/src/wirings/agent/agent-utils.ts +20 -0
  531. package/src/wirings/{ai-agent/ai-agent.types.ts → agent/agent.types.ts} +54 -51
  532. package/src/wirings/agent/index.ts +57 -0
  533. package/src/wirings/{ai-agent → agent}/voice-input.test.ts +15 -15
  534. package/src/wirings/{ai-agent → agent}/voice-input.ts +11 -11
  535. package/src/wirings/{ai-agent → agent}/voice-output.test.ts +25 -27
  536. package/src/wirings/{ai-agent → agent}/voice-output.ts +11 -11
  537. package/src/wirings/{ai-scorer/ai-scorer-grade.test.ts → agent-scorer/agent-scorer-grade.test.ts} +8 -8
  538. package/src/wirings/{ai-scorer/ai-scorer-grade.ts → agent-scorer/agent-scorer-grade.ts} +9 -9
  539. package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +285 -0
  540. package/src/wirings/agent-scorer/agent-scorer-judge.ts +180 -0
  541. package/src/wirings/{ai-scorer/ai-scorer-live.test.ts → agent-scorer/agent-scorer-live.test.ts} +11 -11
  542. package/src/wirings/{ai-scorer/ai-scorer-live.ts → agent-scorer/agent-scorer-live.ts} +3 -3
  543. package/src/wirings/{ai-scorer/ai-scorer-registry.ts → agent-scorer/agent-scorer-registry.ts} +11 -8
  544. package/src/wirings/{ai-scorer/ai-scorer-sampling.test.ts → agent-scorer/agent-scorer-sampling.test.ts} +1 -1
  545. package/src/wirings/{ai-scorer/ai-scorer-snapshots.test.ts → agent-scorer/agent-scorer-snapshots.test.ts} +2 -2
  546. package/src/wirings/{ai-scorer/ai-scorer-snapshots.ts → agent-scorer/agent-scorer-snapshots.ts} +1 -1
  547. package/src/wirings/{ai-scorer/ai-scorer-worker.test.ts → agent-scorer/agent-scorer-worker.test.ts} +15 -15
  548. package/src/wirings/{ai-scorer/ai-scorer-worker.ts → agent-scorer/agent-scorer-worker.ts} +9 -7
  549. package/src/wirings/{ai-scorer/ai-scorer.ts → agent-scorer/agent-scorer.ts} +15 -7
  550. package/src/wirings/{ai-scorer/ai-scorer.types.ts → agent-scorer/agent-scorer.types.ts} +27 -6
  551. package/src/wirings/agent-scorer/index.ts +23 -0
  552. package/src/wirings/channel/channel-common.ts +4 -2
  553. package/src/wirings/channel/channel-handler.ts +2 -5
  554. package/src/wirings/channel/channel-middleware-runner.ts +1 -1
  555. package/src/wirings/channel/channel-rpc.types.ts +3 -7
  556. package/src/wirings/channel/channel.types.ts +1 -2
  557. package/src/wirings/channel/local/local-channel-runner.test.ts +1 -2
  558. package/src/wirings/channel/serverless/index.ts +1 -0
  559. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +2 -2
  560. package/src/wirings/cli/channel/index.ts +1 -3
  561. package/src/wirings/cli/cli-runner.test.ts +1 -1
  562. package/src/wirings/cli/cli-runner.ts +11 -7
  563. package/src/wirings/cli/cli.types.ts +24 -3
  564. package/src/wirings/cli/command-parser.test.ts +388 -1
  565. package/src/wirings/cli/command-parser.ts +189 -29
  566. package/src/wirings/gateway/gateway-runner.test.ts +1 -2
  567. package/src/wirings/gateway/gateway-runner.ts +3 -6
  568. package/src/wirings/gateway/gateway.types.ts +5 -4
  569. package/src/wirings/http/http-routes.test.ts +1 -2
  570. package/src/wirings/http/http-runner-addon-ref.test.ts +238 -0
  571. package/src/wirings/http/http-runner.test.ts +3 -8
  572. package/src/wirings/http/http-runner.ts +9 -3
  573. package/src/wirings/http/http.types.ts +3 -12
  574. package/src/wirings/http/index.ts +1 -0
  575. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  576. package/src/wirings/http/pikku-fetch-http-response.ts +3 -2
  577. package/src/wirings/mcp/mcp-runner.test.ts +1 -1
  578. package/src/wirings/mcp/mcp.types.ts +1 -2
  579. package/src/wirings/persona/index.ts +1 -4
  580. package/src/wirings/persona/persona.types.ts +14 -0
  581. package/src/wirings/queue/queue-identity.test.ts +1 -1
  582. package/src/wirings/queue/queue.types.ts +2 -6
  583. package/src/wirings/queue/signed-queue-service.ts +1 -1
  584. package/src/wirings/rpc/index.ts +0 -12
  585. package/src/wirings/rpc/rpc-runner.test.ts +4 -4
  586. package/src/wirings/rpc/rpc-runner.ts +5 -5
  587. package/src/wirings/rpc/rpc-types.ts +1 -1
  588. package/src/wirings/scheduler/scheduler.types.ts +2 -5
  589. package/src/wirings/scope/index.ts +1 -0
  590. package/src/wirings/secret/secret.types.ts +10 -0
  591. package/src/wirings/secret/validate-secret-definitions.test.ts +23 -0
  592. package/src/wirings/secret/validate-secret-definitions.ts +2 -0
  593. package/src/wirings/variable/validate-variable-definitions.test.ts +23 -0
  594. package/src/wirings/variable/validate-variable-definitions.ts +2 -0
  595. package/src/wirings/variable/variable.types.ts +9 -0
  596. package/src/wirings/virtual-user/index.ts +1 -4
  597. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +2 -2
  598. package/src/wirings/virtual-user/run-virtual-user.test.ts +2 -2
  599. package/src/wirings/virtual-user/run-virtual-user.ts +3 -3
  600. package/src/wirings/virtual-user/virtual-user-agents.ts +1 -1
  601. package/src/wirings/virtual-user/virtual-user-derive.test.ts +1 -1
  602. package/src/wirings/virtual-user/virtual-user-derive.ts +1 -1
  603. package/src/wirings/virtual-user/virtual-user.types.ts +1 -5
  604. package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +569 -0
  605. package/src/wirings/workflow/graph/graph-foreach.test.ts +626 -0
  606. package/src/wirings/workflow/graph/graph-node.ts +16 -1
  607. package/src/wirings/workflow/graph/graph-runner.ts +387 -61
  608. package/src/wirings/workflow/graph/workflow-graph.types.ts +28 -3
  609. package/src/wirings/workflow/index.ts +8 -0
  610. package/src/wirings/workflow/pikku-scenario-service.ts +59 -19
  611. package/src/wirings/workflow/pikku-workflow-service.ts +6 -8
  612. package/src/wirings/workflow/run-timeline.ts +2 -2
  613. package/src/wirings/workflow/scenario-expectations.test.ts +28 -13
  614. package/src/wirings/workflow/scenario-run.types.ts +186 -0
  615. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  616. package/src/wirings/workflow/scenario-step.test.ts +32 -7
  617. package/src/wirings/workflow/scenario-step.types.ts +27 -12
  618. package/src/wirings/workflow/workflow-approval-policy.test.ts +117 -47
  619. package/src/wirings/workflow/workflow-approval.ts +2 -1
  620. package/src/wirings/workflow/workflow-run-engine.types.ts +2 -1
  621. package/src/wirings/workflow/workflow.types.ts +4 -12
  622. package/src/wirings-stay-decoupled.test.ts +7 -4
  623. package/tsconfig.tsbuildinfo +1 -1
  624. package/tsconfig.type-tests.json +3 -2
  625. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +0 -3
  626. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +0 -16
  627. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +0 -7
  628. package/dist/wirings/ai-agent/ai-agent-utils.d.ts +0 -1
  629. package/dist/wirings/ai-agent/ai-agent-utils.js +0 -1
  630. package/dist/wirings/ai-agent/index.d.ts +0 -12
  631. package/dist/wirings/ai-agent/index.js +0 -10
  632. package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +0 -17
  633. package/dist/wirings/ai-scorer/ai-scorer.types.js +0 -4
  634. package/dist/wirings/ai-scorer/index.d.ts +0 -6
  635. package/dist/wirings/ai-scorer/index.js +0 -5
  636. package/src/ecosystem.ts +0 -40
  637. package/src/index.ts +0 -255
  638. package/src/wirings/ai-agent/ai-agent-utils.ts +0 -1
  639. package/src/wirings/ai-agent/index.ts +0 -65
  640. package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +0 -143
  641. package/src/wirings/ai-scorer/ai-scorer-judge.ts +0 -120
  642. package/src/wirings/ai-scorer/index.ts +0 -24
  643. /package/dist/{services/ai-agent-runner-service.js → bootstrap-compat/root.js} +0 -0
  644. /package/dist/{services/ai-run-state-service.js → classification/data-classification.js} +0 -0
  645. /package/dist/{services/ai-storage-service.js → ecosystem/gateway.js} +0 -0
  646. /package/dist/{wirings/ai-agent/ai-agent.types.js → ecosystem/node.js} +0 -0
  647. /package/dist/wirings/{ai-agent/ai-agent-helpers.js → agent/agent-helpers.js} +0 -0
  648. /package/dist/wirings/{ai-agent/ai-agent-model-config.d.ts → agent/agent-model-config.d.ts} +0 -0
  649. /package/dist/wirings/{ai-agent → agent}/agent-rpc.d.ts +0 -0
  650. /package/dist/wirings/{ai-scorer/ai-scorer-sampling.d.ts → agent-scorer/agent-scorer-sampling.d.ts} +0 -0
  651. /package/dist/wirings/{ai-scorer/ai-scorer-sampling.js → agent-scorer/agent-scorer-sampling.js} +0 -0
  652. /package/dist/wirings/{ai-scorer/ai-scorer-snapshots.js → agent-scorer/agent-scorer-snapshots.js} +0 -0
  653. /package/src/{column-form.ts → classification/column-form.ts} +0 -0
  654. /package/src/{pikku-request.test.ts → function/pikku-request.test.ts} +0 -0
  655. /package/src/{pikku-request.ts → function/pikku-request.ts} +0 -0
  656. /package/src/wirings/{rpc → addon}/addon-auth-tags.test.ts +0 -0
  657. /package/src/wirings/{rpc → addon}/addon-runner.ts +0 -0
  658. /package/src/wirings/{rpc → addon}/addon-secrets.test.ts +0 -0
  659. /package/src/wirings/{rpc → addon}/wire-addon.test.ts +0 -0
  660. /package/src/wirings/{rpc → addon}/wire-remote-addon.ts +0 -0
  661. /package/src/wirings/{ai-scorer/ai-scorer-sampling.ts → agent-scorer/agent-scorer-sampling.ts} +0 -0
@@ -29,10 +29,28 @@ function buildTemplateRegex(nodeId: string): RegExp | null {
29
29
  return new RegExp(`^${escaped}$`)
30
30
  }
31
31
 
32
- function stripInstanceOrdinal(name: string): string {
33
- const hash = name.lastIndexOf('#')
34
- if (hash <= 0) return name
35
- return /^\d+$/.test(name.slice(hash + 1)) ? name.slice(0, hash) : name
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
36
54
  }
37
55
 
38
56
  function remapStepNamesToNodeIds(
@@ -84,14 +102,22 @@ function closesCycle(
84
102
  return false
85
103
  }
86
104
 
105
+ interface GraphFireInstruction {
106
+ logical: string
107
+ instanceKey: string
108
+ fromStepName?: string
109
+ itemIndex?: number
110
+ }
111
+
87
112
  function planGraphTransitions(
88
113
  nodes: Record<string, any>,
89
114
  instances: Array<{ stepName: string; status: string; fromStepName?: string }>,
90
115
  branchByStep: Record<string, string>,
91
116
  entryNodeIds: string[],
92
- graphName: string
117
+ graphName: string,
118
+ fanoutWidths: Record<string, number> = {}
93
119
  ): {
94
- toFire: Array<{ logical: string; instanceKey: string; fromStepName?: string }>
120
+ toFire: GraphFireInstruction[]
95
121
  hasInFlight: boolean
96
122
  blockedWaiting: boolean
97
123
  } {
@@ -99,15 +125,37 @@ function planGraphTransitions(
99
125
  remapStepNamesToNodeIds([name], nodes, graphName)[0]!
100
126
 
101
127
  const countByLogical: Record<string, number> = {}
128
+ const instancesByLogical: Record<
129
+ string,
130
+ Array<{ stepName: string; status: string }>
131
+ > = {}
102
132
  const consumed = new Set<string>()
103
133
  for (const inst of instances) {
104
134
  const logical = toLogical(inst.stepName)
105
135
  countByLogical[logical] = (countByLogical[logical] ?? 0) + 1
136
+ ;(instancesByLogical[logical] ??= []).push(inst)
106
137
  consumed.add(`${inst.fromStepName ?? ENTRY_FROM}->${logical}`)
107
138
  }
108
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
+
109
150
  const completed = instances.filter((i) => i.status === 'succeeded')
110
- const completedLogical = new Set(completed.map((i) => toLogical(i.stepName)))
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
+ }
111
159
 
112
160
  const edges: Array<{
113
161
  from?: string
@@ -118,32 +166,88 @@ function planGraphTransitions(
118
166
  for (const entryId of entryNodeIds) {
119
167
  edges.push({ fromKey: ENTRY_FROM, target: entryId })
120
168
  }
169
+ const fannedEdgesEmitted = new Set<string>()
121
170
  for (const inst of completed) {
122
171
  const fromLogical = toLogical(inst.stepName)
123
172
  const node = nodes[fromLogical]
124
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)
125
194
  for (const target of resolveNextFromConfig(
126
195
  node.next,
127
- branchByStep[inst.stepName]
196
+ branchByStep[nodeId]
128
197
  )) {
129
- edges.push({
130
- from: inst.stepName,
131
- fromKey: inst.stepName,
132
- fromLogical,
133
- target,
134
- })
198
+ edges.push({ from: nodeId, fromKey: nodeId, fromLogical: nodeId, target })
135
199
  }
136
200
  }
137
201
 
138
- const toFire: Array<{
139
- logical: string
140
- instanceKey: string
141
- fromStepName?: string
142
- }> = []
202
+ const toFire: GraphFireInstruction[] = []
203
+ const plannedFanout = new Set<string>()
143
204
  let blockedWaiting = false
144
205
  for (const edge of edges) {
145
206
  const target = edge.target
146
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
+
147
251
  if (consumed.has(edgeKey)) continue
148
252
  const visits = countByLogical[target] ?? 0
149
253
  const isBackEdge =
@@ -298,7 +402,7 @@ function resolveTemplate(
298
402
 
299
403
  function resolveValue(value: unknown, nodeResults: Record<string, any>): any {
300
404
  if (isDataRef(value)) {
301
- if (value.$ref === '$item') {
405
+ if (value.$ref === '$item' && !('$item' in nodeResults)) {
302
406
  return value
303
407
  }
304
408
  const source = nodeResults[value.$ref]
@@ -364,6 +468,8 @@ function extractReferencedNodeIds(
364
468
 
365
469
  const IGNORED_REFS = new Set(['trigger', '$item', 'unknown'])
366
470
 
471
+ const FOREACH_MODES = new Set(['parallel', 'sequential'])
472
+
367
473
  function normalizeNodeTargets(value: unknown): string[] {
368
474
  if (!value) return []
369
475
  if (typeof value === 'string') return [value]
@@ -407,6 +513,29 @@ function validateGraphReferences(
407
513
  }
408
514
  }
409
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
+
410
539
  const nextTargets = normalizeNodeTargets(node.next)
411
540
  for (const nextId of nextTargets) {
412
541
  if (!nodeIds.has(nextId)) {
@@ -427,14 +556,145 @@ function validateGraphReferences(
427
556
  }
428
557
  }
429
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
+
430
606
  function areDependenciesSatisfied(
431
- node: { input?: Record<string, unknown> },
607
+ node: { input?: Record<string, unknown>; forEach?: unknown },
432
608
  completedNodeIds: Set<string>
433
609
  ): boolean {
434
- const deps = extractReferencedNodeIds(node.input).filter(
435
- (id) => !IGNORED_REFS.has(id)
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)
436
631
  )
437
- return deps.every((dep) => completedNodeIds.has(dep))
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
+ }
438
698
  }
439
699
 
440
700
  async function queueGraphNode(
@@ -508,12 +768,22 @@ export async function continueGraph(
508
768
  }
509
769
 
510
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
+ )
511
780
  const plan = planGraphTransitions(
512
781
  nodes,
513
782
  instances,
514
783
  branchByStep,
515
784
  meta.entryNodeIds ?? [],
516
- graphName
785
+ graphName,
786
+ reader.fanoutWidths
517
787
  )
518
788
 
519
789
  if (plan.toFire.length === 0) {
@@ -523,8 +793,6 @@ export async function continueGraph(
523
793
  return
524
794
  }
525
795
 
526
- const triggerInput = currentRun?.input
527
-
528
796
  for (const fire of plan.toFire) {
529
797
  const node = nodes[fire.logical]
530
798
  if (!node?.rpcName) continue
@@ -532,11 +800,14 @@ export async function continueGraph(
532
800
  const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
533
801
  (id) => !IGNORED_REFS.has(id)
534
802
  )
535
- const fetchedResults = await workflowService.getNodeResults(
536
- runId,
537
- referencedNodeIds
538
- )
539
- const nodeResults = { trigger: triggerInput, ...fetchedResults }
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
+ }
540
811
  const resolvedInput = resolveSerializedInput(node.input, nodeResults)
541
812
 
542
813
  await queueGraphNode(
@@ -855,12 +1126,21 @@ async function continueGraphInline(
855
1126
  }
856
1127
 
857
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
+ )
858
1137
  const plan = planGraphTransitions(
859
1138
  nodes,
860
1139
  instances,
861
1140
  branchByStep,
862
1141
  entryNodeIds,
863
- graphName
1142
+ graphName,
1143
+ reader.fanoutWidths
864
1144
  )
865
1145
 
866
1146
  if (plan.toFire.length === 0) {
@@ -879,11 +1159,15 @@ async function continueGraphInline(
879
1159
  const referencedNodeIds = extractReferencedNodeIds(node.input).filter(
880
1160
  (id) => !IGNORED_REFS.has(id)
881
1161
  )
882
- const fetchedResults = await workflowService.getNodeResults(
883
- runId,
884
- referencedNodeIds
885
- )
886
- const nodeResults = { trigger: triggerInput, ...fetchedResults }
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
+ }
887
1171
  const resolvedInput = resolveSerializedInput(node.input, nodeResults)
888
1172
 
889
1173
  executed++
@@ -904,6 +1188,36 @@ async function continueGraphInline(
904
1188
  }
905
1189
  }
906
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
+
907
1221
  export async function runWorkflowGraph(
908
1222
  workflowService: PikkuWorkflowService,
909
1223
  graphName: string,
@@ -977,20 +1291,27 @@ export async function runWorkflowGraph(
977
1291
  const node = nodes[nodeId]
978
1292
  if (!node?.rpcName) return
979
1293
 
980
- const resolvedInput =
981
- node.input && Object.keys(node.input).length > 0
982
- ? resolveSerializedInput(node.input, triggerNodeResults)
983
- : triggerInput
984
-
985
- await executeGraphNodeInline(
986
- workflowService,
987
- rpcService,
988
- runId,
1294
+ const firings = planEntryFirings(
989
1295
  graphName,
990
1296
  nodeId,
991
- nodeId,
992
- resolvedInput,
993
- nodes
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
+ )
994
1315
  )
995
1316
  })
996
1317
  )
@@ -1026,20 +1347,25 @@ export async function runWorkflowGraph(
1026
1347
  const node = nodes[nodeId]
1027
1348
  if (!node?.rpcName) continue
1028
1349
 
1029
- const resolvedInput =
1030
- node.input && Object.keys(node.input).length > 0
1031
- ? resolveSerializedInput(node.input, triggerNodeResults)
1032
- : triggerInput
1033
-
1034
- await queueGraphNode(
1035
- workflowService,
1036
- runId,
1350
+ const firings = planEntryFirings(
1037
1351
  graphName,
1038
1352
  nodeId,
1039
- node.rpcName,
1040
- resolvedInput,
1041
- node
1353
+ node,
1354
+ triggerNodeResults,
1355
+ triggerInput
1042
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
+ }
1043
1369
  }
1044
1370
  if (inline) {
1045
1371
  workflowService.unregisterInlineRun(runId)
@@ -1,3 +1,5 @@
1
+ import type { TemplateString } from './template.js'
2
+
1
3
  export interface RefValue {
2
4
  __isRef: true
3
5
  nodeId: string
@@ -22,13 +24,36 @@ export type RefFn<NodeIds extends string = string> = (
22
24
  ) => RefValue
23
25
 
24
26
  export type NextConfig<NodeIds extends string = string> =
27
+ NodeIds | NodeIds[] | Record<string, NodeIds | NodeIds[]>
28
+
29
+ export type TemplateFn = (
30
+ templateStr: string,
31
+ refs: Array<{ $ref: string; path?: string }>
32
+ ) => TemplateString
33
+
34
+ export type ItemFn = (path?: string) => RefValue
35
+
36
+ export type ForEachConfig<NodeIds extends string = string> =
25
37
  | NodeIds
26
- | NodeIds[]
27
- | Record<string, NodeIds | NodeIds[]>
38
+ | RefValue
39
+ | ((ref: RefFn<NodeIds>) => RefValue)
40
+
41
+ export type ForEachMode = 'parallel' | 'sequential'
28
42
 
29
43
  export interface GraphNodeConfig<NodeIds extends string = string> {
30
44
  func: string
31
- input?: (ref: RefFn<NodeIds>) => Record<string, unknown>
45
+ /**
46
+ * Run this node once per element of an upstream array. The node's own result
47
+ * becomes the ordered array of per-item results.
48
+ */
49
+ forEach?: ForEachConfig<NodeIds>
50
+ /** How the per-item instances of a `forEach` node run. Defaults to 'parallel'. */
51
+ mode?: ForEachMode
52
+ input?: (
53
+ ref: RefFn<NodeIds>,
54
+ template: TemplateFn,
55
+ $item: ItemFn
56
+ ) => Record<string, unknown>
32
57
  next?: NextConfig<NodeIds>
33
58
  onError?: NodeIds | NodeIds[]
34
59
  retries?: number
@@ -93,3 +93,11 @@ export type {
93
93
  WorkflowStepWire,
94
94
  PikkuWorkflowWire,
95
95
  } from './workflow.types.js'
96
+ export { createGraph } from './graph/graph-node.js'
97
+ export type {
98
+ GraphNodeConfig,
99
+ ForEachConfig,
100
+ ForEachMode,
101
+ ItemFn,
102
+ TemplateFn,
103
+ } from './graph/workflow-graph.types.js'