@pikku/core 0.12.72 → 0.12.77

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 (848) hide show
  1. package/CHANGELOG.md +1171 -0
  2. package/dist/column-form.d.ts +32 -0
  3. package/dist/column-form.js +42 -0
  4. package/dist/crypto-utils.d.ts +43 -7
  5. package/dist/crypto-utils.js +163 -42
  6. package/dist/data-classification.d.ts +44 -0
  7. package/dist/dev/hot-reload.js +11 -30
  8. package/dist/dev/module-runner.d.ts +3 -7
  9. package/dist/dev/module-runner.js +4 -10
  10. package/dist/dev/reload-meta.d.ts +8 -20
  11. package/dist/dev/reload-meta.js +9 -29
  12. package/dist/errors/error-handler.d.ts +5 -30
  13. package/dist/errors/error-handler.js +16 -32
  14. package/dist/errors/errors.d.ts +32 -151
  15. package/dist/errors/errors.js +55 -157
  16. package/dist/function/abort-scope.d.ts +47 -0
  17. package/dist/function/abort-scope.js +63 -0
  18. package/dist/function/function-runner.js +37 -32
  19. package/dist/function/functions.types.d.ts +57 -136
  20. package/dist/function/functions.types.js +0 -58
  21. package/dist/function/index.d.ts +1 -1
  22. package/dist/function/list.types.d.ts +12 -62
  23. package/dist/function/list.types.js +4 -25
  24. package/dist/handle-error.d.ts +0 -13
  25. package/dist/handle-error.js +0 -18
  26. package/dist/index.d.ts +11 -5
  27. package/dist/index.js +7 -2
  28. package/dist/middleware/auth-apikey.d.ts +3 -18
  29. package/dist/middleware/auth-apikey.js +0 -17
  30. package/dist/middleware/auth-bearer.d.ts +6 -41
  31. package/dist/middleware/auth-bearer.js +5 -41
  32. package/dist/middleware/auth-cookie.d.ts +5 -27
  33. package/dist/middleware/auth-cookie.js +2 -26
  34. package/dist/middleware/cors.d.ts +7 -34
  35. package/dist/middleware/cors.js +7 -34
  36. package/dist/middleware/remote-auth.d.ts +3 -1
  37. package/dist/middleware/remote-auth.js +4 -3
  38. package/dist/middleware/telemetry.d.ts +8 -33
  39. package/dist/middleware/telemetry.js +2 -31
  40. package/dist/middleware-runner.d.ts +4 -55
  41. package/dist/middleware-runner.js +5 -74
  42. package/dist/permissions.d.ts +3 -44
  43. package/dist/permissions.js +19 -71
  44. package/dist/pikku-request.d.ts +0 -6
  45. package/dist/pikku-request.js +0 -6
  46. package/dist/pikku-state.d.ts +0 -26
  47. package/dist/pikku-state.js +2 -30
  48. package/dist/remote.d.ts +3 -5
  49. package/dist/remote.js +9 -8
  50. package/dist/schema.d.ts +5 -39
  51. package/dist/schema.js +5 -39
  52. package/dist/scopes.d.ts +4 -23
  53. package/dist/scopes.js +7 -48
  54. package/dist/secret-value.d.ts +56 -0
  55. package/dist/secret-value.js +46 -0
  56. package/dist/services/ai-agent-runner-service.d.ts +20 -0
  57. package/dist/services/ai-embedding-service.d.ts +2 -25
  58. package/dist/services/audit-service.d.ts +74 -4
  59. package/dist/services/audit-service.js +8 -7
  60. package/dist/services/content-service.d.ts +1 -46
  61. package/dist/services/credential-service.d.ts +3 -40
  62. package/dist/services/credential-wire-service.d.ts +5 -0
  63. package/dist/services/credential-wire-service.js +9 -1
  64. package/dist/services/deployment-service.d.ts +3 -9
  65. package/dist/services/email-service.d.ts +2 -1
  66. package/dist/services/gateway-service.d.ts +0 -15
  67. package/dist/services/http-personas.d.ts +80 -0
  68. package/dist/services/http-personas.js +233 -0
  69. package/dist/services/in-memory-queue-service.d.ts +0 -14
  70. package/dist/services/in-memory-queue-service.js +1 -15
  71. package/dist/services/in-memory-trigger-service.d.ts +0 -18
  72. package/dist/services/in-memory-trigger-service.js +1 -18
  73. package/dist/services/in-memory-workflow-service.d.ts +0 -16
  74. package/dist/services/in-memory-workflow-service.js +4 -33
  75. package/dist/services/index.d.ts +8 -9
  76. package/dist/services/index.js +3 -6
  77. package/dist/services/istanbul-coverage-service.d.ts +1 -5
  78. package/dist/services/istanbul-coverage-service.js +2 -8
  79. package/dist/services/jwt-service.d.ts +1 -16
  80. package/dist/services/local-content-request-handler.d.ts +29 -0
  81. package/dist/services/local-content-request-handler.js +176 -0
  82. package/dist/services/local-content.d.ts +13 -2
  83. package/dist/services/local-content.js +40 -13
  84. package/dist/services/local-gateway-service.d.ts +0 -16
  85. package/dist/services/local-gateway-service.js +2 -17
  86. package/dist/services/local-secrets.d.ts +4 -7
  87. package/dist/services/local-secrets.js +7 -7
  88. package/dist/services/logger-console.d.ts +3 -7
  89. package/dist/services/logger-console.js +3 -7
  90. package/dist/services/logger.d.ts +22 -40
  91. package/dist/services/meta-service.d.ts +23 -26
  92. package/dist/services/meta-service.js +22 -36
  93. package/dist/services/personas-service.d.ts +134 -0
  94. package/dist/services/personas-service.js +40 -0
  95. package/dist/services/pikku-user-id.js +0 -4
  96. package/dist/services/queue-webhook-service.d.ts +2 -36
  97. package/dist/services/queue-webhook-service.js +10 -42
  98. package/dist/services/scheduler-service.d.ts +1 -50
  99. package/dist/services/scheduler-service.js +0 -10
  100. package/dist/services/schema-service.d.ts +1 -24
  101. package/dist/services/scope-service.d.ts +49 -34
  102. package/dist/services/scoped-secret-service.d.ts +4 -7
  103. package/dist/services/scoped-secret-service.js +0 -4
  104. package/dist/services/secret-host-binding.d.ts +8 -0
  105. package/dist/services/secret-host-binding.js +36 -0
  106. package/dist/services/secret-service.d.ts +12 -35
  107. package/dist/services/secretless.d.ts +6 -0
  108. package/dist/services/secretless.js +21 -0
  109. package/dist/services/stub-tracker.d.ts +7 -18
  110. package/dist/services/stub-tracker.js +8 -18
  111. package/dist/services/system-role-guard.d.ts +33 -0
  112. package/dist/services/system-role-guard.js +38 -0
  113. package/dist/services/trigger-service.d.ts +0 -12
  114. package/dist/services/typed-secret-service.d.ts +5 -11
  115. package/dist/services/typed-secret-service.js +1 -7
  116. package/dist/services/v8-coverage-service.d.ts +2 -3
  117. package/dist/services/v8-coverage-service.js +1 -2
  118. package/dist/services/variables-service.d.ts +1 -8
  119. package/dist/services/webhook-service.d.ts +21 -64
  120. package/dist/services/webhook-service.js +6 -20
  121. package/dist/services/workflow-service.d.ts +3 -15
  122. package/dist/testing/service-tests.js +6 -23
  123. package/dist/time-utils.d.ts +0 -16
  124. package/dist/time-utils.js +1 -19
  125. package/dist/types/core.types.d.ts +120 -219
  126. package/dist/types/core.types.js +0 -42
  127. package/dist/types/state.types.d.ts +4 -9
  128. package/dist/utils/hmac.d.ts +4 -10
  129. package/dist/utils/hmac.js +4 -10
  130. package/dist/utils/safe-fetch.d.ts +7 -35
  131. package/dist/utils/safe-fetch.js +13 -53
  132. package/dist/utils.d.ts +1 -6
  133. package/dist/utils.js +6 -15
  134. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
  135. package/dist/wirings/actor-flow/index.d.ts +0 -9
  136. package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
  137. package/dist/wirings/actor-flow/run-conversation.js +14 -7
  138. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
  139. package/dist/wirings/ai-agent/ai-agent-agui.js +46 -12
  140. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
  141. package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
  142. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
  143. package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
  144. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
  145. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
  146. package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
  147. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
  148. package/dist/wirings/ai-agent/ai-agent-prepare.js +65 -132
  149. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
  150. package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
  151. package/dist/wirings/ai-agent/ai-agent-runner.js +63 -22
  152. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
  153. package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
  154. package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -4
  155. package/dist/wirings/ai-agent/index.d.ts +6 -4
  156. package/dist/wirings/ai-agent/index.js +5 -4
  157. package/dist/wirings/ai-agent/voice-input.d.ts +59 -1
  158. package/dist/wirings/ai-agent/voice-input.js +90 -12
  159. package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
  160. package/dist/wirings/ai-agent/voice-output.js +162 -50
  161. package/dist/wirings/channel/channel-common.d.ts +7 -20
  162. package/dist/wirings/channel/channel-common.js +7 -21
  163. package/dist/wirings/channel/channel-handler.js +25 -6
  164. package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
  165. package/dist/wirings/channel/channel-host-rpc.js +38 -0
  166. package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
  167. package/dist/wirings/channel/channel-middleware-runner.js +0 -12
  168. package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
  169. package/dist/wirings/channel/channel-rpc-registry.js +89 -0
  170. package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
  171. package/dist/wirings/channel/channel-rpc-responder.js +71 -0
  172. package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
  173. package/dist/wirings/channel/channel-rpc-service.js +106 -0
  174. package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
  175. package/dist/wirings/channel/channel-rpc-validators.js +30 -0
  176. package/dist/wirings/channel/channel-rpc.d.ts +5 -0
  177. package/dist/wirings/channel/channel-rpc.js +5 -0
  178. package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
  179. package/dist/wirings/channel/channel-rpc.types.js +50 -0
  180. package/dist/wirings/channel/channel-runner.d.ts +0 -4
  181. package/dist/wirings/channel/channel-runner.js +0 -14
  182. package/dist/wirings/channel/channel-store.d.ts +0 -10
  183. package/dist/wirings/channel/channel.types.d.ts +12 -1
  184. package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
  185. package/dist/wirings/channel/define-channel-routes.js +0 -20
  186. package/dist/wirings/channel/eventhub-service.d.ts +0 -18
  187. package/dist/wirings/channel/index.d.ts +4 -1
  188. package/dist/wirings/channel/index.js +2 -0
  189. package/dist/wirings/channel/local/local-channel-runner.js +3 -1
  190. package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
  191. package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
  192. package/dist/wirings/channel/log-channels.d.ts +0 -4
  193. package/dist/wirings/channel/log-channels.js +0 -4
  194. package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
  195. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
  196. package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
  197. package/dist/wirings/cli/channel/cli-approval.js +81 -0
  198. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
  199. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
  200. package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
  201. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
  202. package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +38 -0
  203. package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
  204. package/dist/wirings/cli/channel/index.d.ts +5 -0
  205. package/dist/wirings/cli/channel/index.js +2 -0
  206. package/dist/wirings/cli/cli-runner.d.ts +20 -20
  207. package/dist/wirings/cli/cli-runner.js +28 -89
  208. package/dist/wirings/cli/cli.types.d.ts +14 -3
  209. package/dist/wirings/cli/command-parser.d.ts +1 -10
  210. package/dist/wirings/cli/command-parser.js +10 -87
  211. package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
  212. package/dist/wirings/cli/define-cli-commands.js +1 -17
  213. package/dist/wirings/credential/credential.types.d.ts +0 -12
  214. package/dist/wirings/credential/define-credential.d.ts +48 -0
  215. package/dist/wirings/credential/define-credential.js +47 -0
  216. package/dist/wirings/credential/index.d.ts +1 -1
  217. package/dist/wirings/credential/index.js +1 -1
  218. package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
  219. package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
  220. package/dist/wirings/gateway/gateway-runner.js +8 -105
  221. package/dist/wirings/gateway/gateway.types.d.ts +7 -80
  222. package/dist/wirings/http/http-routes.d.ts +0 -63
  223. package/dist/wirings/http/http-routes.js +0 -63
  224. package/dist/wirings/http/http-runner.d.ts +0 -99
  225. package/dist/wirings/http/http-runner.js +9 -165
  226. package/dist/wirings/http/http.types.d.ts +14 -55
  227. package/dist/wirings/http/log-http-routes.d.ts +0 -4
  228. package/dist/wirings/http/log-http-routes.js +0 -4
  229. package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
  230. package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
  231. package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
  232. package/dist/wirings/http/routers/path-to-regex.js +2 -13
  233. package/dist/wirings/http/web-request.d.ts +0 -8
  234. package/dist/wirings/http/web-request.js +25 -17
  235. package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
  236. package/dist/wirings/mcp/mcp-runner.js +1 -14
  237. package/dist/wirings/mcp/mcp.types.d.ts +2 -35
  238. package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
  239. package/dist/wirings/oauth2/oauth2.types.js +0 -3
  240. package/dist/wirings/persona/define-personas.d.ts +32 -0
  241. package/dist/wirings/persona/define-personas.js +31 -0
  242. package/dist/wirings/persona/index.d.ts +21 -0
  243. package/dist/wirings/persona/index.js +17 -0
  244. package/dist/wirings/persona/persona-email.d.ts +37 -0
  245. package/dist/wirings/persona/persona-email.js +69 -0
  246. package/dist/wirings/persona/persona-environments.d.ts +45 -0
  247. package/dist/wirings/persona/persona-environments.js +81 -0
  248. package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
  249. package/dist/wirings/persona/persona-mailbox.js +53 -0
  250. package/dist/wirings/persona/persona.types.d.ts +136 -0
  251. package/dist/wirings/persona/persona.types.js +1 -0
  252. package/dist/wirings/persona/validate-personas.d.ts +53 -0
  253. package/dist/wirings/persona/validate-personas.js +94 -0
  254. package/dist/wirings/queue/index.d.ts +3 -0
  255. package/dist/wirings/queue/index.js +2 -3
  256. package/dist/wirings/queue/queue-identity.d.ts +28 -0
  257. package/dist/wirings/queue/queue-identity.js +103 -0
  258. package/dist/wirings/queue/queue-runner.d.ts +0 -19
  259. package/dist/wirings/queue/queue-runner.js +9 -30
  260. package/dist/wirings/queue/queue.types.d.ts +20 -90
  261. package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
  262. package/dist/wirings/queue/register-queue-helper.js +0 -11
  263. package/dist/wirings/queue/signed-queue-service.d.ts +17 -0
  264. package/dist/wirings/queue/signed-queue-service.js +42 -0
  265. package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
  266. package/dist/wirings/queue/validate-worker-config.js +0 -14
  267. package/dist/wirings/role/define-system-role.d.ts +32 -0
  268. package/dist/wirings/role/define-system-role.js +31 -0
  269. package/dist/wirings/role/index.d.ts +3 -0
  270. package/dist/wirings/role/index.js +2 -0
  271. package/dist/wirings/role/role.types.d.ts +43 -0
  272. package/dist/wirings/role/role.types.js +1 -0
  273. package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
  274. package/dist/wirings/role/validate-role-definitions.js +71 -0
  275. package/dist/wirings/rpc/addon-runner.d.ts +0 -19
  276. package/dist/wirings/rpc/addon-runner.js +0 -51
  277. package/dist/wirings/rpc/remote-addon-auth.d.ts +3 -13
  278. package/dist/wirings/rpc/remote-addon-auth.js +7 -11
  279. package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
  280. package/dist/wirings/rpc/rpc-runner.js +88 -105
  281. package/dist/wirings/rpc/rpc-types.d.ts +7 -6
  282. package/dist/wirings/rpc/wire-addon.d.ts +25 -0
  283. package/dist/wirings/rpc/wire-addon.js +62 -0
  284. package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
  285. package/dist/wirings/rpc/wire-remote-addon.js +0 -8
  286. package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
  287. package/dist/wirings/scheduler/log-schedulers.js +0 -4
  288. package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
  289. package/dist/wirings/scheduler/scheduler-runner.js +0 -1
  290. package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
  291. package/dist/wirings/scope/define-scope.d.ts +32 -0
  292. package/dist/wirings/scope/define-scope.js +31 -0
  293. package/dist/wirings/scope/index.d.ts +1 -1
  294. package/dist/wirings/scope/index.js +1 -1
  295. package/dist/wirings/scope/scope.types.d.ts +7 -9
  296. package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
  297. package/dist/wirings/scope/validate-scope-definitions.js +3 -21
  298. package/dist/wirings/secret/index.d.ts +1 -1
  299. package/dist/wirings/secret/index.js +1 -1
  300. package/dist/wirings/secret/secret.types.d.ts +19 -15
  301. package/dist/wirings/secret/secret.types.js +1 -1
  302. package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
  303. package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
  304. package/dist/wirings/trigger/trigger-runner.js +1 -24
  305. package/dist/wirings/trigger/trigger.types.d.ts +1 -82
  306. package/dist/wirings/trigger/trigger.types.js +0 -34
  307. package/dist/wirings/variable/index.d.ts +1 -1
  308. package/dist/wirings/variable/index.js +1 -1
  309. package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
  310. package/dist/wirings/variable/variable.types.d.ts +1 -13
  311. package/dist/wirings/variable/variable.types.js +1 -1
  312. package/dist/wirings/virtual-user/index.d.ts +30 -0
  313. package/dist/wirings/virtual-user/index.js +10 -0
  314. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
  315. package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -0
  316. package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
  317. package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
  318. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
  319. package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
  320. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
  321. package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
  322. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
  323. package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
  324. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
  325. package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
  326. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
  327. package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
  328. package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
  329. package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
  330. package/dist/wirings/virtual-user/virtual-user-run-store.d.ts +90 -0
  331. package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -0
  332. package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
  333. package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
  334. package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
  335. package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
  336. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +19 -15
  337. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
  338. package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
  339. package/dist/wirings/workflow/feature.d.ts +0 -19
  340. package/dist/wirings/workflow/feature.js +0 -19
  341. package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
  342. package/dist/wirings/workflow/graph/graph-node.js +0 -34
  343. package/dist/wirings/workflow/graph/graph-runner.js +6 -41
  344. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
  345. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
  346. package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
  347. package/dist/wirings/workflow/index.d.ts +5 -7
  348. package/dist/wirings/workflow/index.js +3 -17
  349. package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
  350. package/dist/wirings/workflow/pikku-scenario-service.js +204 -43
  351. package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
  352. package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
  353. package/dist/wirings/workflow/run-timeline.d.ts +0 -47
  354. package/dist/wirings/workflow/run-timeline.js +0 -22
  355. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
  356. package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
  357. package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
  358. package/dist/wirings/workflow/scenario-poll.js +0 -12
  359. package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
  360. package/dist/wirings/workflow/scenario-prose.js +1 -19
  361. package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
  362. package/dist/wirings/workflow/scenario-step-guards.js +1 -14
  363. package/dist/wirings/workflow/scenario-step.types.d.ts +84 -12
  364. package/dist/wirings/workflow/scenario-step.types.js +5 -1
  365. package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
  366. package/dist/wirings/workflow/scenario-surface.js +56 -0
  367. package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
  368. package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
  369. package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
  370. package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
  371. package/dist/wirings/workflow/workflow.types.d.ts +5 -195
  372. package/knowledge/decisions/index.md +19 -0
  373. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
  374. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -0
  375. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
  376. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
  377. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
  378. package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
  379. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
  380. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
  381. package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
  382. package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
  383. package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
  384. package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
  385. package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
  386. package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
  387. package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
  388. package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
  389. package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
  390. package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
  391. package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
  392. package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
  393. package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
  394. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
  395. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
  396. package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
  397. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
  398. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
  399. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
  400. package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
  401. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
  402. package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +84 -0
  403. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -0
  404. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
  405. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
  406. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
  407. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
  408. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
  409. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
  410. package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
  411. package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
  412. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
  413. package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
  414. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
  415. package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
  416. package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
  417. package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
  418. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
  419. package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
  420. package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
  421. package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
  422. package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
  423. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
  424. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
  425. package/knowledge/decisions/internals/index.md +117 -0
  426. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
  427. package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
  428. package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
  429. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +53 -0
  430. package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
  431. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
  432. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
  433. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
  434. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
  435. package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
  436. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
  437. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +48 -0
  438. package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
  439. package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
  440. package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
  441. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
  442. package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
  443. package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
  444. package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
  445. package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
  446. package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
  447. package/knowledge/decisions/internals/validate-checks-personas-through-a-shared-module.md +43 -0
  448. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
  449. package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
  450. package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
  451. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
  452. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
  453. package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
  454. package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
  455. package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
  456. package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
  457. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
  458. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
  459. package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
  460. package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
  461. package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
  462. package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
  463. package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
  464. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
  465. package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
  466. package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
  467. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
  468. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
  469. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
  470. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
  471. package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
  472. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
  473. package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
  474. package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
  475. package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
  476. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
  477. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
  478. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
  479. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
  480. package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
  481. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
  482. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
  483. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
  484. package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
  485. package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
  486. package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
  487. package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
  488. package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
  489. package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
  490. package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
  491. package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
  492. package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
  493. package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
  494. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
  495. package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
  496. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
  497. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
  498. package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
  499. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
  500. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
  501. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
  502. package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
  503. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
  504. package/knowledge/decisions/security/index.md +55 -0
  505. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
  506. package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
  507. package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
  508. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
  509. package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
  510. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
  511. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
  512. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
  513. package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
  514. package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
  515. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
  516. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
  517. package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
  518. package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
  519. package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
  520. package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
  521. package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
  522. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
  523. package/knowledge/index.md +24 -0
  524. package/knowledge/questions/index.md +15 -0
  525. package/package.json +6 -2
  526. package/run-tests.sh +0 -0
  527. package/src/column-form.test.ts +97 -0
  528. package/src/column-form.ts +58 -0
  529. package/src/crypto-utils.test.ts +460 -19
  530. package/src/crypto-utils.ts +306 -59
  531. package/src/data-classification.ts +45 -7
  532. package/src/dev/hot-reload.test.ts +0 -4
  533. package/src/dev/hot-reload.ts +11 -30
  534. package/src/dev/module-runner.ts +7 -32
  535. package/src/dev/reload-meta.ts +9 -29
  536. package/src/errors/error-handler.ts +20 -35
  537. package/src/errors/error.test.ts +30 -1
  538. package/src/errors/errors.ts +73 -157
  539. package/src/function/abort-scope.test.ts +97 -0
  540. package/src/function/abort-scope.ts +80 -0
  541. package/src/function/function-runner.test.ts +0 -7
  542. package/src/function/function-runner.ts +62 -32
  543. package/src/function/functions.types.ts +95 -138
  544. package/src/function/index.ts +1 -0
  545. package/src/function/list.types.test.ts +3 -25
  546. package/src/function/list.types.ts +12 -62
  547. package/src/handle-error.ts +0 -18
  548. package/src/index.ts +84 -3
  549. package/src/middleware/auth-apikey.test.ts +0 -1
  550. package/src/middleware/auth-apikey.ts +0 -17
  551. package/src/middleware/auth-bearer.test.ts +3 -5
  552. package/src/middleware/auth-bearer.ts +5 -41
  553. package/src/middleware/auth-cookie.test.ts +0 -6
  554. package/src/middleware/auth-cookie.ts +2 -26
  555. package/src/middleware/cors.test.ts +34 -0
  556. package/src/middleware/cors.ts +12 -33
  557. package/src/middleware/remote-auth.test.ts +26 -10
  558. package/src/middleware/remote-auth.ts +11 -3
  559. package/src/middleware/telemetry.ts +2 -31
  560. package/src/middleware-runner.test.ts +0 -2
  561. package/src/middleware-runner.ts +5 -74
  562. package/src/permissions.test.ts +30 -0
  563. package/src/permissions.ts +24 -74
  564. package/src/pikku-request.ts +0 -6
  565. package/src/pikku-state.ts +2 -30
  566. package/src/production-barrels-stay-lean.test.ts +110 -0
  567. package/src/remote.test.ts +173 -0
  568. package/src/remote.ts +18 -8
  569. package/src/schema.ts +5 -39
  570. package/src/scopes.ts +7 -48
  571. package/src/secret-value.test.ts +204 -0
  572. package/src/secret-value.ts +111 -0
  573. package/src/services/ai-agent-runner-service.ts +20 -0
  574. package/src/services/ai-embedding-service.ts +3 -25
  575. package/src/services/audit-service.ts +88 -11
  576. package/src/services/content-service.ts +1 -46
  577. package/src/services/credential-service.ts +3 -40
  578. package/src/services/credential-wire-service.test.ts +0 -2
  579. package/src/services/credential-wire-service.ts +9 -1
  580. package/src/services/deployment-service.ts +3 -9
  581. package/src/services/email-service.ts +3 -1
  582. package/src/services/gateway-service.ts +0 -15
  583. package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
  584. package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
  585. package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
  586. package/src/services/in-memory-queue-service.ts +1 -15
  587. package/src/services/in-memory-trigger-service.ts +1 -18
  588. package/src/services/in-memory-workflow-service.test.ts +0 -13
  589. package/src/services/in-memory-workflow-service.ts +4 -38
  590. package/src/services/index.ts +23 -18
  591. package/src/services/istanbul-coverage-service.ts +2 -8
  592. package/src/services/jwt-service.ts +1 -16
  593. package/src/services/local-content-request-handler.test.ts +202 -0
  594. package/src/services/local-content-request-handler.ts +267 -0
  595. package/src/services/local-content.test.ts +159 -27
  596. package/src/services/local-content.ts +55 -23
  597. package/src/services/local-gateway-service.ts +2 -17
  598. package/src/services/local-secrets.test.ts +20 -5
  599. package/src/services/local-secrets.ts +15 -11
  600. package/src/services/logger-console.test.ts +0 -1
  601. package/src/services/logger-console.ts +3 -7
  602. package/src/services/logger.ts +31 -46
  603. package/src/services/meta-service.test.ts +1 -5
  604. package/src/services/meta-service.ts +41 -61
  605. package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
  606. package/src/services/pikku-user-id.ts +0 -4
  607. package/src/services/queue-webhook-service.test.ts +2 -1
  608. package/src/services/queue-webhook-service.ts +10 -42
  609. package/src/services/scheduler-service.ts +1 -50
  610. package/src/services/schema-service.ts +1 -24
  611. package/src/services/scope-service.ts +50 -34
  612. package/src/services/scoped-secret-service.ts +4 -7
  613. package/src/services/secret-host-binding.test.ts +138 -0
  614. package/src/services/secret-host-binding.ts +51 -0
  615. package/src/services/secret-service.ts +12 -35
  616. package/src/services/secretless.test.ts +54 -0
  617. package/src/services/secretless.ts +29 -0
  618. package/src/services/stub-tracker.ts +8 -18
  619. package/src/services/system-role-guard.test.ts +93 -0
  620. package/src/services/system-role-guard.ts +71 -0
  621. package/src/services/trigger-service.ts +0 -12
  622. package/src/services/typed-secret-service.ts +12 -14
  623. package/src/services/v8-coverage-service.ts +3 -6
  624. package/src/services/variables-service.ts +1 -8
  625. package/src/services/webhook-service.ts +23 -64
  626. package/src/services/workflow-service.ts +3 -20
  627. package/src/testing/service-tests.ts +6 -32
  628. package/src/time-utils.ts +1 -19
  629. package/src/types/core.types.ts +137 -229
  630. package/src/types/state.types.ts +7 -9
  631. package/src/utils/hmac.ts +4 -10
  632. package/src/utils/safe-fetch.ts +13 -54
  633. package/src/utils.test.ts +11 -2
  634. package/src/utils.ts +6 -15
  635. package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
  636. package/src/wirings/actor-flow/index.ts +0 -9
  637. package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
  638. package/src/wirings/actor-flow/run-conversation.ts +19 -12
  639. package/src/wirings/ai-agent/ai-agent-agui.test.ts +91 -10
  640. package/src/wirings/ai-agent/ai-agent-agui.ts +49 -17
  641. package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
  642. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
  643. package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
  644. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
  645. package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
  646. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
  647. package/src/wirings/ai-agent/ai-agent-prepare.ts +89 -139
  648. package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
  649. package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
  650. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
  651. package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
  652. package/src/wirings/ai-agent/ai-agent-runner.ts +85 -35
  653. package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
  654. package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
  655. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
  656. package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
  657. package/src/wirings/ai-agent/index.ts +37 -3
  658. package/src/wirings/ai-agent/voice-input.test.ts +137 -7
  659. package/src/wirings/ai-agent/voice-input.ts +96 -12
  660. package/src/wirings/ai-agent/voice-output.test.ts +512 -0
  661. package/src/wirings/ai-agent/voice-output.ts +243 -56
  662. package/src/wirings/channel/channel-common.ts +15 -20
  663. package/src/wirings/channel/channel-handler.test.ts +50 -0
  664. package/src/wirings/channel/channel-handler.ts +32 -11
  665. package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
  666. package/src/wirings/channel/channel-host-rpc.ts +69 -0
  667. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
  668. package/src/wirings/channel/channel-middleware-runner.ts +0 -12
  669. package/src/wirings/channel/channel-rpc-registry.ts +116 -0
  670. package/src/wirings/channel/channel-rpc-responder.ts +117 -0
  671. package/src/wirings/channel/channel-rpc-service.ts +146 -0
  672. package/src/wirings/channel/channel-rpc-validators.ts +65 -0
  673. package/src/wirings/channel/channel-rpc.test.ts +820 -0
  674. package/src/wirings/channel/channel-rpc.ts +5 -0
  675. package/src/wirings/channel/channel-rpc.types.ts +150 -0
  676. package/src/wirings/channel/channel-runner.ts +0 -14
  677. package/src/wirings/channel/channel-store.ts +0 -10
  678. package/src/wirings/channel/channel.types.ts +19 -8
  679. package/src/wirings/channel/define-channel-routes.ts +0 -20
  680. package/src/wirings/channel/eventhub-service.ts +0 -18
  681. package/src/wirings/channel/index.ts +35 -0
  682. package/src/wirings/channel/local/local-channel-handler.ts +3 -1
  683. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
  684. package/src/wirings/channel/local/local-channel-runner.ts +3 -1
  685. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
  686. package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
  687. package/src/wirings/channel/log-channels.ts +0 -4
  688. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
  689. package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
  690. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
  691. package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
  692. package/src/wirings/cli/channel/cli-approval.ts +135 -0
  693. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
  694. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
  695. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
  696. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
  697. package/src/wirings/cli/channel/cli-raw-client-runner.ts +185 -0
  698. package/src/wirings/cli/channel/index.ts +13 -0
  699. package/src/wirings/cli/cli-runner.test.ts +0 -1
  700. package/src/wirings/cli/cli-runner.ts +46 -88
  701. package/src/wirings/cli/cli.types.ts +14 -3
  702. package/src/wirings/cli/command-parser.test.ts +0 -4
  703. package/src/wirings/cli/command-parser.ts +11 -91
  704. package/src/wirings/cli/define-cli-commands.ts +1 -17
  705. package/src/wirings/credential/credential.types.ts +0 -12
  706. package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
  707. package/src/wirings/credential/index.ts +1 -1
  708. package/src/wirings/credential/validate-credential-definitions.ts +2 -4
  709. package/src/wirings/gateway/gateway-runner.test.ts +1 -21
  710. package/src/wirings/gateway/gateway-runner.ts +8 -110
  711. package/src/wirings/gateway/gateway.types.ts +7 -80
  712. package/src/wirings/http/http-routes.test.ts +0 -3
  713. package/src/wirings/http/http-routes.ts +0 -86
  714. package/src/wirings/http/http-runner.test.ts +0 -1
  715. package/src/wirings/http/http-runner.ts +8 -167
  716. package/src/wirings/http/http.types.ts +15 -62
  717. package/src/wirings/http/log-http-routes.ts +0 -4
  718. package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
  719. package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
  720. package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
  721. package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
  722. package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
  723. package/src/wirings/http/routers/path-to-regex.ts +2 -13
  724. package/src/wirings/http/web-request.test.ts +33 -2
  725. package/src/wirings/http/web-request.ts +30 -17
  726. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
  727. package/src/wirings/mcp/mcp-runner.ts +2 -17
  728. package/src/wirings/mcp/mcp.types.ts +7 -42
  729. package/src/wirings/oauth2/oauth2.types.ts +0 -30
  730. package/src/wirings/persona/define-personas.ts +33 -0
  731. package/src/wirings/persona/index.ts +62 -0
  732. package/src/wirings/persona/persona-email.ts +87 -0
  733. package/src/wirings/persona/persona-environments.test.ts +183 -0
  734. package/src/wirings/persona/persona-environments.ts +138 -0
  735. package/src/wirings/persona/persona-mailbox.ts +156 -0
  736. package/src/wirings/persona/persona.test.ts +220 -0
  737. package/src/wirings/persona/persona.types.ts +142 -0
  738. package/src/wirings/persona/validate-personas.ts +133 -0
  739. package/src/wirings/queue/index.ts +13 -3
  740. package/src/wirings/queue/queue-identity.test.ts +454 -0
  741. package/src/wirings/queue/queue-identity.ts +176 -0
  742. package/src/wirings/queue/queue-runner.ts +12 -31
  743. package/src/wirings/queue/queue.types.ts +25 -90
  744. package/src/wirings/queue/register-queue-helper.ts +0 -14
  745. package/src/wirings/queue/signed-queue-service.ts +60 -0
  746. package/src/wirings/queue/validate-worker-config.ts +2 -28
  747. package/src/wirings/role/define-system-role.ts +33 -0
  748. package/src/wirings/role/index.ts +13 -0
  749. package/src/wirings/role/role.test.ts +104 -0
  750. package/src/wirings/role/role.types.ts +47 -0
  751. package/src/wirings/role/validate-role-definitions.ts +93 -0
  752. package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
  753. package/src/wirings/rpc/addon-runner.ts +0 -56
  754. package/src/wirings/rpc/addon-scopes.test.ts +225 -0
  755. package/src/wirings/rpc/remote-addon-auth.ts +9 -16
  756. package/src/wirings/rpc/rpc-runner.test.ts +192 -6
  757. package/src/wirings/rpc/rpc-runner.ts +145 -127
  758. package/src/wirings/rpc/rpc-types.ts +11 -6
  759. package/src/wirings/rpc/wire-addon.test.ts +43 -1
  760. package/src/wirings/rpc/wire-addon.ts +99 -0
  761. package/src/wirings/rpc/wire-remote-addon.ts +9 -29
  762. package/src/wirings/scheduler/log-schedulers.ts +0 -4
  763. package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
  764. package/src/wirings/scheduler/scheduler-runner.ts +0 -2
  765. package/src/wirings/scheduler/scheduler.types.ts +1 -14
  766. package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
  767. package/src/wirings/scope/index.ts +1 -1
  768. package/src/wirings/scope/scope.test.ts +1 -2
  769. package/src/wirings/scope/scope.types.ts +7 -9
  770. package/src/wirings/scope/validate-scope-definitions.ts +3 -21
  771. package/src/wirings/secret/index.ts +1 -1
  772. package/src/wirings/secret/secret.types.ts +19 -15
  773. package/src/wirings/secret/validate-secret-definitions.ts +2 -4
  774. package/src/wirings/trigger/trigger-runner.ts +1 -27
  775. package/src/wirings/trigger/trigger.types.ts +1 -82
  776. package/src/wirings/variable/index.ts +1 -1
  777. package/src/wirings/variable/validate-variable-definitions.ts +2 -4
  778. package/src/wirings/variable/variable.types.ts +1 -13
  779. package/src/wirings/virtual-user/index.ts +88 -0
  780. package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
  781. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -0
  782. package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
  783. package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
  784. package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
  785. package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
  786. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
  787. package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
  788. package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
  789. package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
  790. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
  791. package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
  792. package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
  793. package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
  794. package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
  795. package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
  796. package/src/wirings/virtual-user/virtual-user-run-store.ts +98 -0
  797. package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
  798. package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
  799. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +19 -20
  800. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
  801. package/src/wirings/workflow/feature.ts +0 -19
  802. package/src/wirings/workflow/graph/graph-node.ts +0 -136
  803. package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
  804. package/src/wirings/workflow/graph/graph-runner.ts +6 -41
  805. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
  806. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
  807. package/src/wirings/workflow/index.ts +10 -44
  808. package/src/wirings/workflow/pikku-scenario-service.ts +235 -61
  809. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
  810. package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
  811. package/src/wirings/workflow/run-timeline.test.ts +7 -19
  812. package/src/wirings/workflow/run-timeline.ts +0 -56
  813. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
  814. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
  815. package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
  816. package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
  817. package/src/wirings/workflow/scenario-poll.test.ts +0 -2
  818. package/src/wirings/workflow/scenario-poll.ts +0 -15
  819. package/src/wirings/workflow/scenario-prose.test.ts +5 -7
  820. package/src/wirings/workflow/scenario-prose.ts +1 -29
  821. package/src/wirings/workflow/scenario-service.test.ts +2 -10
  822. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  823. package/src/wirings/workflow/scenario-step.test.ts +163 -19
  824. package/src/wirings/workflow/scenario-step.types.ts +94 -12
  825. package/src/wirings/workflow/scenario-surface.test.ts +146 -0
  826. package/src/wirings/workflow/scenario-surface.ts +71 -0
  827. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
  828. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
  829. package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
  830. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
  831. package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
  832. package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
  833. package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
  834. package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
  835. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
  836. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
  837. package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
  838. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
  839. package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
  840. package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
  841. package/src/wirings/workflow/workflow.types.ts +5 -201
  842. package/tsconfig.tsbuildinfo +1 -1
  843. package/tsconfig.type-tests.json +12 -0
  844. package/src/middleware/timeout.ts +0 -22
  845. package/src/pikku-response.ts +0 -5
  846. package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
  847. package/src/wirings/workflow/dsl/index.ts +0 -36
  848. package/src/wirings/workflow/graph/index.ts +0 -15
