@pikku/core 0.12.79 → 0.12.82

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 (479) hide show
  1. package/CHANGELOG.md +473 -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/errors/index.d.ts +1 -1
  7. package/dist/errors/index.js +1 -1
  8. package/dist/function/function-runner.js +22 -47
  9. package/dist/function/functions.types.d.ts +9 -5
  10. package/dist/function/index.d.ts +1 -1
  11. package/dist/index.d.ts +14 -19
  12. package/dist/index.js +6 -11
  13. package/dist/middleware/auth-cookie.d.ts +0 -4
  14. package/dist/middleware/auth-cookie.js +38 -2
  15. package/dist/middleware/cors.js +1 -0
  16. package/dist/middleware/index.d.ts +1 -1
  17. package/dist/middleware/index.js +1 -1
  18. package/dist/middleware/remote-auth.js +14 -3
  19. package/dist/permissions.d.ts +8 -10
  20. package/dist/permissions.js +0 -11
  21. package/dist/pikku-state.js +16 -5
  22. package/dist/schema.js +35 -1
  23. package/dist/services/ai-agent-runner-service.d.ts +7 -0
  24. package/dist/services/ai-run-state-service.d.ts +17 -1
  25. package/dist/services/in-memory-ai-run-state-service.d.ts +6 -2
  26. package/dist/services/in-memory-ai-run-state-service.js +11 -1
  27. package/dist/services/in-memory-workflow-service.js +2 -0
  28. package/dist/services/index.d.ts +15 -15
  29. package/dist/services/index.js +5 -5
  30. package/dist/services/local-content-request-handler.d.ts +21 -0
  31. package/dist/services/local-content-request-handler.js +72 -53
  32. package/dist/services/local-content.d.ts +6 -0
  33. package/dist/services/local-content.js +14 -1
  34. package/dist/services/scoped-credential-service.d.ts +21 -0
  35. package/dist/services/scoped-credential-service.js +53 -0
  36. package/dist/services/workflow-service.d.ts +4 -2
  37. package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
  38. package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
  39. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
  40. package/dist/testing/service-tests/ai-storage-service-tests.js +302 -0
  41. package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
  42. package/dist/testing/service-tests/channel-store-tests.js +72 -0
  43. package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
  44. package/dist/testing/service-tests/credential-service-tests.js +109 -0
  45. package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
  46. package/dist/testing/service-tests/deployment-service-tests.js +21 -0
  47. package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
  48. package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
  49. package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
  50. package/dist/testing/service-tests/secret-service-tests.js +80 -0
  51. package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
  52. package/dist/testing/service-tests/session-store-tests.js +43 -0
  53. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
  54. package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
  55. package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
  56. package/dist/testing/service-tests/workflow-service-tests.js +150 -0
  57. package/dist/testing/service-tests.d.ts +6 -0
  58. package/dist/testing/service-tests.js +26 -791
  59. package/dist/types/core.types.d.ts +11 -3
  60. package/dist/types/state.types.d.ts +14 -1
  61. package/dist/wirings/actor-flow/index.d.ts +1 -1
  62. package/dist/wirings/actor-flow/run-conversation.js +1 -6
  63. package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
  64. package/dist/wirings/ai-agent/agent-rpc.js +53 -0
  65. package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
  66. package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
  67. package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
  68. package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
  69. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
  70. package/dist/wirings/ai-agent/ai-agent-memory.js +37 -18
  71. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
  72. package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
  73. package/dist/wirings/ai-agent/ai-agent-prepare.js +5 -9
  74. package/dist/wirings/ai-agent/ai-agent-runner.js +89 -147
  75. package/dist/wirings/ai-agent/ai-agent-stream.js +109 -97
  76. package/dist/wirings/ai-agent/ai-agent-turn.d.ts +57 -0
  77. package/dist/wirings/ai-agent/ai-agent-turn.js +82 -0
  78. package/dist/wirings/ai-agent/ai-agent.types.d.ts +47 -2
  79. package/dist/wirings/ai-agent/index.d.ts +8 -7
  80. package/dist/wirings/ai-agent/index.js +5 -4
  81. package/dist/wirings/ai-agent/voice-input.js +1 -6
  82. package/dist/wirings/ai-agent/voice-output.js +2 -12
  83. package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
  84. package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
  85. package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
  86. package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
  87. package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
  88. package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
  89. package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
  90. package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
  91. package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
  92. package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
  93. package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
  94. package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
  95. package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
  96. package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
  97. package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
  98. package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
  99. package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
  100. package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
  101. package/dist/wirings/ai-scorer/index.d.ts +6 -0
  102. package/dist/wirings/ai-scorer/index.js +5 -0
  103. package/dist/wirings/channel/channel-common.js +1 -0
  104. package/dist/wirings/channel/channel-handler.js +3 -5
  105. package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
  106. package/dist/wirings/channel/channel-rpc-service.js +0 -8
  107. package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
  108. package/dist/wirings/channel/channel-rpc.types.js +8 -0
  109. package/dist/wirings/channel/channel-runner.d.ts +1 -3
  110. package/dist/wirings/channel/channel-runner.js +16 -8
  111. package/dist/wirings/channel/channel.types.d.ts +2 -0
  112. package/dist/wirings/channel/index.d.ts +5 -6
  113. package/dist/wirings/channel/index.js +3 -4
  114. package/dist/wirings/channel/local/local-channel-runner.js +8 -1
  115. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  116. package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
  117. package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
  118. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
  119. package/dist/wirings/cli/channel/index.d.ts +1 -2
  120. package/dist/wirings/cli/channel/index.js +0 -1
  121. package/dist/wirings/cli/cli-runner.js +17 -3
  122. package/dist/wirings/cli/cli.types.d.ts +0 -8
  123. package/dist/wirings/cli/command-parser.js +13 -0
  124. package/dist/wirings/credential/index.d.ts +1 -1
  125. package/dist/wirings/gateway/gateway-runner.js +9 -2
  126. package/dist/wirings/gateway/index.d.ts +1 -1
  127. package/dist/wirings/http/http-routes.js +2 -0
  128. package/dist/wirings/http/http-runner.d.ts +0 -10
  129. package/dist/wirings/http/http-runner.js +14 -15
  130. package/dist/wirings/http/http.types.d.ts +0 -10
  131. package/dist/wirings/http/index.d.ts +2 -3
  132. package/dist/wirings/http/index.js +1 -1
  133. package/dist/wirings/mcp/index.d.ts +1 -1
  134. package/dist/wirings/mcp/mcp-runner.d.ts +15 -7
  135. package/dist/wirings/mcp/mcp-runner.js +18 -11
  136. package/dist/wirings/persona/index.d.ts +3 -4
  137. package/dist/wirings/persona/index.js +2 -3
  138. package/dist/wirings/queue/index.d.ts +1 -3
  139. package/dist/wirings/queue/index.js +1 -3
  140. package/dist/wirings/rpc/addon-runner.d.ts +4 -0
  141. package/dist/wirings/rpc/addon-runner.js +19 -3
  142. package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
  143. package/dist/wirings/rpc/rpc-runner.js +55 -86
  144. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  145. package/dist/wirings/rpc/wire-addon.d.ts +13 -0
  146. package/dist/wirings/rpc/wire-addon.js +4 -0
  147. package/dist/wirings/scheduler/index.d.ts +1 -1
  148. package/dist/wirings/secret/validate-secret-definitions.js +2 -2
  149. package/dist/wirings/trigger/index.d.ts +1 -1
  150. package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
  151. package/dist/wirings/trigger/trigger-runner.js +1 -0
  152. package/dist/wirings/virtual-user/index.d.ts +5 -6
  153. package/dist/wirings/virtual-user/index.js +2 -4
  154. package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
  155. package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
  156. package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
  157. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +100 -3
  158. package/dist/wirings/workflow/feature.js +7 -4
  159. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
  160. package/dist/wirings/workflow/graph/graph-runner.js +8 -7
  161. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
  162. package/dist/wirings/workflow/index.d.ts +12 -7
  163. package/dist/wirings/workflow/index.js +7 -3
  164. package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
  165. package/dist/wirings/workflow/pikku-scenario-service.js +64 -10
  166. package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -147
  167. package/dist/wirings/workflow/pikku-workflow-service.js +85 -493
  168. package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
  169. package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
  170. package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
  171. package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
  172. package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
  173. package/dist/wirings/workflow/workflow-approval.d.ts +67 -0
  174. package/dist/wirings/workflow/workflow-approval.js +177 -0
  175. package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
  176. package/dist/wirings/workflow/workflow-constants.js +35 -0
  177. package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
  178. package/dist/wirings/workflow/workflow-errors.js +112 -0
  179. package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
  180. package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
  181. package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
  182. package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
  183. package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
  184. package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
  185. package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
  186. package/dist/wirings/workflow/workflow-recovery.js +101 -0
  187. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
  188. package/dist/wirings/workflow/workflow-run-ownership.d.ts +17 -0
  189. package/dist/wirings/workflow/workflow-run-ownership.js +30 -0
  190. package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
  191. package/dist/wirings/workflow/workflow-suspend.js +33 -0
  192. package/dist/wirings/workflow/workflow.types.d.ts +8 -1
  193. package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
  194. package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
  195. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
  196. package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
  197. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
  198. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
  199. package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
  200. package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
  201. package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
  202. package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
  203. package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
  204. package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
  205. package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
  206. package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
  207. package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
  208. package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
  209. package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
  210. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
  211. package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
  212. package/knowledge/decisions/internals/index.md +42 -3
  213. package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
  214. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
  215. package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
  216. package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
  217. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
  218. package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
  219. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
  220. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
  221. package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
  222. package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
  223. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
  224. package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
  225. package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
  226. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
  227. package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
  228. package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
  229. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
  230. package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
  231. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
  232. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
  233. package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
  234. package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
  235. package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
  236. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
  237. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
  238. package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +50 -0
  239. package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
  240. package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
  241. package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
  242. package/knowledge/decisions/security/index.md +9 -0
  243. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
  244. package/knowledge/questions/index.md +2 -1
  245. package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
  246. package/package.json +15 -3
  247. package/scripts/generate-api-report.d.mts +1 -0
  248. package/scripts/generate-api-report.mjs +89 -0
  249. package/scripts/generate-api-report.mts +343 -0
  250. package/src/api-report.test.ts +69 -0
  251. package/src/column-form.ts +1 -4
  252. package/src/crypto-utils.test.ts +15 -2
  253. package/src/dev/hot-reload.ts +2 -7
  254. package/src/ecosystem.ts +40 -0
  255. package/src/errors/error-handler.ts +5 -3
  256. package/src/errors/error.test.ts +4 -1
  257. package/src/errors/index.ts +1 -1
  258. package/src/function/function-runner.test.ts +53 -1
  259. package/src/function/function-runner.ts +33 -48
  260. package/src/function/functions.types.ts +15 -9
  261. package/src/function/index.ts +0 -2
  262. package/src/handle-error.ts +1 -1
  263. package/src/index.ts +3 -57
  264. package/src/middleware/auth-cookie.test.ts +50 -0
  265. package/src/middleware/auth-cookie.ts +38 -2
  266. package/src/middleware/cors.ts +2 -1
  267. package/src/middleware/index.ts +1 -1
  268. package/src/middleware/remote-auth.test.ts +43 -0
  269. package/src/middleware/remote-auth.ts +17 -3
  270. package/src/middleware-runner.ts +4 -2
  271. package/src/no-any-casts.test.ts +57 -0
  272. package/src/permissions.test.ts +3 -1
  273. package/src/permissions.ts +22 -24
  274. package/src/pikku-state.ts +22 -6
  275. package/src/public-surface.json +554 -0
  276. package/src/public-surface.json.README +25 -0
  277. package/src/public-surface.test.ts +105 -0
  278. package/src/removed-legacy-exports.test.ts +62 -0
  279. package/src/schema.test.ts +78 -0
  280. package/src/schema.ts +36 -1
  281. package/src/services/ai-agent-runner-service.ts +12 -1
  282. package/src/services/ai-run-state-service.ts +18 -1
  283. package/src/services/audit-service.ts +2 -2
  284. package/src/services/in-memory-ai-run-state-service.ts +16 -2
  285. package/src/services/in-memory-workflow-service.ts +2 -0
  286. package/src/services/index.ts +4 -47
  287. package/src/services/local-content-request-handler.test.ts +43 -5
  288. package/src/services/local-content-request-handler.ts +103 -74
  289. package/src/services/local-content.ts +15 -1
  290. package/src/services/local-email-service.ts +5 -1
  291. package/src/services/scoped-credential-service.test.ts +86 -0
  292. package/src/services/scoped-credential-service.ts +63 -0
  293. package/src/services/system-role-guard.test.ts +4 -1
  294. package/src/services/workflow-service.ts +9 -2
  295. package/src/side-effects-are-declared.test.ts +84 -0
  296. package/src/source-files-stay-composable.test.ts +41 -0
  297. package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
  298. package/src/testing/service-tests/ai-storage-service-tests.ts +379 -0
  299. package/src/testing/service-tests/channel-store-tests.ts +98 -0
  300. package/src/testing/service-tests/credential-service-tests.ts +143 -0
  301. package/src/testing/service-tests/deployment-service-tests.ts +33 -0
  302. package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
  303. package/src/testing/service-tests/secret-service-tests.ts +105 -0
  304. package/src/testing/service-tests/session-store-tests.ts +62 -0
  305. package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
  306. package/src/testing/service-tests/workflow-service-tests.ts +308 -0
  307. package/src/testing/service-tests.ts +31 -1111
  308. package/src/types/core.types.ts +14 -3
  309. package/src/types/state.types.ts +17 -1
  310. package/src/wirings/actor-flow/index.ts +0 -3
  311. package/src/wirings/actor-flow/run-conversation.ts +1 -6
  312. package/src/wirings/ai-agent/agent-rpc.ts +120 -0
  313. package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
  314. package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
  315. package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
  316. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
  317. package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
  318. package/src/wirings/ai-agent/ai-agent-memory.ts +62 -39
  319. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
  320. package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
  321. package/src/wirings/ai-agent/ai-agent-prepare.ts +12 -12
  322. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
  323. package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
  324. package/src/wirings/ai-agent/ai-agent-runner.ts +120 -160
  325. package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
  326. package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
  327. package/src/wirings/ai-agent/ai-agent-stream.ts +152 -117
  328. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
  329. package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
  330. package/src/wirings/ai-agent/ai-agent-turn.ts +122 -0
  331. package/src/wirings/ai-agent/ai-agent.types.ts +65 -5
  332. package/src/wirings/ai-agent/index.ts +2 -16
  333. package/src/wirings/ai-agent/voice-input.ts +1 -6
  334. package/src/wirings/ai-agent/voice-output.ts +2 -12
  335. package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
  336. package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
  337. package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
  338. package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
  339. package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
  340. package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
  341. package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
  342. package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
  343. package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
  344. package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
  345. package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
  346. package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
  347. package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
  348. package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
  349. package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
  350. package/src/wirings/ai-scorer/index.ts +24 -0
  351. package/src/wirings/channel/channel-common.ts +5 -2
  352. package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
  353. package/src/wirings/channel/channel-handler.ts +7 -7
  354. package/src/wirings/channel/channel-rpc-service.ts +0 -14
  355. package/src/wirings/channel/channel-rpc.test.ts +25 -4
  356. package/src/wirings/channel/channel-rpc.types.ts +14 -0
  357. package/src/wirings/channel/channel-runner.ts +33 -20
  358. package/src/wirings/channel/channel.types.ts +2 -0
  359. package/src/wirings/channel/index.ts +1 -20
  360. package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
  361. package/src/wirings/channel/local/local-channel-runner.ts +9 -2
  362. package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
  363. package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
  364. package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
  365. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
  366. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
  367. package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
  368. package/src/wirings/cli/channel/index.ts +0 -7
  369. package/src/wirings/cli/cli-runner.test.ts +68 -0
  370. package/src/wirings/cli/cli-runner.ts +25 -5
  371. package/src/wirings/cli/cli.types.ts +0 -39
  372. package/src/wirings/cli/command-parser.test.ts +19 -0
  373. package/src/wirings/cli/command-parser.ts +17 -1
  374. package/src/wirings/credential/index.ts +0 -1
  375. package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
  376. package/src/wirings/gateway/gateway-runner.ts +27 -19
  377. package/src/wirings/gateway/index.ts +0 -3
  378. package/src/wirings/http/http-routes.ts +4 -1
  379. package/src/wirings/http/http-runner.test.ts +66 -0
  380. package/src/wirings/http/http-runner.ts +21 -28
  381. package/src/wirings/http/http.types.ts +0 -15
  382. package/src/wirings/http/index.ts +2 -8
  383. package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
  384. package/src/wirings/http/web-request.ts +1 -1
  385. package/src/wirings/mcp/index.ts +0 -1
  386. package/src/wirings/mcp/mcp-runner.test.ts +181 -0
  387. package/src/wirings/mcp/mcp-runner.ts +37 -21
  388. package/src/wirings/persona/index.ts +0 -8
  389. package/src/wirings/persona/persona-environments.test.ts +14 -3
  390. package/src/wirings/persona/persona.test.ts +13 -3
  391. package/src/wirings/persona/validate-personas.ts +5 -1
  392. package/src/wirings/queue/index.ts +0 -14
  393. package/src/wirings/queue/queue-runner.ts +1 -1
  394. package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
  395. package/src/wirings/rpc/addon-runner.ts +34 -3
  396. package/src/wirings/rpc/addon-secrets.test.ts +261 -0
  397. package/src/wirings/rpc/rpc-runner.test.ts +2 -0
  398. package/src/wirings/rpc/rpc-runner.ts +60 -136
  399. package/src/wirings/rpc/rpc-types.ts +11 -0
  400. package/src/wirings/rpc/wire-addon.ts +20 -1
  401. package/src/wirings/scheduler/index.ts +0 -1
  402. package/src/wirings/secret/validate-secret-definitions.test.ts +22 -0
  403. package/src/wirings/secret/validate-secret-definitions.ts +2 -2
  404. package/src/wirings/trigger/index.ts +0 -1
  405. package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
  406. package/src/wirings/trigger/trigger-runner.ts +7 -5
  407. package/src/wirings/virtual-user/index.ts +0 -16
  408. package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
  409. package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
  410. package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
  411. package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
  412. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
  413. package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
  414. package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
  415. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +117 -4
  416. package/src/wirings/workflow/feature.ts +7 -4
  417. package/src/wirings/workflow/graph/graph-node.ts +1 -1
  418. package/src/wirings/workflow/graph/graph-runner.test.ts +76 -2
  419. package/src/wirings/workflow/graph/graph-runner.ts +13 -16
  420. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
  421. package/src/wirings/workflow/index.ts +14 -24
  422. package/src/wirings/workflow/pikku-scenario-service.ts +101 -27
  423. package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -14
  424. package/src/wirings/workflow/pikku-workflow-service.ts +214 -743
  425. package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
  426. package/src/wirings/workflow/scenario-hooks.test.ts +52 -0
  427. package/src/wirings/workflow/scenario-step.types.ts +8 -0
  428. package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
  429. package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
  430. package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
  431. package/src/wirings/workflow/workflow-approval.ts +289 -0
  432. package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
  433. package/src/wirings/workflow/workflow-constants.ts +47 -0
  434. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
  435. package/src/wirings/workflow/workflow-errors.ts +128 -0
  436. package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
  437. package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
  438. package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
  439. package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
  440. package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
  441. package/src/wirings/workflow/workflow-recovery.ts +162 -0
  442. package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
  443. package/src/wirings/workflow/workflow-run-authority.test.ts +212 -0
  444. package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
  445. package/src/wirings/workflow/workflow-run-ownership.ts +37 -0
  446. package/src/wirings/workflow/workflow-suspend.ts +61 -0
  447. package/src/wirings/workflow/workflow.types.ts +7 -9
  448. package/src/wirings-stay-decoupled.test.ts +127 -0
  449. package/tsconfig.json +1 -1
  450. package/tsconfig.tsbuildinfo +1 -1
  451. package/dist/internal.d.ts +0 -3
  452. package/dist/internal.js +0 -2
  453. package/dist/middleware/timeout.d.ts +0 -9
  454. package/dist/middleware/timeout.js +0 -15
  455. package/dist/pikku-response.d.ts +0 -6
  456. package/dist/pikku-response.js +0 -6
  457. package/dist/services/gopass-secrets.d.ts +0 -15
  458. package/dist/services/gopass-secrets.js +0 -76
  459. package/dist/services/http-scenario-actors.d.ts +0 -75
  460. package/dist/services/http-scenario-actors.js +0 -195
  461. package/dist/services/http-user-flow-actors.d.ts +0 -67
  462. package/dist/services/http-user-flow-actors.js +0 -193
  463. package/dist/services/scenario-actors-service.d.ts +0 -127
  464. package/dist/services/scenario-actors-service.js +0 -40
  465. package/dist/services/user-flow-actors-service.d.ts +0 -39
  466. package/dist/wirings/credential/wire-credential.d.ts +0 -48
  467. package/dist/wirings/credential/wire-credential.js +0 -47
  468. package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
  469. package/dist/wirings/oauth2/oauth2-client.js +0 -263
  470. package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
  471. package/dist/wirings/oauth2/oauth2-routes.js +0 -146
  472. package/dist/wirings/scope/wire-scope.d.ts +0 -33
  473. package/dist/wirings/scope/wire-scope.js +0 -32
  474. package/dist/wirings/workflow/dsl/index.d.ts +0 -5
  475. package/dist/wirings/workflow/dsl/index.js +0 -4
  476. package/dist/wirings/workflow/graph/index.d.ts +0 -5
  477. package/dist/wirings/workflow/graph/index.js +0 -4
  478. package/src/internal.ts +0 -10
  479. /package/dist/{services/user-flow-actors-service.js → wirings/workflow/workflow-run-engine.types.js} +0 -0
