@pikku/core 0.12.72 → 0.12.74

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 (811) hide show
  1. package/CHANGELOG.md +793 -0
  2. package/dist/crypto-utils.d.ts +30 -5
  3. package/dist/crypto-utils.js +146 -41
  4. package/dist/dev/hot-reload.js +11 -30
  5. package/dist/dev/module-runner.d.ts +3 -7
  6. package/dist/dev/module-runner.js +4 -10
  7. package/dist/dev/reload-meta.d.ts +8 -20
  8. package/dist/dev/reload-meta.js +9 -29
  9. package/dist/errors/error-handler.d.ts +5 -30
  10. package/dist/errors/error-handler.js +16 -32
  11. package/dist/errors/errors.d.ts +32 -151
  12. package/dist/errors/errors.js +55 -157
  13. package/dist/function/abort-scope.d.ts +47 -0
  14. package/dist/function/abort-scope.js +63 -0
  15. package/dist/function/function-runner.js +37 -32
  16. package/dist/function/functions.types.d.ts +44 -136
  17. package/dist/function/functions.types.js +0 -58
  18. package/dist/function/list.types.d.ts +12 -62
  19. package/dist/function/list.types.js +4 -25
  20. package/dist/handle-error.d.ts +0 -13
  21. package/dist/handle-error.js +0 -18
  22. package/dist/index.d.ts +5 -2
  23. package/dist/index.js +4 -1
  24. package/dist/middleware/auth-apikey.d.ts +3 -18
  25. package/dist/middleware/auth-apikey.js +0 -17
  26. package/dist/middleware/auth-bearer.d.ts +6 -41
  27. package/dist/middleware/auth-bearer.js +3 -40
  28. package/dist/middleware/auth-cookie.d.ts +5 -27
  29. package/dist/middleware/auth-cookie.js +2 -26
  30. package/dist/middleware/cors.d.ts +7 -34
  31. package/dist/middleware/cors.js +7 -34
  32. package/dist/middleware/remote-auth.d.ts +3 -1
  33. package/dist/middleware/remote-auth.js +3 -2
  34. package/dist/middleware/telemetry.d.ts +8 -33
  35. package/dist/middleware/telemetry.js +2 -31
  36. package/dist/middleware-runner.d.ts +4 -55
  37. package/dist/middleware-runner.js +5 -74
  38. package/dist/permissions.d.ts +3 -44
  39. package/dist/permissions.js +19 -71
  40. package/dist/pikku-request.d.ts +0 -6
  41. package/dist/pikku-request.js +0 -6
  42. package/dist/pikku-state.d.ts +0 -26
  43. package/dist/pikku-state.js +2 -30
  44. package/dist/remote.d.ts +3 -5
  45. package/dist/remote.js +8 -7
  46. package/dist/schema.d.ts +5 -39
  47. package/dist/schema.js +5 -39
  48. package/dist/scopes.d.ts +4 -23
  49. package/dist/scopes.js +7 -48
  50. package/dist/services/ai-agent-runner-service.d.ts +20 -0
  51. package/dist/services/ai-embedding-service.d.ts +2 -25
  52. package/dist/services/audit-service.js +1 -2
  53. package/dist/services/content-service.d.ts +1 -46
  54. package/dist/services/credential-service.d.ts +3 -40
  55. package/dist/services/deployment-service.d.ts +3 -9
  56. package/dist/services/gateway-service.d.ts +0 -15
  57. package/dist/services/http-personas.d.ts +80 -0
  58. package/dist/services/http-personas.js +233 -0
  59. package/dist/services/in-memory-queue-service.d.ts +0 -14
  60. package/dist/services/in-memory-queue-service.js +1 -15
  61. package/dist/services/in-memory-trigger-service.d.ts +0 -18
  62. package/dist/services/in-memory-trigger-service.js +1 -18
  63. package/dist/services/in-memory-workflow-service.d.ts +0 -16
  64. package/dist/services/in-memory-workflow-service.js +4 -33
  65. package/dist/services/index.d.ts +5 -6
  66. package/dist/services/index.js +2 -5
  67. package/dist/services/istanbul-coverage-service.d.ts +1 -5
  68. package/dist/services/istanbul-coverage-service.js +2 -8
  69. package/dist/services/jwt-service.d.ts +1 -16
  70. package/dist/services/local-content.d.ts +13 -2
  71. package/dist/services/local-content.js +40 -13
  72. package/dist/services/local-gateway-service.d.ts +0 -16
  73. package/dist/services/local-gateway-service.js +2 -17
  74. package/dist/services/local-secrets.d.ts +0 -4
  75. package/dist/services/local-secrets.js +0 -4
  76. package/dist/services/logger-console.d.ts +3 -7
  77. package/dist/services/logger-console.js +3 -7
  78. package/dist/services/logger.d.ts +2 -37
  79. package/dist/services/meta-service.d.ts +23 -26
  80. package/dist/services/meta-service.js +22 -36
  81. package/dist/services/personas-service.d.ts +134 -0
  82. package/dist/services/personas-service.js +40 -0
  83. package/dist/services/pikku-user-id.js +0 -4
  84. package/dist/services/queue-webhook-service.d.ts +2 -36
  85. package/dist/services/queue-webhook-service.js +9 -41
  86. package/dist/services/scheduler-service.d.ts +1 -50
  87. package/dist/services/scheduler-service.js +0 -10
  88. package/dist/services/schema-service.d.ts +1 -24
  89. package/dist/services/scope-service.d.ts +49 -34
  90. package/dist/services/scoped-secret-service.d.ts +0 -4
  91. package/dist/services/scoped-secret-service.js +0 -4
  92. package/dist/services/secret-host-binding.d.ts +8 -0
  93. package/dist/services/secret-host-binding.js +36 -0
  94. package/dist/services/secret-service.d.ts +5 -33
  95. package/dist/services/secretless.d.ts +6 -0
  96. package/dist/services/secretless.js +21 -0
  97. package/dist/services/stub-tracker.d.ts +7 -18
  98. package/dist/services/stub-tracker.js +8 -18
  99. package/dist/services/system-role-guard.d.ts +33 -0
  100. package/dist/services/system-role-guard.js +38 -0
  101. package/dist/services/trigger-service.d.ts +0 -12
  102. package/dist/services/typed-secret-service.d.ts +0 -7
  103. package/dist/services/typed-secret-service.js +1 -7
  104. package/dist/services/v8-coverage-service.d.ts +2 -3
  105. package/dist/services/v8-coverage-service.js +1 -2
  106. package/dist/services/variables-service.d.ts +1 -8
  107. package/dist/services/webhook-service.d.ts +19 -63
  108. package/dist/services/webhook-service.js +6 -20
  109. package/dist/services/workflow-service.d.ts +3 -15
  110. package/dist/testing/service-tests.js +0 -17
  111. package/dist/time-utils.d.ts +0 -16
  112. package/dist/time-utils.js +1 -19
  113. package/dist/types/core.types.d.ts +99 -219
  114. package/dist/types/core.types.js +0 -42
  115. package/dist/types/state.types.d.ts +4 -9
  116. package/dist/utils/hmac.d.ts +4 -10
  117. package/dist/utils/hmac.js +4 -10
  118. package/dist/utils/safe-fetch.d.ts +7 -35
  119. package/dist/utils/safe-fetch.js +13 -53
  120. package/dist/utils.d.ts +1 -6
  121. package/dist/utils.js +6 -15
  122. package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
  123. package/dist/wirings/actor-flow/index.d.ts +0 -9
  124. package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
  125. package/dist/wirings/actor-flow/run-conversation.js +14 -7
  126. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
  127. package/dist/wirings/ai-agent/ai-agent-agui.js +34 -12
  128. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
  129. package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
  130. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
  131. package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
  132. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
  133. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
  134. package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
  135. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
  136. package/dist/wirings/ai-agent/ai-agent-prepare.js +58 -131
  137. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
  138. package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
  139. package/dist/wirings/ai-agent/ai-agent-runner.js +49 -20
  140. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
  141. package/dist/wirings/ai-agent/ai-agent-stream.js +153 -63
  142. package/dist/wirings/ai-agent/ai-agent.types.d.ts +84 -4
  143. package/dist/wirings/ai-agent/index.d.ts +6 -4
  144. package/dist/wirings/ai-agent/index.js +5 -4
  145. package/dist/wirings/ai-agent/voice-input.d.ts +39 -1
  146. package/dist/wirings/ai-agent/voice-input.js +46 -3
  147. package/dist/wirings/ai-agent/voice-output.d.ts +54 -1
  148. package/dist/wirings/ai-agent/voice-output.js +153 -50
  149. package/dist/wirings/channel/channel-common.d.ts +7 -20
  150. package/dist/wirings/channel/channel-common.js +7 -21
  151. package/dist/wirings/channel/channel-handler.js +25 -6
  152. package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
  153. package/dist/wirings/channel/channel-host-rpc.js +38 -0
  154. package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
  155. package/dist/wirings/channel/channel-middleware-runner.js +0 -12
  156. package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
  157. package/dist/wirings/channel/channel-rpc-registry.js +89 -0
  158. package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
  159. package/dist/wirings/channel/channel-rpc-responder.js +71 -0
  160. package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
  161. package/dist/wirings/channel/channel-rpc-service.js +106 -0
  162. package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
  163. package/dist/wirings/channel/channel-rpc-validators.js +30 -0
  164. package/dist/wirings/channel/channel-rpc.d.ts +5 -0
  165. package/dist/wirings/channel/channel-rpc.js +5 -0
  166. package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
  167. package/dist/wirings/channel/channel-rpc.types.js +50 -0
  168. package/dist/wirings/channel/channel-runner.d.ts +0 -4
  169. package/dist/wirings/channel/channel-runner.js +0 -14
  170. package/dist/wirings/channel/channel-store.d.ts +0 -10
  171. package/dist/wirings/channel/channel.types.d.ts +12 -1
  172. package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
  173. package/dist/wirings/channel/define-channel-routes.js +0 -20
  174. package/dist/wirings/channel/eventhub-service.d.ts +0 -18
  175. package/dist/wirings/channel/index.d.ts +4 -1
  176. package/dist/wirings/channel/index.js +2 -0
  177. package/dist/wirings/channel/local/local-channel-runner.js +3 -1
  178. package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
  179. package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
  180. package/dist/wirings/channel/log-channels.d.ts +0 -4
  181. package/dist/wirings/channel/log-channels.js +0 -4
  182. package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
  183. package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
  184. package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
  185. package/dist/wirings/cli/channel/cli-approval.js +81 -0
  186. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
  187. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
  188. package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
  189. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
  190. package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +20 -0
  191. package/dist/wirings/cli/channel/cli-raw-client-runner.js +121 -0
  192. package/dist/wirings/cli/channel/index.d.ts +4 -0
  193. package/dist/wirings/cli/channel/index.js +2 -0
  194. package/dist/wirings/cli/cli-runner.d.ts +20 -20
  195. package/dist/wirings/cli/cli-runner.js +28 -89
  196. package/dist/wirings/cli/cli.types.d.ts +14 -3
  197. package/dist/wirings/cli/command-parser.d.ts +1 -10
  198. package/dist/wirings/cli/command-parser.js +10 -87
  199. package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
  200. package/dist/wirings/cli/define-cli-commands.js +1 -17
  201. package/dist/wirings/credential/credential.types.d.ts +0 -12
  202. package/dist/wirings/credential/define-credential.d.ts +48 -0
  203. package/dist/wirings/credential/define-credential.js +47 -0
  204. package/dist/wirings/credential/index.d.ts +1 -1
  205. package/dist/wirings/credential/index.js +1 -1
  206. package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
  207. package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
  208. package/dist/wirings/gateway/gateway-runner.js +8 -105
  209. package/dist/wirings/gateway/gateway.types.d.ts +7 -80
  210. package/dist/wirings/http/http-routes.d.ts +0 -63
  211. package/dist/wirings/http/http-routes.js +0 -63
  212. package/dist/wirings/http/http-runner.d.ts +0 -99
  213. package/dist/wirings/http/http-runner.js +9 -165
  214. package/dist/wirings/http/http.types.d.ts +14 -55
  215. package/dist/wirings/http/log-http-routes.d.ts +0 -4
  216. package/dist/wirings/http/log-http-routes.js +0 -4
  217. package/dist/wirings/http/pikku-fetch-http-request.d.ts +0 -40
  218. package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
  219. package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
  220. package/dist/wirings/http/routers/path-to-regex.js +2 -13
  221. package/dist/wirings/http/web-request.d.ts +0 -8
  222. package/dist/wirings/http/web-request.js +25 -17
  223. package/dist/wirings/mcp/mcp-runner.d.ts +1 -4
  224. package/dist/wirings/mcp/mcp-runner.js +1 -14
  225. package/dist/wirings/mcp/mcp.types.d.ts +2 -35
  226. package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
  227. package/dist/wirings/oauth2/oauth2.types.js +0 -3
  228. package/dist/wirings/persona/define-personas.d.ts +28 -0
  229. package/dist/wirings/persona/define-personas.js +27 -0
  230. package/dist/wirings/persona/index.d.ts +21 -0
  231. package/dist/wirings/persona/index.js +17 -0
  232. package/dist/wirings/persona/persona-email.d.ts +37 -0
  233. package/dist/wirings/persona/persona-email.js +69 -0
  234. package/dist/wirings/persona/persona-environments.d.ts +45 -0
  235. package/dist/wirings/persona/persona-environments.js +81 -0
  236. package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
  237. package/dist/wirings/persona/persona-mailbox.js +53 -0
  238. package/dist/wirings/persona/persona.types.d.ts +125 -0
  239. package/dist/wirings/persona/persona.types.js +1 -0
  240. package/dist/wirings/persona/validate-personas.d.ts +53 -0
  241. package/dist/wirings/persona/validate-personas.js +94 -0
  242. package/dist/wirings/queue/index.d.ts +3 -0
  243. package/dist/wirings/queue/index.js +2 -3
  244. package/dist/wirings/queue/queue-identity.d.ts +28 -0
  245. package/dist/wirings/queue/queue-identity.js +102 -0
  246. package/dist/wirings/queue/queue-runner.d.ts +0 -19
  247. package/dist/wirings/queue/queue-runner.js +9 -30
  248. package/dist/wirings/queue/queue.types.d.ts +18 -89
  249. package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
  250. package/dist/wirings/queue/register-queue-helper.js +0 -11
  251. package/dist/wirings/queue/signed-queue-service.d.ts +16 -0
  252. package/dist/wirings/queue/signed-queue-service.js +42 -0
  253. package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
  254. package/dist/wirings/queue/validate-worker-config.js +0 -14
  255. package/dist/wirings/role/define-system-role.d.ts +32 -0
  256. package/dist/wirings/role/define-system-role.js +31 -0
  257. package/dist/wirings/role/index.d.ts +3 -0
  258. package/dist/wirings/role/index.js +2 -0
  259. package/dist/wirings/role/role.types.d.ts +43 -0
  260. package/dist/wirings/role/role.types.js +1 -0
  261. package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
  262. package/dist/wirings/role/validate-role-definitions.js +71 -0
  263. package/dist/wirings/rpc/addon-runner.d.ts +0 -19
  264. package/dist/wirings/rpc/addon-runner.js +0 -51
  265. package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -12
  266. package/dist/wirings/rpc/remote-addon-auth.js +1 -9
  267. package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
  268. package/dist/wirings/rpc/rpc-runner.js +88 -105
  269. package/dist/wirings/rpc/rpc-types.d.ts +7 -6
  270. package/dist/wirings/rpc/wire-addon.d.ts +25 -0
  271. package/dist/wirings/rpc/wire-addon.js +62 -0
  272. package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
  273. package/dist/wirings/rpc/wire-remote-addon.js +0 -8
  274. package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
  275. package/dist/wirings/scheduler/log-schedulers.js +0 -4
  276. package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
  277. package/dist/wirings/scheduler/scheduler-runner.js +0 -1
  278. package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
  279. package/dist/wirings/scope/define-scope.d.ts +32 -0
  280. package/dist/wirings/scope/define-scope.js +31 -0
  281. package/dist/wirings/scope/index.d.ts +1 -1
  282. package/dist/wirings/scope/index.js +1 -1
  283. package/dist/wirings/scope/scope.types.d.ts +7 -9
  284. package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
  285. package/dist/wirings/scope/validate-scope-definitions.js +3 -21
  286. package/dist/wirings/secret/index.d.ts +1 -1
  287. package/dist/wirings/secret/index.js +1 -1
  288. package/dist/wirings/secret/secret.types.d.ts +19 -15
  289. package/dist/wirings/secret/secret.types.js +1 -1
  290. package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
  291. package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
  292. package/dist/wirings/trigger/trigger-runner.js +1 -24
  293. package/dist/wirings/trigger/trigger.types.d.ts +1 -82
  294. package/dist/wirings/trigger/trigger.types.js +0 -34
  295. package/dist/wirings/variable/index.d.ts +1 -1
  296. package/dist/wirings/variable/index.js +1 -1
  297. package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
  298. package/dist/wirings/variable/variable.types.d.ts +1 -13
  299. package/dist/wirings/variable/variable.types.js +1 -1
  300. package/dist/wirings/virtual-user/index.d.ts +27 -0
  301. package/dist/wirings/virtual-user/index.js +8 -0
  302. package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
  303. package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
  304. package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
  305. package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
  306. package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
  307. package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
  308. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
  309. package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
  310. package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
  311. package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
  312. package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
  313. package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
  314. package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
  315. package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
  316. package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
  317. package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
  318. package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
  319. package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
  320. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +5 -5
  321. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
  322. package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
  323. package/dist/wirings/workflow/feature.d.ts +0 -19
  324. package/dist/wirings/workflow/feature.js +0 -19
  325. package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
  326. package/dist/wirings/workflow/graph/graph-node.js +0 -34
  327. package/dist/wirings/workflow/graph/graph-runner.js +6 -41
  328. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
  329. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
  330. package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
  331. package/dist/wirings/workflow/index.d.ts +5 -7
  332. package/dist/wirings/workflow/index.js +3 -17
  333. package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
  334. package/dist/wirings/workflow/pikku-scenario-service.js +204 -42
  335. package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
  336. package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
  337. package/dist/wirings/workflow/run-timeline.d.ts +0 -47
  338. package/dist/wirings/workflow/run-timeline.js +0 -22
  339. package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
  340. package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
  341. package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
  342. package/dist/wirings/workflow/scenario-poll.js +0 -12
  343. package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
  344. package/dist/wirings/workflow/scenario-prose.js +0 -18
  345. package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
  346. package/dist/wirings/workflow/scenario-step-guards.js +1 -14
  347. package/dist/wirings/workflow/scenario-step.types.d.ts +72 -6
  348. package/dist/wirings/workflow/scenario-step.types.js +5 -1
  349. package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
  350. package/dist/wirings/workflow/scenario-surface.js +56 -0
  351. package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
  352. package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
  353. package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
  354. package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
  355. package/dist/wirings/workflow/workflow.types.d.ts +0 -197
  356. package/knowledge/decisions/index.md +19 -0
  357. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
  358. package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
  359. package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
  360. package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
  361. package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
  362. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
  363. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
  364. package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
  365. package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
  366. package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
  367. package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
  368. package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
  369. package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
  370. package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
  371. package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
  372. package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
  373. package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
  374. package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
  375. package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
  376. package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
  377. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
  378. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
  379. package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
  380. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
  381. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
  382. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
  383. package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
  384. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
  385. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +34 -0
  386. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
  387. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
  388. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
  389. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
  390. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
  391. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
  392. package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
  393. package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
  394. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
  395. package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
  396. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
  397. package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
  398. package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
  399. package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
  400. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
  401. package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
  402. package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
  403. package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
  404. package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
  405. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
  406. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
  407. package/knowledge/decisions/internals/index.md +113 -0
  408. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
  409. package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
  410. package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
  411. package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
  412. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
  413. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
  414. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
  415. package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
  416. package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
  417. package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
  418. package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
  419. package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
  420. package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
  421. package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
  422. package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
  423. package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
  424. package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
  425. package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
  426. package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
  427. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
  428. package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
  429. package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
  430. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
  431. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
  432. package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
  433. package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
  434. package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
  435. package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
  436. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
  437. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
  438. package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
  439. package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
  440. package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
  441. package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
  442. package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
  443. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
  444. package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
  445. package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
  446. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
  447. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
  448. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
  449. package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
  450. package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
  451. package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
  452. package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
  453. package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
  454. package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
  455. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
  456. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
  457. package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
  458. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
  459. package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
  460. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
  461. package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
  462. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
  463. package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
  464. package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
  465. package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
  466. package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
  467. package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
  468. package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
  469. package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
  470. package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
  471. package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
  472. package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
  473. package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
  474. package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
  475. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
  476. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
  477. package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
  478. package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
  479. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
  480. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
  481. package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
  482. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
  483. package/knowledge/decisions/security/index.md +55 -0
  484. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
  485. package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
  486. package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
  487. package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
  488. package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
  489. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
  490. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
  491. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
  492. package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
  493. package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
  494. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
  495. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
  496. package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
  497. package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
  498. package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
  499. package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
  500. package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
  501. package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
  502. package/knowledge/index.md +24 -0
  503. package/knowledge/questions/index.md +15 -0
  504. package/package.json +4 -1
  505. package/run-tests.sh +0 -0
  506. package/src/crypto-utils.test.ts +460 -19
  507. package/src/crypto-utils.ts +283 -55
  508. package/src/data-classification.ts +1 -7
  509. package/src/dev/hot-reload.test.ts +0 -4
  510. package/src/dev/hot-reload.ts +11 -30
  511. package/src/dev/module-runner.ts +7 -32
  512. package/src/dev/reload-meta.ts +9 -29
  513. package/src/errors/error-handler.ts +20 -35
  514. package/src/errors/error.test.ts +30 -1
  515. package/src/errors/errors.ts +73 -157
  516. package/src/function/abort-scope.test.ts +97 -0
  517. package/src/function/abort-scope.ts +80 -0
  518. package/src/function/function-runner.test.ts +0 -7
  519. package/src/function/function-runner.ts +62 -32
  520. package/src/function/functions.types.ts +56 -136
  521. package/src/function/list.types.test.ts +3 -25
  522. package/src/function/list.types.ts +12 -62
  523. package/src/handle-error.ts +0 -18
  524. package/src/index.ts +60 -1
  525. package/src/middleware/auth-apikey.test.ts +0 -1
  526. package/src/middleware/auth-apikey.ts +0 -17
  527. package/src/middleware/auth-bearer.test.ts +0 -3
  528. package/src/middleware/auth-bearer.ts +3 -40
  529. package/src/middleware/auth-cookie.test.ts +0 -6
  530. package/src/middleware/auth-cookie.ts +2 -26
  531. package/src/middleware/cors.test.ts +34 -0
  532. package/src/middleware/cors.ts +12 -33
  533. package/src/middleware/remote-auth.test.ts +24 -9
  534. package/src/middleware/remote-auth.ts +10 -2
  535. package/src/middleware/telemetry.ts +2 -31
  536. package/src/middleware-runner.test.ts +0 -2
  537. package/src/middleware-runner.ts +5 -74
  538. package/src/permissions.test.ts +30 -0
  539. package/src/permissions.ts +24 -74
  540. package/src/pikku-request.ts +0 -6
  541. package/src/pikku-state.ts +2 -30
  542. package/src/production-barrels-stay-lean.test.ts +110 -0
  543. package/src/remote.test.ts +172 -0
  544. package/src/remote.ts +17 -7
  545. package/src/schema.ts +5 -39
  546. package/src/scopes.ts +7 -48
  547. package/src/services/ai-agent-runner-service.ts +20 -0
  548. package/src/services/ai-embedding-service.ts +3 -25
  549. package/src/services/audit-service.ts +1 -2
  550. package/src/services/content-service.ts +1 -46
  551. package/src/services/credential-service.ts +3 -40
  552. package/src/services/credential-wire-service.test.ts +0 -2
  553. package/src/services/deployment-service.ts +3 -9
  554. package/src/services/gateway-service.ts +0 -15
  555. package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
  556. package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
  557. package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
  558. package/src/services/in-memory-queue-service.ts +1 -15
  559. package/src/services/in-memory-trigger-service.ts +1 -18
  560. package/src/services/in-memory-workflow-service.test.ts +0 -13
  561. package/src/services/in-memory-workflow-service.ts +4 -38
  562. package/src/services/index.ts +20 -15
  563. package/src/services/istanbul-coverage-service.ts +2 -8
  564. package/src/services/jwt-service.ts +1 -16
  565. package/src/services/local-content.test.ts +159 -27
  566. package/src/services/local-content.ts +55 -23
  567. package/src/services/local-gateway-service.ts +2 -17
  568. package/src/services/local-secrets.ts +0 -4
  569. package/src/services/logger-console.test.ts +0 -1
  570. package/src/services/logger-console.ts +3 -7
  571. package/src/services/logger.ts +2 -37
  572. package/src/services/meta-service.test.ts +1 -5
  573. package/src/services/meta-service.ts +41 -61
  574. package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
  575. package/src/services/pikku-user-id.ts +0 -4
  576. package/src/services/queue-webhook-service.ts +9 -41
  577. package/src/services/scheduler-service.ts +1 -50
  578. package/src/services/schema-service.ts +1 -24
  579. package/src/services/scope-service.ts +50 -34
  580. package/src/services/scoped-secret-service.ts +0 -4
  581. package/src/services/secret-host-binding.test.ts +138 -0
  582. package/src/services/secret-host-binding.ts +51 -0
  583. package/src/services/secret-service.ts +5 -33
  584. package/src/services/secretless.test.ts +54 -0
  585. package/src/services/secretless.ts +29 -0
  586. package/src/services/stub-tracker.ts +8 -18
  587. package/src/services/system-role-guard.test.ts +93 -0
  588. package/src/services/system-role-guard.ts +71 -0
  589. package/src/services/trigger-service.ts +0 -12
  590. package/src/services/typed-secret-service.ts +1 -7
  591. package/src/services/v8-coverage-service.ts +3 -6
  592. package/src/services/variables-service.ts +1 -8
  593. package/src/services/webhook-service.ts +19 -63
  594. package/src/services/workflow-service.ts +3 -20
  595. package/src/testing/service-tests.ts +0 -26
  596. package/src/time-utils.ts +1 -19
  597. package/src/types/core.types.ts +116 -229
  598. package/src/types/state.types.ts +7 -9
  599. package/src/utils/hmac.ts +4 -10
  600. package/src/utils/safe-fetch.ts +13 -54
  601. package/src/utils.test.ts +11 -2
  602. package/src/utils.ts +6 -15
  603. package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
  604. package/src/wirings/actor-flow/index.ts +0 -9
  605. package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
  606. package/src/wirings/actor-flow/run-conversation.ts +19 -12
  607. package/src/wirings/ai-agent/ai-agent-agui.test.ts +75 -10
  608. package/src/wirings/ai-agent/ai-agent-agui.ts +36 -17
  609. package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
  610. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
  611. package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
  612. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
  613. package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
  614. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
  615. package/src/wirings/ai-agent/ai-agent-prepare.ts +82 -138
  616. package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
  617. package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
  618. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
  619. package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
  620. package/src/wirings/ai-agent/ai-agent-runner.ts +67 -33
  621. package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
  622. package/src/wirings/ai-agent/ai-agent-stream.ts +192 -75
  623. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
  624. package/src/wirings/ai-agent/ai-agent.types.ts +85 -4
  625. package/src/wirings/ai-agent/index.ts +35 -3
  626. package/src/wirings/ai-agent/voice-input.test.ts +72 -7
  627. package/src/wirings/ai-agent/voice-input.ts +48 -3
  628. package/src/wirings/ai-agent/voice-output.test.ts +422 -0
  629. package/src/wirings/ai-agent/voice-output.ts +216 -56
  630. package/src/wirings/channel/channel-common.ts +15 -20
  631. package/src/wirings/channel/channel-handler.test.ts +50 -0
  632. package/src/wirings/channel/channel-handler.ts +32 -11
  633. package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
  634. package/src/wirings/channel/channel-host-rpc.ts +69 -0
  635. package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
  636. package/src/wirings/channel/channel-middleware-runner.ts +0 -12
  637. package/src/wirings/channel/channel-rpc-registry.ts +116 -0
  638. package/src/wirings/channel/channel-rpc-responder.ts +117 -0
  639. package/src/wirings/channel/channel-rpc-service.ts +146 -0
  640. package/src/wirings/channel/channel-rpc-validators.ts +65 -0
  641. package/src/wirings/channel/channel-rpc.test.ts +820 -0
  642. package/src/wirings/channel/channel-rpc.ts +5 -0
  643. package/src/wirings/channel/channel-rpc.types.ts +150 -0
  644. package/src/wirings/channel/channel-runner.ts +0 -14
  645. package/src/wirings/channel/channel-store.ts +0 -10
  646. package/src/wirings/channel/channel.types.ts +19 -8
  647. package/src/wirings/channel/define-channel-routes.ts +0 -20
  648. package/src/wirings/channel/eventhub-service.ts +0 -18
  649. package/src/wirings/channel/index.ts +35 -0
  650. package/src/wirings/channel/local/local-channel-handler.ts +3 -1
  651. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
  652. package/src/wirings/channel/local/local-channel-runner.ts +3 -1
  653. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
  654. package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
  655. package/src/wirings/channel/log-channels.ts +0 -4
  656. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
  657. package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
  658. package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
  659. package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
  660. package/src/wirings/cli/channel/cli-approval.ts +135 -0
  661. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
  662. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
  663. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
  664. package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
  665. package/src/wirings/cli/channel/cli-raw-client-runner.ts +155 -0
  666. package/src/wirings/cli/channel/index.ts +9 -0
  667. package/src/wirings/cli/cli-runner.test.ts +0 -1
  668. package/src/wirings/cli/cli-runner.ts +46 -88
  669. package/src/wirings/cli/cli.types.ts +14 -3
  670. package/src/wirings/cli/command-parser.test.ts +0 -4
  671. package/src/wirings/cli/command-parser.ts +11 -91
  672. package/src/wirings/cli/define-cli-commands.ts +1 -17
  673. package/src/wirings/credential/credential.types.ts +0 -12
  674. package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
  675. package/src/wirings/credential/index.ts +1 -1
  676. package/src/wirings/credential/validate-credential-definitions.ts +2 -4
  677. package/src/wirings/gateway/gateway-runner.test.ts +1 -21
  678. package/src/wirings/gateway/gateway-runner.ts +8 -110
  679. package/src/wirings/gateway/gateway.types.ts +7 -80
  680. package/src/wirings/http/http-routes.test.ts +0 -3
  681. package/src/wirings/http/http-routes.ts +0 -86
  682. package/src/wirings/http/http-runner.test.ts +0 -1
  683. package/src/wirings/http/http-runner.ts +8 -167
  684. package/src/wirings/http/http.types.ts +15 -62
  685. package/src/wirings/http/log-http-routes.ts +0 -4
  686. package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
  687. package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
  688. package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
  689. package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
  690. package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
  691. package/src/wirings/http/routers/path-to-regex.ts +2 -13
  692. package/src/wirings/http/web-request.test.ts +33 -2
  693. package/src/wirings/http/web-request.ts +30 -17
  694. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
  695. package/src/wirings/mcp/mcp-runner.ts +2 -17
  696. package/src/wirings/mcp/mcp.types.ts +7 -42
  697. package/src/wirings/oauth2/oauth2.types.ts +0 -30
  698. package/src/wirings/persona/define-personas.ts +29 -0
  699. package/src/wirings/persona/index.ts +62 -0
  700. package/src/wirings/persona/persona-email.ts +87 -0
  701. package/src/wirings/persona/persona-environments.test.ts +183 -0
  702. package/src/wirings/persona/persona-environments.ts +138 -0
  703. package/src/wirings/persona/persona-mailbox.ts +156 -0
  704. package/src/wirings/persona/persona.test.ts +220 -0
  705. package/src/wirings/persona/persona.types.ts +131 -0
  706. package/src/wirings/persona/validate-personas.ts +133 -0
  707. package/src/wirings/queue/index.ts +13 -3
  708. package/src/wirings/queue/queue-identity.test.ts +453 -0
  709. package/src/wirings/queue/queue-identity.ts +173 -0
  710. package/src/wirings/queue/queue-runner.ts +12 -31
  711. package/src/wirings/queue/queue.types.ts +19 -89
  712. package/src/wirings/queue/register-queue-helper.ts +0 -14
  713. package/src/wirings/queue/signed-queue-service.ts +59 -0
  714. package/src/wirings/queue/validate-worker-config.ts +2 -28
  715. package/src/wirings/role/define-system-role.ts +33 -0
  716. package/src/wirings/role/index.ts +13 -0
  717. package/src/wirings/role/role.test.ts +104 -0
  718. package/src/wirings/role/role.types.ts +47 -0
  719. package/src/wirings/role/validate-role-definitions.ts +93 -0
  720. package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
  721. package/src/wirings/rpc/addon-runner.ts +0 -56
  722. package/src/wirings/rpc/addon-scopes.test.ts +225 -0
  723. package/src/wirings/rpc/remote-addon-auth.ts +1 -13
  724. package/src/wirings/rpc/rpc-runner.test.ts +186 -2
  725. package/src/wirings/rpc/rpc-runner.ts +145 -127
  726. package/src/wirings/rpc/rpc-types.ts +11 -6
  727. package/src/wirings/rpc/wire-addon.test.ts +43 -1
  728. package/src/wirings/rpc/wire-addon.ts +99 -0
  729. package/src/wirings/rpc/wire-remote-addon.ts +9 -29
  730. package/src/wirings/scheduler/log-schedulers.ts +0 -4
  731. package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
  732. package/src/wirings/scheduler/scheduler-runner.ts +0 -2
  733. package/src/wirings/scheduler/scheduler.types.ts +1 -14
  734. package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
  735. package/src/wirings/scope/index.ts +1 -1
  736. package/src/wirings/scope/scope.test.ts +1 -2
  737. package/src/wirings/scope/scope.types.ts +7 -9
  738. package/src/wirings/scope/validate-scope-definitions.ts +3 -21
  739. package/src/wirings/secret/index.ts +1 -1
  740. package/src/wirings/secret/secret.types.ts +19 -15
  741. package/src/wirings/secret/validate-secret-definitions.ts +2 -4
  742. package/src/wirings/trigger/trigger-runner.ts +1 -27
  743. package/src/wirings/trigger/trigger.types.ts +1 -82
  744. package/src/wirings/variable/index.ts +1 -1
  745. package/src/wirings/variable/validate-variable-definitions.ts +2 -4
  746. package/src/wirings/variable/variable.types.ts +1 -13
  747. package/src/wirings/virtual-user/index.ts +76 -0
  748. package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
  749. package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
  750. package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
  751. package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
  752. package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
  753. package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
  754. package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
  755. package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
  756. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
  757. package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
  758. package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
  759. package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
  760. package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
  761. package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
  762. package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
  763. package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
  764. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +5 -4
  765. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
  766. package/src/wirings/workflow/feature.ts +0 -19
  767. package/src/wirings/workflow/graph/graph-node.ts +0 -136
  768. package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
  769. package/src/wirings/workflow/graph/graph-runner.ts +6 -41
  770. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
  771. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
  772. package/src/wirings/workflow/index.ts +10 -44
  773. package/src/wirings/workflow/pikku-scenario-service.ts +235 -52
  774. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
  775. package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
  776. package/src/wirings/workflow/run-timeline.test.ts +7 -19
  777. package/src/wirings/workflow/run-timeline.ts +0 -56
  778. package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
  779. package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
  780. package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
  781. package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
  782. package/src/wirings/workflow/scenario-poll.test.ts +0 -2
  783. package/src/wirings/workflow/scenario-poll.ts +0 -15
  784. package/src/wirings/workflow/scenario-prose.ts +0 -28
  785. package/src/wirings/workflow/scenario-service.test.ts +2 -9
  786. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  787. package/src/wirings/workflow/scenario-step.test.ts +159 -14
  788. package/src/wirings/workflow/scenario-step.types.ts +82 -6
  789. package/src/wirings/workflow/scenario-surface.test.ts +145 -0
  790. package/src/wirings/workflow/scenario-surface.ts +71 -0
  791. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
  792. package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
  793. package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
  794. package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
  795. package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
  796. package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
  797. package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
  798. package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
  799. package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
  800. package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
  801. package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
  802. package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
  803. package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
  804. package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
  805. package/src/wirings/workflow/workflow.types.ts +0 -203
  806. package/tsconfig.tsbuildinfo +1 -1
  807. package/src/middleware/timeout.ts +0 -22
  808. package/src/pikku-response.ts +0 -5
  809. package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
  810. package/src/wirings/workflow/dsl/index.ts +0 -36
  811. package/src/wirings/workflow/graph/index.ts +0 -15
