@pikku/core 0.12.79 → 0.12.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (479) hide show
  1. package/CHANGELOG.md +473 -0
  2. package/dist/dev/hot-reload.js +1 -6
  3. package/dist/ecosystem.d.ts +27 -0
  4. package/dist/ecosystem.js +26 -0
  5. package/dist/errors/error-handler.js +4 -2
  6. package/dist/errors/index.d.ts +1 -1
  7. package/dist/errors/index.js +1 -1
  8. package/dist/function/function-runner.js +22 -47
  9. package/dist/function/functions.types.d.ts +9 -5
  10. package/dist/function/index.d.ts +1 -1
  11. package/dist/index.d.ts +14 -19
  12. package/dist/index.js +6 -11
  13. package/dist/middleware/auth-cookie.d.ts +0 -4
  14. package/dist/middleware/auth-cookie.js +38 -2
  15. package/dist/middleware/cors.js +1 -0
  16. package/dist/middleware/index.d.ts +1 -1
  17. package/dist/middleware/index.js +1 -1
  18. package/dist/middleware/remote-auth.js +14 -3
  19. package/dist/permissions.d.ts +8 -10
  20. package/dist/permissions.js +0 -11
  21. package/dist/pikku-state.js +16 -5
  22. package/dist/schema.js +35 -1
  23. package/dist/services/ai-agent-runner-service.d.ts +7 -0
  24. package/dist/services/ai-run-state-service.d.ts +17 -1
  25. package/dist/services/in-memory-ai-run-state-service.d.ts +6 -2
  26. package/dist/services/in-memory-ai-run-state-service.js +11 -1
  27. package/dist/services/in-memory-workflow-service.js +2 -0
  28. package/dist/services/index.d.ts +15 -15
  29. package/dist/services/index.js +5 -5
  30. package/dist/services/local-content-request-handler.d.ts +21 -0
  31. package/dist/services/local-content-request-handler.js +72 -53
  32. package/dist/services/local-content.d.ts +6 -0
  33. package/dist/services/local-content.js +14 -1
  34. package/dist/services/scoped-credential-service.d.ts +21 -0
  35. package/dist/services/scoped-credential-service.js +53 -0
  36. package/dist/services/workflow-service.d.ts +4 -2
  37. package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
  38. package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
  39. package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
  40. package/dist/testing/service-tests/ai-storage-service-tests.js +302 -0
  41. package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
  42. package/dist/testing/service-tests/channel-store-tests.js +72 -0
  43. package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
  44. package/dist/testing/service-tests/credential-service-tests.js +109 -0
  45. package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
  46. package/dist/testing/service-tests/deployment-service-tests.js +21 -0
  47. package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
  48. package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
  49. package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
  50. package/dist/testing/service-tests/secret-service-tests.js +80 -0
  51. package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
  52. package/dist/testing/service-tests/session-store-tests.js +43 -0
  53. package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
  54. package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
  55. package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
  56. package/dist/testing/service-tests/workflow-service-tests.js +150 -0
  57. package/dist/testing/service-tests.d.ts +6 -0
  58. package/dist/testing/service-tests.js +26 -791
  59. package/dist/types/core.types.d.ts +11 -3
  60. package/dist/types/state.types.d.ts +14 -1
  61. package/dist/wirings/actor-flow/index.d.ts +1 -1
  62. package/dist/wirings/actor-flow/run-conversation.js +1 -6
  63. package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
  64. package/dist/wirings/ai-agent/agent-rpc.js +53 -0
  65. package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
  66. package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
  67. package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
  68. package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
  69. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
  70. package/dist/wirings/ai-agent/ai-agent-memory.js +37 -18
  71. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
  72. package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
  73. package/dist/wirings/ai-agent/ai-agent-prepare.js +5 -9
  74. package/dist/wirings/ai-agent/ai-agent-runner.js +89 -147
  75. package/dist/wirings/ai-agent/ai-agent-stream.js +109 -97
  76. package/dist/wirings/ai-agent/ai-agent-turn.d.ts +57 -0
  77. package/dist/wirings/ai-agent/ai-agent-turn.js +82 -0
  78. package/dist/wirings/ai-agent/ai-agent.types.d.ts +47 -2
  79. package/dist/wirings/ai-agent/index.d.ts +8 -7
  80. package/dist/wirings/ai-agent/index.js +5 -4
  81. package/dist/wirings/ai-agent/voice-input.js +1 -6
  82. package/dist/wirings/ai-agent/voice-output.js +2 -12
  83. package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
  84. package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
  85. package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
  86. package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
  87. package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
  88. package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
  89. package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
  90. package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
  91. package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
  92. package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
  93. package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
  94. package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
  95. package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
  96. package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
  97. package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
  98. package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
  99. package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
  100. package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
  101. package/dist/wirings/ai-scorer/index.d.ts +6 -0
  102. package/dist/wirings/ai-scorer/index.js +5 -0
  103. package/dist/wirings/channel/channel-common.js +1 -0
  104. package/dist/wirings/channel/channel-handler.js +3 -5
  105. package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
  106. package/dist/wirings/channel/channel-rpc-service.js +0 -8
  107. package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
  108. package/dist/wirings/channel/channel-rpc.types.js +8 -0
  109. package/dist/wirings/channel/channel-runner.d.ts +1 -3
  110. package/dist/wirings/channel/channel-runner.js +16 -8
  111. package/dist/wirings/channel/channel.types.d.ts +2 -0
  112. package/dist/wirings/channel/index.d.ts +5 -6
  113. package/dist/wirings/channel/index.js +3 -4
  114. package/dist/wirings/channel/local/local-channel-runner.js +8 -1
  115. package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
  116. package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
  117. package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
  118. package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
  119. package/dist/wirings/cli/channel/index.d.ts +1 -2
  120. package/dist/wirings/cli/channel/index.js +0 -1
  121. package/dist/wirings/cli/cli-runner.js +17 -3
  122. package/dist/wirings/cli/cli.types.d.ts +0 -8
  123. package/dist/wirings/cli/command-parser.js +13 -0
  124. package/dist/wirings/credential/index.d.ts +1 -1
  125. package/dist/wirings/gateway/gateway-runner.js +9 -2
  126. package/dist/wirings/gateway/index.d.ts +1 -1
  127. package/dist/wirings/http/http-routes.js +2 -0
  128. package/dist/wirings/http/http-runner.d.ts +0 -10
  129. package/dist/wirings/http/http-runner.js +14 -15
  130. package/dist/wirings/http/http.types.d.ts +0 -10
  131. package/dist/wirings/http/index.d.ts +2 -3
  132. package/dist/wirings/http/index.js +1 -1
  133. package/dist/wirings/mcp/index.d.ts +1 -1
  134. package/dist/wirings/mcp/mcp-runner.d.ts +15 -7
  135. package/dist/wirings/mcp/mcp-runner.js +18 -11
  136. package/dist/wirings/persona/index.d.ts +3 -4
  137. package/dist/wirings/persona/index.js +2 -3
  138. package/dist/wirings/queue/index.d.ts +1 -3
  139. package/dist/wirings/queue/index.js +1 -3
  140. package/dist/wirings/rpc/addon-runner.d.ts +4 -0
  141. package/dist/wirings/rpc/addon-runner.js +19 -3
  142. package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
  143. package/dist/wirings/rpc/rpc-runner.js +55 -86
  144. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  145. package/dist/wirings/rpc/wire-addon.d.ts +13 -0
  146. package/dist/wirings/rpc/wire-addon.js +4 -0
  147. package/dist/wirings/scheduler/index.d.ts +1 -1
  148. package/dist/wirings/secret/validate-secret-definitions.js +2 -2
  149. package/dist/wirings/trigger/index.d.ts +1 -1
  150. package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
  151. package/dist/wirings/trigger/trigger-runner.js +1 -0
  152. package/dist/wirings/virtual-user/index.d.ts +5 -6
  153. package/dist/wirings/virtual-user/index.js +2 -4
  154. package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
  155. package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
  156. package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
  157. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +100 -3
  158. package/dist/wirings/workflow/feature.js +7 -4
  159. package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
  160. package/dist/wirings/workflow/graph/graph-runner.js +8 -7
  161. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
  162. package/dist/wirings/workflow/index.d.ts +12 -7
  163. package/dist/wirings/workflow/index.js +7 -3
  164. package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
  165. package/dist/wirings/workflow/pikku-scenario-service.js +64 -10
  166. package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -147
  167. package/dist/wirings/workflow/pikku-workflow-service.js +85 -493
  168. package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
  169. package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
  170. package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
  171. package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
  172. package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
  173. package/dist/wirings/workflow/workflow-approval.d.ts +67 -0
  174. package/dist/wirings/workflow/workflow-approval.js +177 -0
  175. package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
  176. package/dist/wirings/workflow/workflow-constants.js +35 -0
  177. package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
  178. package/dist/wirings/workflow/workflow-errors.js +112 -0
  179. package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
  180. package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
  181. package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
  182. package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
  183. package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
  184. package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
  185. package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
  186. package/dist/wirings/workflow/workflow-recovery.js +101 -0
  187. package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
  188. package/dist/wirings/workflow/workflow-run-ownership.d.ts +17 -0
  189. package/dist/wirings/workflow/workflow-run-ownership.js +30 -0
  190. package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
  191. package/dist/wirings/workflow/workflow-suspend.js +33 -0
  192. package/dist/wirings/workflow/workflow.types.d.ts +8 -1
  193. package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
  194. package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
  195. package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
  196. package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
  197. package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
  198. package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
  199. package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
  200. package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
  201. package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
  202. package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
  203. package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
  204. package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
  205. package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
  206. package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
  207. package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
  208. package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
  209. package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
  210. package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
  211. package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
  212. package/knowledge/decisions/internals/index.md +42 -3
  213. package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
  214. package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
  215. package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
  216. package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
  217. package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
  218. package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
  219. package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
  220. package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
  221. package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
  222. package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
  223. package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
  224. package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
  225. package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
  226. package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
  227. package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
  228. package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
  229. package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
  230. package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
  231. package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
  232. package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
  233. package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
  234. package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
  235. package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
  236. package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
  237. package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
  238. package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +50 -0
  239. package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
  240. package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
  241. package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
  242. package/knowledge/decisions/security/index.md +9 -0
  243. package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
  244. package/knowledge/questions/index.md +2 -1
  245. package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
  246. package/package.json +15 -3
  247. package/scripts/generate-api-report.d.mts +1 -0
  248. package/scripts/generate-api-report.mjs +89 -0
  249. package/scripts/generate-api-report.mts +343 -0
  250. package/src/api-report.test.ts +69 -0
  251. package/src/column-form.ts +1 -4
  252. package/src/crypto-utils.test.ts +15 -2
  253. package/src/dev/hot-reload.ts +2 -7
  254. package/src/ecosystem.ts +40 -0
  255. package/src/errors/error-handler.ts +5 -3
  256. package/src/errors/error.test.ts +4 -1
  257. package/src/errors/index.ts +1 -1
  258. package/src/function/function-runner.test.ts +53 -1
  259. package/src/function/function-runner.ts +33 -48
  260. package/src/function/functions.types.ts +15 -9
  261. package/src/function/index.ts +0 -2
  262. package/src/handle-error.ts +1 -1
  263. package/src/index.ts +3 -57
  264. package/src/middleware/auth-cookie.test.ts +50 -0
  265. package/src/middleware/auth-cookie.ts +38 -2
  266. package/src/middleware/cors.ts +2 -1
  267. package/src/middleware/index.ts +1 -1
  268. package/src/middleware/remote-auth.test.ts +43 -0
  269. package/src/middleware/remote-auth.ts +17 -3
  270. package/src/middleware-runner.ts +4 -2
  271. package/src/no-any-casts.test.ts +57 -0
  272. package/src/permissions.test.ts +3 -1
  273. package/src/permissions.ts +22 -24
  274. package/src/pikku-state.ts +22 -6
  275. package/src/public-surface.json +554 -0
  276. package/src/public-surface.json.README +25 -0
  277. package/src/public-surface.test.ts +105 -0
  278. package/src/removed-legacy-exports.test.ts +62 -0
  279. package/src/schema.test.ts +78 -0
  280. package/src/schema.ts +36 -1
  281. package/src/services/ai-agent-runner-service.ts +12 -1
  282. package/src/services/ai-run-state-service.ts +18 -1
  283. package/src/services/audit-service.ts +2 -2
  284. package/src/services/in-memory-ai-run-state-service.ts +16 -2
  285. package/src/services/in-memory-workflow-service.ts +2 -0
  286. package/src/services/index.ts +4 -47
  287. package/src/services/local-content-request-handler.test.ts +43 -5
  288. package/src/services/local-content-request-handler.ts +103 -74
  289. package/src/services/local-content.ts +15 -1
  290. package/src/services/local-email-service.ts +5 -1
  291. package/src/services/scoped-credential-service.test.ts +86 -0
  292. package/src/services/scoped-credential-service.ts +63 -0
  293. package/src/services/system-role-guard.test.ts +4 -1
  294. package/src/services/workflow-service.ts +9 -2
  295. package/src/side-effects-are-declared.test.ts +84 -0
  296. package/src/source-files-stay-composable.test.ts +41 -0
  297. package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
  298. package/src/testing/service-tests/ai-storage-service-tests.ts +379 -0
  299. package/src/testing/service-tests/channel-store-tests.ts +98 -0
  300. package/src/testing/service-tests/credential-service-tests.ts +143 -0
  301. package/src/testing/service-tests/deployment-service-tests.ts +33 -0
  302. package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
  303. package/src/testing/service-tests/secret-service-tests.ts +105 -0
  304. package/src/testing/service-tests/session-store-tests.ts +62 -0
  305. package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
  306. package/src/testing/service-tests/workflow-service-tests.ts +308 -0
  307. package/src/testing/service-tests.ts +31 -1111
  308. package/src/types/core.types.ts +14 -3
  309. package/src/types/state.types.ts +17 -1
  310. package/src/wirings/actor-flow/index.ts +0 -3
  311. package/src/wirings/actor-flow/run-conversation.ts +1 -6
  312. package/src/wirings/ai-agent/agent-rpc.ts +120 -0
  313. package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
  314. package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
  315. package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
  316. package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
  317. package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
  318. package/src/wirings/ai-agent/ai-agent-memory.ts +62 -39
  319. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
  320. package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
  321. package/src/wirings/ai-agent/ai-agent-prepare.ts +12 -12
  322. package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
  323. package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
  324. package/src/wirings/ai-agent/ai-agent-runner.ts +120 -160
  325. package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
  326. package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
  327. package/src/wirings/ai-agent/ai-agent-stream.ts +152 -117
  328. package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
  329. package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
  330. package/src/wirings/ai-agent/ai-agent-turn.ts +122 -0
  331. package/src/wirings/ai-agent/ai-agent.types.ts +65 -5
  332. package/src/wirings/ai-agent/index.ts +2 -16
  333. package/src/wirings/ai-agent/voice-input.ts +1 -6
  334. package/src/wirings/ai-agent/voice-output.ts +2 -12
  335. package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
  336. package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
  337. package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
  338. package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
  339. package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
  340. package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
  341. package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
  342. package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
  343. package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
  344. package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
  345. package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
  346. package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
  347. package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
  348. package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
  349. package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
  350. package/src/wirings/ai-scorer/index.ts +24 -0
  351. package/src/wirings/channel/channel-common.ts +5 -2
  352. package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
  353. package/src/wirings/channel/channel-handler.ts +7 -7
  354. package/src/wirings/channel/channel-rpc-service.ts +0 -14
  355. package/src/wirings/channel/channel-rpc.test.ts +25 -4
  356. package/src/wirings/channel/channel-rpc.types.ts +14 -0
  357. package/src/wirings/channel/channel-runner.ts +33 -20
  358. package/src/wirings/channel/channel.types.ts +2 -0
  359. package/src/wirings/channel/index.ts +1 -20
  360. package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
  361. package/src/wirings/channel/local/local-channel-runner.ts +9 -2
  362. package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
  363. package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
  364. package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
  365. package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
  366. package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
  367. package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
  368. package/src/wirings/cli/channel/index.ts +0 -7
  369. package/src/wirings/cli/cli-runner.test.ts +68 -0
  370. package/src/wirings/cli/cli-runner.ts +25 -5
  371. package/src/wirings/cli/cli.types.ts +0 -39
  372. package/src/wirings/cli/command-parser.test.ts +19 -0
  373. package/src/wirings/cli/command-parser.ts +17 -1
  374. package/src/wirings/credential/index.ts +0 -1
  375. package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
  376. package/src/wirings/gateway/gateway-runner.ts +27 -19
  377. package/src/wirings/gateway/index.ts +0 -3
  378. package/src/wirings/http/http-routes.ts +4 -1
  379. package/src/wirings/http/http-runner.test.ts +66 -0
  380. package/src/wirings/http/http-runner.ts +21 -28
  381. package/src/wirings/http/http.types.ts +0 -15
  382. package/src/wirings/http/index.ts +2 -8
  383. package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
  384. package/src/wirings/http/web-request.ts +1 -1
  385. package/src/wirings/mcp/index.ts +0 -1
  386. package/src/wirings/mcp/mcp-runner.test.ts +181 -0
  387. package/src/wirings/mcp/mcp-runner.ts +37 -21
  388. package/src/wirings/persona/index.ts +0 -8
  389. package/src/wirings/persona/persona-environments.test.ts +14 -3
  390. package/src/wirings/persona/persona.test.ts +13 -3
  391. package/src/wirings/persona/validate-personas.ts +5 -1
  392. package/src/wirings/queue/index.ts +0 -14
  393. package/src/wirings/queue/queue-runner.ts +1 -1
  394. package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
  395. package/src/wirings/rpc/addon-runner.ts +34 -3
  396. package/src/wirings/rpc/addon-secrets.test.ts +261 -0
  397. package/src/wirings/rpc/rpc-runner.test.ts +2 -0
  398. package/src/wirings/rpc/rpc-runner.ts +60 -136
  399. package/src/wirings/rpc/rpc-types.ts +11 -0
  400. package/src/wirings/rpc/wire-addon.ts +20 -1
  401. package/src/wirings/scheduler/index.ts +0 -1
  402. package/src/wirings/secret/validate-secret-definitions.test.ts +22 -0
  403. package/src/wirings/secret/validate-secret-definitions.ts +2 -2
  404. package/src/wirings/trigger/index.ts +0 -1
  405. package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
  406. package/src/wirings/trigger/trigger-runner.ts +7 -5
  407. package/src/wirings/virtual-user/index.ts +0 -16
  408. package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
  409. package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
  410. package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
  411. package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
  412. package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
  413. package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
  414. package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
  415. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +117 -4
  416. package/src/wirings/workflow/feature.ts +7 -4
  417. package/src/wirings/workflow/graph/graph-node.ts +1 -1
  418. package/src/wirings/workflow/graph/graph-runner.test.ts +76 -2
  419. package/src/wirings/workflow/graph/graph-runner.ts +13 -16
  420. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
  421. package/src/wirings/workflow/index.ts +14 -24
  422. package/src/wirings/workflow/pikku-scenario-service.ts +101 -27
  423. package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -14
  424. package/src/wirings/workflow/pikku-workflow-service.ts +214 -743
  425. package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
  426. package/src/wirings/workflow/scenario-hooks.test.ts +52 -0
  427. package/src/wirings/workflow/scenario-step.types.ts +8 -0
  428. package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
  429. package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
  430. package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
  431. package/src/wirings/workflow/workflow-approval.ts +289 -0
  432. package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
  433. package/src/wirings/workflow/workflow-constants.ts +47 -0
  434. package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
  435. package/src/wirings/workflow/workflow-errors.ts +128 -0
  436. package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
  437. package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
  438. package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
  439. package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
  440. package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
  441. package/src/wirings/workflow/workflow-recovery.ts +162 -0
  442. package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
  443. package/src/wirings/workflow/workflow-run-authority.test.ts +212 -0
  444. package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
  445. package/src/wirings/workflow/workflow-run-ownership.ts +37 -0
  446. package/src/wirings/workflow/workflow-suspend.ts +61 -0
  447. package/src/wirings/workflow/workflow.types.ts +7 -9
  448. package/src/wirings-stay-decoupled.test.ts +127 -0
  449. package/tsconfig.json +1 -1
  450. package/tsconfig.tsbuildinfo +1 -1
  451. package/dist/internal.d.ts +0 -3
  452. package/dist/internal.js +0 -2
  453. package/dist/middleware/timeout.d.ts +0 -9
  454. package/dist/middleware/timeout.js +0 -15
  455. package/dist/pikku-response.d.ts +0 -6
  456. package/dist/pikku-response.js +0 -6
  457. package/dist/services/gopass-secrets.d.ts +0 -15
  458. package/dist/services/gopass-secrets.js +0 -76
  459. package/dist/services/http-scenario-actors.d.ts +0 -75
  460. package/dist/services/http-scenario-actors.js +0 -195
  461. package/dist/services/http-user-flow-actors.d.ts +0 -67
  462. package/dist/services/http-user-flow-actors.js +0 -193
  463. package/dist/services/scenario-actors-service.d.ts +0 -127
  464. package/dist/services/scenario-actors-service.js +0 -40
  465. package/dist/services/user-flow-actors-service.d.ts +0 -39
  466. package/dist/wirings/credential/wire-credential.d.ts +0 -48
  467. package/dist/wirings/credential/wire-credential.js +0 -47
  468. package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
  469. package/dist/wirings/oauth2/oauth2-client.js +0 -263
  470. package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
  471. package/dist/wirings/oauth2/oauth2-routes.js +0 -146
  472. package/dist/wirings/scope/wire-scope.d.ts +0 -33
  473. package/dist/wirings/scope/wire-scope.js +0 -32
  474. package/dist/wirings/workflow/dsl/index.d.ts +0 -5
  475. package/dist/wirings/workflow/dsl/index.js +0 -4
  476. package/dist/wirings/workflow/graph/index.d.ts +0 -5
  477. package/dist/wirings/workflow/graph/index.js +0 -4
  478. package/src/internal.ts +0 -10
  479. /package/dist/{services/user-flow-actors-service.js → wirings/workflow/workflow-run-engine.types.js} +0 -0
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ CoreHTTPFunctionWiring,
2
3
  HTTPRouteConfig,