@@ -6,118 +6,72 @@ import { verifyScopes } from '../../scopes.js';
6
6
  import { pikkuState, getSingletonServices } from '../../pikku-state.js';
7
7
  import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js';
8
8
  import { randomUUID } from './ai-agent-utils.js';
9
+ import { awaitPendingInterruptNote } from './ai-agent-interrupt.js';
9
10
  import { streamAIAgent } from './ai-agent-stream.js';
10
11
  import { runAIAgent } from './ai-agent-runner.js';
11
12
  import { resolveNamespace, ContextAwareRPCService, } from '../../wirings/rpc/rpc-runner.js';
12
13
  import { getOrCreatePackageSingletonServices } from '../../wirings/rpc/addon-runner.js';
13
14
  import { resolveMemoryServices, loadContextMessages, trimMessages, } from './ai-agent-memory.js';
14
15
  import { resolveModelConfig } from './ai-agent-model-config.js';
15
- /**
16
- * The ownership key for a thread/run: the trusted principal (the authenticated
17
- * `session.userId` for `'user'` scope, or `session.orgId` for `'org'` scope)
18
- * composed with the client-supplied `resourceId` as a sub-partition —
19
- * `principal:resourceId`. Because the principal is always the prefix, a client
20
- * `resourceId` can sub-divide within the caller's own boundary but can never
21
- * widen access to another user's or org's threads.
22
- *
23
- * Idempotent: a value that is already within the caller's namespace (top-level
24
- * re-entry, sub-agent recursion, or resume, which all pass an already-composite
25
- * `resourceId`) is returned unchanged rather than double-composed.
26
- *
27
- * `'org'` scope with no session org throws {@link ForbiddenError} — falling back
28
- * to a bare/shared key would leak across organizations. Sessionless `'user'`
29
- * wirings have no trusted principal and fall back to the requested `resourceId`
30
- * as a best-effort partition key.
31
- */
32
- export function resolveOwnerResourceId(params, sessionScope, requestedResourceId) {
16
+ export function resolveSessionPrincipal(params, sessionScope) {
33
17
  const session = params.sessionService?.get();
34
- let principal;
35
18
  if ((sessionScope ?? 'user') === 'org') {
36
19
  if (!session?.orgId) {
37
20
  throw new ForbiddenError('This agent is org-scoped but the session has no organization');
38
21
  }
39
- principal = session.orgId;
22
+ return session.orgId;
40
23
  }
41
- else {
42
- principal = session?.userId;
24
+ return session?.userId;
25
+ }
26
+ export function resolveOwnerResourceId(params, sessionScope, requestedResourceId) {
27
+ const principal = resolveSessionPrincipal(params, sessionScope);
28
+ if (!principal) {
29
+ params.anonymousOwnerResourceId ??= `anon-${randomUUID()}`;
30
+ return params.anonymousOwnerResourceId;
43
31
  }
44
- if (!principal)
45
- return requestedResourceId;
46
32
  if (requestedResourceId === principal ||
47
33
  requestedResourceId.startsWith(`${principal}:`)) {
48
34
  return requestedResourceId;
49
35
  }
50
36
  return `${principal}:${requestedResourceId}`;
51
37
  }
52
- /** The declared {@link SessionScope} for an agent, defaulting to `'user'`. */
38
+ export function assertResourcePrincipalOwner(params, sessionScope, storedResourceId, kind) {
39
+ const principal = resolveSessionPrincipal(params, sessionScope);
40
+ if (!principal || !isOwnedByPrincipal(storedResourceId, principal)) {
41
+ throw new ForbiddenError(`Not authorized to access this ${kind}`);
42
+ }
43
+ }
53
44
  export function agentSessionScope(agentName) {
54
45
  return resolveAgent(agentName).agent.sessionScope ?? 'user';
55
46
  }
56
- /**
57
- * Enforce that a stored thread/run belongs to the caller's owner resource,
58
- * throwing {@link ForbiddenError} (without echoing the id, to avoid an
59
- * existence oracle) on a mismatch.
60
- */
61
47
  export function assertResourceOwner(ownerResourceId, storedResourceId, kind) {
62
48
  if (storedResourceId !== ownerResourceId) {
63
49
  throw new ForbiddenError(`Not authorized to access this ${kind}`);
64
50
  }
65
51
  }
66
- /** A session's trusted principals, in the order they may be read as. */
67
52
  export function sessionPrincipals(session) {
68
53
  return [session?.userId, session?.orgId].filter((principal) => Boolean(principal));
69
54
  }
70
- /**
71
- * Whether `storedResourceId` belongs to `principal` under the composition
72
- * {@link resolveOwnerResourceId} performs — either the bare principal or one of
73
- * its `principal:` sub-partitions. The `:` is required so that `alice` does not
74
- * match a `alice-evil:…` lookalike.
75
- */
76
55
  export function isOwnedByPrincipal(storedResourceId, principal) {
77
56
  return (storedResourceId === principal ||
78
57
  storedResourceId.startsWith(`${principal}:`));
79
58
  }
80
- /**
81
- * The `owners` constraint to pass to `AgentRunService.listThreads` for a caller.
82
- *
83
- * Returns `undefined` — not `[]` — for a session with no principal, because an
84
- * empty list means "match nothing" whereas a sessionless deployment (agent
85
- * `no-auth`) has no ownership model to constrain by. Keeping that carve-out here
86
- * rather than at each call site stops it from being re-derived inconsistently.
87
- */
88
59
  export function threadOwnerConstraint(session) {
89
- const principals = sessionPrincipals(session);
90
- return principals.length > 0 ? principals : undefined;
60
+ return sessionPrincipals(session);
91
61
  }
92
- /**
93
- * Whether a stored thread/run may be read by the caller. Shaped as a predicate
94
- * so it can back a `pikkuPermission` — authorization belongs in a function's
95
- * `permissions` field, never in its body.
96
- *
97
- * Unlike {@link assertResourceOwner}, which compares against a single composed
98
- * owner key on the run path, this guards the thread-management reads where the
99
- * caller supplies only a `threadId` — so ownership has to be derived from the
100
- * session rather than from the request.
101
- *
102
- * A session with no principal means the deployment opted out of authorization
103
- * (agent `no-auth`), so there is no ownership model to enforce and access is not
104
- * gated — mirroring {@link resolveOwnerResourceId}'s sessionless fallback to a
105
- * bare resourceId.
106
- */
107
62
  export function canAccessThread(storedResourceId, session) {
108
63
  const principals = sessionPrincipals(session);
109
64
  if (principals.length === 0)
110
- return true;
65
+ return false;
111
66
  return principals.some((principal) => isOwnedByPrincipal(storedResourceId, principal));
112
67
  }
68
+ export const APPROVAL_REQUIRED = Symbol('pikku.ai.approvalRequired');
113
69
  /**
114
- * Non-forgeable brand for the sub-agent approval marker. Only framework code
115
- * (the delegating sub-agent tools below) sets this Symbol on a tool result; a
116
- * sub-agent's LLM-shaped `result.object` plain JSON cannot carry a Symbol,
117
- * so `checkForApprovals` trusts the brand rather than the `__approvalRequired`
118
- * string key to decide an approval must be surfaced.
70
+ * In-process brand proving a credential request was produced by pikku itself and
71
+ * not by tool output an attacker can influence. Never serialized — a value that
72
+ * has crossed a JSON boundary has lost the brand and is treated as untrusted.
119
73
  */
120
- export const APPROVAL_REQUIRED = Symbol('pikku.ai.approvalRequired');
74
+ export const CREDENTIAL_REQUIRED = Symbol('pikku.ai.credentialRequired');
121
75
  export class ToolApprovalRequired extends PikkuError {
122
76
  toolCallId;
123
77
  toolName;
@@ -154,10 +108,6 @@ export class ToolCredentialRequired extends PikkuError {
154
108
  this.connectUrl = connectUrl;
155
109
  }
156
110
  }
157
- /**
158
- * Given a list of tool names (e.g. ["oauth-api:getProfile"]),
159
- * returns the wire OAuth credentials required by their addons.
160
- */
161
111
  export function getAddonCredentialRequirements(toolNames) {
162
112
  const requirements = new Map();
163
113
  for (const toolName of toolNames) {
@@ -211,26 +161,6 @@ export const resolveAgent = (agentName) => {
211
161
  }
212
162
  throw new Error(`AI agent not found: ${agentName}`);
213
163
  };
214
- /**
215
- * Enforces an agent's own authorization before it runs: session presence
216
- * (`auth`), then `scopes`, then `permissions`.
217
- *
218
- * The ordering mirrors the function runner — scopes are an AND gate checked
219
- * first, so they can only ever narrow access, and a missing scope short-circuits
220
- * before any permission function does I/O.
221
- *
222
- * `auth` follows `pikkuSessionlessFunc` rather than `pikkuFunc`: a session is
223
- * required only when `auth: true` is set explicitly. An agent is normally
224
- * reached from a function that has already enforced its own auth, and agents are
225
- * also run from genuinely sessionless contexts (crons, queue workers), so
226
- * requiring a session by default would reject those without adding a meaningful
227
- * gate. `scopes` and `permissions` are always enforced when declared.
228
- *
229
- * Globals are evaluated here too (via {@link runPermissions}) rather than being
230
- * assumed to have already run: an agent is reachable from entry points that do
231
- * not go through the function runner, and re-evaluating an AND gate of
232
- * side-effect-free predicates is idempotent.
233
- */
234
164
  export async function assertAgentAuthorized(agent, params, packageName) {
235
165
  const session = params.sessionService
236
166
  ? await params.sessionService.get()
@@ -322,31 +252,13 @@ export function createScopedChannel(parent, agentName, session) {
322
252
  setState: (s) => parent.setState(s),
323
253
  getState: () => parent.getState(),
324
254
  clearState: () => parent.clearState(),
255
+ remote: (funcName, data) => parent.remote(funcName, data),
325
256
  };
326
257
  }
327
- /**
328
- * Build the run input for a delegated sub-agent.
329
- *
330
- * `context` is the PARENT run's identifier block (the "Current context" text
331
- * with organizationId, project/stage ids). A sub-agent's tool-call schema only
332
- * carries { message, session }, so unless the sub-agent inherits the parent's
333
- * context it never sees the authoritative ids — it depends on the model
334
- * re-typing them into `message`, which weak models botch, causing
335
- * schema/permission rejections and retry loops. Forwarding it here is the
336
- * regression this seam guards.
337
- */
338
258
  export function buildSubAgentRunInput(message, threadId, resourceId, parentContext) {
339
259
  return { message, threadId, resourceId, context: parentContext };
340
260
  }
341
- export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares, agentMode,
342
- // The parent run's `context` (the "Current context" identifier block). A
343
- // delegated sub-agent's tool-call input schema only carries { message,
344
- // session }, so without inheriting this the sub-agent never sees the
345
- // authoritative ids (organizationId, project/stage ids) — it depends on the
346
- // model re-typing them into `message`, which weak models botch, causing
347
- // schema/permission rejections and retry loops. Forward it so the sub-agent
348
- // gets the same context block in its instructions.
349
- parentContext) {
261
+ export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares, agentMode, parentContext) {
350
262
  const singletonServices = getSingletonServices();
351
263
  const tools = [];
352
264
  const missingRpcs = [];
@@ -354,7 +266,22 @@ parentContext) {
354
266
  const meta = pikkuState(packageName, 'agent', 'agentsMeta')[agentName];
355
267
  if (!meta)
356
268
  return { tools, missingRpcs };
357
- // Get session for permission filtering
269
+ /**
270
+ * A tool's description is what the model is told it does, and the main thing
271
+ * it chooses between tools on. It does not survive into the meta registered at
272
+ * boot: `description` is classed as a verbose field, so the bundled copy has
273
+ * it stripped and `fnMeta.description` is always undefined — every tool was
274
+ * being offered under its own bare name regardless of what its author wrote.
275
+ *
276
+ * `getFunctionsMeta` reads the verbose file and falls back to the minimal one,
277
+ * recovering the authored description wherever the generated `.pikku`
278
+ * directory is readable. Where it is not — no `metaService`, or a deployment
279
+ * shipping only the stripped copy — tools fall back to their name, which is
280
+ * what they did before this lookup existed.
281
+ */
282
+ const describedFunctions = await singletonServices.metaService
283
+ ?.getFunctionsMeta()
284
+ .catch(() => undefined);
358
285
  const session = params.sessionService
359
286
  ? await params.sessionService.get()
360
287
  : null;
@@ -389,10 +316,6 @@ parentContext) {
389
316
  missingRpcs.push(toolName);
390
317
  continue;
391
318
  }
392
- // Filter out tools the user doesn't have auth for. The `pikkuAuth` brand
393
- // only survives on the live permission objects in the function config, so
394
- // the check reads those rather than the metadata (whose by-name registry
395
- // is never populated, which would let every gated tool through).
396
319
  if (fnMeta.permissions?.length) {
397
320
  if (!session)
398
321
  continue;
@@ -415,7 +338,6 @@ parentContext) {
415
338
  }
416
339
  const needsApproval = approvalPolicy === 'all' ||
417
340
  (approvalPolicy === 'explicit' && fnMeta?.approvalRequired);
418
- // Build approvalDescriptionFn if the function has an approvalDescription configured
419
341
  let approvalDescriptionFn;
420
342
  if (needsApproval && pikkuFuncId) {
421
343
  const funcConfig = pikkuState(resolvedPkg, 'function', 'functions').get(pikkuFuncId);
@@ -445,10 +367,13 @@ parentContext) {
445
367
  }
446
368
  tools.push({
447
369
  name: toolName.replaceAll('@', '_').replaceAll(':', '__'),
448
- description: fnMeta?.description || fnMeta?.title || toolName,
370
+ description: describedFunctions?.[pikkuFuncId]?.description ||
371
+ fnMeta?.description ||
372
+ toolName,
449
373
  inputSchema,
450
374
  needsApproval: needsApproval || undefined,
451
375
  approvalDescriptionFn,
376
+ readonly: fnMeta?.readonly || undefined,
452
377
  execute: async (toolInput) => {
453
378
  const wire = params.sessionService
454
379
  ? { ...createMiddlewareSessionWireProps(params.sessionService) }
@@ -467,8 +392,6 @@ parentContext) {
467
392
  singletonServices.logger.warn(`Sub-agent '${subAgentName}' not found in agent registry`);
468
393
  continue;
469
394
  }
470
- // Filter out sub-agents the user doesn't have auth for, reading the live
471
- // agent config for the same reason the tool path does.
472
395
  if (subMeta.permissions?.length) {
473
396
  if (!session)
474
397
  continue;
@@ -513,8 +436,6 @@ parentContext) {
513
436
  input: message,
514
437
  });
515
438
  const subChannel = createScopedChannel(channel, subAgentName, session);
516
- // In supervise mode, suppress sub-agent text from reaching the client.
517
- // Approvals still flow through normally.
518
439
  const effectiveChannel = isDelegate
519
440
  ? subChannel
520
441
  : {
@@ -545,7 +466,6 @@ parentContext) {
545
466
  });
546
467
  return resultText;
547
468
  }
548
- // No stream context: sub-agent runs non-streaming
549
469
  const result = await runAIAgent(subAgentName, buildSubAgentRunInput(message, threadId, resourceId, parentContext), params, agentSessionMap);
550
470
  if (result.status === 'suspended' &&
551
471
  result.pendingApprovals?.length) {
@@ -610,11 +530,6 @@ parentContext) {
610
530
  });