@@ -1,10 +1,48 @@
1
+ /**
2
+ * Raised when every audio part in a turn turned out to be non-speech.
3
+ *
4
+ * Distinct from a transcription failure, because the response is different: a
5
+ * failure is worth reporting, whereas this is the microphone doing its job on a
6
+ * pause. A voice loop should catch it and go back to listening without running
7
+ * the agent — answering a hallucinated sentence is worse than answering nothing.
8
+ */
9
+ export declare class NoSpeechDetectedError extends Error {
10
+ constructor();
11
+ }
12
+ /**
13
+ * Whether nothing usable was said — an empty transcript, and nothing cleverer
14
+ * than that.
15
+ *
16
+ * There was a confidence gate here once, and it is worth recording why it is
17
+ * gone. Whisper is trained on subtitles, so audio it cannot parse comes back
18
+ * not as nothing but as stock filler appended to real speech: "Hello, my name
19
+ * is Yasir. Thank you." where only the first sentence was spoken. The obvious
20
+ * defence is to drop low-confidence segments, and it does not work. Measured on
21
+ * a real turn, the invented "Thank you." scored `avg_logprob` -0.52 against
22
+ * -0.30 for the genuine sentence beside it, and `no_speech_prob` read 0.000 for
23
+ * both. Whisper is *confident* when it invents, because the text it invents is
24
+ * high-probability text. No threshold separates those two numbers, and one set
25
+ * low enough to try would take real quiet speech with it.
26
+ *
27
+ * The fix belongs at the model, not behind it: an ASR that is not a
28
+ * subtitle-trained autoregressive decoder returns an empty string on non-speech
29
+ * and there is nothing left to filter. Hence this reduces to asking whether
30
+ * anything came back at all — which is a property every provider reports
31
+ * honestly, unlike per-segment confidence (Nemotron, for one, hardcodes
32
+ * `avg_logprob` to 0.0).
33
+ */
34
+ export declare const readsAsNonSpeech: (result: {
35
+ text?: string;
36
+ }) => boolean;
1
37
  export declare const voiceInput: (config?: {
2
38
  language?: string;
3
39
  model?: string;
4
40
  allowedAudioHosts?: string[];
5
41
  }) => import("./ai-agent.types.js").PikkuAIMiddlewareHooks<Record<string, unknown>, import("../../types/core.types.js").CoreSingletonServices<{
6
42
  logLevel?: import("../../services/logger.js").LogLevel;
7
- secrets?: {};
43
+ secrets?: {
44
+ requireAllowedHosts?: boolean;
45
+ };
8
46
  workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
9
47
  webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
10
48
  postgres?: import("../../types/core.types.js").PostgresConfig;
@@ -9,6 +9,43 @@ function base64ToUint8Array(base64) {
9
9
  return bytes;
10
10
  }
11
11
  const MAX_AUDIO_SIZE = 50 * 1024 * 1024;
12
+ /**
13
+ * Raised when every audio part in a turn turned out to be non-speech.
14
+ *
15
+ * Distinct from a transcription failure, because the response is different: a
16
+ * failure is worth reporting, whereas this is the microphone doing its job on a
17
+ * pause. A voice loop should catch it and go back to listening without running
18
+ * the agent — answering a hallucinated sentence is worse than answering nothing.
19
+ */
20
+ export class NoSpeechDetectedError extends Error {
21
+ constructor() {
22
+ super('No speech was detected in the audio.');
23
+ this.name = 'NoSpeechDetectedError';
24
+ }
25
+ }
26
+ /**
27
+ * Whether nothing usable was said — an empty transcript, and nothing cleverer
28
+ * than that.
29
+ *
30
+ * There was a confidence gate here once, and it is worth recording why it is
31
+ * gone. Whisper is trained on subtitles, so audio it cannot parse comes back
32
+ * not as nothing but as stock filler appended to real speech: "Hello, my name
33
+ * is Yasir. Thank you." where only the first sentence was spoken. The obvious
34
+ * defence is to drop low-confidence segments, and it does not work. Measured on
35
+ * a real turn, the invented "Thank you." scored `avg_logprob` -0.52 against
36
+ * -0.30 for the genuine sentence beside it, and `no_speech_prob` read 0.000 for
37
+ * both. Whisper is *confident* when it invents, because the text it invents is
38
+ * high-probability text. No threshold separates those two numbers, and one set
39
+ * low enough to try would take real quiet speech with it.
40
+ *
41
+ * The fix belongs at the model, not behind it: an ASR that is not a
42
+ * subtitle-trained autoregressive decoder returns an empty string on non-speech
43
+ * and there is nothing left to filter. Hence this reduces to asking whether
44
+ * anything came back at all — which is a property every provider reports
45
+ * honestly, unlike per-segment confidence (Nemotron, for one, hardcodes
46
+ * `avg_logprob` to 0.0).
47
+ */
48
+ export const readsAsNonSpeech = (result) => !(result.text ?? '').trim();
12
49
  async function fetchAsUint8Array(url, allowedAudioHosts) {
13
50
  const response = await safeFetch(url, {}, { allowedHosts: allowedAudioHosts });
14
51
  const contentLength = response.headers.get('content-length');
@@ -36,9 +73,6 @@ export const voiceInput = (config) => pikkuAIMiddleware({
36
73
  const hasAudio = parts.some((p) => p.type === 'file' && !!p.mediaType?.startsWith('audio/'));
37
74
  if (!hasAudio)
38
75
  return { messages, instructions };
39
- // Process parts in order, replacing each audio part with its transcription
40
- // in place. Sequential, so no unbounded parallel downloads/transcriptions
41
- // and original content ordering is preserved.
42
76
  const updatedContent = [];
43
77
  for (const p of parts) {
44
78
  if (!(p.type === 'file' && p.mediaType?.startsWith('audio/'))) {
@@ -64,8 +98,17 @@ export const voiceInput = (config) => pikkuAIMiddleware({
64
98
  }
65
99
  : {}),
66
100
  });
101
+ // Dropped when nothing was said: an empty text part is still a turn the
102
+ // model will answer, and what it answers is a guess about what it could
103
+ // not hear.
104
+ if (readsAsNonSpeech(result))
105
+ continue;
67
106
  updatedContent.push({ type: 'text', text: result.text });
68
107
  }
108
+ // Every part was audio, and none of it was speech. There is nothing left
109
+ // to send, and a message with no content is not a question.
110
+ if (updatedContent.length === 0)
111
+ throw new NoSpeechDetectedError();
69
112
  return {
70
113
  messages: [
71
114
  ...messages.slice(0, -1),
@@ -1,6 +1,47 @@
1
1
  type VoiceOutputState = {
2
2
  textBuffer?: string;
3
+ /**
4
+ * The audio emitted so far, as a chain.
5
+ *
6
+ * Synthesis for every finished sentence starts immediately, so the second
7
+ * sentence is being generated while the first is still being spoken. That
8
+ * also means the second can finish first — a short sentence after a long one
9
+ * routinely does. Chaining the *emissions* keeps the client receiving audio
10
+ * in the order it was written while leaving the generation overlapped.
11
+ */
12
+ tail?: Promise<void>;
13
+ /** Whether this reply has already said it cannot be spoken aloud. */
14
+ reportedUnspeakable?: boolean;
3
15
  };
16
+ /**
17
+ * The scripts a model can pronounce, and optionally the voice each one needs.
18
+ *
19
+ * The array form is for a model whose voice is the same whatever the script.
20
+ * The record form exists because that is not the common case: Kokoro speaks
21
+ * Mandarin, Japanese and Hindi well, but only through a voice belonging to that
22
+ * language. Asked for Chinese in its default American-English voice it spells
23
+ * the characters out — 9.9 seconds of "Chinese letter, Chinese letter" for a
24
+ * sentence the right voice says in 3.5. Same model, same text, same price.
25
+ */
26
+ export type SpeakableScripts = string[] | Record<string, string>;
27
+ /**
28
+ * The scripts present in `text` that the model was not said to handle.
29
+ *
30
+ * Silence would be the wrong answer here and so would a best effort. Handed
31
+ * Arabic — which it has no voice for at all — Kokoro does not fail and does not
32
+ * stay quiet: it reads out the *letter names*, twenty-four seconds of "Arabic
33
+ * meem, Arabic ra" for a one-line sentence, which is worse than either. Naming
34
+ * the gap lets the caller say so instead.
35
+ */
36
+ export declare const unspeakableScripts: (text: string, speakable: SpeakableScripts) => string[];
37
+ /**
38
+ * The voice to speak `text` in, or `fallback` if no mapped script appears.
39
+ *
40
+ * A sentence is regularly in more than one script, so which one decides is
41
+ * settled by {@link SCRIPT_PRECEDENCE} rather than by the order the config
42
+ * happens to be written in.
43
+ */
44
+ export declare const voiceForText: (text: string, speakable: SpeakableScripts, fallback?: string) => string | undefined;
4
45
  export declare const voiceOutput: (config?: {
5
46
  model?: string;
6
47
  format?: string;
@@ -8,9 +49,21 @@ export declare const voiceOutput: (config?: {
8
49
  instructions?: string;
9
50
  speed?: number;
10
51
  language?: string;
52
+ /**
53
+ * Scripts the configured model can actually pronounce, and the voice each
54
+ * needs — see {@link SpeakableScripts}. Anything written in another script is
55
+ * left unspoken and reported once, as a `voice-unsupported` data event,
56
+ * rather than sent to a model that will mangle it.
57
+ *
58
+ * Omitted means no check: every model is trusted with every script, which is
59
+ * the right default for a provider that genuinely is multilingual.
60
+ */
61
+ speakableScripts?: SpeakableScripts;
11
62
  }) => import("./ai-agent.types.js").PikkuAIMiddlewareHooks<VoiceOutputState, import("../../types/core.types.js").CoreSingletonServices<{
12
63
  logLevel?: import("../../services/logger.js").LogLevel;
13
- secrets?: {};
64
+ secrets?: {
65
+ requireAllowedHosts?: boolean;
66
+ };
14
67
  workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
15
68
  webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
16
69
  postgres?: import("../../types/core.types.js").PostgresConfig;
@@ -10,6 +10,76 @@ const SENTENCE_BOUNDARY = /[.!?]\s*$/;
10
10
  function isSentenceBoundary(text) {
11
11
  return SENTENCE_BOUNDARY.test(text);
12
12
  }
13
+ /**
14
+ * Scripts a speech model can pronounce, as named by {@link voiceOutput}'s
15
+ * `speakableScripts`.
16
+ *
17
+ * Script rather than language because script is what is decidable from the text
18
+ * alone. Spanish, French and English are one test, not three — and the models
19
+ * that handle one Latin-script language generally handle the others. What a
20
+ * model cannot do is invent a phoneme set it was never given.
21
+ */
22
+ const SCRIPT_RANGES = {
23
+ latin: /[A-ɏ]/,
24
+ devanagari: /[ऀ-ॿ]/,
25
+ han: /[㐀-鿿]/,
26
+ kana: /[぀-ヿ]/,
27
+ arabic: /[؀-ۿݐ-ݿ]/,
28
+ cyrillic: /[Ѐ-ӿ]/,
29
+ hangul: /[가-힯ᄀ-ᇿ]/,
30
+ hebrew: /[֐-׿]/,
31
+ greek: /[Ͱ-Ͽ]/,
32
+ thai: /[฀-๿]/,
33
+ };
34
+ /**
35
+ * Which script decides the voice when a sentence contains several.
36
+ *
37
+ * The ordering is by how much a script narrows down the language, not by
38
+ * preference. Kana appears only in Japanese, so a sentence holding any settles
39
+ * it — while Han is written in both Chinese and Japanese and so cannot, which
40
+ * matters because ordinary Japanese is mostly kanji. Latin comes last for the
41
+ * same reason from the other end: it turns up inside sentences in every other
42
+ * script, and it is the one whose voice is least often the one that counts. A
43
+ * Chinese voice reading an English word is accented; an English voice reading
44
+ * Chinese spells it out.
45
+ *
46
+ * Everything else — Han included — sits between the two in config order.
47
+ */
48
+ const SCRIPT_PRECEDENCE = { kana: -1, latin: 1 };
49
+ const scriptRank = (name) => SCRIPT_PRECEDENCE[name] ?? 0;
50
+ const scriptNames = (speakable) => Array.isArray(speakable) ? speakable : Object.keys(speakable);
51
+ /**
52
+ * The scripts present in `text` that the model was not said to handle.
53
+ *
54
+ * Silence would be the wrong answer here and so would a best effort. Handed
55
+ * Arabic — which it has no voice for at all — Kokoro does not fail and does not
56
+ * stay quiet: it reads out the *letter names*, twenty-four seconds of "Arabic
57
+ * meem, Arabic ra" for a one-line sentence, which is worse than either. Naming
58
+ * the gap lets the caller say so instead.
59
+ */
60
+ export const unspeakableScripts = (text, speakable) => {
61
+ const allowed = new Set(scriptNames(speakable));
62
+ return Object.entries(SCRIPT_RANGES)
63
+ .filter(([name, range]) => !allowed.has(name) && range.test(text))
64
+ .map(([name]) => name);
65
+ };
66
+ /**
67
+ * The voice to speak `text` in, or `fallback` if no mapped script appears.
68
+ *
69
+ * A sentence is regularly in more than one script, so which one decides is
70
+ * settled by {@link SCRIPT_PRECEDENCE} rather than by the order the config
71
+ * happens to be written in.
72
+ */
73
+ export const voiceForText = (text, speakable, fallback) => {
74
+ if (Array.isArray(speakable))
75
+ return fallback;
76
+ const mapped = Object.entries(speakable).sort(([a], [b]) => scriptRank(a) - scriptRank(b));
77
+ for (const [name, voice] of mapped) {
78
+ if (SCRIPT_RANGES[name]?.test(text))
79
+ return voice;
80
+ }
81
+ return fallback;
82
+ };
13
83
  async function synthesizeAudio(aiAgentRunner, input) {
14
84
  const result = await aiAgentRunner.generateSpeech?.({
15
85
  model: input.model,
@@ -19,76 +89,109 @@ async function synthesizeAudio(aiAgentRunner, input) {
19
89
  instructions: input.instructions,
20
90
  speed: input.speed,
21
91
  language: input.language,
92
+ abortSignal: input.abortSignal,
22
93
  });
23
94
  if (!result) {
24
95
  throw new Error('voiceOutput requires an aiAgentRunner with generateSpeech support');
25
96
  }
26
- // Label chunks with the format the provider actually returned (config.format
27
- // is only a request), falling back to the requested format then pcm16.
28
97
  return {
29
98
  bytes: result.audio.uint8Array,
30
99
  format: result.audio.format || input.format || 'pcm16',
31
100
  };
32
101
  }
33
102
  export const voiceOutput = (config) => pikkuAIMiddleware({
34
- modifyOutputStream: async (services, { event, state }) => {
35
- const aiAgentRunner = services.aiAgentRunner;
103
+ modifyOutputStream: async (services, { event, state, emit, signal }) => {
104
+ const { aiAgentRunner, logger } = services;
36
105
  if (!aiAgentRunner?.generateSpeech)
37
106
  return event;
38
- if (event.type === 'done') {
39
- const remaining = state.textBuffer ?? '';
40
- if (remaining) {
41
- state.textBuffer = '';
42
- if (!config?.model) {
43
- throw new Error('voiceOutput requires a speech model (e.g. openai/tts-1)');
107
+ /**
108
+ * Queue a finished sentence for speech.
109
+ *
110
+ * Nothing here is awaited by the caller. Synthesis is kicked off at once
111
+ * and its emission is chained behind the previous sentence, which is
112
+ * what keeps the text flowing at the speed the model writes it instead
113
+ * of the speed the speech provider answers.
114
+ */
115
+ const speak = (text) => {
116
+ if (!config?.model) {
117
+ throw new Error('voiceOutput requires a speech model (e.g. openai/tts-1)');
118
+ }
119
+ // Checked per sentence but announced once per reply: a bilingual answer
120
+ // should still speak the half it can, and repeating the notice for
121
+ // every sentence of a long one would bury the reply itself.
122
+ //
123
+ // Per sentence is also what makes the voice right. A reply that answers
124
+ // in English and then quotes a Chinese title is two sentences in two
125
+ // scripts, and each is synthesized in the voice its own script needs.
126
+ let voice = config.voice;
127
+ if (config.speakableScripts) {
128
+ const unspeakable = unspeakableScripts(text, config.speakableScripts);
129
+ voice = voiceForText(text, config.speakableScripts, config.voice);
130
+ if (unspeakable.length > 0) {
131
+ if (!state.reportedUnspeakable) {
132
+ state.reportedUnspeakable = true;
133
+ state.tail = (state.tail ?? Promise.resolve()).then(() => emit({
134
+ type: 'data',
135
+ name: 'voice-unsupported',
136
+ data: { model: config.model, scripts: unspeakable },
137
+ }));
138
+ }
139
+ return;
44
140
  }
45
- const audio = await synthesizeAudio(aiAgentRunner, {
46
- model: config.model,
47
- text: remaining,
48
- voice: config?.voice,
49
- format: config?.format,
50
- instructions: config?.instructions,
51
- speed: config?.speed,
52
- language: config?.language,
141
+ }
142
+ // Settled into a value rather than left as a rejectable promise: it
143
+ // sits unobserved until the chain reaches it, and an unhandled
144
+ // rejection in that window would take the process down.
145
+ const synthesis = synthesizeAudio(aiAgentRunner, {
146
+ model: config.model,
147
+ text,
148
+ voice,
149
+ format: config?.format,
150
+ instructions: config?.instructions,
151
+ speed: config?.speed,
152
+ language: config?.language,
153
+ // Barge-in should stop the bill, not just the playback. Without this
154
+ // every sentence already in flight is synthesized in full and paid
155
+ // for after the user has stopped listening.
156
+ abortSignal: signal,
157
+ }).then((audio) => ({ ok: true, audio }), (error) => ({ ok: false, error }));
158
+ state.tail = (state.tail ?? Promise.resolve()).then(async () => {
159
+ const result = await synthesis;
160
+ if (!result.ok) {
161
+ // One sentence going unspoken is better than the rest of the reply
162
+ // never arriving, so the chain carries on.
163
+ logger?.error(`voiceOutput could not synthesize a sentence: ${String(result.error)}`);
164
+ return;
165
+ }
166
+ await emit({
167
+ type: 'audio-delta',
168
+ data: bufferToBase64(result.audio.bytes),
169
+ format: result.audio.format,
53
170
  });
54
- return [
55
- {
56
- type: 'audio-delta',
57
- data: bufferToBase64(audio.bytes),
58
- format: audio.format,
59
- },
60
- { type: 'audio-done' },
61
- event,
62
- ];
171
+ });
172
+ };
173
+ if (event.type === 'done') {
174
+ const remaining = state.textBuffer ?? '';
175
+ state.textBuffer = '';
176
+ if (remaining.trim()) {
177
+ speak(remaining);
63
178
  }
179
+ // The only place this hook waits. The reply is already over, so the
180
+ // wait costs the reader nothing, and it is what makes `audio-done`
181
+ // mean what it says rather than racing the last chunk.
182
+ await state.tail;
183
+ state.tail = undefined;
64
184
  return [{ type: 'audio-done' }, event];
65
185
  }
66
186
  if (event.type !== 'text-delta')
67
187
  return event;
68
188
  state.textBuffer = `${state.textBuffer ?? ''}${event.text}`;
69
- if (!isSentenceBoundary(state.textBuffer))
70
- return event;
71
- const text = state.textBuffer;
72
- state.textBuffer = '';
73
- if (!config?.model) {
74
- throw new Error('voiceOutput requires a speech model (e.g. openai/tts-1)');
189
+ if (isSentenceBoundary(state.textBuffer)) {
190
+ const text = state.textBuffer;
191
+ state.textBuffer = '';
192
+ speak(text);
75
193
  }
76
- const audio = await synthesizeAudio(aiAgentRunner, {
77
- model: config.model,
78
- text,
79
- voice: config?.voice,
80
- format: config?.format,
81
- instructions: config?.instructions,
82
- speed: config?.speed,
83
- language: config?.language,
84
- });
85
- return [
86
- event,
87
- {
88
- type: 'audio-delta',
89
- data: bufferToBase64(audio.bytes),
90
- format: audio.format,
91
- },
92
- ];
194
+ // Returned without waiting for any audio the entire point.
195
+ return event;
93
196
  },
94
197
  });
@@ -1,25 +1,7 @@
1
1
  import type { CoreSingletonServices, MiddlewareMetadata } from '../../types/core.types.js';
2
2
  import type { CoreChannel, ChannelMessageMeta } from './channel.types.js';
3
- /**
4
- * Runs a channel lifecycle function (onConnect or onDisconnect) with proper middleware handling.
5
- *
6
- * This function:
7
- * 1. Extracts inline middleware from the lifecycle config if present
8
- * 2. Combines metadata middleware with inline middleware using combineMiddleware()
9
- * 3. Wraps the channel with channel middleware if present
10
- * 4. Runs the lifecycle function with middleware support
11
- *
12
- * @param channelConfig - The channel configuration
13
- * @param meta - Metadata for the lifecycle function (connect or disconnect)
14
- * @param lifecycleConfig - The onConnect or onDisconnect config (can be function or object with middleware)
15
- * @param lifecycleType - Type of lifecycle for cache key ('connect' or 'disconnect')
16
- * @param services - All services (singleton + session)
17
- * @param channel - The channel instance
18
- * @param data - Optional data to pass to the lifecycle function (for onConnect)
19
- * @param channelMiddlewareMeta - Optional channel middleware metadata for wrapping channel.send()
20
- * @returns Promise<unknown> - Result from the lifecycle function (if any)
21
- */
22
- export declare const runChannelLifecycleWithMiddleware: ({ channelConfig, meta, lifecycleConfig, lifecycleType, services, channel, data, channelMiddlewareMeta, }: {
3
+ import { type PikkuSessionService } from '../../services/user-session-service.js';
4
+ export declare const runChannelLifecycleWithMiddleware: ({ channelConfig, meta, lifecycleConfig, lifecycleType, services, channel, data, channelMiddlewareMeta, userSession, }: {
23
5
  channelConfig: CoreChannel<unknown, any>;
24
6
  meta: ChannelMessageMeta;
25
7
  lifecycleConfig: any;
@@ -28,4 +10,9 @@ export declare const runChannelLifecycleWithMiddleware: ({ channelConfig, meta,
28
10
  channel: any;
29
11
  data?: unknown;
30
12
  channelMiddlewareMeta?: MiddlewareMetadata[];
13
+ /**
14
+ * Established while the socket was upgrading, so `onConnect` can tell who
15
+ * just connected.
16
+ */
17
+ userSession?: PikkuSessionService<any>;
31
18
  }) => Promise<unknown>;
@@ -1,26 +1,8 @@
1
1
  import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
2
2
  import { runPikkuFunc } from '../../function/function-runner.js';
3
+ import { createMiddlewareSessionWireProps, } from '../../services/user-session-service.js';
3
4
  import { combineChannelMiddleware, wrapChannelWithMiddleware, } from './channel-middleware-runner.js';
4
- /**
5
- * Runs a channel lifecycle function (onConnect or onDisconnect) with proper middleware handling.
6
- *
7
- * This function:
8
- * 1. Extracts inline middleware from the lifecycle config if present
9
- * 2. Combines metadata middleware with inline middleware using combineMiddleware()
10
- * 3. Wraps the channel with channel middleware if present
11
- * 4. Runs the lifecycle function with middleware support
12
- *
13
- * @param channelConfig - The channel configuration
14
- * @param meta - Metadata for the lifecycle function (connect or disconnect)
15
- * @param lifecycleConfig - The onConnect or onDisconnect config (can be function or object with middleware)
16
- * @param lifecycleType - Type of lifecycle for cache key ('connect' or 'disconnect')
17
- * @param services - All services (singleton + session)
18
- * @param channel - The channel instance
19
- * @param data - Optional data to pass to the lifecycle function (for onConnect)
20
- * @param channelMiddlewareMeta - Optional channel middleware metadata for wrapping channel.send()
21
- * @returns Promise<unknown> - Result from the lifecycle function (if any)
22
- */
23
- export const runChannelLifecycleWithMiddleware = async ({ channelConfig, meta, lifecycleConfig, lifecycleType, services, channel, data, channelMiddlewareMeta, }) => {
5
+ export const runChannelLifecycleWithMiddleware = async ({ channelConfig, meta, lifecycleConfig, lifecycleType, services, channel, data, channelMiddlewareMeta, userSession, }) => {
24
6
  const lifecycleMiddleware = typeof lifecycleConfig === 'object' && 'middleware' in lifecycleConfig
25
7
  ? lifecycleConfig.middleware || []
26
8
  : [];
@@ -32,7 +14,10 @@ export const runChannelLifecycleWithMiddleware = async ({ channelConfig, meta, l
32
14
  wireInheritedChannelMiddleware: channelMiddlewareMeta,
33
15
  wireChannelMiddleware: channelConfig.channelMiddleware,
34
16
  });
35
- let wire = { channel };
17
+ let wire = {
18
+ channel,
19
+ ...(userSession ? createMiddlewareSessionWireProps(userSession) : {}),
20
+ };
36
21
  if (allChannelMiddleware.length > 0) {
37
22
  wire = wrapChannelWithMiddleware(wire, services, allChannelMiddleware);
38
23
  }
@@ -41,6 +26,7 @@ export const runChannelLifecycleWithMiddleware = async ({ channelConfig, meta, l
41
26
  singletonServices: services,
42
27
  data: () => data,
43
28
  wire,
29
+ sessionService: userSession,
44
30
  tags: meta.tags ?? [],
45
31
  packageName: meta.packageName ?? null,
46
32
  });
@@ -1,5 +1,7 @@
1
1
  import { pikkuState } from '../../pikku-state.js';
2
2
  import { runPikkuFunc } from '../../function/function-runner.js';
3
+ import { isChannelRPCPending, isChannelRPCResponse } from './channel-rpc.js';
4
+ import { handleChannelRPCResponse } from './channel-host-rpc.js';
3
5
  import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js';
4
6
  const getChannelMeta = (channelName) => {
5
7
  return pikkuState(null, 'channel', 'meta')[channelName];
@@ -95,15 +97,25 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
95
97
  const onMessage = async (rawData) => {
96
98
  let result;
97
99
  let processed = false;
98
- // Route-specific handling
99
- if (typeof rawData === 'string' && channelConfig.onMessageWiring) {
100
- let messageData;
100
+ let frame;
101
+ if (typeof rawData === 'string') {
101
102
  try {
102
- messageData = JSON.parse(rawData);
103
+ frame = JSON.parse(rawData);
103
104
  }
104
105
  catch {
105
106
  // Most likely a json error.. ignore
106
107
  }
108
+ }
109
+ // Taken ahead of routing so every channel gets reverse RPC without
110
+ // declaring a route for replies, and so an answer to a call someone is
111
+ // still awaiting can never be mistaken for a new message.
112
+ if (isChannelRPCResponse(frame) || isChannelRPCPending(frame)) {
113
+ handleChannelRPCResponse(channelHandler.getChannel().channelId, frame);
114
+ return;
115
+ }
116
+ // Route-specific handling
117
+ if (typeof rawData === 'string' && channelConfig.onMessageWiring) {
118
+ const messageData = frame;
107
119
  if (messageData) {
108
120
  const entries = Object.entries(channelConfig.onMessageWiring);
109
121
  for (const [routingProperty, routes] of entries) {
@@ -111,9 +123,16 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
111
123
  if (routerValue && routes[routerValue]) {
112
124
  const { [routingProperty]: _, ...data } = messageData;
113
125
  processed = true;
126
+ const routeResult = await processMessage(data, routes[routerValue], routingProperty, routerValue);
127
+ // The routing key is echoed so the client can match the reply.
128
+ // Assigning it to a primitive throws under ESM strict mode, so a
129
+ // primitive result is wrapped rather than mutated.
114
130
  result =
115
- (await processMessage(data, routes[routerValue], routingProperty, routerValue)) || {};
116
- result[routingProperty] = routerValue;
131
+ routeResult !== null && typeof routeResult === 'object'
132
+ ? Object.assign(routeResult, { [routingProperty]: routerValue })
133
+ : routeResult === undefined
134
+ ? { [routingProperty]: routerValue }
135
+ : { [routingProperty]: routerValue, result: routeResult };
117
136
  break;
118
137
  }
119
138
  }
@@ -0,0 +1,25 @@
1
+ import { ChannelDeploymentService } from './channel-rpc.js';
2
+ import type { ChannelRPCValidator } from './channel-rpc.js';
3
+ import type { PikkuChannel } from './channel.types.js';
4
+ /**
5
+ * The transport for a connection, created on first use. `options` apply only
6
+ * to the call that creates it — one connection has one transport, so the first
7
+ * caller's timeout and validators become the connection's.
8
+ */
9
+ export declare const getChannelHostRPC: (channel: PikkuChannel<unknown, any>, options?: {
10
+ timeoutMs?: number;
11
+ validateInput?: ChannelRPCValidator;
12
+ validateResult?: ChannelRPCValidator;
13
+ }) => ChannelDeploymentService;
14
+ /**
15
+ * Kept out of the channel handler so a channel nobody calls back on pays for no
16
+ * registry, and because a handler has no services to build a validator with.
17
+ */
18
+ export declare const channelRemote: (channel: PikkuChannel<unknown, any, any>, funcName: string, data?: unknown) => Promise<unknown>;
19
+ /** False for an unknown connection or id, so a stray frame is dropped. */
20
+ export declare const handleChannelRPCResponse: (channelId: string, message: unknown) => boolean;
21
+ /**
22
+ * Must run on disconnect: without it a caller waits out the full timeout on a
23
+ * dead socket, and the map grows for the life of the process.
24
+ */
25
+ export declare const releaseChannelHostRPC: (channelId: string) => Promise<void>;
@@ -0,0 +1,38 @@
1
+ import { ChannelDeploymentService, createChannelRPCInputValidator, createChannelRPCResultValidator, } from './channel-rpc.js';
2
+ import { getSingletonServices } from '../../pikku-state.js';
3
+ /** Reverse-RPC transports, one per open connection. */
4
+ const hostRPCByChannel = new Map();
5
+ /**
6
+ * The transport for a connection, created on first use. `options` apply only
7
+ * to the call that creates it — one connection has one transport, so the first
8
+ * caller's timeout and validators become the connection's.
9
+ */
10
+ export const getChannelHostRPC = (channel, options = {}) => {
11
+ let service = hostRPCByChannel.get(channel.channelId);
12
+ if (!service) {
13
+ service = new ChannelDeploymentService((data) => channel.send(data), options);
14
+ hostRPCByChannel.set(channel.channelId, service);
15
+ }
16
+ return service;
17
+ };
18
+ /**
19
+ * Kept out of the channel handler so a channel nobody calls back on pays for no
20
+ * registry, and because a handler has no services to build a validator with.
21
+ */
22
+ export const channelRemote = async (channel, funcName, data) => getChannelHostRPC(channel, {
23
+ validateInput: createChannelRPCInputValidator(getSingletonServices()),
24
+ validateResult: createChannelRPCResultValidator(getSingletonServices()),
25
+ }).invoke(funcName, data);
26
+ /** False for an unknown connection or id, so a stray frame is dropped. */
27
+ export const handleChannelRPCResponse = (channelId, message) => hostRPCByChannel.get(channelId)?.handleResponse(message) ?? false;
28
+ /**
29
+ * Must run on disconnect: without it a caller waits out the full timeout on a
30
+ * dead socket, and the map grows for the life of the process.
31
+ */
32
+ export const releaseChannelHostRPC = async (channelId) => {
33
+ const service = hostRPCByChannel.get(channelId);
34
+ if (service) {
35
+ hostRPCByChannel.delete(channelId);
36
+ await service.stop();
37
+ }
38
+ };
@@ -2,18 +2,6 @@ import type { CoreSingletonServices, MiddlewareMetadata, PikkuRawWire } from '..
2
2
  import type { CorePikkuChannelMiddleware } from './channel.types.js';
3
3
  export declare const addChannelMiddleware: (tag: string, middleware: CorePikkuChannelMiddleware[], packageName?: string | null) => CorePikkuChannelMiddleware[];
4
4
  export declare const clearChannelMiddlewareCache: () => void;
5
- /**
6
- * Combine the inherited (tag/named) channel middleware with any per-run
7
- * middleware for a wiring.
8
- *
9
- * Only the statically-resolved inherited middleware is deterministic per `uid`
10
- * and safe to cache. `wireChannelMiddleware` is a per-run set of closures (e.g.
11
- * an AI agent's per-invocation stream middleware holding that run's
12
- * thread/session state) and MUST NOT be cached — caching it lets a later run of
13
- * the same `uid` reuse an earlier run's closures, leaking that run's state (and
14
- * growing memory) across invocations. It is therefore appended fresh on every
15
- * call after the cached inherited slice.
16
- */
17
5
  export declare const combineChannelMiddleware: (wireType: string, uid: string, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName, }?: {
18
6
  wireInheritedChannelMiddleware?: MiddlewareMetadata[];
19
7
  wireChannelMiddleware?: CorePikkuChannelMiddleware[];