@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,5 +1,6 @@
|
|
|
1
1
|
export class InMemoryAIRunStateService {
|
|
2
2
|
runs = new Map();
|
|
3
|
+
scores = new Map();
|
|
3
4
|
counter = 0;
|
|
4
5
|
async createRun(run) {
|
|
5
6
|
const runId = `run-${++this.counter}-${Date.now()}`;
|
|
@@ -25,10 +26,11 @@ export class InMemoryAIRunStateService {
|
|
|
25
26
|
if (approval) {
|
|
26
27
|
run.pendingApprovals = run.pendingApprovals.filter((a) => a.toolCallId !== toolCallId);
|
|
27
28
|
run.updatedAt = new Date();
|
|
28
|
-
return;
|
|
29
|
+
return true;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
}
|
|
33
|
+
return false;
|
|
32
34
|
}
|
|
33
35
|
async findRunByToolCallId(toolCallId) {
|
|
34
36
|
for (const run of this.runs.values()) {
|
|
@@ -41,4 +43,12 @@ export class InMemoryAIRunStateService {
|
|
|
41
43
|
}
|
|
42
44
|
return null;
|
|
43
45
|
}
|
|
46
|
+
async saveScore(score) {
|
|
47
|
+
const existing = this.scores.get(score.runId) ?? [];
|
|
48
|
+
existing.push({ ...score, createdAt: new Date() });
|
|
49
|
+
this.scores.set(score.runId, existing);
|
|
50
|
+
}
|
|
51
|
+
async getScores(runId) {
|
|
52
|
+
return [...(this.scores.get(runId) ?? [])];
|
|
53
|
+
}
|
|
44
54
|
}
|
|
@@ -74,6 +74,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
74
74
|
const step = {
|
|
75
75
|
stepId,
|
|
76
76
|
status: 'pending',
|
|
77
|
+
rpcName,
|
|
77
78
|
attemptCount: 1,
|
|
78
79
|
retries: stepOptions?.retries,
|
|
79
80
|
retryDelay: stepOptions?.retryDelay,
|
|
@@ -177,6 +178,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
177
178
|
const newStep = {
|
|
178
179
|
stepId: newStepId,
|
|
179
180
|
status,
|
|
181
|
+
rpcName: failedStep.rpcName,
|
|
180
182
|
attemptCount: failedStep.attemptCount + 1,
|
|
181
183
|
retries: failedStep.retries,
|
|
182
184
|
retryDelay: failedStep.retryDelay,
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { LogLevel } from './logger.js';
|
|
2
2
|
export { ScopedSecretService } from './scoped-secret-service.js';
|
|
3
|
-
export {
|
|
3
|
+
export { ScopedCredentialService } from './scoped-credential-service.js';
|
|
4
|
+
export { PikkuSessionService, createMiddlewareSessionWireProps, } from './user-session-service.js';
|
|
4
5
|
export { TypedSecretService } from './typed-secret-service.js';
|
|
5
|
-
export { PikkuCredentialWireService,
|
|
6
|
+
export { PikkuCredentialWireService, } from './credential-wire-service.js';
|
|
6
7
|
export { TypedVariablesService } from './typed-variables-service.js';
|
|
7
8
|
export { LocalSecretService } from './local-secrets.js';
|
|
8
9
|
export { LocalEmailService } from './local-email-service.js';
|
|
@@ -16,11 +17,11 @@ export { InMemoryTriggerService } from './in-memory-trigger-service.js';
|
|
|
16
17
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
17
18
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
18
19
|
export type { ContentService, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './content-service.js';
|
|
19
|
-
export type { ScenarioPersona, ResolvedPersona,
|
|
20
|
+
export type { ScenarioPersona, ResolvedPersona, ScenarioPersonas, ScenarioHttpResponse, } from './personas-service.js';
|
|
20
21
|
export type { HttpPersonasConfig } from './http-personas.js';
|
|
21
22
|
export type { JWTService } from './jwt-service.js';
|
|
22
|
-
export type { EmailService,
|
|
23
|
-
export { DEFAULT_WEBHOOK_RETRIES,
|
|
23
|
+
export type { EmailService, SendEmailInput, SendEmailResult, SendHTMLEmailInput, SendTemplateEmailInput, SendTextEmailInput, } from './email-service.js';
|
|
24
|
+
export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, type SendWebhookInput, type SendWebhookResult, type WebhookAttemptResult, type WebhookDeliveryRecord, type WebhookDeliveryWithAttempts, type WebhookJobData, type WebhookServiceConfig, } from './webhook-service.js';
|
|
24
25
|
export type { Logger } from './logger.js';
|
|
25
26
|
export type { SecretService, SecretValues } from './secret-service.js';
|
|
26
27
|
export type { VariablesService } from './variables-service.js';
|
|
@@ -31,23 +32,22 @@ export type { TriggerService } from './trigger-service.js';
|
|
|
31
32
|
export type { GatewayService } from './gateway-service.js';
|
|
32
33
|
export type { DeploymentService, DeploymentConfig, DeploymentInfo, DeploymentServiceConfig, } from './deployment-service.js';
|
|
33
34
|
export type { AIStorageService } from './ai-storage-service.js';
|
|
34
|
-
export type { AIAgentRunnerParams, AIAgentRunnerResult, AIAgentStepResult,
|
|
35
|
+
export type { AIAgentRunnerParams, AIAgentRunnerResult, AIAgentStepResult, AIAgentRunnerService, } from './ai-agent-runner-service.js';
|
|
35
36
|
export type { AIEmbeddingService } from './ai-embedding-service.js';
|
|
36
|
-
export type { CreateRunInput, AIRunStateService, } from './ai-run-state-service.js';
|
|
37
|
-
export type {
|
|
37
|
+
export type { CreateRunInput, SaveScoreInput, AIRunStateService, } from './ai-run-state-service.js';
|
|
38
|
+
export type { CredentialMeta, } from './typed-secret-service.js';
|
|
38
39
|
export type { CredentialService } from './credential-service.js';
|
|
39
40
|
export { TypedCredentialService } from './typed-credential-service.js';
|
|
40
|
-
export type {
|
|
41
|
-
export type {
|
|
41
|
+
export type { CredentialMetaInfo, } from './typed-credential-service.js';
|
|
42
|
+
export type { VariableMeta } from './typed-variables-service.js';
|
|
42
43
|
export type { MetaService } from './meta-service.js';
|
|
43
44
|
export type { SessionStore } from './session-store.js';
|
|
44
45
|
export type { ScopeService, Role } from './scope-service.js';
|
|
45
|
-
export { assertRoleIsMutable, assertRoleNameAvailable, roleLockReason, } from './system-role-guard.js';
|
|
46
46
|
export type { IsSystemRole } from './system-role-guard.js';
|
|
47
|
-
export { NoopAuditService, createInvocationAudit,
|
|
48
|
-
export type { AuditConfig, AuditDurability, AuditEvent, AuditEventBatch, AuditLog,
|
|
47
|
+
export { NoopAuditService, createInvocationAudit, } from './audit-service.js';
|
|
48
|
+
export type { AuditConfig, AuditDurability, AuditEvent, AuditEventBatch, AuditLog, AuditService, AuditUserIdentity, ResolvedAuditConfig, } from './audit-service.js';
|
|
49
49
|
export { InMemorySessionStore } from './in-memory-session-store.js';
|
|
50
|
-
export type { MCPMeta, RPCMetaRecord, ServiceMeta, ServicesMetaRecord, MiddlewareDefinitionMeta, MiddlewareInstanceMeta, GroupMeta, MiddlewareGroupsMeta, PermissionDefinitionMeta, PermissionsGroupsMeta, FunctionsMeta, FunctionMeta, MiddlewareMeta, PermissionMeta, AgentsMeta, AgentMeta, EmailsMeta, EmailTemplateMeta,
|
|
51
|
-
export type { CoverageService,
|
|
50
|
+
export type { MCPMeta, RPCMetaRecord, ServiceMeta, ServicesMetaRecord, MiddlewareDefinitionMeta, MiddlewareInstanceMeta, GroupMeta, MiddlewareGroupsMeta, PermissionDefinitionMeta, PermissionsGroupsMeta, FunctionsMeta, FunctionMeta, MiddlewareMeta, PermissionMeta, AgentsMeta, AgentMeta, EmailsMeta, EmailTemplateMeta, } from './meta-service.js';
|
|
51
|
+
export type { CoverageService, ScriptCoverage, FunctionCoverageEntry, FunctionCoverageReport, CoverageFunctionMeta, } from './v8-coverage-service.js';
|
|
52
52
|
export { StubTracker, createStubProxy, getStubTracker, isTestRun, stub, spy, type StubCall, } from './stub-tracker.js';
|
|
53
53
|
export { SecretHostNotAllowedError, assertSecretAllowedForHost, } from './secret-host-binding.js';
|
package/dist/services/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { LogLevel } from './logger.js';
|
|
2
2
|
export { ScopedSecretService } from './scoped-secret-service.js';
|
|
3
|
-
export {
|
|
3
|
+
export { ScopedCredentialService } from './scoped-credential-service.js';
|
|
4
|
+
export { PikkuSessionService, createMiddlewareSessionWireProps, } from './user-session-service.js';
|
|
4
5
|
export { TypedSecretService } from './typed-secret-service.js';
|
|
5
|
-
export { PikkuCredentialWireService,
|
|
6
|
+
export { PikkuCredentialWireService, } from './credential-wire-service.js';
|
|
6
7
|
export { TypedVariablesService } from './typed-variables-service.js';
|
|
7
8
|
export { LocalSecretService } from './local-secrets.js';
|
|
8
9
|
export { LocalEmailService } from './local-email-service.js';
|
|
@@ -15,10 +16,9 @@ export { InMemoryQueueService } from './in-memory-queue-service.js';
|
|
|
15
16
|
export { InMemoryTriggerService } from './in-memory-trigger-service.js';
|
|
16
17
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
17
18
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
18
|
-
export { DEFAULT_WEBHOOK_RETRIES,
|
|
19
|
+
export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, } from './webhook-service.js';
|
|
19
20
|
export { TypedCredentialService } from './typed-credential-service.js';
|
|
20
|
-
export {
|
|
21
|
-
export { NoopAuditService, createInvocationAudit, resolveAuditConfig, resolveAuditUserIdentityFromWire, } from './audit-service.js';
|
|
21
|
+
export { NoopAuditService, createInvocationAudit, } from './audit-service.js';
|
|
22
22
|
export { InMemorySessionStore } from './in-memory-session-store.js';
|
|
23
23
|
export { StubTracker, createStubProxy, getStubTracker, isTestRun, stub, spy, } from './stub-tracker.js';
|
|
24
24
|
export { SecretHostNotAllowedError, assertSecretAllowedForHost, } from './secret-host-binding.js';
|
|
@@ -26,4 +26,25 @@ export type LocalContentRequestHandlerOptions = {
|
|
|
26
26
|
*/
|
|
27
27
|
getJWT: () => JWTService | undefined;
|
|
28
28
|
};
|
|
29
|
+
export type SignedContentVerification = {
|
|
30
|
+
ok: true;
|
|
31
|
+
} | {
|
|
32
|
+
ok: false;
|
|
33
|
+
status: number;
|
|
34
|
+
body: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Verifies a signed content URL — the one function that decides whether a
|
|
38
|
+
* signed read or a signed upload is genuine.
|
|
39
|
+
*
|
|
40
|
+
* Exported and shared so the runtimes that serve content (the core handler here,
|
|
41
|
+
* the node server, the express adapter) verify identically. They used to each
|
|
42
|
+
* carry their own copy, which is how the express upload path ended up with no
|
|
43
|
+
* check at all: one copy can rot or be forgotten in isolation.
|
|
44
|
+
*
|
|
45
|
+
* `onMissingJWT` is called at most where the caller wants to log the
|
|
46
|
+
* misconfiguration once; a signed request with no verifier is treated as
|
|
47
|
+
* invalid, never as trusted.
|
|
48
|
+
*/
|
|
49
|
+
export declare const verifySignedContentRequest: (requestUrl: URL, jwt: JWTService | undefined, onMissingJWT?: () => void) => Promise<SignedContentVerification>;
|
|
29
50
|
export declare const createLocalContentRequestHandler: ({ content, logger, getJWT, }: LocalContentRequestHandlerOptions) => LocalContentRequestHandler;
|
|
@@ -36,69 +36,88 @@ const text = (status, body) => new Response(body, {
|
|
|
36
36
|
status,
|
|
37
37
|
headers: { 'content-type': 'text/plain; charset=utf-8' },
|
|
38
38
|
});
|
|
39
|
+
/**
|
|
40
|
+
* Verifies a signed content URL — the one function that decides whether a
|
|
41
|
+
* signed read or a signed upload is genuine.
|
|
42
|
+
*
|
|
43
|
+
* Exported and shared so the runtimes that serve content (the core handler here,
|
|
44
|
+
* the node server, the express adapter) verify identically. They used to each
|
|
45
|
+
* carry their own copy, which is how the express upload path ended up with no
|
|
46
|
+
* check at all: one copy can rot or be forgotten in isolation.
|
|
47
|
+
*
|
|
48
|
+
* `onMissingJWT` is called at most where the caller wants to log the
|
|
49
|
+
* misconfiguration once; a signed request with no verifier is treated as
|
|
50
|
+
* invalid, never as trusted.
|
|
51
|
+
*/
|
|
52
|
+
export const verifySignedContentRequest = async (requestUrl, jwt, onMissingJWT) => {
|
|
53
|
+
const signedAtValue = requestUrl.searchParams.get('signedAt');
|
|
54
|
+
const expiresAtValue = requestUrl.searchParams.get('expiresAt');
|
|
55
|
+
const notBeforeValue = requestUrl.searchParams.get('notBefore');
|
|
56
|
+
const signature = requestUrl.searchParams.get('signature');
|
|
57
|
+
if (!signedAtValue || !expiresAtValue) {
|
|
58
|
+
return { ok: false, status: 403, body: 'Signed URL required' };
|
|
59
|
+
}
|
|
60
|
+
const signedAt = Number(signedAtValue);
|
|
61
|
+
const expiresAt = Number(expiresAtValue);
|
|
62
|
+
const notBefore = notBeforeValue == null ? undefined : Number(notBeforeValue);
|
|
63
|
+
if (!Number.isFinite(signedAt) ||
|
|
64
|
+
!Number.isFinite(expiresAt) ||
|
|
65
|
+
(notBefore != null && !Number.isFinite(notBefore))) {
|
|
66
|
+
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
67
|
+
}
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
if (now > expiresAt || (notBefore != null && now < notBefore)) {
|
|
70
|
+
return { ok: false, status: 403, body: 'Signed URL expired' };
|
|
71
|
+
}
|
|
72
|
+
if (!jwt) {
|
|
73
|
+
onMissingJWT?.();
|
|
74
|
+
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
75
|
+
}
|
|
76
|
+
if (!signature) {
|
|
77
|
+
return { ok: false, status: 403, body: 'Signed URL signature required' };
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const payload = await jwt.decode(signature);
|
|
81
|
+
// Every claim is compared, the path included: without it a signature
|
|
82
|
+
// minted for one asset would read any other.
|
|
83
|
+
if (payload.signedAt !== signedAt ||
|
|
84
|
+
payload.expiresAt !== expiresAt ||
|
|
85
|
+
payload.notBefore !== notBefore ||
|
|
86
|
+
payload.path !== signedContentPath(requestUrl.pathname)) {
|
|
87
|
+
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
92
|
+
}
|
|
93
|
+
return { ok: true };
|
|
94
|
+
};
|
|
39
95
|
export const createLocalContentRequestHandler = ({ content, logger, getJWT, }) => {
|
|
40
96
|
// Logged at most once. An unverifiable request is attacker-triggerable, so
|
|
41
97
|
// this reports a startup misconfiguration rather than per-request news.
|
|
42
98
|
let loggedMissingJWT = false;
|
|
43
|
-
const validateSignedAssetRequest =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
(
|
|
57
|
-
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
58
|
-
}
|
|
59
|
-
const now = Date.now();
|
|
60
|
-
if (now > expiresAt || (notBefore != null && now < notBefore)) {
|
|
61
|
-
return { ok: false, status: 403, body: 'Signed URL expired' };
|
|
62
|
-
}
|
|
63
|
-
const jwt = getJWT();
|
|
64
|
-
if (!jwt) {
|
|
65
|
-
if (!loggedMissingJWT) {
|
|
66
|
-
loggedMissingJWT = true;
|
|
67
|
-
logger.error('pikku: refusing signed asset reads — no JWTService is available to verify them. Pass `contentSigningJWT` (the same service LocalContent signs with) or expose it as `singletonServices.jwt`.');
|
|
68
|
-
}
|
|
69
|
-
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
70
|
-
}
|
|
71
|
-
if (!signature) {
|
|
72
|
-
return { ok: false, status: 403, body: 'Signed URL signature required' };
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
const payload = await jwt.decode(signature);
|
|
76
|
-
// Every claim is compared, the path included: without it a signature
|
|
77
|
-
// minted for one asset would read any other.
|
|
78
|
-
if (payload.signedAt !== signedAt ||
|
|
79
|
-
payload.expiresAt !== expiresAt ||
|
|
80
|
-
payload.notBefore !== notBefore ||
|
|
81
|
-
payload.path !== signedContentPath(requestUrl.pathname)) {
|
|
82
|
-
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return { ok: false, status: 403, body: 'Invalid signed URL' };
|
|
99
|
+
const validateSignedAssetRequest = (requestUrl) => verifySignedContentRequest(requestUrl, getJWT(), () => {
|
|
100
|
+
if (loggedMissingJWT)
|
|
101
|
+
return;
|
|
102
|
+
loggedMissingJWT = true;
|
|
103
|
+
logger.error('pikku: refusing signed asset reads — no JWTService is available to verify them. Pass `contentSigningJWT` (the same service LocalContent signs with) or expose it as `singletonServices.jwt`.');
|
|
104
|
+
});
|
|
105
|
+
const handleUpload = async (request, requestUrl, pathname) => {
|
|
106
|
+
// Uploads are presigned exactly like reads: getUploadURL mints a signed URL
|
|
107
|
+
// and this verifies it before writing. Without this an unauthenticated PUT
|
|
108
|
+
// could write arbitrary bytes to any key under the content root — the write
|
|
109
|
+
// side had none of the signature checking the read side has always had.
|
|
110
|
+
const signed = await validateSignedAssetRequest(requestUrl);
|
|
111
|
+
if (!signed.ok) {
|
|
112
|
+
return text(signed.status, signed.body);
|
|
87
113
|
}
|
|
88
|
-
return { ok: true };
|
|
89
|
-
};
|
|
90
|
-
const handleUpload = async (request, pathname) => {
|
|
91
114
|
const key = contentKey(pathname, content.uploadUrlPrefix);
|
|
92
115
|
const targetPath = toTargetPath(content.localFileUploadPath, key);
|
|
93
116
|
if (!targetPath) {
|
|
94
117
|
return text(400, 'Invalid path');
|
|
95
118
|
}
|
|
96
119
|
const maxBytes = parseSizeLimit(content.sizeLimit ?? '1mb');
|
|
97
|
-
//
|
|
98
|
-
// oversized upload costs the limit rather than its own size — `arrayBuffer()`
|
|
99
|
-
// would have to hold all of it first, which hands an unauthenticated caller
|
|
100
|
-
// a way to spend the server's memory. Mirrors node-http-server's
|
|
101
|
-
// `readRequestBody`, which aborts the same way.
|
|
120
|
+
// knowledge: decisions/security/an-upload-is-counted-as-it-arrives-not-buffered-then-measured.md
|
|
102
121
|
const chunks = [];
|
|
103
122
|
let bytesRead = 0;
|
|
104
123
|
const reader = request.body?.getReader();
|
|
@@ -165,7 +184,7 @@ export const createLocalContentRequestHandler = ({ content, logger, getJWT, }) =
|
|
|
165
184
|
const pathname = decodeURIComponent(requestUrl.pathname);
|
|
166
185
|
if (request.method === 'PUT' &&
|
|
167
186
|
matchesPrefix(pathname, content.uploadUrlPrefix)) {
|
|
168
|
-
return handleUpload(request, pathname);
|
|
187
|
+
return handleUpload(request, requestUrl, pathname);
|
|
169
188
|
}
|
|
170
189
|
if ((request.method === 'GET' || request.method === 'HEAD') &&
|
|
171
190
|
matchesPrefix(pathname, content.assetUrlPrefix)) {
|
|
@@ -28,6 +28,12 @@ export declare class LocalContent implements ContentService {
|
|
|
28
28
|
private signParams;
|
|
29
29
|
signURL(args: SignURLArgs): Promise<string>;
|
|
30
30
|
signContentKey(args: SignContentKeyArgs): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Presigned upload, mirroring the read side: the URL carries a short-lived,
|
|
33
|
+
* path-bound signature that {@link createLocalContentRequestHandler} verifies
|
|
34
|
+
* before writing. An unsigned upload URL cannot be verified, and the handler
|
|
35
|
+
* now refuses one — so this must sign, or every upload 403s.
|
|
36
|
+
*/
|
|
31
37
|
getUploadURL(args: GetUploadURLArgs): Promise<UploadURLResult>;
|
|
32
38
|
writeFile(args: WriteFileArgs): Promise<boolean>;
|
|
33
39
|
copyFile(args: CopyFileArgs): Promise<boolean>;
|
|
@@ -27,6 +27,8 @@ export const signedContentPath = (urlOrPath) => {
|
|
|
27
27
|
return pathname;
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
+
/** How long a presigned upload URL stays valid. Short, like an S3 PUT URL. */
|
|
31
|
+
const UPLOAD_URL_TTL_MS = 15 * 60 * 1000;
|
|
30
32
|
export class LocalContent {
|
|
31
33
|
config;
|
|
32
34
|
logger;
|
|
@@ -90,13 +92,24 @@ export class LocalContent {
|
|
|
90
92
|
dateGreaterThan: args.dateGreaterThan,
|
|
91
93
|
});
|
|
92
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Presigned upload, mirroring the read side: the URL carries a short-lived,
|
|
97
|
+
* path-bound signature that {@link createLocalContentRequestHandler} verifies
|
|
98
|
+
* before writing. An unsigned upload URL cannot be verified, and the handler
|
|
99
|
+
* now refuses one — so this must sign, or every upload 403s.
|
|
100
|
+
*/
|
|
93
101
|
async getUploadURL(args) {
|
|
94
102
|
void args.visibility;
|
|
95
103
|
const fullKey = this.joinKey(args.bucket, args.fileKey);
|
|
96
104
|
this.logger.debug(`Going to upload with key: ${fullKey}`);
|
|
105
|
+
const uploadUrl = await this.signURL({
|
|
106
|
+
url: `${this.config.uploadUrlPrefix}/${fullKey}`,
|
|
107
|
+
dateLessThan: new Date(Date.now() + UPLOAD_URL_TTL_MS),
|
|
108
|
+
});
|
|
97
109
|
return {
|
|
98
|
-
uploadUrl
|
|
110
|
+
uploadUrl,
|
|
99
111
|
assetKey: fullKey,
|
|
112
|
+
uploadMethod: 'PUT',
|
|
100
113
|
};
|
|
101
114
|
}
|
|
102
115
|
async writeFile(args) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CredentialService } from './credential-service.js';
|
|
2
|
+
/**
|
|
3
|
+
* A `CredentialService` narrowed to the credentials a package declared.
|
|
4
|
+
*
|
|
5
|
+
* Unlike `ScopedSecretService` this stays writable — an addon refreshing its
|
|
6
|
+
* own OAuth token is the normal case. What it cannot do is reach a credential
|
|
7
|
+
* it never declared, or enumerate the app's users.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ScopedCredentialService implements CredentialService {
|
|
10
|
+
private credentials;
|
|
11
|
+
private allowedNames;
|
|
12
|
+
constructor(credentials: CredentialService, allowedNames: Set<string>);
|
|
13
|
+
private assertAllowed;
|
|
14
|
+
get<T = unknown>(name: string, userId?: string): Promise<T | null>;
|
|
15
|
+
set(name: string, value: unknown, userId?: string): Promise<void>;
|
|
16
|
+
delete(name: string, userId?: string): Promise<void>;
|
|
17
|
+
has(name: string, userId?: string): Promise<boolean>;
|
|
18
|
+
getAll(userId: string): Promise<Record<string, unknown>>;
|
|
19
|
+
getUsersWithCredential(name: string): Promise<string[]>;
|
|
20
|
+
getAllUsers(): Promise<string[]>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `CredentialService` narrowed to the credentials a package declared.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `ScopedSecretService` this stays writable — an addon refreshing its
|
|
5
|
+
* own OAuth token is the normal case. What it cannot do is reach a credential
|
|
6
|
+
* it never declared, or enumerate the app's users.
|
|
7
|
+
*/
|
|
8
|
+
export class ScopedCredentialService {
|
|
9
|
+
credentials;
|
|
10
|
+
allowedNames;
|
|
11
|
+
constructor(credentials, allowedNames) {
|
|
12
|
+
this.credentials = credentials;
|
|
13
|
+
this.allowedNames = allowedNames;
|
|
14
|
+
}
|
|
15
|
+
assertAllowed(name) {
|
|
16
|
+
if (!this.allowedNames.has(name)) {
|
|
17
|
+
throw new Error(`Access denied to credential: ${name}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async get(name, userId) {
|
|
21
|
+
this.assertAllowed(name);
|
|
22
|
+
return this.credentials.get(name, userId);
|
|
23
|
+
}
|
|
24
|
+
async set(name, value, userId) {
|
|
25
|
+
this.assertAllowed(name);
|
|
26
|
+
return this.credentials.set(name, value, userId);
|
|
27
|
+
}
|
|
28
|
+
async delete(name, userId) {
|
|
29
|
+
this.assertAllowed(name);
|
|
30
|
+
return this.credentials.delete(name, userId);
|
|
31
|
+
}
|
|
32
|
+
async has(name, userId) {
|
|
33
|
+
this.assertAllowed(name);
|
|
34
|
+
return this.credentials.has(name, userId);
|
|
35
|
+
}
|
|
36
|
+
async getAll(userId) {
|
|
37
|
+
const all = await this.credentials.getAll(userId);
|
|
38
|
+
const scoped = {};
|
|
39
|
+
for (const name of this.allowedNames) {
|
|
40
|
+
if (name in all) {
|
|
41
|
+
scoped[name] = all[name];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return scoped;
|
|
45
|
+
}
|
|
46
|
+
async getUsersWithCredential(name) {
|
|
47
|
+
this.assertAllowed(name);
|
|
48
|
+
return this.credentials.getUsersWithCredential(name);
|
|
49
|
+
}
|
|
50
|
+
async getAllUsers() {
|
|
51
|
+
throw new Error('Access denied: enumerating users is not allowed in a scoped credential service');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SerializedError } from '../types/core.types.js';
|
|
1
|
+
import type { CoreUserSession, SerializedError } from '../types/core.types.js';
|
|
2
2
|
import type { WorkflowRun, WorkflowPlannedStep, WorkflowRunWire, WorkflowRunStatus, StepState, WorkflowStatus, WorkflowVersionStatus } from '../wirings/workflow/workflow.types.js';
|
|
3
3
|
import type { RunTimeline, ReconstructedRunState } from '../wirings/workflow/run-timeline.js';
|
|
4
4
|
export interface WorkflowService {
|
|
@@ -21,8 +21,10 @@ export interface WorkflowService {
|
|
|
21
21
|
/**
|
|
22
22
|
* The payload is stored as given and validated on replay inside the workflow
|
|
23
23
|
* body, so an invalid one re-closes the gate rather than failing the run.
|
|
24
|
+
*
|
|
25
|
+
* The session must belong to the run's owner — see `assertWorkflowRunOwner`.
|
|
24
26
|
*/
|
|
25
|
-
approveStep(runId: string, reason: string, decision: unknown): Promise<void>;
|
|
27
|
+
approveStep(runId: string, reason: string, decision: unknown, session?: CoreUserSession): Promise<void>;
|
|
26
28
|
startWorkflow<I>(name: string, input: I, wire: WorkflowRunWire, rpcService: any, options?: {
|
|
27
29
|
inline?: boolean;
|
|
28
30
|
startNode?: string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ServiceTestConfig } from '../service-tests.js';
|
|
2
|
+
/** Conformance suite for `agentRunService`. Runs only when a backend supplies one. */
|
|
3
|
+
export declare const defineAgentRunServiceTests: (name: string, agentRunService: NonNullable<ServiceTestConfig["services"]["agentRunService"]>,
|
|
4
|
+
/**
|
|
5
|
+
* Thread-ownership is a property of the two services together — the run
|
|
6
|
+
* service lists what the storage service owns — so that half of the suite
|
|
7
|
+
* only runs when a backend supplies both. Passed explicitly rather than
|
|
8
|
+
* closed over, so the dependency is visible in the signature.
|
|
9
|
+
*/
|
|
10
|
+
aiStorageService?: ServiceTestConfig["services"]["aiStorageService"]) => void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, test, before } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
/** Conformance suite for `agentRunService`. Runs only when a backend supplies one. */
|
|
4
|
+
export const defineAgentRunServiceTests = (name, agentRunService,
|
|
5
|
+
/**
|
|
6
|
+
* Thread-ownership is a property of the two services together — the run
|
|
7
|
+
* service lists what the storage service owns — so that half of the suite
|
|
8
|
+
* only runs when a backend supplies both. Passed explicitly rather than
|
|
9
|
+
* closed over, so the dependency is visible in the signature.
|
|
10
|
+
*/
|
|
11
|
+
aiStorageService) => {
|
|
12
|
+
const factory = agentRunService;
|
|
13
|
+
describe(`AgentRunService [${name}]`, () => {
|
|
14
|
+
let agentService;
|
|
15
|
+
before(async () => {
|
|
16
|
+
agentService = await factory();
|
|
17
|
+
});
|
|
18
|
+
test('listThreads', async () => {
|
|
19
|
+
const threads = await agentService.listThreads();
|
|
20
|
+
assert.ok(Array.isArray(threads));
|
|
21
|
+
});
|
|
22
|
+
if (aiStorageService) {
|
|
23
|
+
const storageFactory = aiStorageService;
|
|
24
|
+
// The `owners` constraint is what keeps the generated thread-management
|
|
25
|
+
// functions from leaking across tenants: a caller may only list threads
|
|
26
|
+
// owned by one of their session principals, matching the
|
|
27
|
+
// `principal:sub-partition` composition resolveOwnerResourceId writes.
|
|
28
|
+
test('listThreads scopes to the given owners, including sub-partitions', async () => {
|
|
29
|
+
const storage = await storageFactory();
|
|
30
|
+
await storage.createThread('owner-alice');
|
|
31
|
+
await storage.createThread('owner-alice:project-1');
|
|
32
|
+
await storage.createThread('owner-bob:secret');
|
|
33
|
+
const threads = await agentService.listThreads({
|
|
34
|
+
owners: ['owner-alice'],
|
|
35
|
+
});
|
|
36
|
+
const ids = threads.map((t) => t.resourceId);
|
|
37
|
+
assert.ok(ids.includes('owner-alice'));
|
|
38
|
+
assert.ok(ids.includes('owner-alice:project-1'));
|
|
39
|
+
assert.ok(!ids.some((id) => id.startsWith('owner-bob')), "another owner's threads must not be listed");
|
|
40
|
+
});
|
|
41
|
+
test('listThreads with an owner does not match a lookalike prefix', async () => {
|
|
42
|
+
const storage = await storageFactory();
|
|
43
|
+
await storage.createThread('owner-al');
|
|
44
|
+
await storage.createThread('owner-alice-evil:p');
|
|
45
|
+
const threads = await agentService.listThreads({
|
|
46
|
+
owners: ['owner-al'],
|
|
47
|
+
});
|
|
48
|
+
const ids = threads.map((t) => t.resourceId);
|
|
49
|
+
assert.ok(ids.includes('owner-al'));
|
|
50
|
+
assert.ok(!ids.includes('owner-alice-evil:p'));
|
|
51
|
+
});
|
|
52
|
+
test('listThreads with an empty owners list returns nothing', async () => {
|
|
53
|
+
const storage = await storageFactory();
|
|
54
|
+
await storage.createThread('owner-empty-check');
|
|
55
|
+
const threads = await agentService.listThreads({ owners: [] });
|
|
56
|
+
assert.deepEqual(threads, []);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
test('getThread returns null for missing', async () => {
|
|
60
|
+
const thread = await agentService.getThread('missing-thread');
|
|
61
|
+
assert.equal(thread, null);
|
|
62
|
+
});
|
|
63
|
+
test('getDistinctAgentNames', async () => {
|
|
64
|
+
const names = await agentService.getDistinctAgentNames();
|
|
65
|
+
assert.ok(Array.isArray(names));
|
|
66
|
+
});
|
|
67
|
+
test('deleteThread returns false for missing', async () => {
|
|
68
|
+
const result = await agentService.deleteThread('missing-thread');
|
|
69
|
+
assert.equal(result, false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ServiceTestConfig } from '../service-tests.js';
|
|
2
|
+
/** Conformance suite for `aiStorageService`. Runs only when a backend supplies one. */
|
|
3
|
+
export declare const defineAiStorageServiceTests: (name: string, aiStorageService: NonNullable<ServiceTestConfig["services"]["aiStorageService"]>) => void;
|