611
531
  }
612
532
  }
613
- // A tool's execute() can throw (bad input, RPC failure, DB error, ...). The AI
614
- // SDK catches that at the tool-call boundary and turns it into a conversational
615
- // "tool error" reply — without this, the exception never reaches pikku's own
616
- // logger, so a failing tool is undiagnosable server-side. Log unconditionally,
617
- // even when no aiMiddleware afterToolCall hook is registered to see it.
618
533
  for (const tool of tools) {
619
534
  const originalExecute = tool.execute;
620
535
  tool.execute = async (toolInput) => {
@@ -622,6 +537,13 @@ parentContext) {
622
537
  return await originalExecute(toolInput);
623
538
  }
624
539
  catch (err) {
540
+ if (err?.payload?.error === 'missing_credential') {
541
+ return {
542
+ [CREDENTIAL_REQUIRED]: true,
543
+ __credentialRequired: true,
544
+ ...err.payload,
545
+ };
546
+ }
625
547
  singletonServices.logger.error(`AI agent tool '${tool.name}' threw during execute()`, err);
626
548
  throw err;
627
549
  }
@@ -726,6 +648,11 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
726
648
  }
727
649
  let messages = [];
728
650
  if (storage) {
651
+ // A tool whose run was interrupted may still be writing its result to this
652
+ // thread. In voice the next turn lands within a second or two, so without
653
+ // this the model would load context that is missing the very thing it is
654
+ // about to be asked about.
655
+ await awaitPendingInterruptNote(threadId);
729
656
  messages = await storage.getMessages(threadId, {
730
657
  lastN: memoryConfig?.lastMessages ?? 20,
731
658
  });
@@ -733,7 +660,13 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
733
660
  const contextMessages = await loadContextMessages(memoryConfig, storage, input, workingMemoryJsonSchema);
734
661
  const userContent = input.attachments?.length
735
662
  ? [
736
- { type: 'text', text: input.message },
663
+ // Omitted when there is nothing to say. An attachment on its own is a
664
+ // real turn — a spoken one carries audio and no text at all — and an
665
+ // empty text part alongside it is a part providers are entitled to
666
+ // reject, for a caller who never wrote one.
667
+ ...(input.message
668
+ ? [{ type: 'text', text: input.message }]
669
+ : []),
737
670
  ...input.attachments.map((a) => ({
738
671
  type: a.type,
739
672
  data: a.data,
@@ -758,7 +691,6 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
758
691
  instructions = `${instructions}\n\nCurrent context (use these identifiers directly in tool calls — do not ask the user for them):\n${input.context}`;
759
692
  }
760
693
  const resolved = resolveModelConfig(resolvedName, agent);
761
- // Per-request overrides
762
694
  if (input.model) {
763
695
  resolved.model = resolveModelConfig(resolvedName, {
764
696
  ...agent,
@@ -777,6 +709,7 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
777
709
  tools,
778
710
  maxSteps: 1,
779
711
  toolChoice: agent.toolChoice ?? 'auto',
712
+ providerOptions: agent.providerOptions,
780
713
  outputSchema,
781
714
  };
782
715
  return {
@@ -1,10 +1,11 @@
1
1
  import type { CoreAIAgent } from './ai-agent.types.js';
2
2
  import type { AIRunStateService } from '../../services/ai-run-state-service.js';
3
+ import { type RunAIAgentParams } from './ai-agent-prepare.js';
3
4
  export declare const addAIAgent: (agentName: string, agent: CoreAIAgent<any, any>, packageName?: string | null) => void;
4
5
  export declare function approveAIAgent(aiRunState: AIRunStateService, runId: string, approvals: {
5
6
  toolCallId: string;
6
7
  approved: boolean;
7
- }[], expectedAgentName?: string): Promise<{
8
+ }[], expectedAgentName?: string, params?: RunAIAgentParams): Promise<{
8
9
  status: 'resumed' | 'suspended';
9
10
  runId: string;
10
11
  approved: string[];
@@ -1,4 +1,5 @@
1
1
  import { pikkuState } from '../../pikku-state.js';
2
+ import { agentSessionScope, assertAgentAuthorized, assertResourcePrincipalOwner, resolveAgent, } from './ai-agent-prepare.js';
2
3
  export const addAIAgent = (agentName, agent, packageName = null) => {
3
4
  const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta');
4
5
  const agentMeta = agentsMeta[agentName];
@@ -12,17 +13,20 @@ export const addAIAgent = (agentName, agent, packageName = null) => {
12
13
  }
13
14
  agents.set(agentName, agent);
14
15
  };
15
- export async function approveAIAgent(aiRunState, runId, approvals, expectedAgentName) {
16
+ export async function approveAIAgent(aiRunState, runId, approvals, expectedAgentName, params = {}) {
16
17
  if (!aiRunState)
17
18
  throw new Error('AIRunStateService not available');
18
19
  const run = await aiRunState.getRun(runId);
19
20
  if (!run)
20
21
  throw new Error('Run not found: ' + runId);
22
+ assertResourcePrincipalOwner(params, agentSessionScope(run.agentName), run.resourceId, 'run');
21
23
  if (expectedAgentName && run.agentName !== expectedAgentName) {
22
24
  throw new Error(`Run ${runId} belongs to agent '${run.agentName}', not '${expectedAgentName}'`);
23
25
  }
24
26
  if (run.status !== 'suspended')
25
27
  throw new Error('Run is not suspended: ' + run.status);
28
+ const { agent, packageName } = resolveAgent(run.agentName);
29
+ await assertAgentAuthorized(agent, params, packageName);
26
30
  const approvedIds = new Set(approvals.filter((a) => a.approved).map((a) => a.toolCallId));
27
31
  const rejectedIds = new Set(approvals.filter((a) => !a.approved).map((a) => a.toolCallId));
28
32
  const remaining = (run.pendingApprovals ?? []).filter((p) => !approvedIds.has(p.toolCallId) && !rejectedIds.has(p.toolCallId));
@@ -1,6 +1,7 @@
1
1
  import { saveMessages, resolveMemoryServices, loadContextMessages, trimMessages, getWorkingMemoryMiddleware, } from './ai-agent-memory.js';
2
- import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope, assertResourceOwner, assertAgentAuthorized, } from './ai-agent-prepare.js';
2
+ import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope, assertResourcePrincipalOwner, assertAgentAuthorized, } from './ai-agent-prepare.js';
3
3
  import { checkForApprovals, appendStepMessages } from './ai-agent-stream.js';
4
+ import { AgentInterruptedError, isAbortError, persistOrphanedToolResults, registerInterruptibleRun, trackInterruptNote, trackToolExecution, } from './ai-agent-interrupt.js';
4
5
  import { pikkuState, getSingletonServices } from '../../pikku-state.js';
5
6
  import { resolveModelConfig } from './ai-agent-model-config.js';
6
7
  import { AIProviderNotConfiguredError } from '../../errors/errors.js';
@@ -72,6 +73,8 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
72
73
  }),
73
74
  ...(agent.aiMiddleware ?? []),
74
75
  ];
76
+ // One bag per run, shared by every middleware — see PikkuAIMiddlewareHooks.
77
+ const sharedNotes = {};
75
78
  let modifiedMessages = runnerParams.messages;
76
79
  let modifiedInstructions = runnerParams.instructions;
77
80
  for (const mw of aiMiddlewares) {
@@ -79,6 +82,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
79
82
  const result = await mw.modifyInput(singletonServices, {
80
83
  messages: modifiedMessages,
81
84
  instructions: modifiedInstructions,
85
+ shared: sharedNotes,
82
86
  });
83
87
  modifiedMessages = result.messages;
84
88
  modifiedInstructions = result.instructions;
@@ -86,6 +90,12 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
86
90
  }
87
91
  runnerParams.messages = modifiedMessages;
88
92
  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.
97
+ const lastModified = modifiedMessages[modifiedMessages.length - 1];
98
+ const persistedUserMessage = lastModified?.id === userMessage.id ? lastModified : userMessage;
89
99
  const runId = await aiRunState.createRun({
90
100
  agentName,
91
101
  threadId,
@@ -95,6 +105,13 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
95
105
  createdAt: new Date(),
96
106
  updatedAt: new Date(),
97
107
  });
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.
112
+ const interruptHandle = registerInterruptibleRun(runId);
113
+ runnerParams.abortSignal = interruptHandle.signal;
114
+ runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
98
115
  try {
99
116
  const accumulatedSteps = [];
100
117
  const totalUsage = { inputTokens: 0, outputTokens: 0 };
@@ -146,7 +163,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
146
163
  });
147
164
  if (stepResult.toolCalls.length === 0)
148
165
  break;
149
- const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools, runId);
166
+ const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools);
150
167
  if (approvalsNeeded.length > 0) {
151
168
  for (const approval of approvalsNeeded) {
152
169
  const toolDef = runnerParams.tools.find((t) => t.name === approval.toolName);
@@ -154,9 +171,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
154
171
  try {
155
172
  approval.reason = await toolDef.approvalDescriptionFn(approval.args);
156
173
  }
157
- catch {
158
- // If description generation fails, continue without it
159
- }
174
+ catch { }
160
175
  }
161
176
  }
162
177
  const pendingApprovals = approvalsNeeded.map((a) => a.agentRunId
@@ -175,7 +190,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
175
190
  args: a.args,
176
191
  });
