@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
@@ -3,6 +3,8 @@ import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolv
3
3
  import { checkForApprovals, appendStepMessages } from './ai-agent-stream.js';
4
4
  import { AgentInterruptedError, isAbortError, persistOrphanedToolResults, registerInterruptibleRun, trackInterruptNote, trackToolExecution, } from './ai-agent-interrupt.js';
5
5
  import { pikkuState, getSingletonServices } from '../../pikku-state.js';
6
+ import { applyInputMiddleware, describeApprovals, notifyAfterStep, toAccumulatedStep, } from './ai-agent-turn.js';
7
+ import { applyOutputMiddleware, finalizeAgentRun, lastUserMessageText, } from './ai-agent-finalize.js';
6
8
  import { resolveModelConfig } from './ai-agent-model-config.js';
7
9
  import { AIProviderNotConfiguredError } from '../../errors/errors.js';
8
10
  import { randomUUID } from './ai-agent-utils.js';
@@ -75,25 +77,13 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
75
77
  ];
76
78
  // One bag per run, shared by every middleware — see PikkuAIMiddlewareHooks.
77
79
  const sharedNotes = {};
78
- let modifiedMessages = runnerParams.messages;
79
- let modifiedInstructions = runnerParams.instructions;
80
- for (const mw of aiMiddlewares) {
81
- if (mw.modifyInput) {
82
- const result = await mw.modifyInput(singletonServices, {
83
- messages: modifiedMessages,
84
- instructions: modifiedInstructions,
85
- shared: sharedNotes,
86
- });
87
- modifiedMessages = result.messages;
88
- modifiedInstructions = result.instructions;
89
- }
90
- }
80
+ const { messages: modifiedMessages, instructions: modifiedInstructions } = await applyInputMiddleware(aiMiddlewares, singletonServices, {
81
+ messages: runnerParams.messages,
82
+ instructions: runnerParams.instructions,
83
+ }, sharedNotes);
91
84
  runnerParams.messages = modifiedMessages;
92
85
  runnerParams.instructions = modifiedInstructions;
93
- // History records what the model was asked, which for a spoken turn is the
94
- // transcript rather than the base64 audio that arrived — see the same note on
95
- // the streaming path. Identity-checked, because a middleware may legitimately
96
- // replace the message list with something unrelated to this turn.
86
+ // knowledge: decisions/internals/thread-history-records-the-transcript-not-the-audio.md
97
87
  const lastModified = modifiedMessages[modifiedMessages.length - 1];
98
88
  const persistedUserMessage = lastModified?.id === userMessage.id ? lastModified : userMessage;
99
89
  const runId = await aiRunState.createRun({
@@ -105,10 +95,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
105
95
  createdAt: new Date(),
106
96
  updatedAt: new Date(),
107
97
  });
108
- // Registered on the same terms as `streamAIAgent`. A run created here is
109
- // visible to `interruptAIAgent` through `aiRunState` either way, so skipping
110
- // this would leave that call finding the run, passing the ownership check and
111
- // then failing to stop it — reported as if it were running on another host.
98
+ // knowledge: decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md
112
99
  const interruptHandle = registerInterruptibleRun(runId);
113
100
  runnerParams.abortSignal = interruptHandle.signal;
114
101
  runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
@@ -136,44 +123,13 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
136
123
  lastStepResult = stepResult;
137
124
  totalUsage.inputTokens += stepResult.usage.inputTokens;
138
125
  totalUsage.outputTokens += stepResult.usage.outputTokens;
139
- for (const mw of aiMiddlewares) {
140
- if (mw.afterStep) {
141
- await mw.afterStep(singletonServices, {
142
- stepNumber: step,
143
- text: stepResult.text,
144
- toolCalls: stepResult.toolCalls,
145
- toolResults: stepResult.toolResults,
146
- usage: stepResult.usage,
147
- finishReason: stepResult.finishReason,
148
- });
149
- }
150
- }
151
- accumulatedSteps.push({
152
- usage: stepResult.usage,
153
- toolCalls: stepResult.toolCalls.map((tc) => {
154
- const tr = stepResult.toolResults.find((r) => r.toolCallId === tc.toolCallId);
155
- return {
156
- name: tc.toolName,
157
- args: tc.args,
158
- result: typeof tr?.result === 'string'
159
- ? tr.result
160
- : JSON.stringify(tr?.result ?? ''),
161
- };
162
- }),
163
- });
126
+ await notifyAfterStep(aiMiddlewares, singletonServices, step, stepResult);
127
+ accumulatedSteps.push(toAccumulatedStep(stepResult));
164
128
  if (stepResult.toolCalls.length === 0)
