@pikku/core 0.12.84 → 0.12.86

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 (564) hide show
  1. package/CHANGELOG.md +424 -0
  2. package/dist/bootstrap-compat/root.d.ts +20 -0
  3. package/dist/classification/column-form.d.ts +32 -0
  4. package/dist/classification/column-form.js +42 -0
  5. package/dist/classification/data-classification.d.ts +64 -0
  6. package/dist/classification/index.d.ts +13 -0
  7. package/dist/classification/index.js +2 -0
  8. package/dist/classification/secret-value.d.ts +56 -0
  9. package/dist/classification/secret-value.js +46 -0
  10. package/dist/crypto-utils.d.ts +1 -1
  11. package/dist/ecosystem/agent-scorer.d.ts +1 -1
  12. package/dist/ecosystem/agent.d.ts +4 -1
  13. package/dist/ecosystem/channel/local.d.ts +2 -0
  14. package/dist/ecosystem/channel/local.js +2 -0
  15. package/dist/ecosystem/channel/serverless.d.ts +9 -0
  16. package/dist/ecosystem/channel/serverless.js +1 -0
  17. package/dist/ecosystem/channel.d.ts +3 -0
  18. package/dist/ecosystem/channel.js +1 -0
  19. package/dist/ecosystem/cli.d.ts +1 -1
  20. package/dist/ecosystem/cli.js +1 -1
  21. package/dist/ecosystem/credential.d.ts +1 -0
  22. package/dist/ecosystem/crypto-utils.d.ts +8 -0
  23. package/dist/ecosystem/crypto-utils.js +1 -0
  24. package/dist/ecosystem/dev.d.ts +1 -0
  25. package/dist/ecosystem/dev.js +1 -0
  26. package/{src/ecosystem/testing.ts → dist/ecosystem/errors.d.ts} +3 -3
  27. package/dist/ecosystem/errors.js +2 -0
  28. package/dist/ecosystem/function.d.ts +1 -1
  29. package/dist/ecosystem/function.js +1 -1
  30. package/dist/ecosystem/http.d.ts +3 -1
  31. package/dist/ecosystem/http.js +3 -1
  32. package/dist/ecosystem/mcp.d.ts +1 -1
  33. package/dist/ecosystem/mcp.js +1 -1
  34. package/dist/ecosystem/middleware.d.ts +2 -1
  35. package/dist/ecosystem/middleware.js +2 -1
  36. package/dist/ecosystem/persona.d.ts +4 -2
  37. package/dist/ecosystem/persona.js +2 -1
  38. package/dist/ecosystem/queue.d.ts +4 -2
  39. package/dist/ecosystem/queue.js +3 -1
  40. package/dist/ecosystem/role.d.ts +1 -0
  41. package/dist/ecosystem/rpc.d.ts +2 -0
  42. package/dist/ecosystem/rpc.js +1 -0
  43. package/dist/ecosystem/scenario.d.ts +8 -2
  44. package/dist/ecosystem/scenario.js +5 -1
  45. package/dist/ecosystem/scheduler.d.ts +2 -1
  46. package/dist/ecosystem/scheduler.js +2 -1
  47. package/dist/ecosystem/schema.d.ts +2 -1
  48. package/dist/ecosystem/schema.js +1 -1
  49. package/dist/ecosystem/scope.d.ts +2 -0
  50. package/dist/ecosystem/scope.js +1 -0
  51. package/dist/ecosystem/secret.d.ts +2 -0
  52. package/dist/ecosystem/secret.js +1 -0
  53. package/dist/ecosystem/services/local-content.d.ts +2 -1
  54. package/dist/ecosystem/services/local-content.js +1 -1
  55. package/dist/ecosystem/services/local-meta.d.ts +1 -0
  56. package/dist/ecosystem/services/local-meta.js +1 -0
  57. package/dist/ecosystem/services.d.ts +11 -3
  58. package/dist/ecosystem/services.js +7 -1
  59. package/dist/ecosystem/trigger.d.ts +1 -0
  60. package/dist/ecosystem/trigger.js +1 -1
  61. package/dist/ecosystem/types.d.ts +6 -3
  62. package/dist/ecosystem/types.js +3 -2
  63. package/dist/ecosystem/variable.d.ts +1 -0
  64. package/dist/ecosystem/virtual-user.d.ts +3 -0
  65. package/dist/ecosystem/virtual-user.js +3 -0
  66. package/dist/ecosystem/workflow.d.ts +2 -0
  67. package/dist/ecosystem/workflow.js +2 -0
  68. package/dist/errors/index.d.ts +8 -0
  69. package/dist/errors/index.js +1 -0
  70. package/dist/errors/serialized-error.d.ts +7 -0
  71. package/dist/function/function-meta.types.d.ts +139 -0
  72. package/dist/function/function-runner.d.ts +3 -2
  73. package/dist/function/function-runner.js +31 -11
  74. package/dist/function/functions.types.d.ts +10 -2
  75. package/dist/function/index.d.ts +8 -2
  76. package/dist/function/index.js +4 -1
  77. package/dist/function/pikku-request.d.ts +8 -0
  78. package/dist/function/pikku-request.js +15 -0
  79. package/dist/middleware/auth-apikey.d.ts +2 -10
  80. package/dist/middleware/auth-apikey.js +1 -1
  81. package/dist/middleware/auth-bearer.d.ts +2 -10
  82. package/dist/middleware/auth-bearer.js +1 -1
  83. package/dist/middleware/auth-cookie.d.ts +2 -10
  84. package/dist/middleware/auth-cookie.js +1 -1
  85. package/dist/middleware/cors.d.ts +5 -11
  86. package/dist/middleware/cors.js +13 -6
  87. package/dist/middleware/index.d.ts +3 -0
  88. package/dist/middleware/index.js +1 -0
  89. package/dist/middleware/middleware-factories.d.ts +9 -0
  90. package/dist/middleware/middleware-factories.js +19 -0
  91. package/dist/middleware/middleware.types.d.ts +27 -0
  92. package/dist/middleware/middleware.types.js +1 -0
  93. package/dist/middleware/remote-auth.d.ts +2 -2
  94. package/dist/middleware/remote-auth.js +1 -1
  95. package/dist/middleware/telemetry.d.ts +4 -20
  96. package/dist/middleware/telemetry.js +1 -1
  97. package/dist/middleware-runner.d.ts +2 -1
  98. package/dist/pikku-state.d.ts +2 -1
  99. package/dist/services/audit-service.d.ts +1 -1
  100. package/dist/services/credential-wire-service.js +1 -1
  101. package/dist/services/email-service.d.ts +1 -1
  102. package/dist/services/file-scenario-run-store.d.ts +58 -0
  103. package/dist/services/file-scenario-run-store.js +214 -0
  104. package/dist/services/in-memory-workflow-service.d.ts +1 -1
  105. package/dist/services/index.d.ts +5 -1
  106. package/dist/services/index.js +3 -0
  107. package/dist/services/local-secrets.d.ts +1 -1
  108. package/dist/services/local-secrets.js +1 -1
  109. package/dist/services/logger.d.ts +7 -7
  110. package/dist/services/meta-service.d.ts +2 -1
  111. package/dist/services/scoped-secret-service.d.ts +1 -1
  112. package/dist/services/secret-service.d.ts +1 -1
  113. package/dist/services/typed-secret-service.d.ts +16 -2
  114. package/dist/services/typed-secret-service.js +5 -0
  115. package/dist/services/webhook-service.d.ts +1 -1
  116. package/dist/services/workflow-service.d.ts +2 -1
  117. package/dist/testing/index.d.ts +1 -0
  118. package/dist/testing/index.js +1 -0
  119. package/dist/types/core.types.d.ts +30 -180
  120. package/dist/types/core.types.js +1 -19
  121. package/dist/types/index.d.ts +2 -0
  122. package/dist/types/index.js +1 -0
  123. package/dist/types/state.types.d.ts +3 -1
  124. package/dist/utils.d.ts +13 -0
  125. package/dist/utils.js +2 -0
  126. package/dist/wirings/addon/addon-runner.d.ts +17 -0
  127. package/dist/wirings/addon/addon-runner.js +150 -0
  128. package/dist/wirings/addon/index.d.ts +6 -0
  129. package/dist/wirings/addon/index.js +3 -0
  130. package/dist/wirings/addon/remote-addon-auth.d.ts +16 -0
  131. package/dist/wirings/addon/remote-addon-auth.js +39 -0
  132. package/dist/wirings/addon/wire-addon.d.ts +80 -0
  133. package/dist/wirings/addon/wire-addon.js +120 -0
  134. package/dist/wirings/addon/wire-remote-addon.d.ts +22 -0
  135. package/dist/wirings/addon/wire-remote-addon.js +11 -0
  136. package/dist/wirings/agent/agent-prepare.d.ts +3 -3
  137. package/dist/wirings/agent/agent-prepare.js +1 -1
  138. package/dist/wirings/agent/agent-runner.js +2 -3
  139. package/dist/wirings/agent/agent-stream.js +2 -2
  140. package/dist/wirings/agent/agent-utils.d.ts +13 -0
  141. package/dist/wirings/agent/agent-utils.js +16 -0
  142. package/dist/wirings/agent/agent.types.d.ts +3 -2
  143. package/dist/wirings/agent/index.d.ts +1 -1
  144. package/dist/wirings/agent/voice-input.js +1 -1
  145. package/dist/wirings/agent/voice-output.js +1 -1
  146. package/dist/wirings/agent-scorer/agent-scorer-judge.d.ts +13 -0
  147. package/dist/wirings/agent-scorer/agent-scorer-judge.js +52 -0
  148. package/dist/wirings/agent-scorer/agent-scorer.d.ts +7 -1
  149. package/dist/wirings/agent-scorer/agent-scorer.js +1 -0
  150. package/dist/wirings/agent-scorer/agent-scorer.types.d.ts +20 -0
  151. package/dist/wirings/agent-scorer/index.d.ts +1 -1
  152. package/dist/wirings/channel/channel-common.d.ts +2 -1
  153. package/dist/wirings/channel/channel-middleware-runner.d.ts +2 -1
  154. package/dist/wirings/channel/channel.types.d.ts +1 -1
  155. package/dist/wirings/channel/serverless/index.d.ts +1 -0
  156. package/dist/wirings/cli/channel/index.d.ts +1 -1
  157. package/dist/wirings/cli/cli-runner.d.ts +2 -1
  158. package/dist/wirings/cli/cli-runner.js +4 -1
  159. package/dist/wirings/cli/cli.types.d.ts +21 -2
  160. package/dist/wirings/cli/command-parser.js +157 -23
  161. package/dist/wirings/gateway/gateway.types.d.ts +2 -1
  162. package/dist/wirings/http/http-runner.d.ts +1 -1
  163. package/dist/wirings/http/http-runner.js +1 -1
  164. package/dist/wirings/http/http.types.d.ts +2 -2
  165. package/dist/wirings/http/index.d.ts +1 -0
  166. package/dist/wirings/http/index.js +1 -0
  167. package/dist/wirings/http/pikku-fetch-http-request.js +1 -1
  168. package/dist/wirings/http/pikku-fetch-http-response.js +2 -2
  169. package/dist/wirings/mcp/mcp.types.d.ts +1 -1
  170. package/dist/wirings/persona/index.d.ts +1 -1
  171. package/dist/wirings/persona/index.js +1 -1
  172. package/dist/wirings/persona/persona.types.d.ts +14 -0
  173. package/dist/wirings/queue/queue.types.d.ts +1 -1
  174. package/dist/wirings/queue/signed-queue-service.d.ts +1 -1
  175. package/dist/wirings/rpc/index.d.ts +0 -6
  176. package/dist/wirings/rpc/index.js +0 -3
  177. package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -1
  178. package/dist/wirings/rpc/remote-addon-auth.js +1 -1
  179. package/dist/wirings/rpc/rpc-runner.js +2 -2
  180. package/dist/wirings/rpc/wire-addon.d.ts +1 -1
  181. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -1
  182. package/dist/wirings/scope/index.d.ts +1 -0
  183. package/dist/wirings/scope/index.js +1 -0
  184. package/dist/wirings/secret/secret.types.d.ts +10 -0
  185. package/dist/wirings/secret/validate-secret-definitions.js +2 -0
  186. package/dist/wirings/variable/validate-variable-definitions.js +2 -0
  187. package/dist/wirings/variable/variable.types.d.ts +9 -0
  188. package/dist/wirings/virtual-user/index.d.ts +1 -1
  189. package/dist/wirings/virtual-user/index.js +1 -1
  190. package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +1 -1
  191. package/dist/wirings/virtual-user/virtual-user-derive.d.ts +1 -1
  192. package/dist/wirings/workflow/graph/graph-node.d.ts +9 -2
  193. package/dist/wirings/workflow/graph/graph-node.js +2 -0
  194. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -0
  195. package/dist/wirings/workflow/graph/graph-runner.js +283 -31
  196. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +16 -1
  197. package/dist/wirings/workflow/index.d.ts +2 -0
  198. package/dist/wirings/workflow/index.js +1 -0
  199. package/dist/wirings/workflow/pikku-scenario-service.d.ts +14 -4
  200. package/dist/wirings/workflow/pikku-scenario-service.js +44 -16
  201. package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -1
  202. package/dist/wirings/workflow/pikku-workflow-service.js +3 -4
  203. package/dist/wirings/workflow/run-timeline.d.ts +1 -1
  204. package/dist/wirings/workflow/scenario-run.types.d.ts +171 -0
  205. package/dist/wirings/workflow/scenario-run.types.js +1 -0
  206. package/dist/wirings/workflow/scenario-step-guards.d.ts +1 -2
  207. package/dist/wirings/workflow/scenario-step-guards.js +0 -8
  208. package/dist/wirings/workflow/scenario-step.types.d.ts +27 -12
  209. package/dist/wirings/workflow/workflow-approval.js +2 -1
  210. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +2 -1
  211. package/dist/wirings/workflow/workflow.types.d.ts +2 -1
  212. package/knowledge/decisions/index.md +2 -0
  213. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +1 -1
  214. package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +1 -1
  215. package/knowledge/decisions/internals/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +2 -2
  216. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +6 -6
  217. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +1 -1
  218. package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +1 -1
  219. package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +1 -1
  220. package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +1 -1
  221. package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +1 -1
  222. package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +1 -1
  223. package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +1 -1
  224. package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +1 -1
  225. package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +1 -1
  226. package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +1 -1
  227. package/knowledge/decisions/internals/core-column-form-is-an-axis-of-its-own.md +4 -4
  228. package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +1 -1
  229. package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +3 -3
  230. package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +2 -2
  231. package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +2 -2
  232. package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +1 -1
  233. package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +1 -1
  234. package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +3 -3
  235. package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +1 -1
  236. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +4 -4
  237. package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +1 -1
  238. package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +1 -1
  239. package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +1 -1
  240. package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +1 -1
  241. package/knowledge/decisions/internals/index.md +4 -2
  242. package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +1 -1
  243. package/knowledge/decisions/internals/one-project-shape-check-two-validators.md +1 -1
  244. package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +1 -1
  245. package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +1 -1
  246. package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +1 -1
  247. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +2 -2
  248. package/knowledge/decisions/internals/scenarios-live-in-files-named-for-them.md +5 -5
  249. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +1 -1
  250. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +1 -1
  251. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +43 -19
  252. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +1 -1
  253. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +1 -1
  254. package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +3 -3
  255. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +1 -1
  256. package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +1 -1
  257. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +1 -1
  258. package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +1 -1
  259. package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +1 -1
  260. package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +1 -1
  261. package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +1 -1
  262. package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +1 -1
  263. package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +1 -1
  264. package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +9 -5
  265. package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +1 -1
  266. package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +2 -2
  267. package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +1 -1
  268. package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +1 -1
  269. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +1 -1
  270. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +2 -3
  271. package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +1 -1
  272. package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +1 -1
  273. package/knowledge/decisions/security/agent-gate-requires-a-session-only-when-auth-is-true.md +1 -1
  274. package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +3 -3
  275. package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +4 -3
  276. package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +1 -1
  277. package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +2 -2
  278. package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +1 -1
  279. package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +2 -2
  280. package/knowledge/decisions/security/index.md +2 -0
  281. package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +1 -1
  282. package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +3 -3
  283. package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +1 -1
  284. package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +2 -2
  285. package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +1 -1
  286. package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +2 -2
  287. package/knowledge/index.md +3 -1
  288. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +1 -1
  289. package/knowledge/questions/index.md +2 -0
  290. package/package.json +14 -13
  291. package/run-tests.sh +0 -0
  292. package/scripts/generate-api-report.d.mts +1 -1
  293. package/scripts/generate-api-report.mjs +67 -60
  294. package/scripts/generate-api-report.mts +11 -45
  295. package/src/api-report.test.ts +70 -1
  296. package/src/app-alias-surface.test.ts +179 -0
  297. package/src/app-leaf-surface.test.ts +217 -0
  298. package/src/bootstrap-compat/root.ts +20 -0
  299. package/src/{column-form.test.ts → classification/column-form.test.ts} +2 -2
  300. package/src/{data-classification.ts → classification/data-classification.ts} +1 -5
  301. package/src/classification/index.ts +38 -0
  302. package/src/{secret-value.test.ts → classification/secret-value.test.ts} +2 -2
  303. package/src/{secret-value.ts → classification/secret-value.ts} +1 -6
  304. package/src/crypto-utils.ts +1 -1
  305. package/src/dev/reload-meta.test.ts +1 -1
  306. package/src/errors/index.ts +9 -0
  307. package/src/errors/serialized-error.ts +9 -0
  308. package/src/factory-functions.test.ts +4 -2
  309. package/src/function/function-meta.types.ts +151 -0
  310. package/src/function/function-runner.test.ts +4 -2
  311. package/src/function/function-runner.ts +47 -14
  312. package/src/function/functions.types.ts +11 -7
  313. package/src/function/index.ts +24 -5
  314. package/src/function/list.types.ts +1 -3
  315. package/src/middleware/auth-apikey.ts +4 -2
  316. package/src/middleware/auth-bearer.test.ts +1 -1
  317. package/src/middleware/auth-bearer.ts +4 -2
  318. package/src/middleware/auth-cookie.ts +4 -1
  319. package/src/middleware/cors.test.ts +126 -5
  320. package/src/middleware/cors.ts +19 -8
  321. package/src/middleware/index.ts +16 -0
  322. package/src/middleware/middleware-factories.ts +62 -0
  323. package/src/middleware/middleware.types.ts +61 -0
  324. package/src/middleware/remote-auth.test.ts +1 -1
  325. package/src/middleware/remote-auth.ts +1 -1
  326. package/src/middleware/telemetry.ts +4 -2
  327. package/src/middleware-runner.test.ts +2 -3
  328. package/src/middleware-runner.ts +2 -2
  329. package/src/no-root-barrel.test.ts +114 -0
  330. package/src/permissions.ts +2 -4
  331. package/src/pikku-state.ts +3 -1
  332. package/src/public-surface.json +56 -241
  333. package/src/public-surface.json.README +3 -3
  334. package/src/public-surface.test.ts +5 -5
  335. package/src/remote.test.ts +1 -1
  336. package/src/removed-legacy-exports.test.ts +5 -1
  337. package/src/services/audit-service.ts +1 -1
  338. package/src/services/credential-wire-service.ts +1 -1
  339. package/src/services/email-service.ts +2 -4
  340. package/src/services/file-scenario-run-store.test.ts +349 -0
  341. package/src/services/file-scenario-run-store.ts +282 -0
  342. package/src/services/in-memory-workflow-service.ts +1 -1
  343. package/src/services/index.ts +13 -1
  344. package/src/services/local-content-request-handler.ts +1 -2
  345. package/src/services/local-secrets.ts +1 -1
  346. package/src/services/logger.ts +7 -7
  347. package/src/services/meta-service.ts +2 -2
  348. package/src/services/queue-webhook-service.test.ts +1 -1
  349. package/src/services/scoped-secret-service.ts +1 -1
  350. package/src/services/secret-service.ts +1 -1
  351. package/src/services/typed-secret-service.test.ts +52 -0
  352. package/src/services/typed-secret-service.ts +26 -2
  353. package/src/services/webhook-service.ts +1 -1
  354. package/src/services/workflow-service.ts +2 -1
  355. package/src/template-alias-surface.test.ts +240 -0
  356. package/src/testing/index.ts +1 -0
  357. package/src/types/core.types.ts +33 -285
  358. package/src/types/index.ts +2 -0
  359. package/src/types/state.types.ts +6 -5
  360. package/src/types/typed-credentials.test.ts +72 -0
  361. package/src/utils.ts +34 -0
  362. package/src/wirings/{rpc → addon}/addon-scopes.test.ts +1 -1
  363. package/src/wirings/addon/index.ts +12 -0
  364. package/src/wirings/{rpc → addon}/remote-addon-auth.ts +4 -1
  365. package/src/wirings/{rpc → addon}/wire-addon.ts +37 -2
  366. package/src/wirings/agent/agent-prepare.ts +8 -5
  367. package/src/wirings/agent/agent-runner.ts +2 -3
  368. package/src/wirings/agent/agent-stream.ts +2 -3
  369. package/src/wirings/agent/agent-utils.ts +19 -0
  370. package/src/wirings/agent/agent.types.ts +3 -3
  371. package/src/wirings/agent/index.ts +1 -0
  372. package/src/wirings/agent/voice-input.ts +1 -1
  373. package/src/wirings/agent/voice-output.test.ts +2 -4
  374. package/src/wirings/agent/voice-output.ts +1 -1
  375. package/src/wirings/agent-scorer/agent-scorer-judge.test.ts +145 -0
  376. package/src/wirings/agent-scorer/agent-scorer-judge.ts +60 -0
  377. package/src/wirings/agent-scorer/agent-scorer.ts +8 -0
  378. package/src/wirings/agent-scorer/agent-scorer.types.ts +21 -0
  379. package/src/wirings/agent-scorer/index.ts +1 -0
  380. package/src/wirings/channel/channel-common.ts +4 -2
  381. package/src/wirings/channel/channel-handler.ts +2 -5
  382. package/src/wirings/channel/channel-middleware-runner.ts +1 -1
  383. package/src/wirings/channel/channel-rpc.types.ts +1 -5
  384. package/src/wirings/channel/channel.types.ts +1 -2
  385. package/src/wirings/channel/local/local-channel-runner.test.ts +1 -2
  386. package/src/wirings/channel/serverless/index.ts +1 -0
  387. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +2 -2
  388. package/src/wirings/cli/channel/index.ts +1 -3
  389. package/src/wirings/cli/cli-runner.test.ts +1 -1
  390. package/src/wirings/cli/cli-runner.ts +11 -7
  391. package/src/wirings/cli/cli.types.ts +24 -3
  392. package/src/wirings/cli/command-parser.test.ts +388 -1
  393. package/src/wirings/cli/command-parser.ts +189 -29
  394. package/src/wirings/gateway/gateway-runner.test.ts +1 -2
  395. package/src/wirings/gateway/gateway-runner.ts +3 -6
  396. package/src/wirings/gateway/gateway.types.ts +5 -4
  397. package/src/wirings/http/http-routes.test.ts +1 -2
  398. package/src/wirings/http/http-runner-addon-ref.test.ts +238 -0
  399. package/src/wirings/http/http-runner.test.ts +3 -8
  400. package/src/wirings/http/http-runner.ts +9 -3
  401. package/src/wirings/http/http.types.ts +3 -12
  402. package/src/wirings/http/index.ts +1 -0
  403. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  404. package/src/wirings/http/pikku-fetch-http-response.ts +3 -2
  405. package/src/wirings/mcp/mcp-runner.test.ts +1 -1
  406. package/src/wirings/mcp/mcp.types.ts +1 -2
  407. package/src/wirings/persona/index.ts +1 -4
  408. package/src/wirings/persona/persona.types.ts +14 -0
  409. package/src/wirings/queue/queue-identity.test.ts +1 -1
  410. package/src/wirings/queue/queue.types.ts +2 -6
  411. package/src/wirings/queue/signed-queue-service.ts +1 -1
  412. package/src/wirings/rpc/index.ts +0 -12
  413. package/src/wirings/rpc/rpc-runner.test.ts +4 -4
  414. package/src/wirings/rpc/rpc-runner.ts +3 -3
  415. package/src/wirings/scheduler/scheduler.types.ts +2 -5
  416. package/src/wirings/scope/index.ts +1 -0
  417. package/src/wirings/secret/secret.types.ts +10 -0
  418. package/src/wirings/secret/validate-secret-definitions.test.ts +23 -0
  419. package/src/wirings/secret/validate-secret-definitions.ts +2 -0
  420. package/src/wirings/variable/validate-variable-definitions.test.ts +23 -0
  421. package/src/wirings/variable/validate-variable-definitions.ts +2 -0
  422. package/src/wirings/variable/variable.types.ts +9 -0
  423. package/src/wirings/virtual-user/index.ts +1 -4
  424. package/src/wirings/virtual-user/prepare-virtual-user-run.ts +1 -1
  425. package/src/wirings/virtual-user/virtual-user-derive.test.ts +1 -1
  426. package/src/wirings/virtual-user/virtual-user-derive.ts +1 -1
  427. package/src/wirings/virtual-user/virtual-user.types.ts +1 -5
  428. package/src/wirings/workflow/graph/graph-foreach-queued.test.ts +569 -0
  429. package/src/wirings/workflow/graph/graph-foreach.test.ts +626 -0
  430. package/src/wirings/workflow/graph/graph-node.ts +16 -1
  431. package/src/wirings/workflow/graph/graph-runner.ts +387 -61
  432. package/src/wirings/workflow/graph/workflow-graph.types.ts +28 -3
  433. package/src/wirings/workflow/index.ts +8 -0
  434. package/src/wirings/workflow/pikku-scenario-service.ts +59 -19
  435. package/src/wirings/workflow/pikku-workflow-service.ts +6 -8
  436. package/src/wirings/workflow/run-timeline.ts +1 -1
  437. package/src/wirings/workflow/scenario-expectations.test.ts +28 -13
  438. package/src/wirings/workflow/scenario-run.types.ts +186 -0
  439. package/src/wirings/workflow/scenario-step-guards.ts +1 -14
  440. package/src/wirings/workflow/scenario-step.test.ts +32 -7
  441. package/src/wirings/workflow/scenario-step.types.ts +27 -12
  442. package/src/wirings/workflow/workflow-approval-policy.test.ts +117 -47
  443. package/src/wirings/workflow/workflow-approval.ts +2 -1
  444. package/src/wirings/workflow/workflow-run-engine.types.ts +2 -1
  445. package/src/wirings/workflow/workflow.types.ts +4 -12
  446. package/src/wirings-stay-decoupled.test.ts +6 -3
  447. package/tsconfig.tsbuildinfo +1 -1
  448. package/tsconfig.type-tests.json +3 -2
  449. package/dist/ecosystem/ai-agent.d.ts +0 -18
  450. package/dist/ecosystem/ai-agent.js +0 -6
  451. package/dist/ecosystem/ai-scorer.d.ts +0 -12
  452. package/dist/ecosystem/ai-scorer.js +0 -5
  453. package/dist/services/ai-agent-runner-service.d.ts +0 -220
  454. package/dist/services/ai-run-state-service.d.ts +0 -29
  455. package/dist/services/ai-storage-service.d.ts +0 -18
  456. package/dist/services/in-memory-ai-run-state-service.d.ts +0 -19
  457. package/dist/services/in-memory-ai-run-state-service.js +0 -54
  458. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +0 -3
  459. package/dist/testing/service-tests/ai-storage-service-tests.js +0 -302
  460. package/dist/wirings/ai-agent/agent-rpc.d.ts +0 -15
  461. package/dist/wirings/ai-agent/agent-rpc.js +0 -53
  462. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -79
  463. package/dist/wirings/ai-agent/ai-agent-agui.js +0 -327
  464. package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +0 -58
  465. package/dist/wirings/ai-agent/ai-agent-finalize.js +0 -138
  466. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +0 -35
  467. package/dist/wirings/ai-agent/ai-agent-helpers.js +0 -47
  468. package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +0 -153
  469. package/dist/wirings/ai-agent/ai-agent-interrupt.js +0 -257
  470. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +0 -42
  471. package/dist/wirings/ai-agent/ai-agent-memory.js +0 -333
  472. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -16
  473. package/dist/wirings/ai-agent/ai-agent-model-config.js +0 -51
  474. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +0 -117
  475. package/dist/wirings/ai-agent/ai-agent-prepare.js +0 -728
  476. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +0 -16
  477. package/dist/wirings/ai-agent/ai-agent-registry.js +0 -51
  478. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +0 -7
  479. package/dist/wirings/ai-agent/ai-agent-runner.js +0 -580
  480. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +0 -41
  481. package/dist/wirings/ai-agent/ai-agent-stream.js +0 -1029
  482. package/dist/wirings/ai-agent/ai-agent-turn.d.ts +0 -57
  483. package/dist/wirings/ai-agent/ai-agent-turn.js +0 -82
  484. package/dist/wirings/ai-agent/ai-agent-utils.d.ts +0 -1
  485. package/dist/wirings/ai-agent/ai-agent-utils.js +0 -1
  486. package/dist/wirings/ai-agent/ai-agent.types.d.ts +0 -625
  487. package/dist/wirings/ai-agent/index.d.ts +0 -12
  488. package/dist/wirings/ai-agent/index.js +0 -10
  489. package/dist/wirings/ai-agent/voice-input.d.ts +0 -69
  490. package/dist/wirings/ai-agent/voice-input.js +0 -150
  491. package/dist/wirings/ai-agent/voice-output.d.ts +0 -85
  492. package/dist/wirings/ai-agent/voice-output.js +0 -196
  493. package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +0 -26
  494. package/dist/wirings/ai-scorer/ai-scorer-grade.js +0 -33
  495. package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +0 -17
  496. package/dist/wirings/ai-scorer/ai-scorer-judge.js +0 -92
  497. package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +0 -15
  498. package/dist/wirings/ai-scorer/ai-scorer-live.js +0 -38
  499. package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +0 -18
  500. package/dist/wirings/ai-scorer/ai-scorer-registry.js +0 -46
  501. package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +0 -8
  502. package/dist/wirings/ai-scorer/ai-scorer-sampling.js +0 -31
  503. package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +0 -10
  504. package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +0 -40
  505. package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +0 -15
  506. package/dist/wirings/ai-scorer/ai-scorer-worker.js +0 -58
  507. package/dist/wirings/ai-scorer/ai-scorer.d.ts +0 -39
  508. package/dist/wirings/ai-scorer/ai-scorer.js +0 -40
  509. package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +0 -90
  510. package/dist/wirings/ai-scorer/ai-scorer.types.js +0 -4
  511. package/dist/wirings/ai-scorer/index.d.ts +0 -6
  512. package/dist/wirings/ai-scorer/index.js +0 -5
  513. package/src/ecosystem/agent-scorer.ts +0 -24
  514. package/src/ecosystem/agent.ts +0 -42
  515. package/src/ecosystem/channel/local.ts +0 -1
  516. package/src/ecosystem/channel.ts +0 -22
  517. package/src/ecosystem/cli/channel.ts +0 -25
  518. package/src/ecosystem/cli.ts +0 -21
  519. package/src/ecosystem/credential.ts +0 -10
  520. package/src/ecosystem/dev.ts +0 -12
  521. package/src/ecosystem/function.ts +0 -28
  522. package/src/ecosystem/gateway.ts +0 -4
  523. package/src/ecosystem/hmac.ts +0 -1
  524. package/src/ecosystem/http.ts +0 -22
  525. package/src/ecosystem/mcp.ts +0 -17
  526. package/src/ecosystem/middleware.ts +0 -27
  527. package/src/ecosystem/node-host-resolver.ts +0 -1
  528. package/src/ecosystem/node.ts +0 -5
  529. package/src/ecosystem/oauth2.ts +0 -4
  530. package/src/ecosystem/persona.ts +0 -30
  531. package/src/ecosystem/queue.ts +0 -23
  532. package/src/ecosystem/remote.ts +0 -9
  533. package/src/ecosystem/role.ts +0 -13
  534. package/src/ecosystem/rpc.ts +0 -7
  535. package/src/ecosystem/safe-fetch.ts +0 -8
  536. package/src/ecosystem/scenario.ts +0 -32
  537. package/src/ecosystem/scheduler.ts +0 -5
  538. package/src/ecosystem/schema.ts +0 -1
  539. package/src/ecosystem/scope.ts +0 -14
  540. package/src/ecosystem/secret.ts +0 -15
  541. package/src/ecosystem/services/istanbul-coverage.ts +0 -1
  542. package/src/ecosystem/services/local-content-request-handler.ts +0 -16
  543. package/src/ecosystem/services/local-content.ts +0 -1
  544. package/src/ecosystem/services/v8-coverage.ts +0 -1
  545. package/src/ecosystem/services.ts +0 -82
  546. package/src/ecosystem/trigger.ts +0 -7
  547. package/src/ecosystem/types.ts +0 -34
  548. package/src/ecosystem/variable.ts +0 -14
  549. package/src/ecosystem/virtual-user.ts +0 -48
  550. package/src/ecosystem/workflow.ts +0 -68
  551. package/src/ecosystem.ts +0 -40
  552. package/src/index.ts +0 -244
  553. /package/dist/{services/ai-agent-runner-service.js → bootstrap-compat/root.js} +0 -0
  554. /package/dist/{services/ai-run-state-service.js → classification/data-classification.js} +0 -0
  555. /package/dist/{services/ai-storage-service.js → errors/serialized-error.js} +0 -0
  556. /package/dist/{wirings/ai-agent/ai-agent.types.js → function/function-meta.types.js} +0 -0
  557. /package/src/{column-form.ts → classification/column-form.ts} +0 -0
  558. /package/src/{pikku-request.test.ts → function/pikku-request.test.ts} +0 -0
  559. /package/src/{pikku-request.ts → function/pikku-request.ts} +0 -0
  560. /package/src/wirings/{rpc → addon}/addon-auth-tags.test.ts +0 -0
  561. /package/src/wirings/{rpc → addon}/addon-runner.ts +0 -0
  562. /package/src/wirings/{rpc → addon}/addon-secrets.test.ts +0 -0
  563. /package/src/wirings/{rpc → addon}/wire-addon.test.ts +0 -0
  564. /package/src/wirings/{rpc → addon}/wire-remote-addon.ts +0 -0