177
192
  const completedStepsForSave = accumulatedSteps.slice(0, -1);
178
- await saveMessages(storage, threadId, input.resourceId, memoryConfig, userMessage, { text: '', steps: completedStepsForSave });
193
+ await saveMessages(storage, threadId, input.resourceId, memoryConfig, persistedUserMessage, { text: '', steps: completedStepsForSave });
179
194
  if (storage) {
180
195
  await storage.saveMessages(threadId, [
181
196
  {
@@ -236,7 +251,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
236
251
  outputMessages = modResult.messages;
237
252
  }
238
253
  }
239
- await saveMessages(storage, threadId, input.resourceId, memoryConfig, userMessage, {
254
+ await saveMessages(storage, threadId, input.resourceId, memoryConfig, persistedUserMessage, {
240
255
  ...result,
241
256
  text: outputText,
242
257
  uiSpec: structuredOutput.uiSpec,
@@ -255,6 +270,18 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
255
270
  };
256
271
  }
257
272
  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.
277
+ const interruption = interruptHandle.interruption;
278
+ if (interruption || isAbortError(error)) {
279
+ await aiRunState.updateRun(runId, { status: 'interrupted' });
280
+ if (storage) {
281
+ trackInterruptNote(threadId, persistOrphanedToolResults(interruptHandle, storage, threadId));
282
+ }
283
+ throw new AgentInterruptedError(runId, interruption ?? { reason: 'user' });
284
+ }
258
285
  for (const mw of aiMiddlewares) {
259
286
  if (mw.onError) {
260
287
  try {
@@ -264,9 +291,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
264
291
  messages: runnerParams.messages,
265
292
  });
266
293
  }
267
- catch {
268
- // onError hooks must not affect error flow
269
- }
294
+ catch { }
270
295
  }
271
296
  }
272
297
  await aiRunState.updateRun(runId, {
@@ -275,6 +300,9 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
275
300
  });
276
301
  throw error;
277
302
  }
303
+ finally {
304
+ interruptHandle.release();
305
+ }
278
306
  }