@@ -0,0 +1,62 @@
1
+ import { describe, test } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { readFileSync, readdirSync } from 'node:fs'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { join, dirname, relative } from 'node:path'
6
+
7
+ const srcRoot = dirname(fileURLToPath(import.meta.url))
8
+ const thisFile = fileURLToPath(import.meta.url)
9
+
10
+ /**
11
+ * Names removed from the public surface, each with the entry point that must
12
+ * no longer carry it.
13
+ *
14
+ * They survived as throwing stubs only so the pinned bootstrap CLI could
15
+ * resolve the import; `@pikku/cli@0.12.96` emits none of them, so the stubs
16
+ * went too.
17
+ */
18
+ const REMOVED = [
19
+ { name: 'addTagPermission', entry: './middleware/index.js' },
20
+ { name: 'addHTTPPermission', entry: './wirings/http/index.js' },
21
+ { name: 'ZodLike', entry: './index.js' },
22
+ ]
23
+
24
+ const collectSourceFiles = (directory: string): string[] =>
25
+ readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
26
+ const entryPath = join(directory, entry.name)
27
+ if (entry.isDirectory()) {
28
+ return entry.name === 'dist' ? [] : collectSourceFiles(entryPath)
29
+ }
30
+ return /\.ts$/.test(entry.name) ? [entryPath] : []
31
+ })
32
+
33
+ describe('removed legacy exports stay removed', () => {
34
+ for (const { name, entry } of REMOVED) {
35
+ test(`${entry} no longer exports ${name}`, async () => {
36
+ const module = await import(entry)
37
+ assert.equal(
38
+ name in module,
39
+ false,
40
+ `${entry} exports ${name} again; it was removed in #972`
41
+ )
42
+ })
43
+ }
44
+
45
+ test('no source file mentions the removed permission wrappers', () => {
46
+ const offenders = collectSourceFiles(srcRoot)
47
+ .filter(
48
+ (file) =>
49
+ file !== thisFile &&
50
+ /\baddTagPermission\b|\baddHTTPPermission\b|\bZodLike\b/.test(
51
+ readFileSync(file, 'utf-8')
52
+ )
53
+ )
54
+ .map((file) => relative(srcRoot, file))
55
+
56
+ assert.deepEqual(
57
+ offenders,
58
+ [],
59
+ `removed names still referenced in:\n${offenders.join('\n')}`
60
+ )
61
+ })
62
+ })
@@ -265,6 +265,84 @@ describe('Schema', () => {
265
265
  await validateSchema(logger, schemaService, null, {})
266
266
  })
