@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
@@ -4,6 +4,7 @@ import type {
4
4
  CoreAIAgent,
5
5
  AIAgentMemoryConfig,
6
6
  AIAgentInput,
7
+ AIAgentStep,
7
8
  AIMessage,
8
9
  } from './ai-agent.types.js'
9
10
  import type { AIStorageService } from '../../services/ai-storage-service.js'
@@ -19,7 +20,14 @@ export function resolveMemoryServices(
19
20
  } {
20
21
  const memoryConfig = agent.memory
21
22
  const storage = memoryConfig?.storage
22
- ? (singletonServices as any)[memoryConfig.storage]
23
+ ? // The service is named by string in agent config, so the lookup cannot be
24
+ // checked — only the shape it is required to have.
25
+ (
26
+ singletonServices as unknown as Record<
27
+ string,
28
+ AIStorageService | undefined
29
+ >
30
+ )[memoryConfig.storage]
23
31
  : singletonServices.aiStorage
24
32
  return { storage }
25
33
  }
@@ -136,13 +144,7 @@ export async function saveMessages(
136
144
  result: {
137
145
  text: string
138
146
  uiSpec?: unknown
139
- steps: {
140
- toolCalls?: {
141
- name: string
142
- args: Record<string, unknown>
143
- result: string
144
- }[]
145
- }[]
147
+ steps: Pick<AIAgentStep, 'toolCalls'>[]
146
148
  }
147
149
  ): Promise<string> {
148
150
  const responseText = memoryConfig?.workingMemory
@@ -172,6 +174,7 @@ export async function saveMessages(
172
174
  id: toolCallIds[i],
173
175
  name: tc.name,
174
176
  result: tc.result,
177
+ ...(tc.error ? { error: tc.error } : {}),
175
178
  })),
176
179
  createdAt: new Date(),
177
180
  })
@@ -363,6 +366,39 @@ export function stripWorkingMemoryForStreaming(text: string): string {
363
366
  return output
364
367
  }
365
368
 