279
307
  export async function resumeAIAgentSync(runId, approvals, params, expectedAgentName) {
280
308
  const singletonServices = getSingletonServices();
@@ -285,7 +313,7 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
285
313
  const run = await aiRunState.getRun(runId);
286
314
  if (!run)
287
315
  throw new Error(`No run found for runId ${runId}`);
288
- assertResourceOwner(resolveOwnerResourceId(params, agentSessionScope(run.agentName), run.resourceId), run.resourceId, 'run');
316
+ assertResourcePrincipalOwner(params, agentSessionScope(run.agentName), run.resourceId, 'run');
289
317
  if (expectedAgentName && run.agentName !== expectedAgentName) {
290
318
  throw new Error(`Run ${runId} belongs to agent '${run.agentName}', not '${expectedAgentName}'`);
291
319
  }
@@ -293,9 +321,6 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
293
321
  throw new Error(`Run ${runId} is not suspended (status: ${run.status})`);
294
322
  }
295
323
  const { agent, packageName, resolvedName } = resolveAgent(run.agentName);
296
- // Resuming re-runs the agent, so it re-runs the agent's gate. Run ownership
297
- // alone is not enough: a grant revoked while the run was suspended must stop
298
- // the caller from approving its pending tool calls.
299
324
  await assertAgentAuthorized(agent, params, packageName);