3
4
  HTTPRouteMap,
4
5
  HTTPRouteContract,
@@ -84,7 +85,9 @@ function registerRoute(
84
85
  timeout: route.timeout,
85
86
  headers: route.headers,
86
87
  sse: route.sse,
87
- } as any)
88
+ // `CoreHTTPFunctionWiring` is discriminated by `method`, and a group builds
89
+ // its routes from a method chosen at runtime — no arm can be narrowed to.
90
+ } as CoreHTTPFunctionWiring<unknown, unknown, string>)
88
91
  }
89
92
 
90
93
  function isRouteConfig(value: unknown): value is HTTPRouteConfig {
@@ -70,6 +70,11 @@ class TestResponse extends PikkuMockResponse {
70
70
  return this
71
71
  }
72
72
 
73
+ redirect(location: string, status: number = 302): this {
74
+ this.status(status)
75
+ return this.header('Location', location)
76
+ }
77
+
73
78
  setMode(mode: 'stream') {
74
79
  this.mode = mode
75
80
  }
@@ -365,6 +370,67 @@ describe('http-runner helpers', () => {
365
370
  assert.equal(response.statusCode, 204)
366
371
  })
367
372
 
373
+ test('fetchData keeps a redirect status when the route returns undefined', async () => {
374
+ setRouteMeta('/redirect')
375
+ addFunction('pikku_func_name', {
376
+ func: async (_services: any, _data: any, { http }: any) => {
377
+ http?.response?.redirect('https://example.com/done', 302)
378
+ },
379
+ })
380
+ wireHTTP({
381
+ route: '/redirect',
382
+ method: 'get',
383
+ auth: false,
384
+ func: {
385
+ func: async (_services: any, _data: any, { http }: any) => {
386
+ http?.response?.redirect('https://example.com/done', 302)
387
+ },
388
+ },
389
+ })
390
+ httpRouter.initialize()
391
+
392
+ const request = new TestRequest('/redirect', 'get')
393
+ const response = new TestResponse()
394
+
395
+ await fetchData(request, response)
396
+
397
+ assert.equal(response.statusCode, 302)
398
+ assert.equal(
399
+ response.headersMap.get('Location'),
400
+ 'https://example.com/done'
401
+ )
402
+ })
403
+
404
+ test('fetchData keeps a status the route set alongside a body', async () => {
405
+ setRouteMeta('/created')
406
+ addFunction('pikku_func_name', {
407
+ func: async (_services: any, _data: any, { http }: any) => {
408
+ http?.response?.status(201)
409
+ return { id: 'thing-1' }
410
+ },
411
+ })
412
+ wireHTTP({
413
+ route: '/created',
414
+ method: 'get',
415
+ auth: false,
416
+ func: {
417
+ func: async (_services: any, _data: any, { http }: any) => {
418
+ http?.response?.status(201)
419
+ return { id: 'thing-1' }
420
+ },
421
+ },
422
+ })
423
+ httpRouter.initialize()
424
+
425
+ const request = new TestRequest('/created', 'get')
426
+ const response = new TestResponse()
427
+
428
+ await fetchData(request, response)
429
+
430
+ assert.equal(response.statusCode, 201)
431
+ assert.deepEqual(response.jsonBody, { id: 'thing-1' })
432
+ })
433
+
368
434
  test('fetchData writes binary responses when returnsJSON is false', async () => {
369
435
  setRouteMeta('/binary')
370
436
  wireHTTP({
@@ -33,8 +33,10 @@ import { isProduction } from '../../env.js'
33
33
  import { pikkuState } from '../../pikku-state.js'
34
34
  import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
35
35
  import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js'
36
- import type { PikkuChannel } from '../channel/channel.types.js'
37
- import { unsupportedChannelRemote } from '../channel/channel-rpc.js'
36
+ import type { BinaryData, PikkuChannel } from '../channel/channel.types.js'
37
+ // The leaf module, not the channel-rpc barrel: http needs one refusal
38
+ // function, and the barrel drags in 4,932 lines of channel RPC runtime.
39
+ import { unsupportedChannelRemote } from '../channel/channel-rpc.types.js'
38
40
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
39
41
  import { applyWebResponse } from './web-request.js'
40
42
  import { httpRouter } from './routers/http-router.js'
@@ -68,26 +70,6 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
68
70
  return middleware
69
71
  }
70
72
 
71
- /**
72
- * @deprecated HTTP-route-level permissions were removed in #972 — permissions
73
- * are now function-scoped only (declare them on the function via
74
- * `pikkuFunc({ permissions })`). This throwing stub exists solely so the pinned
75
- * bootstrap CLI (which still generates an `addHTTPPermission` wrapper) can
76
- * resolve the import at build time; it is never called. Delete once
77
- * `PIKKU_CLI_VERSION` in the CLI build is bumped past the release that removes
78
- * HTTP-route permissions.
79
- */
80
- export const addHTTPPermission = (
81
- _pattern: string,
82
- _permissions:
83
- | Record<string, CorePikkuPermission | CorePikkuPermission[]>
84
- | CorePikkuPermission[]
85
- ): never => {
86
- throw new Error(
87
- 'addHTTPPermission was removed in #972 — HTTP-route-level permissions no longer exist. Declare permissions on the function definition instead: pikkuFunc({ permissions }).'
88
- )
89
- }
90
-
91
73
  export const wireHTTP = <
92
74
  In,
93
75
  Out,
@@ -126,7 +108,8 @@ export const wireHTTP = <
126
108
  }
127
109
  pikkuState(null, 'http', 'routes')
128
110
  .get(httpWiring.method)
129
- ?.set(httpWiring.route, httpWiring as any)
111
+ // knowledge: decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md
112
+ ?.set(httpWiring.route, httpWiring as CoreHTTPFunctionWiring<any, any, any>)
130
113
  }
131
114
 
132
115
  const getMatchingRoute = (requestType: string, requestPath: string) => {
@@ -261,7 +244,8 @@ const executeRoute = async (
261
244
  setState: (s) => {
262
245
  sseState = s
263
246
  },
264
- getState: () => sseState as any,
247
+ // knowledge: decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md
248
+ getState: () => sseState as never,
265
249
  clearState: () => {
266
250
  sseState = undefined
267
251
  },
@@ -275,7 +259,7 @@ const executeRoute = async (
275
259
  const channelHandler = {
276
260
  getChannel: () => channelRef,
277
261
  send: (data: unknown, isBinary?: boolean) => {
278
- if (isBinary) channelRef.sendBinary(data as any)
262
+ if (isBinary) channelRef.sendBinary(data as BinaryData)
279
263
  else channelRef.send(data)
280
264
  },
281
265
  sendBinary: (data: any) => channelRef.sendBinary(data),
@@ -299,6 +283,8 @@ const executeRoute = async (
299
283
  hasSessionChanged: () => userSession.sessionChanged,
300
284
  }
301
285
 
286
+ const statusBeforeRoute = http?.response?.statusCode
287
+
302
288
  try {
303
289
  result = await runPikkuFunc(
304
290
  'http',
@@ -339,14 +325,20 @@ const executeRoute = async (
339
325
  if (matchedRoute.route.sse) {
340
326
  http?.response?.flushHeaders?.()
341
327
  } else {
328
+ const statusSetByRoute = http?.response?.statusCode !== statusBeforeRoute
329
+
342
330
  if (result instanceof Response) {
343
331
  await applyWebResponse(http!.response!, result)
344
332
  } else if (result === undefined || result === null) {
345
- http?.response?.status(204)
333
+ if (!statusSetByRoute) {
334
+ http?.response?.status(204)
335
+ }
346
336
  } else if (route.returnsJSON === false) {
347
337
  http?.response?.arrayBuffer(result)
348
338
  } else {
349
- http?.response?.status(200)
339
+ if (!statusSetByRoute) {
340
+ http?.response?.status(200)
341
+ }
350
342
  http?.response?.json(result)
351
343
  }
352
344
  }
@@ -424,7 +416,8 @@ export const fetchData = async <In, Out>(
424
416
  globalMiddleware as CorePikkuMiddleware[]
425
417
  )
426
418
  }
427
- response.status(204).json(undefined as any)
419
+ // 204 carries no body, and `json` has no no-content overload.
420
+ response.status(204).json(undefined as never)
428
421
  return
429
422
  }
430
423
  scopedLogger.info({
@@ -73,10 +73,6 @@ export interface PikkuHTTP<In = unknown> {
73
73
  response?: PikkuHTTPResponse
74
74
  }
75
75
 
76
- export type RequestHeaders =
77
- | Record<string, string | string[] | undefined>
78
- | ((headerName: string) => string | string[] | undefined)
79
-
80
76
  export type PikkuQuery<T = Record<string, string | undefined>> = Record<
81
77
  string,
82
78
  string | T | null | Array<T | null>
@@ -207,17 +203,6 @@ export type HTTPWiringMeta = CommonWireMeta & {
207
203
  }
208
204
  export type HTTPWiringsMeta = Record<HTTPMethod, Record<string, HTTPWiringMeta>>
209
205
 
210
- export type HTTPFunctionsMeta = Array<{
211
- name: string
212
- inputs: string[] | null
213
- outputs: string[] | null
214
- }>
215
-
216
- export type HTTPWiringMiddleware = {
217
- route: string
218
- middleware: CorePikkuMiddleware[]
219
- }
220
-
221
206
  export interface PikkuHTTPRequest<In = unknown> {
222
207
  method(): HTTPMethod
223
208
  path(): string
@@ -2,17 +2,10 @@ export {
2
2
  PikkuFetchHTTPRequest,
3
3
  DEFAULT_MAX_BODY_SIZE,
4
4
  } from './pikku-fetch-http-request.js'
5
- export type { PikkuFetchHTTPRequestOptions } from './pikku-fetch-http-request.js'
6
5
  export { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js'
7
6
  export { logRoutes } from './log-http-routes.js'
8
7
 
9
- export {
10
- fetch,
11
- fetchData,
12
- wireHTTP,
13
- addHTTPMiddleware,
14
- addHTTPPermission,
15
- } from './http-runner.js'
8
+ export { fetch, fetchData, wireHTTP, addHTTPMiddleware } from './http-runner.js'
16
9
 
17
10
  export { wireHTTPRoutes, defineHTTPRoutes } from './http-routes.js'
18
11
  export { toWebRequest, applyWebResponse } from './web-request.js'
@@ -25,6 +18,7 @@ export type {
25
18
  HTTPRouteContract,
26
19
  HTTPRouteMap,
27
20
  HTTPWiringsMeta,
21
+ PikkuHTTP,
28
22
  PikkuHTTPRequest,
29
23
  PikkuHTTPResponse,
30
24
  PikkuQuery,
@@ -248,7 +248,7 @@ function valuesAreEquivalent(a: unknown, b: unknown): boolean {
248
248
  return coerce(a) === coerce(b)
249
249
  }
250
250
 
251
- function coerce(value: unknown): string | number | boolean {
251
+ function coerce(value: unknown): unknown {
252
252
  if (typeof value === 'boolean' || typeof value === 'number') return value
253
253
  if (typeof value === 'string') {
254
254
  if (value === 'true') return true
@@ -256,5 +256,5 @@ function coerce(value: unknown): string | number | boolean {
256
256
  const num = Number(value)
257
257
  return isNaN(num) ? value : num
258
258
  }
259
- return value as any
259
+ return value
260
260
  }
@@ -40,7 +40,7 @@ export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
40
40
  if (
41
41
  parsed &&
42
42
  typeof parsed === 'object' &&
43
- Object.keys(parsed as any).length > 0
43
+ Object.keys(parsed as object).length > 0
44
44
  ) {
45
45
  let reconstructed: string
46
46
  if (contentType.includes('application/x-www-form-urlencoded')) {
@@ -16,7 +16,6 @@ export type {
16
16
  AssertMCPResourceURIParams,
17
17
  CoreMCPPrompt,
18
18
  CoreMCPResource,
19
- CoreMCPTool,
20
19
  MCPPromptResponse,
21
20
  MCPResourceMeta,
22
21
  MCPResourceResponse,
@@ -9,8 +9,11 @@ import {
9
9
  wireMCPPrompt,
10
10
  wireMCPResource,
11
11
  } from './mcp-runner.js'
12
+ import { addGlobalMiddleware } from '../../middleware-runner.js'
12
13
  import { addFunction } from '../../function/function-runner.js'
13
14
  import { pikkuState, resetPikkuState } from '../../pikku-state.js'
15
+ import { pikkuMiddleware } from '../../types/core.types.js'
16
+ import { addTagMiddleware } from '../../middleware-runner.js'
14
17
 
15
18
  const logger = {
16
19
  debug: () => {},
@@ -166,6 +169,49 @@ describe('runMCPResource', () => {
166
169
  },
167
170
  })
168
171
  })
172
+
173
+ test('runs a templated resource middleware when invoked by concrete uri', async () => {
174
+ let middlewareRan = false
175
+ // A tag-derived middleware group (this is where a tag-based auth gate lands).
176
+ addTagMiddleware('secure', [
177
+ pikkuMiddleware(async (_services, _wire, next) => {
178
+ middlewareRan = true
179
+ await next()
180
+ }),
181
+ ])
182
+ pikkuState(null, 'mcp', 'resourcesMeta')['resource://secure/{id}'] = {
183
+ uri: 'resource://secure/{id}',
184
+ title: 'Secure',
185
+ description: 'Secure',
186
+ pikkuFuncId: 'secureResourceFunc',
187
+ inputSchema: null,
188
+ outputSchema: null,
189
+ // The resource's merged middleware metadata. It must resolve for a concrete
190
+ // request against the template, or the resource is reachable with its gate
191
+ // skipped.
192
+ middleware: [{ type: 'tag', tag: 'secure' }],
193
+ } as never
194
+ registerFunction('secureResourceFunc', async () => ({ ok: true }))
195
+
196
+ wireMCPResource({
197
+ uri: 'resource://secure/{id}',
198
+ title: 'Secure',
199
+ description: 'Secure',
200
+ func: { func: async () => ({ ok: true }) } as never,
201
+ })
202
+
203
+ await runMCPResource(
204
+ { jsonrpc: '2.0', id: 'req-2', params: {} },
205
+ { mcp: mcpWire as never },
206
+ 'resource://secure/99'
207
+ )
208
+
209
+ assert.equal(
210
+ middlewareRan,
211
+ true,
212
+ 'the templated resource middleware must run for a concrete uri'
213
+ )
214
+ })
169
215
  })
170
216
 
171
217
  describe('runMCPTool', () => {
@@ -371,6 +417,141 @@ describe('runMCPTool', () => {
371
417
  })
372
418
  })
373
419
 
420
+ describe("MCP carries the caller's HTTP request", () => {
421
+ // Without this, every auth middleware bails on its first line — each one
422
+ // opens with `if (!http?.request) return`, so an MCP call arrived at the
423
+ // function with no session, and a tool fronting a session-requiring function
424
+ // answered 'Authentication required' to every caller. Nothing else was
425
+ // missing: global middleware already runs for MCP, and the runner already
426
+ // builds a session service. Only the request was being dropped.
427
+ test('exposes http on the wire so session middleware can read it', async () => {
428
+ pikkuState(null, 'mcp', 'toolsMeta').whoami = {
429
+ name: 'whoami',
430
+ title: 'Who am I',
431
+ description: 'Who am I',
432
+ pikkuFuncId: 'whoamiFunc',
433
+ inputSchema: null,
434
+ outputSchema: 'MCPToolResponse',
435
+ } as never
436
+
437
+ let seenAuthorization: string | undefined
438
+ registerFunction('whoamiFunc', async (_services, _data, wire) => {
439
+ seenAuthorization = wire.http?.request?.header('authorization')
440
+ return [{ type: 'text', text: seenAuthorization ?? 'anonymous' }]
441
+ })
442
+
443
+ const http = {
444
+ request: {
445
+ header: (name: string) =>
446
+ name.toLowerCase() === 'authorization'
447
+ ? 'Bearer token-abc'
448
+ : undefined,
449
+ },
450
+ }
451
+
452
+ const response = await runMCPTool(
453
+ { jsonrpc: '2.0', id: 'req-http', params: {} },
454
+ { mcp: mcpWire as never, http: http as never },
455
+ 'whoami'
456
+ )
457
+
458
+ assert.equal(seenAuthorization, 'Bearer token-abc')
459
+ assert.deepEqual(response, {
460
+ id: 'req-http',
461
+ result: [{ type: 'text', text: 'Bearer token-abc' }],
462
+ })
463
+ })
464
+
465
+ test('omitting http leaves the wire without one rather than inventing it', async () => {
466
+ pikkuState(null, 'mcp', 'toolsMeta').anon = {
467
+ name: 'anon',
468
+ title: 'Anon',
469
+ description: 'Anon',
470
+ pikkuFuncId: 'anonFunc',
471
+ inputSchema: null,
472
+ outputSchema: 'MCPToolResponse',
473
+ } as never
474
+
475
+ let sawHttp: unknown = 'unset'
476
+ registerFunction('anonFunc', async (_services, _data, wire) => {
477
+ sawHttp = wire.http
478
+ return [{ type: 'text', text: 'ok' }]
479
+ })
480
+
481
+ await runMCPTool(
482
+ { jsonrpc: '2.0', id: 'req-anon', params: {} },
483
+ { mcp: mcpWire as never },
484
+ 'anon'
485
+ )
486
+
487
+ assert.equal(sawHttp, undefined)
488
+ })
489
+ })
490
+
491
+ describe('MCP tools fronting a session-requiring function', () => {
492
+ // The whole point of carrying the request: this is the template failure,
493
+ // reproduced. `listRoomsTool` and five others front a `pikkuFunc`, which
494
+ // requires a session, and answered 'Authentication required' to every caller
495
+ // because no request ever reached the middleware that would have set one.
496
+ test('receive the session set by global middleware from the request', async () => {
497
+ addGlobalMiddleware([
498
+ async (_services, wire, next) => {
499
+ const header = wire.http?.request?.header('authorization')
500
+ if (header === 'Bearer token-abc') {
501
+ wire.setSession?.({ userId: 'usr_1', name: 'Rafa' } as never)
502
+ }
503
+ await next()
504
+ },
505
+ ] as never)
506
+
507
+ pikkuState(null, 'mcp', 'toolsMeta').listRooms = {
508
+ name: 'listRooms',
509
+ title: 'List rooms',
510
+ description: 'List rooms',
511
+ pikkuFuncId: 'listRoomsFunc',
512
+ inputSchema: null,
513
+ outputSchema: 'MCPToolResponse',
514
+ } as never
515
+
516
+ // sessionless: false — the distinction that made these tools fail.
517
+ addFunction(
518
+ 'listRoomsFunc',
519
+ {
520
+ func: async (_services: any, _data: any, wire: any) => [
521
+ { type: 'text', text: wire.session?.userId ?? 'anonymous' },
522
+ ],
523
+ } as never,
524
+ null
525
+ )
526
+ pikkuState(null, 'function', 'meta').listRoomsFunc = {
527
+ name: 'listRoomsFunc',
528
+ sessionless: false,
529
+ permissions: [],
530
+ } as never
531
+
532
+ const response = await runMCPTool(
533
+ { jsonrpc: '2.0', id: 'req-session', params: {} },
534
+ {
535
+ mcp: mcpWire as never,
536
+ http: {
537
+ request: {
538
+ header: (name: string) =>
539
+ name.toLowerCase() === 'authorization'
540
+ ? 'Bearer token-abc'
541
+ : undefined,
542
+ },
543
+ } as never,
544
+ },
545
+ 'listRooms'
546
+ )
547
+
548
+ assert.deepEqual(response, {
549
+ id: 'req-session',
550
+ result: [{ type: 'text', text: 'usr_1' }],
551
+ })
552
+ })
553
+ })
554
+
374
555
  describe('runMCPPrompt', () => {
375
556
  test('maps missing prompt registration to not found MCP errors', async () => {
376
557
  pikkuState(null, 'mcp', 'promptsMeta').missingPrompt = {
@@ -1,4 +1,5 @@
1
1
  import type { PikkuRawWire } from '../../types/core.types.js'
2
+ import type { PikkuHTTP } from '../http/http.types.js'
2
3
  import type {
3
4
  CoreMCPResource,
4
5
  CoreMCPPrompt,
@@ -35,16 +36,24 @@ export class MCPError extends Error {
35
36
 
36
37
  export type RunMCPEndpointParams<Tools extends string = any> = {
37
38
  mcp?: PikkuMCP<Tools>
39
+ /**
40
+ * The HTTP request the MCP call arrived on, when it arrived over HTTP.
41
+ *
42
+ * Auth middleware reads the session off `wire.http.request` — every
43
+ * implementation opens with `if (!http?.request) return` — so without this an
44
+ * MCP call reaches the function unauthenticated no matter what middleware the
45
+ * app has registered, and a tool fronting a session-requiring function can
46
+ * only ever answer 'Authentication required'.
47
+ *
48
+ * Left undefined for transports that have no request to offer, such as stdio.
49
+ * Those remain anonymous, which is a property of the transport rather than a
50
+ * default chosen here.
51
+ */
52
+ http?: PikkuHTTP
38
53
  /** Defaults to enabled outside production. */
39
54
  exposeErrors?: boolean
40
55
  }
41
56
 
42
- export type JsonRpcError = {
43
- code: number
44
- message: string
45
- data?: any
46
- }
47
-
48
57
  export const wireMCPResource = <
49
58
  PikkuFunctionConfig extends CorePikkuFunctionConfig<
50
59
  CorePikkuFunctionSessionless<any, any>
@@ -60,7 +69,7 @@ export const wireMCPResource = <
60
69
  )
61
70
  return
62
71
  }
63
- addFunction(mcpResourceMeta.pikkuFuncId, mcpResource.func as any)
72
+ addFunction(mcpResourceMeta.pikkuFuncId, mcpResource.func)
64
73
  const resources = pikkuState(null, 'mcp', 'resources')
65
74
  if (resources.has(mcpResource.uri)) {
66
75
  throw new Error(`MCP resource already exists: ${mcpResource.uri}`)
@@ -83,7 +92,7 @@ export const wireMCPPrompt = <
83
92
  )
84
93
  return
85
94
  }
86
- addFunction(mcpPromptMeta.pikkuFuncId, mcpPrompt.func as any)
95
+ addFunction(mcpPromptMeta.pikkuFuncId, mcpPrompt.func)
87
96
  const prompts = pikkuState(null, 'mcp', 'prompts')
88
97
  if (prompts.has(mcpPrompt.name)) {
89
98
  throw new Error(`MCP prompt already exists: ${mcpPrompt.name}`)
@@ -103,6 +112,12 @@ export async function runMCPResource(
103
112
  const metas = pikkuState(null, 'mcp', 'resourcesMeta')
104
113
  const endpoints = pikkuState(null, 'mcp', 'resources')
105
114
 
115
+ // The key the resource's meta (and its middleware) is stored under. For a
116
+ // templated resource this is the template, not the concrete request URI — so
117
+ // it must be carried forward, or the meta lookup downstream misses and the
118
+ // resource's declared middleware (including auth) is silently skipped.
119
+ let metaKey = uri
120
+
106
121
  if (endpoints.has(uri)) {
107
122
  endpoint = endpoints.get(uri)
108
123
  pikkuFuncId = metas[uri]?.pikkuFuncId
@@ -119,6 +134,7 @@ export async function runMCPResource(
119
134
 
120
135
  if (match) {
121
136
  endpoint = value
137
+ metaKey = uriTemplate
122
138
  pikkuFuncId = metas[uriTemplate]?.pikkuFuncId
123
139
 
124
140
  for (let i = 0; i < paramNames.length; i++) {
@@ -140,7 +156,8 @@ export async function runMCPResource(
140
156
  pikkuFuncId,
141
157
  { ...params, mcp: { ...params.mcp, uri } } as RunMCPEndpointParams<
142
158
  keyof CoreMCPResource
143
- >
159
+ >,
160
+ metaKey
144
161
  )
145
162
  }
146
163
 
@@ -183,7 +200,11 @@ async function runMCPPikkuFunc(
183
200
  name: string,
184
201
  mcp: CoreMCPResource | CoreMCPPrompt | undefined,
185
202
  pikkuFuncId: string | undefined,
186
- { mcp: mcpWire, exposeErrors = !isProduction() }: RunMCPEndpointParams
203
+ { mcp: mcpWire, http, exposeErrors = !isProduction() }: RunMCPEndpointParams,
204
+ // The key the endpoint's meta is stored under. Differs from `name` only for a
205
+ // templated resource, where `name` is the concrete URI and the meta lives
206
+ // under the template. Defaults to `name` for tools and prompts.
207
+ metaKey: string = name
187
208
  ): Promise<JsonRpcResponse> {
188
209
  const singletonServices = getSingletonServices()
189
210
  const createWireServices = getCreateWireServices()
@@ -214,16 +235,19 @@ async function runMCPPikkuFunc(
214
235
  )
215
236
  const wire: PikkuRawWire = {
216
237
  mcp: mcpWire,
238
+ // Only when the transport supplied one. Setting `http: undefined`
239
+ // explicitly would be the same to a reader and different to a spread.
240
+ ...(http ? { http } : {}),
217
241
  ...createMiddlewareSessionWireProps(mcpSessionService),
218
242
  }
219
243
 
220
244
  let meta: any
221
245
  if (type === 'resource') {
222
- meta = pikkuState(null, 'mcp', 'resourcesMeta')[name]
246
+ meta = pikkuState(null, 'mcp', 'resourcesMeta')[metaKey]
223
247
  } else if (type === 'tool') {
224
- meta = pikkuState(null, 'mcp', 'toolsMeta')[name]
248
+ meta = pikkuState(null, 'mcp', 'toolsMeta')[metaKey]
225
249
  } else if (type === 'prompt') {
226
- meta = pikkuState(null, 'mcp', 'promptsMeta')[name]
250
+ meta = pikkuState(null, 'mcp', 'promptsMeta')[metaKey]
227
251
  }
228
252
 
229
253
  let resolvedFuncName = pikkuFuncId
@@ -293,10 +317,6 @@ async function runMCPPikkuFunc(
293
317
  }
294
318
  }
295
319
 
296
- export const getMCPResources = () => {
297
- return pikkuState(null, 'mcp', 'resources')
298
- }
299
-
300
320
  export const getMCPResourcesMeta = () => {
301
321
  return pikkuState(null, 'mcp', 'resourcesMeta')
302
322
  }
@@ -305,10 +325,6 @@ export const getMCPToolsMeta = () => {
305
325
  return pikkuState(null, 'mcp', 'toolsMeta')
306
326
  }
307
327
 
308
- export const getMCPPrompts = () => {
309
- return pikkuState(null, 'mcp', 'prompts')
310
- }
311
-
312
328
  export const getMCPPromptsMeta = () => {
313
329
  return pikkuState(null, 'mcp', 'promptsMeta')
314
330
  }
@@ -10,7 +10,6 @@ export type { RoleVerification } from './validate-personas.js'
10
10
  export {
11
11
  personaEnvironmentErrors,
12
12
  personaEnvironmentRefusal,
13
- resolvePersonaEnvironments,
14
13
  } from './persona-environments.js'
15
14
  export type {
16
15
  PersonaEnvironment,
@@ -18,14 +17,8 @@ export type {
18
17
  } from './persona-environments.js'
19
18
  export {
20
19
  personaEmail,
21
- personaEmailLabel,
22
20
  personaEmails,
23
21
  } from './persona-email.js'
24
- export {
25
- allowedLinks,
26
- applyMailboxAllowlist,
27
- isAllowedSender,
28
- } from './persona-mailbox.js'
29
22
  export type {
30
23
  MailboxAllowlist,
31
24
  PersonaMailbox,
@@ -33,7 +26,6 @@ export type {
33
26
  } from './persona-mailbox.js'
34
27
  export type {
35
28
  CorePersona,
36
- CorePersonaAccount,
37
29
  CorePersonas,
38
30
  PersonaAccountMeta,
39
31
  PersonaDefinitions,