267
267
 
268
+ test('strips undefined-valued properties before validating', async () => {
269
+ addSchema('undefinedProps', {
270
+ properties: { name: { type: 'string' }, count: { type: 'number' } },
271
+ })
272
+ const logger = {
273
+ info: () => {},
274
+ warn: () => {},
275
+ error: () => {},
276
+ debug: () => {},
277
+ } as any
278
+ let seen: any
279
+ const schemaService = {
280
+ compileSchema: async () => {},
281
+ validateSchema: async (_name: string, data: any) => {
282
+ seen = data
283
+ },
284
+ getSchemaNames: () => new Set<string>(),
285
+ }
286
+ await validateSchema(logger, schemaService, 'undefinedProps', {
287
+ name: 'ada',
288
+ count: undefined,
289
+ })
290
+ assert.deepStrictEqual(seen, { name: 'ada' })
291
+ assert.ok(!('count' in seen))
292
+ })
293
+
294
+ test('strips undefined nested in objects and arrays', async () => {
295
+ addSchema('nestedUndefined', { properties: {} })
296
+ const logger = {
297
+ info: () => {},
298
+ warn: () => {},
299
+ error: () => {},
300
+ debug: () => {},
301
+ } as any
302
+ let seen: any
303
+ const schemaService = {
304
+ compileSchema: async () => {},
305
+ validateSchema: async (_name: string, data: any) => {
306
+ seen = data
307
+ },
308
+ getSchemaNames: () => new Set<string>(),
309
+ }
310
+ await validateSchema(logger, schemaService, 'nestedUndefined', {
311
+ nested: { keep: 1, drop: undefined },
312
+ list: [{ keep: 2, drop: undefined }],
313
+ })
314
+ assert.deepStrictEqual(seen, {
315
+ nested: { keep: 1 },
316
+ list: [{ keep: 2 }],
317
+ })
318
+ })
319
+
320
+ test('leaves Date instances intact while stripping', async () => {
321
+ addSchema('withDate', { properties: {} })
322
+ const logger = {
323
+ info: () => {},
324
+ warn: () => {},
325
+ error: () => {},
326
+ debug: () => {},
327
+ } as any
328
+ const when = new Date('2020-01-01T00:00:00.000Z')
329
+ let seen: any
330
+ const schemaService = {
331
+ compileSchema: async () => {},
332
+ validateSchema: async (_name: string, data: any) => {
333
+ seen = data
334
+ },
335
+ getSchemaNames: () => new Set<string>(),
336
+ }
337
+ await validateSchema(logger, schemaService, 'withDate', {
338
+ when,
339
+ drop: undefined,
340
+ })
341
+ assert.ok(seen.when instanceof Date)
342
+ assert.equal(seen.when.getTime(), when.getTime())
343
+ assert.ok(!('drop' in seen))
344
+ })
345
+
268
346
  test('should throw MissingSchemaError when schema not found', async () => {
269
347
  const logger = {
270
348
  info: () => {},
package/src/schema.ts CHANGED
@@ -135,6 +135,41 @@ export const coerceTopLevelDataFromSchema = (
135
135
  }
136
136
  }
137
137
 
138
+ /**
139
+ * Drops object properties whose value is literally `undefined`.
140
+ *
141
+ * JSON Schema has no way to describe such a property, and the validator refuses
142
+ * the whole instance rather than reporting it — `{ a: undefined }` throws
143
+ * "Instances of \"undefined\" type are not supported" instead of validating.
144
+ *
145
+ * That matters because whether a payload can contain one depends on how the
146
+ * call travelled. Over HTTP `JSON.stringify` drops these keys before the
147
+ * request is built, so they never arrive. Dispatched in-process — an inline
148
+ * workflow step calling an RPC — the object is handed over as-is, and
149
+ * `{ retries: data.maybeRetries }` with the field omitted by the caller is
150
+ * enough to kill the step. Normalising here makes the two paths agree, and an
151
+ * explicitly-undefined *required* field now reports as the missing property it
152
+ * is rather than as an internal error.
153
+ *
154
+ * Deliberately not a JSON round-trip: `coerceTopLevelDataFromSchema` puts real
155
+ * `Date` instances on the data first, and stringifying would flatten them back
156
+ * to strings the validator has never been given.
157
+ */
158
+ const stripUndefinedValues = <T>(value: T): T => {
159
+ if (Array.isArray(value)) return value.map(stripUndefinedValues) as T
160
+ if (value === null || typeof value !== 'object') return value
161
+ // Only plain objects: a Date, Map or class instance is data, not a bag of
162
+ // properties to be rewritten.
163
+ const prototype = Object.getPrototypeOf(value)
164
+ if (prototype !== Object.prototype && prototype !== null) return value
165
+
166
+ return Object.fromEntries(
167
+ Object.entries(value)
168
+ .filter(([, entry]) => entry !== undefined)
169
+ .map(([key, entry]) => [key, stripUndefinedValues(entry)])
170
+ ) as T
171
+ }
172
+
138
173
  export const validateSchema = async (
139
174
  logger: Logger,
140
175
  schemaService: SchemaService | undefined,
@@ -164,6 +199,6 @@ export const validateSchema = async (
164
199
  )
165
200
  }
166
201
  await schemaService.compileSchema(key, schema)
167
- await schemaService.validateSchema(key, data ?? {})
202
+ await schemaService.validateSchema(key, stripUndefinedValues(data ?? {}))
168
203
  }
169
204
  }