300
325
  const { storage } = resolveMemoryServices(agent, singletonServices);
301
326
  const memoryConfig = agent.memory;
@@ -328,7 +353,6 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
328
353
  const rawArgs = typeof pending.args === 'string'
329
354
  ? JSON.parse(pending.args)
330
355
  : pending.args;
331
- // Strip null values recursively — LLMs send null for optional fields but Zod expects undefined
332
356
  const toolArgs = stripNulls(rawArgs) ?? {};
333
357
  try {
334
358
  const toolResult = await matchingTool.execute(toolArgs);
@@ -401,6 +425,8 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
401
425
  }),
402
426
  ...(agent.aiMiddleware ?? []),
403
427
  ];
428
+ // One bag per run, shared by every middleware — see PikkuAIMiddlewareHooks.
429
+ const sharedNotes = {};
404
430
  let modifiedMessages = trimmedMessages;
405
431
  let modifiedInstructions = instructions;
406
432
  for (const mw of aiMiddlewares) {
@@ -408,6 +434,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
408
434
  const result = await mw.modifyInput(singletonServices, {
409
435
  messages: modifiedMessages,
410
436
  instructions: modifiedInstructions,
437
+ shared: sharedNotes,
411
438
  });
412
439
  modifiedMessages = result.messages;
413
440
  modifiedInstructions = result.instructions;
@@ -424,11 +451,18 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
424
451
  tools: resumeTools,
425
452
  maxSteps: 1,
426
453
  toolChoice: (agent.toolChoice ?? 'auto'),
454
+ providerOptions: agent.providerOptions,
427
455
  outputSchema: meta?.outputSchema
428
456
  ? pikkuState(packageName, 'misc', 'schemas').get(meta.outputSchema)
429
457
  : undefined,
430
458
  agentId: run.agentName,
431
459
  };