369
+ async function persistWorkingMemory(
370
+ options: {
371
+ storage?: AIStorageService
372
+ threadId: string
373
+ workingMemorySchemaName?: string | null
374
+ logger?: Logger
375
+ schemaService?: SchemaService
376
+ },
377
+ workingMemory: Record<string, unknown>
378
+ ): Promise<void> {
379
+ if (!options.storage) return
380
+
381
+ const existing =
382
+ (await options.storage.getWorkingMemory(options.threadId, 'thread')) ?? {}
383
+ const merged = deepMergeWorkingMemory(existing, workingMemory)
384
+
385
+ if (options.schemaService && options.workingMemorySchemaName) {
386
+ try {
387
+ await options.schemaService.validateSchema(
388
+ options.workingMemorySchemaName,
389
+ merged
390
+ )
391
+ } catch (err) {
392
+ options.logger?.warn(
393
+ `Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`
394
+ )
395
+ return
396
+ }
397
+ }
398
+
399
+ await options.storage.saveWorkingMemory(options.threadId, 'thread', merged)
400
+ }
401
+
366
402
  export function createWorkingMemoryMiddleware(options: {
367
403
  storage?: AIStorageService
368
404
  threadId: string
@@ -375,6 +411,21 @@ export function createWorkingMemoryMiddleware(options: {
375
411
  }> {
376
412
  return {
377
413
  modifyOutputStream: async (_services, { event, state }) => {
414
+ // A streamed step ends at its `usage` event, or at `done` for a model
415
+ // that reports no usage. That is the last moment the unstripped text is
416
+ // still reachable: it lives only in `state.rawText`, because the strip
417
+ // below runs before anything downstream — including the channel that
418
+ // accumulates what `modifyOutput` would later be handed.
419
+ if (event.type === 'usage' || event.type === 'done') {
420
+ const { workingMemory } = extractWorkingMemory(state.rawText ?? '')
421
+ state.rawText = ''
422
+ state.emittedVisibleText = ''
423
+ if (workingMemory) {
424
+ await persistWorkingMemory(options, workingMemory)
425
+ }
426
+ return event
427
+ }
428
+
378
429
  if (event.type !== 'text-delta') return event
379
430
 
380
431
  const rawText = `${state.rawText ?? ''}${event.text}`
@@ -393,38 +444,10 @@ export function createWorkingMemoryMiddleware(options: {
393
444
  if (!delta) return null
394
445
  return { ...event, text: delta }
395
446
  },
396
- modifyOutput: async (_services, { text, messages, usage }) => {
447
+ modifyOutput: async (_services, { text, messages }) => {
397
448
  const { workingMemory, cleanedText } = extractWorkingMemory(text)
398
- if (workingMemory && options.storage) {
399
- const existing =
400
- (await options.storage.getWorkingMemory(
401
- options.threadId,
402
- 'thread'
403
- )) ?? {}
404
- const merged = deepMergeWorkingMemory(existing, workingMemory)
405
-
406
- let valid = true
407
- if (options.schemaService && options.workingMemorySchemaName) {
408
- try {
409
- await options.schemaService.validateSchema(
410
- options.workingMemorySchemaName,
411
- merged
412
- )
413
- } catch (err) {
414
- valid = false
415
- options.logger?.warn(
416
- `Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`
417
- )
418
- }
419
- }
420
-
421
- if (valid) {
422
- await options.storage.saveWorkingMemory(
423
- options.threadId,
424
- 'thread',
425
- merged
426
- )
427
- }
449
+ if (workingMemory) {
450
+ await persistWorkingMemory(options, workingMemory)
428
451
  }
429
452
 
430
453
  return {
@@ -1,10 +1,21 @@
1
- import { describe, test, beforeEach } from 'node:test'
1
+ import { describe, test, beforeEach, afterEach } from 'node:test'
2
2
  import assert from 'node:assert'
3
- import { resolveModelConfig } from './ai-agent-model-config.js'
4
- import { resetPikkuState } from '../../pikku-state.js'
3
+ import {
4
+ resolveModelAlias,
5
+ resolveModelConfig,
6
+ } from './ai-agent-model-config.js'
7
+ import { pikkuState, resetPikkuState } from '../../pikku-state.js'
8
+
9
+ const setAliases = (aliases: Record<string, string>) =>
10
+ pikkuState(null, 'agent', 'modelAliases', aliases)
5
11
 
6
12
  beforeEach(() => {
7
13
  resetPikkuState()
14
+ delete process.env.PIKKU_MODEL_ALIASES
15
+ })
16
+
17
+ afterEach(() => {
18
+ delete process.env.PIKKU_MODEL_ALIASES
8
19
  })
9
20
 
10
21
  describe('resolveModelConfig', () => {
@@ -34,4 +45,62 @@ describe('resolveModelConfig', () => {
34
45
  assert.strictEqual(result.temperature, undefined)
35
46
  assert.strictEqual(result.maxSteps, undefined)
36
47
  })
48
+
49
+ test('resolves an aliased agent model through the table', () => {
50
+ setAliases({ cheap: 'openai/gpt-5-mini' })
51
+ const result = resolveModelConfig('testAgent', {
52
+ model: 'cheap',
53
+ temperature: 0.2,
54
+ })
55
+ assert.strictEqual(result.model, 'openai/gpt-5-mini')
56
+ assert.strictEqual(result.temperature, 0.2)
57
+ })
58
+ })
59
+
60
+ describe('resolveModelAlias', () => {
61
+ test('a provider-qualified model is never treated as an alias', () => {
62
+ setAliases({ 'openai/gpt-4': 'anthropic/claude-3' })
63
+ assert.strictEqual(resolveModelAlias('openai/gpt-4'), 'openai/gpt-4')
64
+ })
65
+
66
+ test('an alias resolves to its provider-qualified model', () => {
67
+ setAliases({
68
+ cheap: 'openai/gpt-5-mini',
69
+ tool: 'anthropic/claude-sonnet-5',
70
+ })
71
+ assert.strictEqual(resolveModelAlias('cheap'), 'openai/gpt-5-mini')
72
+ assert.strictEqual(resolveModelAlias('tool'), 'anthropic/claude-sonnet-5')
73
+ })
74
+
75
+ test('PIKKU_MODEL_ALIASES beats the generated table', () => {
76
+ setAliases({ cheap: 'openai/gpt-5-mini' })
77
+ process.env.PIKKU_MODEL_ALIASES = 'cheap:anthropic/claude-haiku-4-5'
78
+ assert.strictEqual(resolveModelAlias('cheap'), 'anthropic/claude-haiku-4-5')
79
+ })
80
+
81
+ test('an env override splits on the first colon only', () => {
82
+ // A model id may itself contain a colon — `ollama/qwen2.5:7b` is the shape
83
+ // the runner's own error message cites. It stays provider-qualified so the
84
+ // resolved value is one `VercelAIAgentRunner.parseModel` would accept; a
85
+ // bare `bedrock:nova-lite:1` would pass here and fail the moment anything
86
+ // tried to use it.
87
+ process.env.PIKKU_MODEL_ALIASES = 'cheap:ollama/qwen2.5:7b'
88
+ assert.strictEqual(resolveModelAlias('cheap'), 'ollama/qwen2.5:7b')
89
+ })
90
+
91
+ test('an env override leaves aliases it does not name alone', () => {
92
+ setAliases({ cheap: 'openai/gpt-5-mini', tool: 'openai/gpt-5' })
93
+ process.env.PIKKU_MODEL_ALIASES = 'cheap:openai/gpt-5-nano'
94
+ assert.strictEqual(resolveModelAlias('tool'), 'openai/gpt-5')
95
+ })
96
+
97
+ test('an unknown alias throws rather than reaching a provider', () => {
98
+ setAliases({ cheap: 'openai/gpt-5-mini' })
99
+ assert.throws(() => resolveModelAlias('expensive'), /expensive/)
100
+ })
101
+
102
+ test('the error names the aliases that do exist', () => {
103
+ setAliases({ cheap: 'openai/gpt-5-mini', tool: 'openai/gpt-5' })
104
+ assert.throws(() => resolveModelAlias('exspensive'), /cheap, tool/)
105
+ })
37
106
  })
@@ -1,10 +1,58 @@
1
1
  // knowledge: decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md
2
+ import { pikkuState } from '../../pikku-state.js'
3
+
4
+ const isProviderQualified = (model: string) => model.includes('/')
5
+
6
+ /** `PIKKU_MODEL_ALIASES=cheap:openai/gpt-5-mini,tool:anthropic/claude-sonnet-5` */
7
+ const envAliases = (): Record<string, string> => {
8
+ const raw = process.env.PIKKU_MODEL_ALIASES
9
+ if (!raw) return {}
10
+ const aliases: Record<string, string> = {}
11
+ for (const entry of raw.split(',')) {
12
+ // First colon only — a model id may contain its own.
13
+ const separator = entry.indexOf(':')
14
+ if (separator === -1) continue
15
+ const alias = entry.slice(0, separator).trim()
16
+ const model = entry.slice(separator + 1).trim()
17
+ if (alias && model) aliases[alias] = model
18
+ }
19
+ return aliases
20
+ }
21
+
22
+ /**
23
+ * Resolves a model name to a concrete `provider/model`. Aliases come from the
24
+ * `models` table in pikku.config.json; a name containing `/` is already
25
+ * concrete. Read from the main package, not the calling addon's — which model
26
+ * a tier points at is the hosting app's decision.
27
+ */
28
+ export const resolveModelAlias = (model: string): string => {
29
+ if (isProviderQualified(model)) return model
30
+
31
+ const generated = pikkuState(null, 'agent', 'modelAliases')
32
+ const override = envAliases()[model]
33
+ const resolved = override ?? generated[model]
34
+
35
+ if (!resolved) {
36
+ const known = Object.keys({ ...generated, ...envAliases() }).sort()
37
+ throw new Error(
38
+ `Unknown model alias '${model}'. ` +
39
+ (known.length
40
+ ? `Known aliases: ${known.join(', ')}. `
41
+ : `No aliases are configured. `) +
42
+ `Add it to the "models" table in pikku.config.json, or name a ` +
43
+ `provider-qualified model such as 'openai/gpt-5-mini'.`
44
+ )
45
+ }
46
+
47
+ return resolved
48
+ }
49
+
2
50
  export function resolveModelConfig(
3
51
  _agentName: string,
4
52
  agent: { model: string; temperature?: number; maxSteps?: number }
5
53
  ): { model: string; temperature?: number; maxSteps?: number } {
6
54
  return {
7
- model: agent.model,
55
+ model: resolveModelAlias(agent.model),
8
56
  temperature: agent.temperature,
9
57
  maxSteps: agent.maxSteps,
10
58
  }
@@ -12,7 +12,11 @@ import type {
12
12
  } from './ai-agent.types.js'
13
13
  import type { AIAgentRunnerParams } from '../../services/ai-agent-runner-service.js'
14
14
  import { PikkuError } from '../../errors/error-handler.js'
15
- import { checkAuthPermissions, runPermissions } from '../../permissions.js'
15
+ import {
16
+ checkAuthPermissions,
17
+ runPermissions,
18
+ type PermissionWire,
19
+ } from '../../permissions.js'
16
20
  import { AIProviderNotConfiguredError } from '../../errors/errors.js'
17
21
  import { ForbiddenError } from '../../errors/errors.js'
18
22
  import { verifyScopes } from '../../scopes.js'
@@ -319,8 +323,8 @@ export async function assertAgentAuthorized(
319
323
 
320
324
  await runPermissions({
321
325
  funcPermissions: agent.permissions,
322
- services: singletonServices as any,
323
- wire: wire as any,
326
+ services: singletonServices,
327
+ wire: wire as PermissionWire,
324
328
  data: {},
325
329
  packageName,
326
330
  label: 'agent',
@@ -395,7 +399,7 @@ export function createScopedChannel(
395
399
  toolName: event.toolName,
396
400
  args: event.args,
397
401
  ...(event.reason !== undefined ? { reason: event.reason } : {}),
398
- runId: (event as any).runId,
402
+ runId: event.runId,
399
403
  })
400
404
  return
401
405
  }
@@ -561,6 +565,8 @@ export async function buildToolDefs(
561
565
  variableOverrides: capturedAddonConfig?.variableOverrides,
562
566
  credentialOverrides:
563
567
  capturedAddonConfig?.credentialOverrides,
568
+ globalSecrets: capturedAddonConfig?.globalSecrets,
569
+ globalCredentials: capturedAddonConfig?.globalCredentials,
564
570
  }
565
571
  : undefined
566
572
  services = await getOrCreatePackageSingletonServices(
@@ -940,10 +946,7 @@ export async function prepareAgentRun(
940
946
 
941
947
  let messages: AIMessage[] = []
942
948
  if (storage) {
943
- // A tool whose run was interrupted may still be writing its result to this
944
- // thread. In voice the next turn lands within a second or two, so without
945
- // this the model would load context that is missing the very thing it is
946
- // about to be asked about.
949
+ // knowledge: decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md
947
950
  await awaitPendingInterruptNote(threadId)
948
951
  messages = await storage.getMessages(threadId, {
949
952
  lastN: memoryConfig?.lastMessages ?? 20,
@@ -959,10 +962,7 @@ export async function prepareAgentRun(
959
962
 
960
963
  const userContent: AIMessage['content'] = input.attachments?.length
961
964
  ? [
962
- // Omitted when there is nothing to say. An attachment on its own is a
963
- // real turn — a spoken one carries audio and no text at all — and an
964
- // empty text part alongside it is a part providers are entitled to
965
- // reject, for a caller who never wrote one.
965
+ // knowledge: decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md
966
966
  ...(input.message
967
967
  ? [{ type: 'text' as const, text: input.message }]
968
968
  : []),
@@ -43,6 +43,7 @@ const setup = (agentName: string, resourceId = 'u1') => {
43
43
  getRun: async () => suspendedRun(agentName, resourceId),
44
44
  resolveApproval: async (toolCallId: string) => {
45
45
  resolved.push(toolCallId)
46
+ return true
46
47
  },
47
48
  },
48
49
  } as any)
@@ -707,7 +707,7 @@ describe('resumeAIAgentSync', () => {
707
707
  createdAt: new Date(),
708
708
  updatedAt: new Date(),
709
709
  }),
710
- resolveApproval: async () => {},
710
+ resolveApproval: async () => true,
711
711
  updateRun: async () => {},
712
712
  },
713
713
  } as any)
@@ -784,6 +784,7 @@ describe('resumeAIAgentSync', () => {
784
784
  },
785
785
  resolveApproval: async (toolCallId: string, status: string) => {
786
786
  resolveCalls.push({ toolCallId, status })
787
+ return true
787
788
  },
788
789
  },
789
790
  aiStorage: {
@@ -816,6 +817,84 @@ describe('resumeAIAgentSync', () => {
816
817
  ])
817
818
  })
818
819
 
820
+ test('an approver that loses the claim never runs the tool', async () => {
821
+ addTestAgent('claim-agent')
822
+ pikkuState(null, 'agent', 'agentsMeta')['claim-agent'].tools = ['refund']
823
+ pikkuState(null, 'rpc', 'meta').refund = 'refund'
824
+ pikkuState(null, 'function', 'meta').refund = {
825
+ description: 'Refund',
826
+ sessionless: true,
827
+ }
828
+
829
+ let executions = 0
830
+ pikkuState(null, 'function', 'functions').set('refund', {
831
+ func: async () => {
832
+ executions++
833
+ return { refunded: true }
834
+ },
835
+ })
836
+
837
+ const run: AgentRunState = {
838
+ runId: 'run-claim',
839
+ agentName: 'claim-agent',
840
+ threadId: 'thread-claim',
841
+ resourceId: 'resource-claim',
842
+ status: 'suspended',
843
+ suspendReason: 'approval',
844
+ pendingApprovals: [
845
+ {
846
+ type: 'tool-call',
847
+ toolCallId: 'tc-claim',
848
+ toolName: 'refund',
849
+ args: {},
850
+ },
851
+ ],
852
+ usage: { inputTokens: 0, outputTokens: 0, model: 'test/test-model' },
853
+ createdAt: new Date(),
854
+ updatedAt: new Date(),
855
+ }
856
+
857
+ // Every concurrent approver reads the same `suspended` run with the same
858
+ // pending list; the store hands the claim to exactly one of them.
859
+ let claimsLeft = 1
860
+ pikkuState(null, 'package', 'singletonServices', {
861
+ logger: {
862
+ info: () => {},
863
+ warn: () => {},
864
+ error: () => {},
865
+ debug: () => {},
866
+ },
867
+ aiAgentRunner: {
868
+ run: async (): Promise<AIAgentStepResult> =>
869
+ makeStepResult({
870
+ text: 'Refunded',
871
+ usage: { inputTokens: 1, outputTokens: 1 },
872
+ }),
873
+ },
874
+ aiRunState: {
875
+ getRun: async () => run,
876
+ createRun: async () => 'unused',
877
+ updateRun: async () => {},
878
+ resolveApproval: async () => claimsLeft-- > 0,
879
+ },
880
+ aiStorage: {
881
+ saveMessages: async () => {},
882
+ getMessages: async () => [],
883
+ },
884
+ } as any)
885
+
886
+ const approvals = [{ toolCallId: 'tc-claim', approved: true }]
887
+ await resumeAIAgentSync('run-claim', approvals, asOwner('resource-claim'))
888
+ assert.equal(executions, 1, 'the winner ran the tool once')
889
+
890
+ await assert.rejects(
891
+ () =>
892
+ resumeAIAgentSync('run-claim', approvals, asOwner('resource-claim')),
893
+ /already resolved by another caller/
894
+ )
895
+ assert.equal(executions, 1, 'the loser did not run it a second time')
896
+ })
897
+
819
898
  test('records denied approvals and rejects agent mismatches', async () => {
820
899
  addTestAgent('resume-agent')
821
900
 
@@ -861,6 +940,7 @@ describe('resumeAIAgentSync', () => {
861
940
  updateRun: async () => {},
862
941
  resolveApproval: async (toolCallId: string, status: string) => {
863
942
  resolveCalls.push({ toolCallId, status })
943
+ return true
864
944
  },
865
945
  },
866
946
  aiStorage: {
@@ -959,7 +1039,7 @@ describe('resumeAIAgentSync', () => {
959
1039
  },
960
1040
  aiRunState: {
961
1041
  getRun: async () => run,
962
- resolveApproval: async () => {},
1042
+ resolveApproval: async () => true,
963
1043
  updateRun: async () => {},
964
1044
  },
965
1045
  aiStorage: {