@@ -52,7 +52,18 @@ export type AIAgentStepResult = {
52
52
  text: string
53
53
  object?: unknown
54
54
  toolCalls: { toolCallId: string; toolName: string; args: unknown }[]
55
- toolResults: { toolCallId: string; toolName: string; result: unknown }[]
55
+ toolResults: {
56
+ toolCallId: string
57
+ toolName: string
58
+ result: unknown
59
+ /**
60
+ * Set when the tool threw rather than returned. Carried as its own field
61
+ * because `result` is a rendered string by the time anything downstream
62
+ * reads it, and "did this tool fail" is not answerable by looking for an
63
+ * `Error:` prefix in text a tool could legitimately have returned.
64
+ */
65
+ error?: string
66
+ }[]
56
67
  usage: { inputTokens: number; outputTokens: number }
57
68
  finishReason: 'stop' | 'tool-calls' | 'length' | 'error' | 'unknown'
58
69
  reasoningContent?: string
@@ -2,19 +2,36 @@ import type {
2
2
  AgentRunState,
3
3
  PendingApproval,
4
4
  } from '../wirings/ai-agent/ai-agent.types.js'
5
+ import type { AIRunScore } from '../wirings/ai-scorer/ai-scorer.types.js'
5
6
 
6
7
  export type CreateRunInput = Omit<AgentRunState, 'runId'>
7
8
 
9
+ export type SaveScoreInput = Omit<AIRunScore, 'createdAt'>
10
+
8
11
  export interface AIRunStateService {
9
12
  createRun(run: CreateRunInput): Promise<string>
10
13
  updateRun(runId: string, updates: Partial<AgentRunState>): Promise<void>
11
14
  getRun(runId: string): Promise<AgentRunState | null>
12
15
  getRunsByThread(threadId: string): Promise<AgentRunState[]>
16
+ /**
17
+ * Claims an approval: removes it from the run's pending list and records the
18
+ * decision, as one atomic step. Returns whether THIS caller made the claim —
19
+ * concurrent approvals of the same tool call produce exactly one `true`, and
20
+ * only that caller may run the tool.
21
+ */
13
22
  resolveApproval(
14
23
  toolCallId: string,
15
24
  status: 'approved' | 'denied'
16
- ): Promise<void>
25
+ ): Promise<boolean>
17
26
  findRunByToolCallId(
18
27
  toolCallId: string
19
28
  ): Promise<{ run: AgentRunState; approval: PendingApproval } | null>
29
+ /**
30
+ * Record one scorer's grade of a finished run. A run accumulates one row per
31
+ * scorer, and a scorer may grade the same run more than once — a retried job
32
+ * appends rather than replaces, so a re-grade never silently overwrites the
33
+ * grade that was acted on.
34
+ */
35
+ saveScore(score: SaveScoreInput): Promise<void>
36
+ getScores(runId: string): Promise<AIRunScore[]>
20
37
  }