460
+ // A resumed run keeps its original runId, so the handle registered for the
461
+ // first leg is long gone — an approval that kicks off more generation has to
462
+ // be interruptible on its own terms.
463
+ const interruptHandle = registerInterruptibleRun(run.runId);
464
+ runnerParams.abortSignal = interruptHandle.signal;
465
+ runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
432
466
  try {
433
467
  const accumulatedSteps = [];
434
468
  const totalUsage = { inputTokens: 0, outputTokens: 0 };
@@ -465,7 +499,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
465
499
  });
466
500
  if (stepResult.toolCalls.length === 0)
467
501
  break;
468
- const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools, run.runId);
502
+ const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools);
469
503
  if (approvalsNeeded.length > 0) {
470
504
  for (const approval of approvalsNeeded) {
471
505
  const toolDef = runnerParams.tools.find((t) => t.name === approval.toolName);
@@ -473,9 +507,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
473
507
  try {
474
508
  approval.reason = await toolDef.approvalDescriptionFn(approval.args);
475
509
  }
476
- catch {
477
- // ignore
478
- }
510
+ catch { }
479
511
  }
480
512
  }
481
513
  const pendingApprovals = approvalsNeeded.map((a) => a.agentRunId
@@ -574,6 +606,14 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
574
606
  };
575
607
  }
576
608
  catch (error) {
609
+ const interruption = interruptHandle.interruption;
610
+ if (interruption || isAbortError(error)) {
611
+ await aiRunState.updateRun(run.runId, { status: 'interrupted' });
612
+ if (storage) {
613
+ trackInterruptNote(run.threadId, persistOrphanedToolResults(interruptHandle, storage, run.threadId));
614
+ }
615
+ throw new AgentInterruptedError(run.runId, interruption ?? { reason: 'user' });
616
+ }
577
617
  for (const mw of aiMiddlewares) {
578
618
  if (mw.onError) {
579
619
  try {
@@ -583,9 +623,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
583
623
  messages: runnerParams.messages,
584
624
  });
585
625
  }
586
- catch {
587
- // ignore
588
- }
626
+ catch { }
589
627
  }
590
628
  }
591
629
  await aiRunState.updateRun(run.runId, {
@@ -594,4 +632,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
594
632
  });
595
633
  throw error;
596
634
  }
635
+ finally {
636
+ interruptHandle.release();
637
+ }
597
638
  }