@@ -1,69 +0,0 @@
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;
37
- /**
38
- * Shared-notes key recording whether the user's turn arrived as audio.
39
- *
40
- * Written here because this is the last point at which it is knowable: the
41
- * transcript that replaces the audio is indistinguishable from something typed.
42
- * Read by `voiceOutput` to decide whether to answer aloud.
43
- *
44
- * Absent — rather than `false` — when this middleware is not wired at all, which
45
- * is what lets `voiceOutput` still speak for a caller that has no voice input.
46
- */
47
- export declare const SPOKEN_TURN = "voice:spokenTurn";
48
- /**
49
- * Shared-notes key holding what the user was heard to say, when they spoke.
50
- *
51
- * Absent on a typed turn. Read by the stream wiring, which forwards it to the
52
- * client as a `transcript` event — a voice client has no idea what its own
53
- * audio said, and without this the user's turn shows up in the UI as an empty
54
- * bubble followed by an answer to a question they cannot see.
55
- */
56
- export declare const SPOKEN_TRANSCRIPT = "voice:transcript";
57
- export declare const voiceInput: (config?: {
58
- language?: string;
59
- model?: string;
60
- allowedAudioHosts?: string[];
61
- }) => import("./ai-agent.types.js").PikkuAIMiddlewareHooks<Record<string, unknown>, import("../../types/core.types.js").CoreSingletonServices<{
62
- logLevel?: import("../../services/logger.js").LogLevel;
63
- secrets?: {
64
- requireAllowedHosts?: boolean;
65
- };
66
- workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
67
- webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
68
- postgres?: import("../../types/core.types.js").PostgresConfig;
69
- }>>;
@@ -1,150 +0,0 @@
1
- import { pikkuAIMiddleware } from '../../types/core.types.js';
2
- import { safeFetch } from '../../utils/safe-fetch.js';
3
- function base64ToUint8Array(base64) {
4
- const binary = atob(base64);
5
- const bytes = new Uint8Array(binary.length);
6
- for (let i = 0; i < binary.length; i++) {
7
- bytes[i] = binary.charCodeAt(i);
8
- }
9
- return bytes;
10
- }
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();
49
- async function fetchAsUint8Array(url, allowedAudioHosts) {
50
- const response = await safeFetch(url, {}, { allowedHosts: allowedAudioHosts });
51
- const contentLength = response.headers.get('content-length');
52
- if (contentLength && parseInt(contentLength, 10) > MAX_AUDIO_SIZE) {
53
- throw new Error('Audio file exceeds maximum size');
54
- }
55
- const buffer = await response.arrayBuffer();
56
- if (buffer.byteLength > MAX_AUDIO_SIZE) {
57
- throw new Error('Audio file exceeds maximum size');
58
- }
59
- return new Uint8Array(buffer);
60
- }
61
- /**
62
- * Shared-notes key recording whether the user's turn arrived as audio.
63
- *
64
- * Written here because this is the last point at which it is knowable: the
65
- * transcript that replaces the audio is indistinguishable from something typed.
66
- * Read by `voiceOutput` to decide whether to answer aloud.
67
- *
68
- * Absent — rather than `false` — when this middleware is not wired at all, which
69
- * is what lets `voiceOutput` still speak for a caller that has no voice input.
70
- */
71
- export const SPOKEN_TURN = 'voice:spokenTurn';
72
- /**
73
- * Shared-notes key holding what the user was heard to say, when they spoke.
74
- *
75
- * Absent on a typed turn. Read by the stream wiring, which forwards it to the
76
- * client as a `transcript` event — a voice client has no idea what its own
77
- * audio said, and without this the user's turn shows up in the UI as an empty
78
- * bubble followed by an answer to a question they cannot see.
79
- */
80
- export const SPOKEN_TRANSCRIPT = 'voice:transcript';
81
- export const voiceInput = (config) => pikkuAIMiddleware({
82
- modifyInput: async (services, { messages, instructions, shared }) => {
83
- const aiAgentRunner = services.aiAgentRunner;
84
- if (!aiAgentRunner?.transcribe)
85
- return { messages, instructions };
86
- const last = messages[messages.length - 1];
87
- const parts = last?.role === 'user' && typeof last.content !== 'string'
88
- ? last.content
89
- : undefined;
90
- const hasAudio = !!parts?.some((p) => p.type === 'file' && !!p.mediaType?.startsWith('audio/'));
91
- // Recorded on every turn this middleware sees, spoken or not, so that a
92
- // typed turn is an explicit `false` downstream rather than a silence that
93
- // could equally mean nobody was asked.
94
- shared[SPOKEN_TURN] = hasAudio;
95
- if (!hasAudio || !parts)
96
- return { messages, instructions };
97
- const updatedContent = [];
98
- const heard = [];
99
- for (const p of parts) {
100
- if (!(p.type === 'file' && p.mediaType?.startsWith('audio/'))) {
101
- updatedContent.push(p);
102
- continue;
103
- }
104
- if (!config?.model) {
105
- throw new Error('voiceInput requires a transcription model (e.g. openai/whisper-1)');
106
- }
107
- const audioData = p.data
108
- ? base64ToUint8Array(p.data)
109
- : await fetchAsUint8Array(p.url, config.allowedAudioHosts);
110
- if (audioData.byteLength > MAX_AUDIO_SIZE) {
111
- throw new Error('Audio file exceeds maximum size');
112
- }
113
- const result = await aiAgentRunner.transcribe({
114
- model: config.model,
115
- audio: audioData,
116
- ...(config.language
117
- ? {
118
- providerOptions: {
119
- openai: {
120
- language: config.language,
121
- },
122
- },
123
- }
124
- : {}),
125
- });
126
- // Dropped when nothing was said: an empty text part is still a turn the
127
- // model will answer, and what it answers is a guess about what it could
128
- // not hear.
129
- if (readsAsNonSpeech(result))
130
- continue;
131
- heard.push(result.text);
132
- updatedContent.push({ type: 'text', text: result.text });
133
- }
134
- // Every part was audio, and none of it was speech. There is nothing left
135
- // to send, and a message with no content is not a question.
136
- if (updatedContent.length === 0)
137
- throw new NoSpeechDetectedError();
138
- // knowledge: decisions/internals/an-empty-transcript-is-not-recorded.md
139
- if (heard.length > 0) {
140
- shared[SPOKEN_TRANSCRIPT] = heard.join(' ');
141
- }
142
- return {
143
- messages: [
144
- ...messages.slice(0, -1),
145
- { ...last, content: updatedContent },
146
- ],
147
- instructions,
148
- };
149
- },
150
- });
@@ -1,85 +0,0 @@
1
- export type VoiceOutputState = {
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;
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;
45
- export declare const voiceOutput: (config?: {
46
- model?: string;
47
- format?: string;
48
- voice?: string;
49
- instructions?: string;
50
- speed?: number;
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;
62
- /**
63
- * Speak every reply, including answers to turns that were typed.
64
- *
65
- * The default is to speak only what was spoken to. An agent is usually one
66
- * agent serving both kinds of caller — the same thread is typed at from a
67
- * desk and talked to from a phone — and synthesizing a reply nobody is
68
- * listening to costs real money on every sentence of every turn. Whether the
69
- * user is in a call is not something the client needs to declare: sending
70
- * audio is what saying so looks like.
71
- *
72
- * Set this for the cases where speech is not a reply to speech at all — a
73
- * read-aloud accessibility mode, a kiosk, anything whose whole output is
74
- * meant to be heard.
75
- */
76
- always?: boolean;
77
- }) => import("./ai-agent.types.js").PikkuAIMiddlewareHooks<VoiceOutputState, import("../../types/core.types.js").CoreSingletonServices<{
78
- logLevel?: import("../../services/logger.js").LogLevel;
79
- secrets?: {
80
- requireAllowedHosts?: boolean;
81
- };
82
- workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
83
- webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
84
- postgres?: import("../../types/core.types.js").PostgresConfig;
85
- }>>;
@@ -1,196 +0,0 @@
1
- import { pikkuAIMiddleware } from '../../types/core.types.js';
2
- import { SPOKEN_TURN } from './voice-input.js';
3
- function bufferToBase64(data) {
4
- let binary = '';
5
- for (let i = 0; i < data.length; i++) {
6
- binary += String.fromCharCode(data[i]);
7
- }
8
- return btoa(binary);
9
- }
10
- const SENTENCE_BOUNDARY = /[.!?]\s*$/;
11
- function isSentenceBoundary(text) {
12
- return SENTENCE_BOUNDARY.test(text);
13
- }
14
- /**
15
- * Scripts a speech model can pronounce, as named by {@link voiceOutput}'s
16
- * `speakableScripts`.
17
- *
18
- * Script rather than language because script is what is decidable from the text
19
- * alone. Spanish, French and English are one test, not three — and the models
20
- * that handle one Latin-script language generally handle the others. What a
21
- * model cannot do is invent a phoneme set it was never given.
22
- */
23
- const SCRIPT_RANGES = {
24
- latin: /[A-ɏ]/,
25
- devanagari: /[ऀ-ॿ]/,
26
- han: /[㐀-鿿]/,
27
- kana: /[぀-ヿ]/,
28
- arabic: /[؀-ۿݐ-ݿ]/,
29
- cyrillic: /[Ѐ-ӿ]/,
30
- hangul: /[가-힯ᄀ-ᇿ]/,
31
- hebrew: /[֐-׿]/,
32
- greek: /[Ͱ-Ͽ]/,
33
- thai: /[฀-๿]/,
34
- };
35
- /**
36
- * Which script decides the voice when a sentence contains several.
37
- *
38
- * The ordering is by how much a script narrows down the language, not by
39
- * preference. Kana appears only in Japanese, so a sentence holding any settles
40
- * it — while Han is written in both Chinese and Japanese and so cannot, which
41
- * matters because ordinary Japanese is mostly kanji. Latin comes last for the
42
- * same reason from the other end: it turns up inside sentences in every other
43
- * script, and it is the one whose voice is least often the one that counts. A
44
- * Chinese voice reading an English word is accented; an English voice reading
45
- * Chinese spells it out.
46
- *
47
- * Everything else — Han included — sits between the two in config order.
48
- */
49
- const SCRIPT_PRECEDENCE = { kana: -1, latin: 1 };
50
- const scriptRank = (name) => SCRIPT_PRECEDENCE[name] ?? 0;
51
- const scriptNames = (speakable) => Array.isArray(speakable) ? speakable : Object.keys(speakable);
52
- /**
53
- * The scripts present in `text` that the model was not said to handle.
54
- *
55
- * Silence would be the wrong answer here and so would a best effort. Handed
56
- * Arabic — which it has no voice for at all — Kokoro does not fail and does not
57
- * stay quiet: it reads out the *letter names*, twenty-four seconds of "Arabic
58
- * meem, Arabic ra" for a one-line sentence, which is worse than either. Naming
59
- * the gap lets the caller say so instead.
60
- */
61
- export const unspeakableScripts = (text, speakable) => {
62
- const allowed = new Set(scriptNames(speakable));
63
- return Object.entries(SCRIPT_RANGES)
64
- .filter(([name, range]) => !allowed.has(name) && range.test(text))
65
- .map(([name]) => name);
66
- };
67
- /**
68
- * The voice to speak `text` in, or `fallback` if no mapped script appears.
69
- *
70
- * A sentence is regularly in more than one script, so which one decides is
71
- * settled by {@link SCRIPT_PRECEDENCE} rather than by the order the config
72
- * happens to be written in.
73
- */
74
- export const voiceForText = (text, speakable, fallback) => {
75
- if (Array.isArray(speakable))
76
- return fallback;
77
- const mapped = Object.entries(speakable).sort(([a], [b]) => scriptRank(a) - scriptRank(b));
78
- for (const [name, voice] of mapped) {
79
- if (SCRIPT_RANGES[name]?.test(text))
80
- return voice;
81
- }
82
- return fallback;
83
- };
84
- async function synthesizeAudio(aiAgentRunner, input) {
85
- const result = await aiAgentRunner.generateSpeech?.({
86
- model: input.model,
87
- text: input.text,
88
- voice: input.voice,
89
- outputFormat: input.format,
90
- instructions: input.instructions,
91
- speed: input.speed,
92
- language: input.language,
93
- abortSignal: input.abortSignal,
94
- });
95
- if (!result) {
96
- throw new Error('voiceOutput requires an aiAgentRunner with generateSpeech support');
97
- }
98
- return {
99
- bytes: result.audio.uint8Array,
100
- format: result.audio.format || input.format || 'pcm16',
101
- };
102
- }
103
- export const voiceOutput = (config) => pikkuAIMiddleware({
104
- modifyOutputStream: async (services, { event, state, shared, emit, signal }) => {
105
- const { aiAgentRunner, logger } = services;
106
- if (!aiAgentRunner?.generateSpeech)
107
- return event;
108
- // knowledge: decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md
109
- if (!config?.always && shared[SPOKEN_TURN] === false)
110
- return event;
111
- /**
112
- * Queue a finished sentence for speech.
113
- *
114
- * Nothing here is awaited by the caller. Synthesis is kicked off at once
115
- * and its emission is chained behind the previous sentence, which is
116
- * what keeps the text flowing at the speed the model writes it instead
117
- * of the speed the speech provider answers.
118
- */
119
- const speak = (text) => {
120
- if (!config?.model) {
121
- throw new Error('voiceOutput requires a speech model (e.g. openai/tts-1)');
122
- }
123
- // knowledge: decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md
124
- let voice = config.voice;
125
- if (config.speakableScripts) {
126
- const unspeakable = unspeakableScripts(text, config.speakableScripts);
127
- voice = voiceForText(text, config.speakableScripts, config.voice);
128
- if (unspeakable.length > 0) {
129
- if (!state.reportedUnspeakable) {
130
- state.reportedUnspeakable = true;
131
- state.tail = (state.tail ?? Promise.resolve()).then(() => emit({
132
- type: 'data',
133
- name: 'voice-unsupported',
134
- data: { model: config.model, scripts: unspeakable },
135
- }));
136
- }
137
- return;
138
- }
139
- }
140
- // Settled into a value rather than left as a rejectable promise: it
141
- // sits unobserved until the chain reaches it, and an unhandled
142
- // rejection in that window would take the process down.
143
- const synthesis = synthesizeAudio(aiAgentRunner, {
144
- model: config.model,
145
- text,
146
- voice,
147
- format: config?.format,
148
- instructions: config?.instructions,
149
- speed: config?.speed,
150
- language: config?.language,
151
- // Barge-in should stop the bill, not just the playback. Without this
152
- // every sentence already in flight is synthesized in full and paid
153
- // for after the user has stopped listening.
154
- abortSignal: signal,
155
- }).then((audio) => ({ ok: true, audio }), (error) => ({ ok: false, error }));
156
- state.tail = (state.tail ?? Promise.resolve()).then(async () => {
157
- const result = await synthesis;
158
- if (!result.ok) {
159
- // One sentence going unspoken is better than the rest of the reply
160
- // never arriving, so the chain carries on.
161
- logger?.error(`voiceOutput could not synthesize a sentence: ${String(result.error)}`);
162
- return;
163
- }
164
- await emit({
165
- type: 'audio-delta',
166
- data: bufferToBase64(result.audio.bytes),
167
- format: result.audio.format,
168
- text,
169
- });
170
- });
171
- };
172
- if (event.type === 'done') {
173
- const remaining = state.textBuffer ?? '';
174
- state.textBuffer = '';
175
- if (remaining.trim()) {
176
- speak(remaining);
177
- }
178
- // The only place this hook waits. The reply is already over, so the
179
- // wait costs the reader nothing, and it is what makes `audio-done`
180
- // mean what it says rather than racing the last chunk.
181
- await state.tail;
182
- state.tail = undefined;
183
- return [{ type: 'audio-done' }, event];
184
- }
185
- if (event.type !== 'text-delta')
186
- return event;
187
- state.textBuffer = `${state.textBuffer ?? ''}${event.text}`;
188
- if (isSentenceBoundary(state.textBuffer)) {
189
- const text = state.textBuffer;
190
- state.textBuffer = '';
191
- speak(text);
192
- }
193
- // Returned without waiting for any audio — the entire point.
194
- return event;
195
- },
196
- });
@@ -1,26 +0,0 @@
1
- import type { ScoreJob, ScorerOutput } from './ai-scorer.types.js';
2
- /**
3
- * Grade one run with one scorer.
4
- *
5
- * The single path both callers take — the lane worker on live traffic and the
6
- * scenario grading RPC — so a scenario's grade is the same computation the
7
- * production sampler would have made, not an approximation of it.
8
- *
9
- * Persisting is optional because the two callers differ on it: a live grade is
10
- * only useful once recorded, while a scenario asserts on the returned value and
11
- * runs against servers that may have no run-state adapter at all.
12
- */
13
- export declare const gradeRun: (job: ScoreJob, services: {
14
- aiAgentRunner?: unknown;
15
- aiRunState?: {
16
- saveScore: (score: {
17
- runId: string;
18
- scorerName: string;
19
- score: number;
20
- reason?: string;
21
- metadata?: Record<string, unknown>;
22
- }) => Promise<void>;
23
- };
24
- }, options: {
25
- persist: boolean;
26
- }) => Promise<ScorerOutput>;
@@ -1,33 +0,0 @@
1
- import { runJudge } from './ai-scorer-judge.js';
2
- import { resolveAIScorer } from './ai-scorer-registry.js';
3
- /**
4
- * Grade one run with one scorer.
5
- *
6
- * The single path both callers take — the lane worker on live traffic and the
7
- * scenario grading RPC — so a scenario's grade is the same computation the
8
- * production sampler would have made, not an approximation of it.
9
- *
10
- * Persisting is optional because the two callers differ on it: a live grade is
11
- * only useful once recorded, while a scenario asserts on the returned value and
12
- * runs against servers that may have no run-state adapter at all.
13
- */
14
- export const gradeRun = async (job, services, options) => {
15
- const { scorerName, ...input } = job;
16
- const scorer = resolveAIScorer(scorerName);
17
- const result = scorer.score
18
- ? await scorer.score(input, services)
19
- : await runJudge(scorer, input, services.aiAgentRunner);
20
- if (options.persist) {
21
- if (!services.aiRunState) {
22
- throw new Error(`AI run state service not initialized: cannot record the '${scorerName}' grade of run ${job.runId}`);
23
- }
24
- await services.aiRunState.saveScore({
25
- runId: job.runId,
26
- scorerName,
27
- score: result.score,
28
- ...(result.reason !== undefined ? { reason: result.reason } : {}),
29
- ...(result.metadata !== undefined ? { metadata: result.metadata } : {}),
30
- });
31
- }
32
- return result;
33
- };
@@ -1,17 +0,0 @@
1
- import type { AIAgentRunnerService } from '../../services/ai-agent-runner-service.js';
2
- import type { PikkuAIScorer, ScorerInput, ScorerJudgeConfig, ScorerOutput } from './ai-scorer.types.js';
3
- /**
4
- * The message a judge grades when its scorer supplies no `prompt`.
5
- *
6
- * A reference-based judge is shown the answer key; a reference-free one is not,
7
- * and grades the answer on its own merits.
8
- */
9
- export declare const buildJudgePrompt: (judge: ScorerJudgeConfig, input: ScorerInput) => string;
10
- /**
11
- * Run an LLM judge and force the `{ score, reason }` contract, so a scorer
12
- * author writes a rubric rather than a parser.
13
- *
14
- * A judge has no tools, which is the one case where an output schema is
15
- * reliably honoured.
16
- */
17
- export declare const runJudge: (scorer: PikkuAIScorer<any>, input: ScorerInput, aiAgentRunner: AIAgentRunnerService | undefined) => Promise<ScorerOutput>;
@@ -1,92 +0,0 @@
1
- import { randomUUID } from '../ai-agent/ai-agent-utils.js';
2
- const JUDGE_OUTPUT_SCHEMA = {
3
- type: 'object',
4
- properties: {
5
- score: {
6
- type: 'number',
7
- minimum: 0,
8
- maximum: 1,
9
- description: 'How well the answer meets the rubric. 1 is best.',
10
- },
11
- reason: {
12
- type: 'string',
13
- description: 'One or two sentences explaining the score.',
14
- },
15
- },
16
- required: ['score', 'reason'],
17
- additionalProperties: false,
18
- };
19
- /**
20
- * The message a judge grades when its scorer supplies no `prompt`.
21
- *
22
- * A reference-based judge is shown the answer key; a reference-free one is not,
23
- * and grades the answer on its own merits.
24
- */
25
- export const buildJudgePrompt = (judge, input) => {
26
- if (judge.prompt)
27
- return judge.prompt(input);
28
- const sections = [`User asked:\n${input.input}`];
29
- if (input.reference !== undefined) {
30
- sections.push(`Reference answer:\n${input.reference}`);
31
- }
32
- sections.push(`Assistant answered:\n${input.output}`);
33
- sections.push(judge.goal);
34
- sections.push('Respond with a score 0..1 and a brief reason.');
35
- return sections.join('\n\n');
36
- };
37
- /**
38
- * Clamp rather than reject: a model that answers 1.2 has still made a legible
39
- * judgement, and failing the job would lose it. A non-number has not.
40
- */
41
- const normalizeScore = (scorerName, value) => {
42
- if (typeof value !== 'number' || Number.isNaN(value)) {
43
- throw new Error(`Judge '${scorerName}' returned a non-numeric score: ${JSON.stringify(value)}`);
44
- }
45
- return Math.min(1, Math.max(0, value));
46
- };
47
- /**
48
- * Run an LLM judge and force the `{ score, reason }` contract, so a scorer
49
- * author writes a rubric rather than a parser.
50
- *
51
- * A judge has no tools, which is the one case where an output schema is
52
- * reliably honoured.
53
- */
54
- export const runJudge = async (scorer, input, aiAgentRunner) => {
55
- const judge = scorer.judge;
56
- if (!judge) {
57
- throw new Error(`Scorer '${scorer.name}' is not a judge`);
58
- }
59
- if (!aiAgentRunner) {
60
- throw new Error(`Judge '${scorer.name}' needs an AI provider, but no aiAgentRunner is registered in this process. ` +
61
- `A worker deployed apart from the API has to register one to run the slow scoring lane.`);
62
- }
63
- if (scorer.requiresReference && input.reference === undefined) {
64
- throw new Error(`Judge '${scorer.name}' grades against a reference answer, but none was supplied`);
65
- }
66
- const messages = [
67
- {
68
- id: randomUUID(),
69
- role: 'user',
70
- content: buildJudgePrompt(judge, input),
71
- createdAt: new Date(),
72
- },
73
- ];
74
- const result = await aiAgentRunner.run({
75
- model: judge.model,
76
- instructions: judge.goal,
77
- messages,
78
- tools: [],
79
- maxSteps: 1,
80
- toolChoice: 'none',
81
- outputSchema: JUDGE_OUTPUT_SCHEMA,
82
- });
83
- const object = (result.object ?? {});
84
- return {
85
- score: normalizeScore(scorer.name, object.score),
86
- ...(typeof object.reason === 'string' ? { reason: object.reason } : {}),
87
- metadata: {
88
- judgeModel: judge.model,
89
- judgeTokens: result.usage.inputTokens + result.usage.outputTokens,
90
- },
91
- };
92
- };