@@ -150,7 +150,7 @@ class DisabledInvocationAudit implements AuditLog {
150
150
  if (!this.warned) {
151
151
  this.warned = true
152
152
  // knowledge: decisions/security/a-dropped-audit-write-is-always-logged.md
153
- const logger = (this.wire as any).logger ?? this.logger
153
+ const logger = this.wire.logger ?? this.logger
154
154
  logger?.warn?.(
155
155
  `audit.write() dropped for '${this.wire.functionId ?? 'unknown function'}' — the function has no audit config (set audit: true on it)`
156
156
  )
@@ -207,7 +207,7 @@ class InvocationAuditLog implements AuditLog {
207
207
  await this.service.audit(event)
208
208
  }
209
209
  } catch (error) {
210
- const logger = (this.wire as any).logger ?? this.logger
210
+ const logger = this.wire.logger ?? this.logger
211
211
  logger?.warn?.('best-effort audit flush failed', error)
212
212
  }
213
213
  }
@@ -1,14 +1,17 @@
1
1
  import type {
2
2
  AIRunStateService,
3
3
  CreateRunInput,
4
+ SaveScoreInput,
4
5
  } from './ai-run-state-service.js'
5
6
  import type {
6
7
  AgentRunState,
7
8
  PendingApproval,
8
9
  } from '../wirings/ai-agent/ai-agent.types.js'