165
129
  break;
166
130
  const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools);
167
131
  if (approvalsNeeded.length > 0) {
168
- for (const approval of approvalsNeeded) {
169
- const toolDef = runnerParams.tools.find((t) => t.name === approval.toolName);
170
- if (toolDef?.approvalDescriptionFn && !approval.reason) {
171
- try {
172
- approval.reason = await toolDef.approvalDescriptionFn(approval.args);
173
- }
174
- catch { }
175
- }
176
- }
132
+ await describeApprovals(approvalsNeeded, runnerParams.tools);
177
133
  const pendingApprovals = approvalsNeeded.map((a) => a.agentRunId
178
134
  ? {
179
135
  type: 'agent-call',
@@ -237,27 +193,25 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
237
193
  text: finalText,
238
194
  steps: accumulatedSteps,
239
195
  };
240
- let outputText = finalText;
241
- let outputMessages = runnerParams.messages;
242
- for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
243
- const mw = aiMiddlewares[i];
244
- if (mw.modifyOutput) {
245
- const modResult = await mw.modifyOutput(singletonServices, {
246
- text: outputText,
247
- messages: outputMessages,
248
- usage: totalUsage,
249
- });
250
- outputText = modResult.text;
251
- outputMessages = modResult.messages;
252
- }
253
- }
196
+ const { text: outputText, steps: outputSteps } = await applyOutputMiddleware(aiMiddlewares, singletonServices, {
197
+ text: finalText,
198
+ messages: runnerParams.messages,
199
+ steps: result.steps,
200
+ usage: totalUsage,
201
+ });
254
202
  await saveMessages(storage, threadId, input.resourceId, memoryConfig, persistedUserMessage, {
255
- ...result,
256
203
  text: outputText,
204
+ steps: outputSteps,
257
205
  uiSpec: structuredOutput.uiSpec,
258
206
  });
259
- await aiRunState.updateRun(runId, {
260
- status: 'completed',
207
+ await finalizeAgentRun(aiRunState, {
208
+ runId,
209
+ agentName,
210
+ threadId,
211
+ resourceId: input.resourceId,
212
+ input: lastUserMessageText(runnerParams.messages),
213
+ text: outputText,
214
+ steps: outputSteps,
261
215
  usage: { ...totalUsage, model: agent.model },
262
216
  });
263
217
  return {
@@ -265,15 +219,12 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
265
219
  text: outputText,
266
220
  object: finalObject,
267
221
  threadId,
268
- steps: accumulatedSteps,
222
+ steps: outputSteps,
269
223
  usage: totalUsage,
270
224
  };
271
225
  }
272
226
  catch (error) {
273
- // An interrupt is not a failure, so it skips the `onError` hooks and never
274
- // becomes an `errorMessage`. Unlike the streaming path there is no partial
275
- // reply to hand back — nothing was delivered — so the caller gets a typed
276
- // throw it can tell apart from a provider outage instead of a result.
227
+ // knowledge: decisions/internals/an-agent-interrupt-is-not-a-failure.md
277
228
  const interruption = interruptHandle.interruption;
278
229
  if (interruption || isAbortError(error)) {
279
230
  await aiRunState.updateRun(runId, { status: 'interrupted' });
@@ -331,8 +282,18 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
331
282
  const approvedIds = new Set(approvals.filter((a) => a.approved).map((a) => a.toolCallId));
332
283
  const rejectedIds = new Set(approvals.filter((a) => !a.approved).map((a) => a.toolCallId));
333
284
  const savedPendingApprovals = [...(run.pendingApprovals ?? [])];
285
+ // The read above is not a claim — concurrent resumes all see the same pending
286
+ // list. `resolveApproval` is the claim, and only the caller it returns true
287
+ // for may run the tool.
288
+ const claimedIds = new Set();
334
289
  for (const { toolCallId, approved } of approvals) {
335
- await aiRunState.resolveApproval(toolCallId, approved ? 'approved' : 'denied');
290
+ const claimed = await aiRunState.resolveApproval(toolCallId, approved ? 'approved' : 'denied');
291
+ if (claimed) {
292
+ claimedIds.add(toolCallId);
293
+ }
294
+ }
295
+ if (approvals.length > 0 && claimedIds.size === 0) {
296
+ throw new Error(`Approvals for run ${runId} were already resolved by another caller`);
336
297
  }
337
298
  const { tools } = await buildToolDefs(params, new Map(), run.resourceId, resolvedName, packageName, undefined, agent.aiMiddleware ?? []);
338
299
  const toolCallMessages = [];
@@ -340,7 +301,10 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
340
301
  if (pending.type !== 'tool-call')
341
302
  continue;
342
303
  const toolCallId = pending.toolCallId;
304
+ if (!claimedIds.has(toolCallId))
305
+ continue;
343
306
  let resultStr;
307
+ let toolError;
344
308
  if (rejectedIds.has(toolCallId)) {
345
309
  resultStr =
346
310
  'The user explicitly declined this action. Inform them that it was declined and do not retry.';
@@ -366,7 +330,8 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
366
330
  resultStr = JSON.stringify(err.payload);
367
331
  }
368
332
  else {
369
- resultStr = `Error: ${err instanceof Error ? err.message : String(err)}`;
333
+ toolError = err instanceof Error ? err.message : String(err);
334
+ resultStr = `Error: ${toolError}`;
370
335
  }
371
336
  }
372
337
  }
@@ -380,6 +345,7 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
380
345
  ? JSON.parse(pending.args)
381
346
  : pending.args,
382
347
  result: resultStr,
348
+ ...(toolError ? { error: toolError } : {}),
383
349
  });
