@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.
- package/CHANGELOG.md +473 -0
- package/dist/dev/hot-reload.js +1 -6
- package/dist/ecosystem.d.ts +27 -0
- package/dist/ecosystem.js +26 -0
- package/dist/errors/error-handler.js +4 -2
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/function/function-runner.js +22 -47
- package/dist/function/functions.types.d.ts +9 -5
- package/dist/function/index.d.ts +1 -1
- package/dist/index.d.ts +14 -19
- package/dist/index.js +6 -11
- package/dist/middleware/auth-cookie.d.ts +0 -4
- package/dist/middleware/auth-cookie.js +38 -2
- package/dist/middleware/cors.js +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.js +14 -3
- package/dist/permissions.d.ts +8 -10
- package/dist/permissions.js +0 -11
- package/dist/pikku-state.js +16 -5
- package/dist/schema.js +35 -1
- package/dist/services/ai-agent-runner-service.d.ts +7 -0
- package/dist/services/ai-run-state-service.d.ts +17 -1
- package/dist/services/in-memory-ai-run-state-service.d.ts +6 -2
- package/dist/services/in-memory-ai-run-state-service.js +11 -1
- package/dist/services/in-memory-workflow-service.js +2 -0
- package/dist/services/index.d.ts +15 -15
- package/dist/services/index.js +5 -5
- package/dist/services/local-content-request-handler.d.ts +21 -0
- package/dist/services/local-content-request-handler.js +72 -53
- package/dist/services/local-content.d.ts +6 -0
- package/dist/services/local-content.js +14 -1
- package/dist/services/scoped-credential-service.d.ts +21 -0
- package/dist/services/scoped-credential-service.js +53 -0
- package/dist/services/workflow-service.d.ts +4 -2
- package/dist/testing/service-tests/agent-run-service-tests.d.ts +10 -0
- package/dist/testing/service-tests/agent-run-service-tests.js +72 -0
- package/dist/testing/service-tests/ai-storage-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/ai-storage-service-tests.js +302 -0
- package/dist/testing/service-tests/channel-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/channel-store-tests.js +72 -0
- package/dist/testing/service-tests/credential-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/credential-service-tests.js +109 -0
- package/dist/testing/service-tests/deployment-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/deployment-service-tests.js +21 -0
- package/dist/testing/service-tests/event-hub-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/event-hub-store-tests.js +34 -0
- package/dist/testing/service-tests/secret-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/secret-service-tests.js +80 -0
- package/dist/testing/service-tests/session-store-tests.d.ts +3 -0
- package/dist/testing/service-tests/session-store-tests.js +43 -0
- package/dist/testing/service-tests/workflow-run-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/workflow-run-service-tests.js +42 -0
- package/dist/testing/service-tests/workflow-service-tests.d.ts +3 -0
- package/dist/testing/service-tests/workflow-service-tests.js +150 -0
- package/dist/testing/service-tests.d.ts +6 -0
- package/dist/testing/service-tests.js +26 -791
- package/dist/types/core.types.d.ts +11 -3
- package/dist/types/state.types.d.ts +14 -1
- package/dist/wirings/actor-flow/index.d.ts +1 -1
- package/dist/wirings/actor-flow/run-conversation.js +1 -6
- package/dist/wirings/ai-agent/agent-rpc.d.ts +15 -0
- package/dist/wirings/ai-agent/agent-rpc.js +53 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +1 -5
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
- package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
- package/dist/wirings/ai-agent/ai-agent-memory.js +37 -18
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +5 -9
- package/dist/wirings/ai-agent/ai-agent-runner.js +89 -147
- package/dist/wirings/ai-agent/ai-agent-stream.js +109 -97
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +57 -0
- package/dist/wirings/ai-agent/ai-agent-turn.js +82 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +47 -2
- package/dist/wirings/ai-agent/index.d.ts +8 -7
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.js +1 -6
- package/dist/wirings/ai-agent/voice-output.js +2 -12
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
- package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
- package/dist/wirings/ai-scorer/index.d.ts +6 -0
- package/dist/wirings/ai-scorer/index.js +5 -0
- package/dist/wirings/channel/channel-common.js +1 -0
- package/dist/wirings/channel/channel-handler.js +3 -5
- package/dist/wirings/channel/channel-rpc-service.d.ts +0 -6
- package/dist/wirings/channel/channel-rpc-service.js +0 -8
- package/dist/wirings/channel/channel-rpc.types.d.ts +6 -0
- package/dist/wirings/channel/channel-rpc.types.js +8 -0
- package/dist/wirings/channel/channel-runner.d.ts +1 -3
- package/dist/wirings/channel/channel-runner.js +16 -8
- package/dist/wirings/channel/channel.types.d.ts +2 -0
- package/dist/wirings/channel/index.d.ts +5 -6
- package/dist/wirings/channel/index.js +3 -4
- package/dist/wirings/channel/local/local-channel-runner.js +8 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +1 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +3 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +2 -0
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
- package/dist/wirings/cli/channel/index.d.ts +1 -2
- package/dist/wirings/cli/channel/index.js +0 -1
- package/dist/wirings/cli/cli-runner.js +17 -3
- package/dist/wirings/cli/cli.types.d.ts +0 -8
- package/dist/wirings/cli/command-parser.js +13 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/gateway/gateway-runner.js +9 -2
- package/dist/wirings/gateway/index.d.ts +1 -1
- package/dist/wirings/http/http-routes.js +2 -0
- package/dist/wirings/http/http-runner.d.ts +0 -10
- package/dist/wirings/http/http-runner.js +14 -15
- package/dist/wirings/http/http.types.d.ts +0 -10
- package/dist/wirings/http/index.d.ts +2 -3
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/index.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +15 -7
- package/dist/wirings/mcp/mcp-runner.js +18 -11
- package/dist/wirings/persona/index.d.ts +3 -4
- package/dist/wirings/persona/index.js +2 -3
- package/dist/wirings/queue/index.d.ts +1 -3
- package/dist/wirings/queue/index.js +1 -3
- package/dist/wirings/rpc/addon-runner.d.ts +4 -0
- package/dist/wirings/rpc/addon-runner.js +19 -3
- package/dist/wirings/rpc/rpc-runner.d.ts +8 -51
- package/dist/wirings/rpc/rpc-runner.js +55 -86
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/rpc/wire-addon.d.ts +13 -0
- package/dist/wirings/rpc/wire-addon.js +4 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/secret/validate-secret-definitions.js +2 -2
- package/dist/wirings/trigger/index.d.ts +1 -1
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +0 -4
- package/dist/wirings/trigger/trigger-runner.js +1 -0
- package/dist/wirings/virtual-user/index.d.ts +5 -6
- package/dist/wirings/virtual-user/index.js +2 -4
- package/dist/wirings/virtual-user/run-virtual-user.js +11 -11
- package/dist/wirings/virtual-user/virtual-user-derive.js +4 -25
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +1 -4
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +100 -3
- package/dist/wirings/workflow/feature.js +7 -4
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -2
- package/dist/wirings/workflow/graph/graph-runner.js +8 -7
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -4
- package/dist/wirings/workflow/index.d.ts +12 -7
- package/dist/wirings/workflow/index.js +7 -3
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -3
- package/dist/wirings/workflow/pikku-scenario-service.js +64 -10
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -147
- package/dist/wirings/workflow/pikku-workflow-service.js +85 -493
- package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
- package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
- package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
- package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
- package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
- package/dist/wirings/workflow/workflow-approval.d.ts +67 -0
- package/dist/wirings/workflow/workflow-approval.js +177 -0
- package/dist/wirings/workflow/workflow-constants.d.ts +26 -0
- package/dist/wirings/workflow/workflow-constants.js +35 -0
- package/dist/wirings/workflow/workflow-errors.d.ts +58 -0
- package/dist/wirings/workflow/workflow-errors.js +112 -0
- package/dist/wirings/workflow/workflow-meta-resolver.d.ts +11 -0
- package/dist/wirings/workflow/workflow-meta-resolver.js +31 -0
- package/dist/wirings/workflow/workflow-queue-routing.d.ts +8 -0
- package/dist/wirings/workflow/workflow-queue-routing.js +38 -0
- package/dist/wirings/workflow/workflow-queue-wiring.d.ts +20 -0
- package/dist/wirings/workflow/workflow-queue-wiring.js +79 -0
- package/dist/wirings/workflow/workflow-recovery.d.ts +68 -0
- package/dist/wirings/workflow/workflow-recovery.js +101 -0
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +54 -0
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +17 -0
- package/dist/wirings/workflow/workflow-run-ownership.js +30 -0
- package/dist/wirings/workflow/workflow-suspend.d.ts +12 -0
- package/dist/wirings/workflow/workflow-suspend.js +33 -0
- package/dist/wirings/workflow/workflow.types.d.ts +8 -1
- package/knowledge/decisions/internals/a-non-streaming-agent-run-registers-with-airunstate-too.md +22 -0
- package/knowledge/decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md +20 -0
- package/knowledge/decisions/internals/a-scenario-step-template-is-offered-unfilled.md +21 -0
- package/knowledge/decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md +21 -0
- package/knowledge/decisions/internals/a-wall-clock-threshold-is-a-load-test-in-disguise.md +46 -0
- package/knowledge/decisions/internals/a-workflow-wire-is-built-from-the-run-not-from-the-rpc-service.md +45 -0
- package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
- package/knowledge/decisions/internals/agent-context-waits-for-a-tool-result-still-being-written.md +21 -0
- package/knowledge/decisions/internals/agent-speech-travels-as-a-custom-agui-event.md +22 -0
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
- package/knowledge/decisions/internals/an-agent-interrupt-is-not-a-failure.md +23 -0
- package/knowledge/decisions/internals/an-agent-run-owned-by-another-instance-says-so.md +25 -0
- package/knowledge/decisions/internals/an-agent-stream-send-must-return-the-inner-sends-promise.md +22 -0
- package/knowledge/decisions/internals/an-empty-text-part-is-omitted-from-an-agent-message.md +20 -0
- package/knowledge/decisions/internals/an-empty-transcript-is-not-recorded.md +22 -0
- package/knowledge/decisions/internals/an-unref-d-timer-cannot-be-awaited-under-node-test.md +66 -0
- package/knowledge/decisions/internals/channel-state-accessors-are-unsound-generics-that-every-implementation-asserts.md +33 -0
- package/knowledge/decisions/internals/gateway-listener-middleware-runs-without-an-rpc-on-the-wire.md +43 -0
- package/knowledge/decisions/internals/hot-reload-writes-into-the-function-map-captured-at-startup.md +26 -0
- package/knowledge/decisions/internals/index.md +42 -3
- package/knowledge/decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md +21 -0
- package/knowledge/decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md +24 -0
- package/knowledge/decisions/internals/side-effects-are-an-allowlist-not-a-boolean.md +34 -0
- package/knowledge/decisions/internals/speech-synthesis-picks-a-voice-per-sentence-and-warns-once.md +24 -0
- package/knowledge/decisions/internals/the-actor-prompt-says-json-because-of-json-object-mode.md +22 -0
- package/knowledge/decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md +26 -0
- package/knowledge/decisions/internals/the-api-report-pins-members-not-just-names.md +43 -0
- package/knowledge/decisions/internals/the-ecosystem-entry-point-carries-the-adapter-surface.md +58 -0
- package/knowledge/decisions/internals/the-middleware-resolution-cache-is-deliberately-unbounded.md +40 -0
- package/knowledge/decisions/internals/the-per-invocation-rpc-view-is-a-class.md +40 -0
- package/knowledge/decisions/internals/the-persona-runtime-is-exported-from-the-persona-entry-point.md +28 -0
- package/knowledge/decisions/internals/the-transcript-event-is-sent-ahead-of-the-run.md +25 -0
- package/knowledge/decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md +21 -0
- package/knowledge/decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md +22 -0
- package/knowledge/decisions/internals/thread-history-records-the-transcript-not-the-audio.md +25 -0
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
- package/knowledge/decisions/internals/virtual-user-step-order-comes-from-insertion-order.md +21 -0
- package/knowledge/decisions/internals/voice-output-speaks-unless-voice-input-explicitly-says-otherwise.md +24 -0
- package/knowledge/decisions/internals/wiring-registries-erase-the-generics-their-wire-functions-capture.md +35 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +4 -2
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
- package/knowledge/decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md +33 -0
- package/knowledge/decisions/security/a-permission-gets-a-wire-it-cannot-reply-on.md +33 -0
- package/knowledge/decisions/security/a-step-runs-the-function-the-workflow-dispatched-it-with.md +37 -0
- package/knowledge/decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md +28 -0
- package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +50 -0
- package/knowledge/decisions/security/an-agent-approval-is-claimed-before-the-tool-runs.md +33 -0
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
- package/knowledge/decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md +24 -0
- package/knowledge/decisions/security/index.md +9 -0
- package/knowledge/questions/channel-middleware-accepts-bare-factories-that-nothing-resolves.md +35 -0
- package/knowledge/questions/index.md +2 -1
- package/knowledge/questions/unauthorized-channel-replies-escape-the-declared-out-type.md +44 -0
- package/package.json +15 -3
- package/scripts/generate-api-report.d.mts +1 -0
- package/scripts/generate-api-report.mjs +89 -0
- package/scripts/generate-api-report.mts +343 -0
- package/src/api-report.test.ts +69 -0
- package/src/column-form.ts +1 -4
- package/src/crypto-utils.test.ts +15 -2
- package/src/dev/hot-reload.ts +2 -7
- package/src/ecosystem.ts +40 -0
- package/src/errors/error-handler.ts +5 -3
- package/src/errors/error.test.ts +4 -1
- package/src/errors/index.ts +1 -1
- package/src/function/function-runner.test.ts +53 -1
- package/src/function/function-runner.ts +33 -48
- package/src/function/functions.types.ts +15 -9
- package/src/function/index.ts +0 -2
- package/src/handle-error.ts +1 -1
- package/src/index.ts +3 -57
- package/src/middleware/auth-cookie.test.ts +50 -0
- package/src/middleware/auth-cookie.ts +38 -2
- package/src/middleware/cors.ts +2 -1
- package/src/middleware/index.ts +1 -1
- package/src/middleware/remote-auth.test.ts +43 -0
- package/src/middleware/remote-auth.ts +17 -3
- package/src/middleware-runner.ts +4 -2
- package/src/no-any-casts.test.ts +57 -0
- package/src/permissions.test.ts +3 -1
- package/src/permissions.ts +22 -24
- package/src/pikku-state.ts +22 -6
- package/src/public-surface.json +554 -0
- package/src/public-surface.json.README +25 -0
- package/src/public-surface.test.ts +105 -0
- package/src/removed-legacy-exports.test.ts +62 -0
- package/src/schema.test.ts +78 -0
- package/src/schema.ts +36 -1
- package/src/services/ai-agent-runner-service.ts +12 -1
- package/src/services/ai-run-state-service.ts +18 -1
- package/src/services/audit-service.ts +2 -2
- package/src/services/in-memory-ai-run-state-service.ts +16 -2
- package/src/services/in-memory-workflow-service.ts +2 -0
- package/src/services/index.ts +4 -47
- package/src/services/local-content-request-handler.test.ts +43 -5
- package/src/services/local-content-request-handler.ts +103 -74
- package/src/services/local-content.ts +15 -1
- package/src/services/local-email-service.ts +5 -1
- package/src/services/scoped-credential-service.test.ts +86 -0
- package/src/services/scoped-credential-service.ts +63 -0
- package/src/services/system-role-guard.test.ts +4 -1
- package/src/services/workflow-service.ts +9 -2
- package/src/side-effects-are-declared.test.ts +84 -0
- package/src/source-files-stay-composable.test.ts +41 -0
- package/src/testing/service-tests/agent-run-service-tests.ts +98 -0
- package/src/testing/service-tests/ai-storage-service-tests.ts +379 -0
- package/src/testing/service-tests/channel-store-tests.ts +98 -0
- package/src/testing/service-tests/credential-service-tests.ts +143 -0
- package/src/testing/service-tests/deployment-service-tests.ts +33 -0
- package/src/testing/service-tests/event-hub-store-tests.ts +48 -0
- package/src/testing/service-tests/secret-service-tests.ts +105 -0
- package/src/testing/service-tests/session-store-tests.ts +62 -0
- package/src/testing/service-tests/workflow-run-service-tests.ts +59 -0
- package/src/testing/service-tests/workflow-service-tests.ts +308 -0
- package/src/testing/service-tests.ts +31 -1111
- package/src/types/core.types.ts +14 -3
- package/src/types/state.types.ts +17 -1
- package/src/wirings/actor-flow/index.ts +0 -3
- package/src/wirings/actor-flow/run-conversation.ts +1 -6
- package/src/wirings/ai-agent/agent-rpc.ts +120 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +1 -5
- package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
- package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +2 -1
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +62 -39
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
- package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
- package/src/wirings/ai-agent/ai-agent-prepare.ts +12 -12
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +82 -2
- package/src/wirings/ai-agent/ai-agent-runner.ts +120 -160
- package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +2 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +152 -117
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
- package/src/wirings/ai-agent/ai-agent-turn.ts +122 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +65 -5
- package/src/wirings/ai-agent/index.ts +2 -16
- package/src/wirings/ai-agent/voice-input.ts +1 -6
- package/src/wirings/ai-agent/voice-output.ts +2 -12
- package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
- package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
- package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
- package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
- package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
- package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
- package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
- package/src/wirings/ai-scorer/index.ts +24 -0
- package/src/wirings/channel/channel-common.ts +5 -2
- package/src/wirings/channel/channel-handler-shapes.test.ts +72 -0
- package/src/wirings/channel/channel-handler.ts +7 -7
- package/src/wirings/channel/channel-rpc-service.ts +0 -14
- package/src/wirings/channel/channel-rpc.test.ts +25 -4
- package/src/wirings/channel/channel-rpc.types.ts +14 -0
- package/src/wirings/channel/channel-runner.ts +33 -20
- package/src/wirings/channel/channel.types.ts +2 -0
- package/src/wirings/channel/index.ts +1 -20
- package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
- package/src/wirings/channel/local/local-channel-runner.ts +9 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +2 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +6 -3
- package/src/wirings/cli/channel/cli-channel-runner.ts +3 -1
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +4 -1
- package/src/wirings/cli/channel/index.ts +0 -7
- package/src/wirings/cli/cli-runner.test.ts +68 -0
- package/src/wirings/cli/cli-runner.ts +25 -5
- package/src/wirings/cli/cli.types.ts +0 -39
- package/src/wirings/cli/command-parser.test.ts +19 -0
- package/src/wirings/cli/command-parser.ts +17 -1
- package/src/wirings/credential/index.ts +0 -1
- package/src/wirings/gateway/gateway-channel-meta.test.ts +44 -0
- package/src/wirings/gateway/gateway-runner.ts +27 -19
- package/src/wirings/gateway/index.ts +0 -3
- package/src/wirings/http/http-routes.ts +4 -1
- package/src/wirings/http/http-runner.test.ts +66 -0
- package/src/wirings/http/http-runner.ts +21 -28
- package/src/wirings/http/http.types.ts +0 -15
- package/src/wirings/http/index.ts +2 -8
- package/src/wirings/http/pikku-fetch-http-request.ts +2 -2
- package/src/wirings/http/web-request.ts +1 -1
- package/src/wirings/mcp/index.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +181 -0
- package/src/wirings/mcp/mcp-runner.ts +37 -21
- package/src/wirings/persona/index.ts +0 -8
- package/src/wirings/persona/persona-environments.test.ts +14 -3
- package/src/wirings/persona/persona.test.ts +13 -3
- package/src/wirings/persona/validate-personas.ts +5 -1
- package/src/wirings/queue/index.ts +0 -14
- package/src/wirings/queue/queue-runner.ts +1 -1
- package/src/wirings/rpc/addon-auth-tags.test.ts +1 -5
- package/src/wirings/rpc/addon-runner.ts +34 -3
- package/src/wirings/rpc/addon-secrets.test.ts +261 -0
- package/src/wirings/rpc/rpc-runner.test.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +60 -136
- package/src/wirings/rpc/rpc-types.ts +11 -0
- package/src/wirings/rpc/wire-addon.ts +20 -1
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/secret/validate-secret-definitions.test.ts +22 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -2
- package/src/wirings/trigger/index.ts +0 -1
- package/src/wirings/trigger/pikku-trigger-service.ts +0 -5
- package/src/wirings/trigger/trigger-runner.ts +7 -5
- package/src/wirings/virtual-user/index.ts +0 -16
- package/src/wirings/virtual-user/run-virtual-user.test.ts +18 -9
- package/src/wirings/virtual-user/run-virtual-user.ts +28 -15
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +4 -1
- package/src/wirings/virtual-user/virtual-user-derive.ts +4 -25
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +7 -2
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +1 -4
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +13 -3
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +117 -4
- package/src/wirings/workflow/feature.ts +7 -4
- package/src/wirings/workflow/graph/graph-node.ts +1 -1
- package/src/wirings/workflow/graph/graph-runner.test.ts +76 -2
- package/src/wirings/workflow/graph/graph-runner.ts +13 -16
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -5
- package/src/wirings/workflow/index.ts +14 -24
- package/src/wirings/workflow/pikku-scenario-service.ts +101 -27
- package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -14
- package/src/wirings/workflow/pikku-workflow-service.ts +214 -743
- package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
- package/src/wirings/workflow/scenario-hooks.test.ts +52 -0
- package/src/wirings/workflow/scenario-step.types.ts +8 -0
- package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
- package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
- package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
- package/src/wirings/workflow/workflow-approval.ts +289 -0
- package/src/wirings/workflow/workflow-child-run-session.test.ts +89 -0
- package/src/wirings/workflow/workflow-constants.ts +47 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +1 -1
- package/src/wirings/workflow/workflow-errors.ts +128 -0
- package/src/wirings/workflow/workflow-inline-authority.test.ts +12 -6
- package/src/wirings/workflow/workflow-meta-resolver.ts +45 -0
- package/src/wirings/workflow/workflow-missing-meta.test.ts +92 -0
- package/src/wirings/workflow/workflow-queue-routing.ts +85 -0
- package/src/wirings/workflow/workflow-queue-wiring.ts +149 -0
- package/src/wirings/workflow/workflow-recovery.ts +162 -0
- package/src/wirings/workflow/workflow-retry-policy.test.ts +1 -1
- package/src/wirings/workflow/workflow-run-authority.test.ts +212 -0
- package/src/wirings/workflow/workflow-run-engine.types.ts +91 -0
- package/src/wirings/workflow/workflow-run-ownership.ts +37 -0
- package/src/wirings/workflow/workflow-suspend.ts +61 -0
- package/src/wirings/workflow/workflow.types.ts +7 -9
- package/src/wirings-stay-decoupled.test.ts +127 -0
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/internal.d.ts +0 -3
- package/dist/internal.js +0 -2
- package/dist/middleware/timeout.d.ts +0 -9
- package/dist/middleware/timeout.js +0 -15
- package/dist/pikku-response.d.ts +0 -6
- package/dist/pikku-response.js +0 -6
- package/dist/services/gopass-secrets.d.ts +0 -15
- package/dist/services/gopass-secrets.js +0 -76
- package/dist/services/http-scenario-actors.d.ts +0 -75
- package/dist/services/http-scenario-actors.js +0 -195
- package/dist/services/http-user-flow-actors.d.ts +0 -67
- package/dist/services/http-user-flow-actors.js +0 -193
- package/dist/services/scenario-actors-service.d.ts +0 -127
- package/dist/services/scenario-actors-service.js +0 -40
- package/dist/services/user-flow-actors-service.d.ts +0 -39
- package/dist/wirings/credential/wire-credential.d.ts +0 -48
- package/dist/wirings/credential/wire-credential.js +0 -47
- package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
- package/dist/wirings/oauth2/oauth2-client.js +0 -263
- package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
- package/dist/wirings/oauth2/oauth2-routes.js +0 -146
- package/dist/wirings/scope/wire-scope.d.ts +0 -33
- package/dist/wirings/scope/wire-scope.js +0 -32
- package/dist/wirings/workflow/dsl/index.d.ts +0 -5
- package/dist/wirings/workflow/dsl/index.js +0 -4
- package/dist/wirings/workflow/graph/index.d.ts +0 -5
- package/dist/wirings/workflow/graph/index.js +0 -4
- package/src/internal.ts +0 -10
- /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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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):
|
|
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
|
|
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
|
|
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')) {
|
package/src/wirings/mcp/index.ts
CHANGED
|
@@ -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
|
|
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
|
|
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')[
|
|
246
|
+
meta = pikkuState(null, 'mcp', 'resourcesMeta')[metaKey]
|
|
223
247
|
} else if (type === 'tool') {
|
|
224
|
-
meta = pikkuState(null, 'mcp', 'toolsMeta')[
|
|
248
|
+
meta = pikkuState(null, 'mcp', 'toolsMeta')[metaKey]
|
|
225
249
|
} else if (type === 'prompt') {
|
|
226
|
-
meta = pikkuState(null, 'mcp', 'promptsMeta')[
|
|
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,
|