10
+ import type { AIRunScore } from '../wirings/ai-scorer/ai-scorer.types.js'
9
11
 
10
12
  export class InMemoryAIRunStateService implements AIRunStateService {
11
13
  private runs = new Map<string, AgentRunState>()
14
+ private scores = new Map<string, AIRunScore[]>()
12
15
  private counter = 0
13
16
 
14
17
  async createRun(run: CreateRunInput): Promise<string> {
@@ -38,7 +41,7 @@ export class InMemoryAIRunStateService implements AIRunStateService {
38
41
  async resolveApproval(
39
42
  toolCallId: string,
40
43
  status: 'approved' | 'denied'
41
- ): Promise<void> {
44
+ ): Promise<boolean> {
42
45
  for (const run of this.runs.values()) {
43
46
  if (run.pendingApprovals) {
44
47
  const approval = run.pendingApprovals.find(
@@ -49,10 +52,11 @@ export class InMemoryAIRunStateService implements AIRunStateService {
49
52
  (a) => a.toolCallId !== toolCallId
50
53
  )
51
54
  run.updatedAt = new Date()
52
- return
55
+ return true
53
56
  }
54
57
  }
55
58
  }
59
+ return false
56
60
  }
57
61
 
58
62
  async findRunByToolCallId(
@@ -70,4 +74,14 @@ export class InMemoryAIRunStateService implements AIRunStateService {
70
74
  }
71
75
  return null
72
76
  }
77
+
78
+ async saveScore(score: SaveScoreInput): Promise<void> {
79
+ const existing = this.scores.get(score.runId) ?? []
80
+ existing.push({ ...score, createdAt: new Date() })
81
+ this.scores.set(score.runId, existing)
82
+ }
83
+
84
+ async getScores(runId: string): Promise<AIRunScore[]> {
85
+ return [...(this.scores.get(runId) ?? [])]
86
+ }
73
87
  }
@@ -142,6 +142,7 @@ export class InMemoryWorkflowService
142
142
  const step: StepState & { stepName: string } = {
143
143
  stepId,
144
144
  status: 'pending',
145
+ rpcName,
145
146
  attemptCount: 1,
146
147
  retries: stepOptions?.retries,
147
148
  retryDelay: stepOptions?.retryDelay,
@@ -273,6 +274,7 @@ export class InMemoryWorkflowService
273
274
  const newStep: StepState & { stepName: string } = {
274
275
  stepId: newStepId,
275
276
  status,
277
+ rpcName: failedStep.rpcName,
276
278
  attemptCount: failedStep.attemptCount + 1,
277
279
  retries: failedStep.retries,
278
280
  retryDelay: failedStep.retryDelay,
@@ -1,15 +1,13 @@
1
1
  export { LogLevel } from './logger.js'
2
2
  export { ScopedSecretService } from './scoped-secret-service.js'
3
+ export { ScopedCredentialService } from './scoped-credential-service.js'
3
4
  export {
4
5
  PikkuSessionService,
5
6
  createMiddlewareSessionWireProps,
6
- createFunctionSessionWireProps,
7
7
  } from './user-session-service.js'
8
8
  export { TypedSecretService } from './typed-secret-service.js'
9
9
  export {
10
10
  PikkuCredentialWireService,
11
- createMiddlewareCredentialWireProps,
12
- createWireServicesCredentialWireProps,
13
11
  } from './credential-wire-service.js'
14
12
  export { TypedVariablesService } from './typed-variables-service.js'
15
13
  export { LocalSecretService } from './local-secrets.js'
@@ -39,21 +37,14 @@ export type {
39
37
  export type {
40
38
  ScenarioPersona,
41
39
  ResolvedPersona,
42
- ScenarioPersonaOf,
43
40
  ScenarioPersonas,
44
- ScenarioInvokeOptions,
45
- ScenarioRpcMap,
46
41
  ScenarioHttpResponse,
47
42
  } from './personas-service.js'
48
- // The persona runtime — `HttpPersona`, `createHttpPersonas`,
49
- // `readScenarioHttpResponse`, `postScenarioJson` — is exported from
50
- // `@pikku/core/persona`, not from here. Types are free; those are values, and
51
- // they reach the actor-flow and agent runners, which no production server runs.
43
+ // knowledge: decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md
52
44
  export type { HttpPersonasConfig } from './http-personas.js'
53
45
  export type { JWTService } from './jwt-service.js'
54
46
  export type {
55
47
  EmailService,
56
- EmailTemplateReference,
57
48
  SendEmailInput,
58
49
  SendEmailResult,
59
50
  SendHTMLEmailInput,
@@ -62,12 +53,10 @@ export type {
62
53
  } from './email-service.js'
63
54
  export {
64
55
  DEFAULT_WEBHOOK_RETRIES,
65
- DEFAULT_WEBHOOK_SIGNATURE_HEADER,
66
56
  PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME,
67
57
  WebhookService,
68
58
  type SendWebhookInput,
69
59
  type SendWebhookResult,
70
- type WebhookAttemptRecord,
71
60
  type WebhookAttemptResult,
72
61
  type WebhookDeliveryRecord,
73
62
  type WebhookDeliveryWithAttempts,
@@ -97,52 +86,30 @@ export type {
97
86
  AIAgentRunnerParams,
98
87
  AIAgentRunnerResult,
99
88
  AIAgentStepResult,
100
- AIEmbedManyParams,
101
- AIEmbedManyResult,
102
- AIEmbedParams,
103
- AIEmbedResult,
104
- AIGenerateImageParams,
105
- AIGenerateImagePrompt,
106
- AIGenerateImageResult,
107
- AIGenerateSpeechParams,
108
- AIGenerateSpeechResult,
109
- AIProviderOptions,
110
- AIRerankParams,
111
- AIRerankResult,
112
- AITranscriptionParams,
113
- AITranscriptionResult,
114
89
  AIAgentRunnerService,
115
90
  } from './ai-agent-runner-service.js'
116
91
  export type { AIEmbeddingService } from './ai-embedding-service.js'
117
92
  export type {
118
93
  CreateRunInput,
94
+ SaveScoreInput,
119
95
  AIRunStateService,
120
96
  } from './ai-run-state-service.js'
121
97
  export type {
122
- CredentialStatus,
123
98
  CredentialMeta,
124
99
  } from './typed-secret-service.js'
125
100
  export type { CredentialService } from './credential-service.js'
126
101
  export { TypedCredentialService } from './typed-credential-service.js'
127
102
  export type {
128
- CredentialStatusInfo,
129
103
  CredentialMetaInfo,
130
104
  } from './typed-credential-service.js'
131
- export type { VariableStatus, VariableMeta } from './typed-variables-service.js'
105
+ export type { VariableMeta } from './typed-variables-service.js'
132
106
  export type { MetaService } from './meta-service.js'
133
107
  export type { SessionStore } from './session-store.js'
134
108
  export type { ScopeService, Role } from './scope-service.js'
135
- export {
136
- assertRoleIsMutable,
137
- assertRoleNameAvailable,
138
- roleLockReason,
139
- } from './system-role-guard.js'
140
109
  export type { IsSystemRole } from './system-role-guard.js'
141
110
  export {
142
111
  NoopAuditService,
143
112
  createInvocationAudit,
144
- resolveAuditConfig,
145
- resolveAuditUserIdentityFromWire,
146
113
  } from './audit-service.js'
147
114
  export type {
148
115
  AuditConfig,
@@ -150,10 +117,7 @@ export type {
150
117
  AuditEvent,
151
118
  AuditEventBatch,
152
119
  AuditLog,
153
- AuditLogWriteInput,
154
- AuditOutcome,
155
120
  AuditService,
156
- AuditSource,
157
121
  AuditUserIdentity,
158
122
  ResolvedAuditConfig,
159
123
  } from './audit-service.js'
@@ -177,17 +141,10 @@ export type {
177
141
  AgentMeta,
178
142
  EmailsMeta,
179
143
  EmailTemplateMeta,
180
- EmailTemplateLocaleMeta,
181
- EmailTemplateAssets,
182
144
  } from './meta-service.js'
183
145
  export type {
184
146
  CoverageService,
185
- CoverageSnapshot,
186
- LineHits,
187
147
  ScriptCoverage,
188
- FunctionCoverage,
189
- CoverageRange,
190
- CoverageStatus,
191
148
  FunctionCoverageEntry,
192
149
  FunctionCoverageReport,
193
150
  CoverageFunctionMeta,
@@ -81,11 +81,17 @@ describe('createLocalContentRequestHandler', () => {
81
81
  test('refuses an upload whose key escapes the content directory', async () => {
82
82
  writeFileSync(join(tmpDir, '..', 'pikku-handler-secret.txt'), 'secret')
83
83
  try {
84
+ // Signed for the escaping path itself, so it clears the signature gate
85
+ // and the path-escape guard is what rejects it.
86
+ const signed = await content.signURL({
87
+ url: '/upload/bucket/..%2f..%2fpikku-handler-secret.txt',
88
+ dateLessThan: new Date(Date.now() + 60_000),
89
+ } as any)
84
90
  const response = await handler(
85
- new Request(
86
- 'http://localhost/upload/bucket/..%2f..%2fpikku-handler-secret.txt',
87
- { method: 'PUT', body: 'overwritten' }
88
- )
91
+ new Request(`http://localhost${signed}`, {
92
+ method: 'PUT',
93
+ body: 'overwritten',
94
+ })
89
95
  )
90
96
  assert.equal(response?.status, 400)
91
97
  assert.equal(
@@ -104,6 +110,33 @@ describe('createLocalContentRequestHandler', () => {
104
110
  assert.equal(response?.status, 400)
105
111
  })
106
112
 
113
+ test('refuses an unsigned PUT to the upload prefix', async () => {
114
+ const put = await handler(
115
+ new Request('http://localhost/upload/bucket/evil.bin', {
116
+ method: 'PUT',
117
+ body: 'attacker-controlled',
118
+ })
119
+ )
120
+ assert.equal(put?.status, 403, 'an upload URL must be signed like a read')
121
+ })
122
+
123
+ test('refuses a PUT whose signature was minted for a different key', async () => {
124
+ const { uploadUrl } = await content.getUploadURL({
125
+ bucket: 'bucket',
126
+ fileKey: 'legit/one.bin',
127
+ contentType: 'application/octet-stream',
128
+ } as any)
129
+ const query = uploadUrl.slice(uploadUrl.indexOf('?'))
130
+ // Same signature, a different target path.
131
+ const put = await handler(
132
+ new Request(`http://localhost/upload/bucket/other.bin${query}`, {
133
+ method: 'PUT',
134
+ body: 'payload',
135
+ })
136
+ )
137
+ assert.equal(put?.status, 403)
138
+ })
139
+
107
140
  test('round-trips an upload and a signed read', async () => {
108
141
  const { uploadUrl } = await content.getUploadURL({
109
142
  bucket: 'bucket',
@@ -188,8 +221,13 @@ describe('createLocalContentRequestHandler', () => {
188
221
  })
189
222
 
190
223
  test('rejects a body over the size limit without writing it', async () => {
224
+ const { uploadUrl } = await content.getUploadURL({
225
+ bucket: 'bucket',
226
+ fileKey: 'big.bin',
227
+ contentType: 'application/octet-stream',
228
+ } as any)
191
229
  const response = await handler(
192
- new Request('http://localhost/upload/bucket/big.bin', {
230
+ new Request(`http://localhost${uploadUrl}`, {
193
231
  method: 'PUT',
194
232
  body: Buffer.alloc(1024 * 1024 + 1),
195
233
  })