384
350
  }
385
351
  if (storage && toolCallMessages.length > 0) {
@@ -397,9 +363,23 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
397
363
  ]);
398
364
  }
399
365
  await aiRunState.updateRun(runId, { status: 'running' });
400
- return continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState);
366
+ return continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState,
367
+ // The approved tools were executed here, before the model was re-entered,
368
+ // so they belong to the run's step record — otherwise a tool that failed
369
+ // after approval leaves no trace on the run at all.
370
+ toolCallMessages.length > 0
371
+ ? {
372
+ usage: { inputTokens: 0, outputTokens: 0 },
373
+ toolCalls: toolCallMessages.map((tc) => ({
374
+ name: tc.toolName,
375
+ args: (tc.args ?? {}),
376
+ result: tc.result,
377
+ ...(tc.error ? { error: tc.error } : {}),
378
+ })),
379
+ }
380
+ : undefined);
401
381
  }
402
- async function continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState) {
382
+ async function continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState, resumedToolStep) {
403
383
  const singletonServices = getSingletonServices();
404
384
  const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta');
405
385
  const meta = agentsMeta[resolvedName];
@@ -427,19 +407,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
427
407
  ];
428
408
  // One bag per run, shared by every middleware — see PikkuAIMiddlewareHooks.
429
409
  const sharedNotes = {};
430
- let modifiedMessages = trimmedMessages;
431
- let modifiedInstructions = instructions;
432
- for (const mw of aiMiddlewares) {
433
- if (mw.modifyInput) {
434
- const result = await mw.modifyInput(singletonServices, {
435
- messages: modifiedMessages,
436
- instructions: modifiedInstructions,
437
- shared: sharedNotes,
438
- });
439
- modifiedMessages = result.messages;
440
- modifiedInstructions = result.instructions;
441
- }
442
- }
410
+ const { messages: modifiedMessages, instructions: modifiedInstructions } = await applyInputMiddleware(aiMiddlewares, singletonServices, { messages: trimmedMessages, instructions: instructions }, sharedNotes);
443
411
  const { tools: resumeTools } = await buildToolDefs(params, new Map(), run.resourceId, resolvedName, packageName, undefined, aiMiddlewares);
444
412
  const resolved = resolveModelConfig(resolvedName, agent);
445
413
  const maxSteps = resolved.maxSteps ?? 10;
@@ -464,6 +432,11 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
464
432
  runnerParams.abortSignal = interruptHandle.signal;
465
433
  runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
466
434
  try {
435
+ // Kept out of `accumulatedSteps` deliberately: that array drives
436
+ // `saveMessages`, and the approved tool's messages were already written to
437
+ // the thread before the model was re-entered. It belongs to the run's step
438
+ // record, not to persistence.
439
+ const withResumedStep = (steps) => resumedToolStep ? [resumedToolStep, ...steps] : steps;
467
440
  const accumulatedSteps = [];
468
441
  const totalUsage = { inputTokens: 0, outputTokens: 0 };
469
442
  let lastStepResult = null;
@@ -472,44 +445,13 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
472
445
  lastStepResult = stepResult;
473
446
  totalUsage.inputTokens += stepResult.usage.inputTokens;
474
447
  totalUsage.outputTokens += stepResult.usage.outputTokens;
475
- for (const mw of aiMiddlewares) {
476
- if (mw.afterStep) {
477
- await mw.afterStep(singletonServices, {
478
- stepNumber: step,
479
- text: stepResult.text,
480
- toolCalls: stepResult.toolCalls,
481
- toolResults: stepResult.toolResults,
482
- usage: stepResult.usage,
483
- finishReason: stepResult.finishReason,
484
- });
485
- }
486
- }
487
- accumulatedSteps.push({
488
- usage: stepResult.usage,
489
- toolCalls: stepResult.toolCalls.map((tc) => {
490
- const tr = stepResult.toolResults.find((r) => r.toolCallId === tc.toolCallId);
491
- return {
492
- name: tc.toolName,
493
- args: tc.args,
494
- result: typeof tr?.result === 'string'
495
- ? tr.result
496
- : JSON.stringify(tr?.result ?? ''),
497
- };
498
- }),
499
- });
448
+ await notifyAfterStep(aiMiddlewares, singletonServices, step, stepResult);
449
+ accumulatedSteps.push(toAccumulatedStep(stepResult));
500
450
  if (stepResult.toolCalls.length === 0)
501
451
  break;
502
452
  const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools);
503
453
  if (approvalsNeeded.length > 0) {
504
- for (const approval of approvalsNeeded) {
505
- const toolDef = runnerParams.tools.find((t) => t.name === approval.toolName);
506
- if (toolDef?.approvalDescriptionFn && !approval.reason) {
507
- try {
508
- approval.reason = await toolDef.approvalDescriptionFn(approval.args);
509
- }
510
- catch { }
511
- }
512
- }
454
+ await describeApprovals(approvalsNeeded, runnerParams.tools);
513
455
  const pendingApprovals = approvalsNeeded.map((a) => a.agentRunId
514
456
  ? {
515
457
  type: 'agent-call',
@@ -554,7 +496,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
554
496
  runId: run.runId,
555
497
  text: suspendedText,
556
498
  threadId: run.threadId,
557
- steps: accumulatedSteps,
499
+ steps: withResumedStep(accumulatedSteps),
558
500
  usage: totalUsage,
559
501
  status: 'suspended',
560
502
  pendingApprovals: approvalsNeeded.map((a) => ({
@@ -574,26 +516,26 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
574
516
  text: finalText,
575
517
  steps: accumulatedSteps,
576
518
  };
577
- let outputText = finalText;
578
- let outputMessages = runnerParams.messages;
579
- for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
580
- const mw = aiMiddlewares[i];
581
- if (mw.modifyOutput) {
582
- const modResult = await mw.modifyOutput(singletonServices, {
583
- text: outputText,
584
- messages: outputMessages,
585
- usage: totalUsage,
586
- });
587
- outputText = modResult.text;
588
- outputMessages = modResult.messages;
589
- }
590
- }
519
+ const { text: outputText, steps: outputSteps } = await applyOutputMiddleware(aiMiddlewares, singletonServices, {
520
+ text: finalText,
521
+ messages: runnerParams.messages,
522
+ steps: withResumedStep(result.steps),
523
+ usage: totalUsage,
524
+ });
591
525
  await saveMessages(storage, run.threadId, run.resourceId, memoryConfig, null, {
592
- ...result,
593
526
  text: outputText,
527
+ // The approved tool's messages were written before the model was
528
+ // re-entered, so only the steps this leg generated are persisted here.
529
+ steps: accumulatedSteps,
594
530
  });
595
- await aiRunState.updateRun(run.runId, {
596
- status: 'completed',
531
+ await finalizeAgentRun(aiRunState, {
532
+ runId: run.runId,
533
+ agentName: resolvedName,
534
+ threadId: run.threadId,
535
+ resourceId: run.resourceId,
536
+ input: lastUserMessageText(runnerParams.messages),
537
+ text: outputText,
538
+ steps: outputSteps,
597
539
  usage: { ...totalUsage, model: agent.model },
598
540
  });
599
541
  return {
@@ -601,7 +543,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
601
543
  text: outputText,
602
544
  object: finalObject,
603
545
  threadId: run.threadId,
604
- steps: accumulatedSteps,
546
+ steps: outputSteps,
605
547
  usage: totalUsage,
606
548
  };
607
549
  }