@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
|
@@ -16,15 +16,14 @@
|
|
|
16
16
|
* {@link VirtualUserTarget}, which in production is an `HttpPersona`
|
|
17
17
|
* signed in as a real user against staging or production.
|
|
18
18
|
*/
|
|
19
|
-
export type { ApiCatalogueEntry,
|
|
19
|
+
export type { ApiCatalogueEntry, IntentSource, VirtualUserDisposition, VirtualUserFinding, VirtualUserRunResult, VirtualUserTarget, } from './virtual-user.types.js';
|
|
20
20
|
export { PRODUCTION_DISPOSITION } from './virtual-user.types.js';
|
|
21
|
-
export { runVirtualUser,
|
|
21
|
+
export { runVirtualUser, type RunVirtualUserParams, } from './run-virtual-user.js';
|
|
22
22
|
export { personaScopes, prepareVirtualUserRun, type VirtualUserPreparation, } from './prepare-virtual-user-run.js';
|
|
23
23
|
export type { VirtualUserRunOutcome, VirtualUserRunRecord, VirtualUserRunStart, VirtualUserRunStore, } from './virtual-user-run-store.js';
|
|
24
24
|
export { DISPOSITIONS, dispositionProfile, type DispositionProfile, type VirtualUserTuning, } from './virtual-user-dispositions.js';
|
|
25
|
-
export { catalogueClassification,
|
|
26
|
-
export {
|
|
27
|
-
export { IntentStack, intentsForPersona,
|
|
28
|
-
export { createRng, type VirtualUserRng } from './virtual-user-rng.js';
|
|
25
|
+
export { catalogueClassification, catalogueLookup, isReadOnly, reachableCatalogue, unreachableCatalogue, } from './virtual-user-catalogue.js';
|
|
26
|
+
export { type AgentReachability, type ReachableAgent, } from './virtual-user-agents.js';
|
|
27
|
+
export { IntentStack, intentsForPersona, } from './virtual-user-intents.js';
|
|
29
28
|
export { deriveCatalogue, deriveIntents, type SchemaMap, } from './virtual-user-derive.js';
|
|
30
29
|
export { personaVirtualUserTarget, type PersonaTargetOptions, } from './virtual-user-target.js';
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
export { PRODUCTION_DISPOSITION } from './virtual-user.types.js';
|
|
2
|
-
export { runVirtualUser,
|
|
2
|
+
export { runVirtualUser, } from './run-virtual-user.js';
|
|
3
3
|
export { personaScopes, prepareVirtualUserRun, } from './prepare-virtual-user-run.js';
|
|
4
4
|
export { DISPOSITIONS, dispositionProfile, } from './virtual-user-dispositions.js';
|
|
5
|
-
export { catalogueClassification,
|
|
6
|
-
export { reachableAgents, } from './virtual-user-agents.js';
|
|
5
|
+
export { catalogueClassification, catalogueLookup, isReadOnly, reachableCatalogue, unreachableCatalogue, } from './virtual-user-catalogue.js';
|
|
7
6
|
export { IntentStack, intentsForPersona, } from './virtual-user-intents.js';
|
|
8
|
-
export { createRng } from './virtual-user-rng.js';
|
|
9
7
|
export { deriveCatalogue, deriveIntents, } from './virtual-user-derive.js';
|
|
10
8
|
export { personaVirtualUserTarget, } from './virtual-user-target.js';
|
|
@@ -97,7 +97,9 @@ export const rememberIds = (body, into, depth = 0) => {
|
|
|
97
97
|
return into;
|
|
98
98
|
}
|
|
99
99
|
for (const [key, value] of Object.entries(body)) {
|
|
100
|
-
if (typeof value === 'string' &&
|
|
100
|
+
if (typeof value === 'string' &&
|
|
101
|
+
MEMORABLE.test(key) &&
|
|
102
|
+
value.length < 200) {
|
|
101
103
|
into[key] = value;
|
|
102
104
|
}
|
|
103
105
|
else if (typeof value === 'object') {
|
|
@@ -203,7 +205,8 @@ export const runVirtualUser = async (params) => {
|
|
|
203
205
|
stoppedBy = 'budget-duration';
|
|
204
206
|
break;
|
|
205
207
|
}
|
|
206
|
-
if (budget?.mutations !== undefined &&
|
|
208
|
+
if (budget?.mutations !== undefined &&
|
|
209
|
+
tally.mutations >= budget.mutations) {
|
|
207
210
|
stoppedBy = 'budget-mutations';
|
|
208
211
|
break;
|
|
209
212
|
}
|
|
@@ -243,10 +246,7 @@ export const runVirtualUser = async (params) => {
|
|
|
243
246
|
if (tick.move === 'resume' || tick.move === 'suspend') {
|
|
244
247
|
messages.push(msg('user', `You were pulled away and have come back to this. Things may have changed since.`));
|
|
245
248
|
}
|
|
246
|
-
//
|
|
247
|
-
// `stale` almost always trusts them, a newcomer has none to trust, and an
|
|
248
|
-
// auditor checks nearly everything — which is the whole difference between
|
|
249
|
-
// those runs, expressed as one roll rather than as prose.
|
|
249
|
+
// knowledge: decisions/internals/a-virtual-user-decides-whether-to-trust-memory-once-per-turn.md
|
|
250
250
|
if (Object.keys(memory).length && !rng.chance(profile.reReadRate)) {
|
|
251
251
|
messages.push(msg('user', `Things you have noted down: ${Object.entries(memory)
|
|
252
252
|
.slice(-25)
|
|
@@ -365,10 +365,7 @@ export const runVirtualUser = async (params) => {
|
|
|
365
365
|
steps.push(record);
|
|
366
366
|
continue;
|
|
367
367
|
}
|
|
368
|
-
//
|
|
369
|
-
// read-only disposition is never offered a mutation and an approval-gated
|
|
370
|
-
// endpoint is never offered at all, so `index` is the gate and there is no
|
|
371
|
-
// second one here to drift out of step with it.
|
|
368
|
+
// knowledge: decisions/internals/the-virtual-user-catalogue-is-the-only-gate-on-what-may-be-called.md
|
|
372
369
|
const mutating = !isReadOnly(entry);
|
|
373
370
|
const args = readArgs(action.args);
|
|
374
371
|
const repeats = profile.repeatRate > 0 && rng.chance(profile.repeatRate) ? 2 : 1;
|
|
@@ -379,7 +376,10 @@ export const runVirtualUser = async (params) => {
|
|
|
379
376
|
response = await target.call(entry.name, args);
|
|
380
377
|
}
|
|
381
378
|
catch (error) {
|
|
382
|
-
record.findingKinds = [
|
|
379
|
+
record.findingKinds = [
|
|
380
|
+
...(record.findingKinds ?? []),
|
|
381
|
+
'transport-error',
|
|
382
|
+
];
|
|
383
383
|
addFinding({
|
|
384
384
|
kind: 'transport-error',
|
|
385
385
|
detail: `${entry.name} threw: ${error.message}`,
|
|
@@ -18,24 +18,10 @@ const topLevelKeys = (schema) => {
|
|
|
18
18
|
export const deriveCatalogue = (functions, schemas = {}) => {
|
|
19
19
|
const entries = [];
|
|
20
20
|
for (const [name, meta] of Object.entries(functions ?? {})) {
|
|
21
|
-
//
|
|
22
|
-
// held out of every deployed unit — so offering one would only ever waste
|
|
23
|
-
// a turn on a 404.
|
|
24
|
-
//
|
|
25
|
-
// For a platform or addon step this is not an efficiency argument but the
|
|
26
|
-
// oracle: a virtual user's findings are worth something only because it
|
|
27
|
-
// cannot manufacture the outcomes it is meant to discover. One that could
|
|
28
|
-
// invoke "Stripe's webhook arrives" would forge its own payment success,
|
|
29
|
-
// and every finding downstream of that is worthless. Same class of argument
|
|
30
|
-
// as `allowApprovalRequired` defaulting to false — and enforced here, at
|
|
31
|
-
// derivation, rather than by convention.
|
|
21
|
+
// knowledge: decisions/security/a-virtual-user-is-never-offered-a-step-that-would-forge-its-own-oracle.md
|
|
32
22
|
if (meta.scenario || meta.scenarioStep || meta.scenarioStepKind)
|
|
33
23
|
continue;
|
|
34
|
-
//
|
|
35
|
-
// what the shipped target calls over. Absent is not permissive: an unexposed
|
|
36
|
-
// function 404s, and offering one spends a step to learn nothing about the
|
|
37
|
-
// product. Measured on the e2e app, 34 of its 72 functions are in exactly
|
|
38
|
-
// that state — nearly half a catalogue that cannot be called.
|
|
24
|
+
// knowledge: decisions/internals/only-exposed-functions-enter-a-virtual-user-catalogue.md
|
|
39
25
|
if (meta.expose !== true)
|
|
40
26
|
continue;
|
|
41
27
|
const inputSchema = meta.inputSchemaName
|
|
@@ -76,10 +62,7 @@ const scenarioSteps = (meta) => {
|
|
|
76
62
|
? [{ stepFunc: step.stepFunc, phase: step.phase, actor: step.actor }]
|
|
77
63
|
: []);
|
|
78
64
|
}
|
|
79
|
-
//
|
|
80
|
-
// the scenario declares them. Following `next` instead would buy an ordering
|
|
81
|
-
// that is already true and cost a traversal that has to decide what a branch
|
|
82
|
-
// means to a reader who will never take one.
|
|
65
|
+
// knowledge: decisions/internals/virtual-user-step-order-comes-from-insertion-order.md
|
|
83
66
|
return Object.values(meta.nodes ?? {}).flatMap((node) => {
|
|
84
67
|
const { rpcName, scenarioStepPhase, actor } = (node ?? {});
|
|
85
68
|
if (!rpcName || !scenarioStepPhase)
|
|
@@ -115,11 +98,7 @@ export const deriveIntents = (workflows, functions = {}) => {
|
|
|
115
98
|
continue;
|
|
116
99
|
steps.push(composeStepProse({
|
|
117
100
|
phase: step.phase,
|
|
118
|
-
//
|
|
119
|
-
// placeholders from a run that happened; there is no run yet, and
|
|
120
|
-
// "invites {email}" tells a user to pick someone where the filled-in
|
|
121
|
-
// form would have told it whom — which is the scenario's answer, not
|
|
122
|
-
// the user's own.
|
|
101
|
+
// knowledge: decisions/internals/a-scenario-step-template-is-offered-unfilled.md
|
|
123
102
|
description: template ?? description ?? '',
|
|
124
103
|
actor: step.actor,
|
|
125
104
|
}));
|
|
@@ -78,10 +78,7 @@ export const DISPOSITIONS = {
|
|
|
78
78
|
reReadRate: 0.2,
|
|
79
79
|
invertedOracle: true,
|
|
80
80
|
},
|
|
81
|
-
//
|
|
82
|
-
// it abandons rarely, runs cool, and is told to stop and say so rather than
|
|
83
|
-
// guess — the failure mode here is a wrong action nobody asked for, not a
|
|
84
|
-
// missed bug.
|
|
81
|
+
// knowledge: decisions/internals/the-worker-disposition-is-the-one-that-is-not-testing.md
|
|
85
82
|
accountable: {
|
|
86
83
|
...REALISTIC,
|
|
87
84
|
instructions: [
|
|
@@ -53,6 +53,19 @@ export interface WorkflowExpectServiceOptions extends WorkflowStepOptions {
|
|
|
53
53
|
/** Assert the exact number of matching calls. Default: at least one. */
|
|
54
54
|
times?: number;
|
|
55
55
|
}
|
|
56
|
+
/** Options for workflow.expectScore() */
|
|
57
|
+
export interface WorkflowExpectScoreOptions extends WorkflowStepOptions {
|
|
58
|
+
/** Fail below this score. Defaults to 0.5 — a scorer that answered at all. */
|
|
59
|
+
atLeast?: number;
|
|
60
|
+
/** Fail above this score, for a scorer where high is the failure. */
|
|
61
|
+
atMost?: number;
|
|
62
|
+
/**
|
|
63
|
+
* The known-correct answer, which is what a reference-based judge grades
|
|
64
|
+
* against. Live traffic has no answer key, so a judge declared
|
|
65
|
+
* `requiresReference` is only ever reachable from a scenario.
|
|
66
|
+
*/
|
|
67
|
+
reference?: string;
|
|
68
|
+
}
|
|
56
69
|
/**
|
|
57
70
|
* Type signature for workflow.do() RPC form - used by inspector
|
|
58
71
|
*/
|
|
@@ -80,10 +93,50 @@ export type WorkflowWireSleep = (stepName: string, duration: string) => Promise<
|
|
|
80
93
|
* loops, like dynamic `do()` step names.
|
|
81
94
|
*/
|
|
82
95
|
export type WorkflowWireSuspend = (reason: string) => Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Who is allowed to answer an approval gate, relative to the user who started
|
|
98
|
+
* the run.
|
|
99
|
+
*
|
|
100
|
+
* - `any` — anyone the approve entrypoint lets through. The gate is a pause for
|
|
101
|
+
* a decision, not an authorization boundary.
|
|
102
|
+
* - `owner` — only the user who started the run, so a gate can be used to
|
|
103
|
+
* confirm an action against the same person who requested it.
|
|
104
|
+
* - `not-initiator` — anyone *except* the user who started the run: four-eyes.
|
|
105
|
+
* A run with no recorded initiator has nobody to exclude, so this degrades to
|
|
106
|
+
* requiring a signed-in decider.
|
|
107
|
+
*/
|
|
108
|
+
export type WorkflowApprovalApprovers = 'any' | 'owner' | 'not-initiator';
|
|
109
|
+
/**
|
|
110
|
+
* Who may answer an approval gate. Declared on the gate rather than the
|
|
111
|
+
* entrypoint because it is a property of the decision being made, and because
|
|
112
|
+
* one workflow can hold several gates with different requirements.
|
|
113
|
+
*/
|
|
114
|
+
export interface WorkflowApprovalPolicy {
|
|
115
|
+
/**
|
|
116
|
+
* Defaults to `any`. See {@link WorkflowApprovalApprovers}.
|
|
117
|
+
*/
|
|
118
|
+
approvers?: WorkflowApprovalApprovers;
|
|
119
|
+
/**
|
|
120
|
+
* Additionally require the decider's session to hold this scope, so
|
|
121
|
+
* "a second pair of eyes" can be narrowed to "a second pair of *senior*
|
|
122
|
+
* eyes". Combines with `approvers` — both must pass.
|
|
123
|
+
*/
|
|
124
|
+
approverScope?: string;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The decider, reduced to the two facts a policy can be expressed in terms of.
|
|
128
|
+
* Recorded alongside the decision so the gate can be judged on replay — the
|
|
129
|
+
* session itself is long gone by then — and carried into the settled outcome so
|
|
130
|
+
* the answer keeps its provenance.
|
|
131
|
+
*/
|
|
132
|
+
export interface ApprovalDecider {
|
|
133
|
+
userId?: string;
|
|
134
|
+
scopes?: string[];
|
|
135
|
+
}
|
|
83
136
|
/**
|
|
84
137
|
* Options for workflow.approval().
|
|
85
138
|
*/
|
|
86
|
-
export interface WorkflowApprovalOptions<TSchema extends StandardSchemaV1 = StandardSchemaV1> {
|
|
139
|
+
export interface WorkflowApprovalOptions<TSchema extends StandardSchemaV1 = StandardSchemaV1> extends WorkflowApprovalPolicy {
|
|
87
140
|
/**
|
|
88
141
|
* Schema the decision payload is validated against. This is a VALUE, not a
|
|
89
142
|
* type generic: the payload arrives from an untrusted caller over the approve
|
|
@@ -107,6 +160,14 @@ export interface WorkflowApprovalOptions<TSchema extends StandardSchemaV1 = Stan
|
|
|
107
160
|
export type ApprovalOutcome<T> = {
|
|
108
161
|
status: 'decided';
|
|
109
162
|
data: T;
|
|
163
|
+
/**
|
|
164
|
+
* Who answered, and when. Run state holds the decision only while the gate
|
|
165
|
+
* is open — it is overwritten by the next write and cleared outright when a
|
|
166
|
+
* decision is refused — so the settled answer carries its own provenance
|
|
167
|
+
* into the step result, which is append-only.
|
|
168
|
+
*/
|
|
169
|
+
decidedBy?: ApprovalDecider;
|
|
170
|
+
decidedAt?: string;
|
|
110
171
|
} | {
|
|
111
172
|
status: 'expired';
|
|
112
173
|
};
|
|
@@ -288,7 +349,7 @@ export interface ReturnStepMeta {
|
|
|
288
349
|
spread?: string[];
|
|
289
350
|
}
|
|
290
351
|
/**
|
|
291
|
-
* Inline step metadata
|
|
352
|
+
* Inline step metadata
|
|
292
353
|
*/
|
|
293
354
|
export interface InlineStepMeta {
|
|
294
355
|
/** Inline form - local execution */
|
|
@@ -386,6 +447,10 @@ export interface ApprovalStepMeta {
|
|
|
386
447
|
outputVar?: string;
|
|
387
448
|
/** Expiry duration, when one was given */
|
|
388
449
|
expiry?: string | number;
|
|
450
|
+
/** Who may answer the gate, when the default was not used */
|
|
451
|
+
approvers?: WorkflowApprovalApprovers;
|
|
452
|
+
/** Scope the decider must hold, when one was required */
|
|
453
|
+
approverScope?: string;
|
|
389
454
|
}
|
|
390
455
|
/**
|
|
391
456
|
* Filter step metadata (array.filter)
|
|
@@ -473,7 +538,30 @@ export interface PikkuWorkflowWire {
|
|
|
473
538
|
/** Suspend workflow until a human records a decision against this gate */
|
|
474
539
|
approval: WorkflowWireApproval;
|
|
475
540
|
}
|
|
476
|
-
|
|
541
|
+
/**
|
|
542
|
+
* What a scenario has accumulated so far, shared by its body and its hooks.
|
|
543
|
+
*
|
|
544
|
+
* `Partial` because a scenario can fail at any step: `Out` describes what a
|
|
545
|
+
* *completed* run produces, and the context holds however much of it this run
|
|
546
|
+
* reached.
|
|
547
|
+
*
|
|
548
|
+
* The `0 extends 1 & Out` branch keeps `any` collapsing to `any` rather than to
|
|
549
|
+
* the union of the other two. `PikkuWire` and `PikkuFunctionConfig` both use
|
|
550
|
+
* this type as a generic *constraint*, and a constraint carrying a concrete
|
|
551
|
+
* context would reject every wire whose scenario output differs from it.
|
|
552
|
+
*/
|
|
553
|
+
export type ScenarioContext<Out = unknown> = 0 extends 1 & Out ? any : Out extends object ? Partial<Out> : Record<string, unknown>;
|
|
554
|
+
export interface PikkuScenarioWire<Out = unknown> extends PikkuWorkflowWire {
|
|
555
|
+
/**
|
|
556
|
+
* Scratch the body writes and the `before`/`after` hooks read. A hook is a
|
|
557
|
+
* separate function and cannot see the body's locals, so this is how teardown
|
|
558
|
+
* learns the ids the body minted.
|
|
559
|
+
*
|
|
560
|
+
* Deliberately *not* a world: it is scoped to one run, and scenario steps
|
|
561
|
+
* cannot reach it. Steps stay pure functions of their declared inputs, so the
|
|
562
|
+
* ladder in the report remains a complete account of what a step saw.
|
|
563
|
+
*/
|
|
564
|
+
context: ScenarioContext<Out>;
|
|
477
565
|
/**
|
|
478
566
|
* Durable polling step: invoke `rpcName` (as an actor when `options.actor`
|
|
479
567
|
* is set) until `predicate` passes or `options.within` elapses.
|
|
@@ -483,6 +571,15 @@ export interface PikkuScenarioWire extends PikkuWorkflowWire {
|
|
|
483
571
|
expectError: <TInput = any>(stepName: string, rpcName: string, data: TInput, options?: WorkflowExpectErrorOptions) => Promise<string>;
|
|
484
572
|
/** Stub-assertion step: asserts `service.method` was called on the target server */
|
|
485
573
|
expectService: (stepName: string, serviceMethod: string, options?: WorkflowExpectServiceOptions) => Promise<void>;
|
|
574
|
+
/**
|
|
575
|
+
* Grade-assertion step: runs one declared scorer against a finished agent run
|
|
576
|
+
* and asserts the score. Returns the grade, so a scenario can report the
|
|
577
|
+
* reason a judge gave rather than only that it fell short.
|
|
578
|
+
*/
|
|
579
|
+
expectScore: (stepName: string, runId: string, scorerName: string, options?: WorkflowExpectScoreOptions) => Promise<{
|
|
580
|
+
score: number;
|
|
581
|
+
reason?: string;
|
|
582
|
+
}>;
|
|
486
583
|
/**
|
|
487
584
|
* Run a registered scenario step, as the setup the scenario starts from.
|
|
488
585
|
*
|
|
@@ -13,8 +13,10 @@ export const resolveFeatureScenarios = (features, registrations) => {
|
|
|
13
13
|
const scenarios = feature.scenarios ?? [];
|
|
14
14
|
for (let index = 0; index < scenarios.length; index++) {
|
|
15
15
|
const entry = scenarios[index];
|
|
16
|
-
const
|
|
17
|
-
|
|
16
|
+
const pairing = typeof entry === 'object' && entry !== null && 'scenario' in entry
|
|
17
|
+
? entry
|
|
18
|
+
: undefined;
|
|
19
|
+
const config = pairing ? pairing.scenario : entry;
|
|
18
20
|
const scenarioName = nameByConfig.get(config);
|
|
19
21
|
if (!scenarioName) {
|
|
20
22
|
unresolved.push({ featureId, index });
|
|
@@ -24,10 +26,11 @@ export const resolveFeatureScenarios = (features, registrations) => {
|
|
|
24
26
|
featureId,
|
|
25
27
|
featureName: feature.name ?? featureId,
|
|
26
28
|
scenarioName,
|
|
27
|
-
data:
|
|
29
|
+
data: pairing?.data,
|
|
28
30
|
tags: [
|
|
29
31
|
...new Set([
|
|
30
|
-
...(registrations.get(scenarioName)?.func
|
|
32
|
+
...(registrations.get(scenarioName)?.func
|
|
33
|
+
?.tags ?? []),
|
|
31
34
|
...(feature.tags ?? []),
|
|
32
35
|
]),
|
|
33
36
|
],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PikkuWorkflowService } from '../pikku-workflow-service.js';
|
|
2
2
|
import type { WorkflowRuntimeMeta, WorkflowRunWire } from '../workflow.types.js';
|
|
3
3
|
export declare class ChildWorkflowStartedException extends Error {
|
|
4
4
|
parentRunId: string;
|
|
@@ -9,7 +9,6 @@ export declare class ChildWorkflowStartedException extends Error {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function continueGraph(workflowService: PikkuWorkflowService, runId: string, graphName: string, overrideMeta?: WorkflowRuntimeMeta): Promise<void>;
|
|
11
11
|
export declare function executeGraphStep(workflowService: PikkuWorkflowService, rpcService: any, runId: string, stepId: string, nodeId: string, rpcName: string, data: any, graphName: string): Promise<any>;
|
|
12
|
-
export declare function onGraphNodeComplete(workflowService: PikkuWorkflowService, runId: string, graphName: string): Promise<void>;
|
|
13
12
|
export declare function runFromMeta(workflowService: PikkuWorkflowService, runId: string, meta: WorkflowRuntimeMeta, _rpcService: any): Promise<void>;
|
|
14
13
|
export declare function runWorkflowGraph(workflowService: PikkuWorkflowService, graphName: string, triggerInput: any, rpcService?: any, inline?: boolean, startNode?: string, wire?: WorkflowRunWire, overrideMeta?: WorkflowRuntimeMeta): Promise<{
|
|
15
14
|
runId: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { WorkflowAsyncException, WorkflowSuspendedException,
|
|
1
|
+
import { WorkflowAsyncException, WorkflowSuspendedException, } from '../workflow-errors.js';
|
|
2
|
+
import { DEFAULT_STEP_RETRIES } from '../workflow-constants.js';
|
|
2
3
|
import { pikkuState, getSingletonServices } from '../../../pikku-state.js';
|
|
3
4
|
import { RPCNotFoundError } from '../../rpc/rpc-runner.js';
|
|
4
5
|
export class ChildWorkflowStartedException extends Error {
|
|
@@ -491,9 +492,6 @@ export async function executeGraphStep(workflowService, rpcService, runId, stepI
|
|
|
491
492
|
throw error;
|
|
492
493
|
}
|
|
493
494
|
}
|
|
494
|
-
export async function onGraphNodeComplete(workflowService, runId, graphName) {
|
|
495
|
-
await continueGraph(workflowService, runId, graphName);
|
|
496
|
-
}
|
|
497
495
|
export async function runFromMeta(workflowService, runId, meta, _rpcService) {
|
|
498
496
|
await continueGraph(workflowService, runId, meta.name, meta);
|
|
499
497
|
}
|
|
@@ -610,9 +608,12 @@ export async function runWorkflowGraph(workflowService, graphName, triggerInput,
|
|
|
610
608
|
throw new Error(`Workflow graph '${graphName}' not found`);
|
|
611
609
|
}
|
|
612
610
|
const nodes = meta.nodes;
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
611
|
+
const declaredEntryNodes = meta.entryNodeIds ?? [];
|
|
612
|
+
// knowledge: decisions/security/a-graph-run-starts-at-an-entry-node-the-graph-declared.md
|
|
613
|
+
if (startNode && !declaredEntryNodes.includes(startNode)) {
|
|
614
|
+
throw new Error(`Workflow graph '${graphName}': '${startNode}' is not an entry node`);
|
|
615
|
+
}
|
|
616
|
+
const entryNodes = startNode ? [startNode] : declaredEntryNodes;
|
|
616
617
|
validateGraphReferences(graphName, nodes, entryNodes);
|
|
617
618
|
if (entryNodes.length === 0) {
|
|
618
619
|
throw new Error(`Workflow graph '${graphName}': no entry nodes found in meta or startNode`);
|
|
@@ -5,10 +5,6 @@ export interface RefValue {
|
|
|
5
5
|
}
|
|
6
6
|
export declare const createRef: (nodeId: string, path?: string) => RefValue;
|
|
7
7
|
export declare const isRef: (value: unknown) => value is RefValue;
|
|
8
|
-
export interface InputRef {
|
|
9
|
-
nodeId: string;
|
|
10
|
-
path?: string;
|
|
11
|
-
}
|
|
12
8
|
export type RefFn<NodeIds extends string = string> = (nodeId: NodeIds, path?: string) => RefValue;
|
|
13
9
|
export type NextConfig<NodeIds extends string = string> = NodeIds | NodeIds[] | Record<string, NodeIds | NodeIds[]>;
|
|
14
10
|
export interface GraphNodeConfig<NodeIds extends string = string> {
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
export { PikkuWorkflowService
|
|
2
|
-
export
|
|
1
|
+
export { PikkuWorkflowService } from './pikku-workflow-service.js';
|
|
2
|
+
export { WorkflowCancelledException, WorkflowSuspendedException, WorkflowDispatchException, WorkflowNotFoundError, WorkflowRunNotFoundError, WorkflowApprovalResolvedError, WorkflowStepFunctionMismatchError, } from './workflow-errors.js';
|
|
3
|
+
export { DEFAULT_STEP_RETRIES } from './workflow-constants.js';
|
|
4
|
+
export { assertWorkflowRunOwner, WorkflowRunForbiddenError, } from './workflow-run-ownership.js';
|
|
5
|
+
export { WorkflowApprovalForbiddenError } from './workflow-approval-policy.js';
|
|
6
|
+
export type { WorkflowRunEngine, WorkflowRunExtension, } from './workflow-run-engine.types.js';
|
|
3
7
|
export { deriveInvocationId, uuidv5 } from './workflow-invocation-id.js';
|
|
8
|
+
export { isRef } from './graph/workflow-graph.types.js';
|
|
9
|
+
export type { RefValue } from './graph/workflow-graph.types.js';
|
|
4
10
|
export { buildRunTimeline, reconstructStateAt, reconstructFinalState, } from './run-timeline.js';
|
|
5
|
-
export type { RunTimeline,
|
|
11
|
+
export type { RunTimeline, ReconstructedRunState, } from './run-timeline.js';
|
|
6
12
|
export { addWorkflow } from './dsl/workflow-runner.js';
|
|
7
13
|
export { addFeature, resolveFeatureScenarios } from './feature.js';
|
|
8
14
|
export { template, type TemplateString } from './graph/template.js';
|
|
9
15
|
export { pikkuWorkflowGraph, type PikkuWorkflowGraphConfig, type PikkuWorkflowGraphResult, } from './graph/wire-workflow-graph.js';
|
|
10
|
-
export { pikkuWorkflowWorkerFunc, pikkuWorkflowOrchestratorFunc, pikkuWorkflowSleeperFunc, } from './workflow-queue-workers.js';
|
|
11
16
|
export type { WorkflowStepInput as WorkflowStepQueueInput, PikkuWorkflowOrchestratorInput, PikkuWorkflowSleeperInput, } from './workflow-queue-workers.js';
|
|
12
|
-
export type { WorkflowService, WorkflowQueueOptions, WorkflowServiceConfig, WorkflowPlannedStep, WorkflowRunWire, WorkflowStatus, WorkflowVersionStatus, StepStatus, WorkflowRun, WorkflowRunStatus, StepState, WorkflowRunService, WorkflowRunMirror, CoreWorkflow, CoreFeature,
|
|
13
|
-
export type { WorkflowStepOptions, WorkflowWireDoRPC,
|
|
17
|
+
export type { WorkflowService, WorkflowQueueOptions, WorkflowServiceConfig, WorkflowPlannedStep, WorkflowRunWire, WorkflowStatus, WorkflowVersionStatus, StepStatus, WorkflowRun, WorkflowRunStatus, StepState, WorkflowRunService, WorkflowRunMirror, CoreWorkflow, CoreFeature, FeatureMeta, FeaturesMeta, FeaturePlanEntry, PikkuWorkflow, ContextVariable, WorkflowContext, WorkflowsMeta, WorkflowsRuntimeMeta, } from './workflow.types.js';
|
|
18
|
+
export type { WorkflowStepOptions, WorkflowWireDoRPC, WorkflowApprovalOptions, ApprovalOutcome, InputSource, OutputBinding, RpcStepMeta, Condition, BranchStepMeta, ParallelGroupStepMeta, FanoutStepMeta, ReturnStepMeta, InlineStepMeta, SleepStepMeta, CancelStepMeta, SuspendStepMeta, ApprovalStepMeta, SetStepMeta, SwitchCaseMeta, SwitchStepMeta, FilterStepMeta, ArrayPredicateStepMeta, ScenarioStepInvocation, ScenarioStepMeta, WorkflowStepMeta, WorkflowStepWire, PikkuWorkflowWire, PikkuScenarioWire, } from './workflow.types.js';
|
|
14
19
|
export type { ScenarioStepPhase, ScenarioStepKind, ScenarioStepOptions, PikkuScenarioStepWire, ScenarioEnvironment, ScenarioSurface, ScenarioSurfaceResolution, } from './scenario-step.types.js';
|
|
15
20
|
export { SCENARIO_SURFACES } from './scenario-step.types.js';
|
|
16
|
-
export { resolveScenarioSurfaces
|
|
21
|
+
export { resolveScenarioSurfaces } from './scenario-surface.js';
|
|
17
22
|
export { requireActor, requireScenarioEnv } from './scenario-step-guards.js';
|
|
18
23
|
export { pollUntil, type PollOptions } from './scenario-poll.js';
|
|
19
24
|
export { createCookieJar } from './scenario-cookie-jar.js';
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
export { PikkuWorkflowService
|
|
1
|
+
export { PikkuWorkflowService } from './pikku-workflow-service.js';
|
|
2
|
+
export { WorkflowCancelledException, WorkflowSuspendedException, WorkflowDispatchException, WorkflowNotFoundError, WorkflowRunNotFoundError, WorkflowApprovalResolvedError, WorkflowStepFunctionMismatchError, } from './workflow-errors.js';
|
|
3
|
+
export { DEFAULT_STEP_RETRIES } from './workflow-constants.js';
|
|
4
|
+
export { assertWorkflowRunOwner, WorkflowRunForbiddenError, } from './workflow-run-ownership.js';
|
|
5
|
+
export { WorkflowApprovalForbiddenError } from './workflow-approval-policy.js';
|
|
2
6
|
export { deriveInvocationId, uuidv5 } from './workflow-invocation-id.js';
|
|
7
|
+
export { isRef } from './graph/workflow-graph.types.js';
|
|
3
8
|
export { buildRunTimeline, reconstructStateAt, reconstructFinalState, } from './run-timeline.js';
|
|
4
9
|
export { addWorkflow } from './dsl/workflow-runner.js';
|
|
5
10
|
export { addFeature, resolveFeatureScenarios } from './feature.js';
|
|
6
11
|
export { template } from './graph/template.js';
|
|
7
12
|
export { pikkuWorkflowGraph, } from './graph/wire-workflow-graph.js';
|
|
8
|
-
export { pikkuWorkflowWorkerFunc, pikkuWorkflowOrchestratorFunc, pikkuWorkflowSleeperFunc, } from './workflow-queue-workers.js';
|
|
9
13
|
export { SCENARIO_SURFACES } from './scenario-step.types.js';
|
|
10
14
|
// Which of a step's bindings run: one for an action, every witness for a `then`
|
|
11
|
-
export { resolveScenarioSurfaces
|
|
15
|
+
export { resolveScenarioSurfaces } from './scenario-surface.js';
|
|
12
16
|
export { requireActor, requireScenarioEnv } from './scenario-step-guards.js';
|
|
13
17
|
export { pollUntil } from './scenario-poll.js';
|
|
14
18
|
export { createCookieJar } from './scenario-cookie-jar.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PikkuError } from '../../errors/error-handler.js';
|
|
2
2
|
import { InMemoryWorkflowService } from '../../services/in-memory-workflow-service.js';
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
3
|
+
import type { RunLifecycleContext, WorkflowRunEngine, WorkflowRunExtension } from './workflow-run-engine.types.js';
|
|
4
|
+
import type { PikkuRawWire } from '../../types/core.types.js';
|
|
5
5
|
import type { ScenarioPersonas } from '../../services/personas-service.js';
|
|
6
6
|
import type { ScenarioBrowserProvider, ScenarioEnvironment, ScenarioSurface } from './scenario-step.types.js';
|
|
7
7
|
import type { PikkuWorkflowWire, WorkflowQueueOptions } from './workflow.types.js';
|
|
@@ -126,6 +126,7 @@ export declare class ScenarioNoWitness extends PikkuError {
|
|
|
126
126
|
export declare class PikkuScenarioService implements WorkflowRunExtension {
|
|
127
127
|
private readonly engine;
|
|
128
128
|
private runActors;
|
|
129
|
+
private runContexts;
|
|
129
130
|
private scenarioBrowserProvider?;
|
|
130
131
|
private scenarioEnvironment?;
|
|
131
132
|
private runSurface;
|
|
@@ -154,7 +155,20 @@ export declare class PikkuScenarioService implements WorkflowRunExtension {
|
|
|
154
155
|
actors?: ScenarioPersonas;
|
|
155
156
|
}): Promise<void>;
|
|
156
157
|
detachRunContext(runId: string): void;
|
|
157
|
-
|
|
158
|
+
/**
|
|
159
|
+
* What the run has accumulated.
|
|
160
|
+
*
|
|
161
|
+
* Undefined only for a run whose wire was never decorated — decoration calls
|
|
162
|
+
* `contextForRun` unconditionally, so a plain workflow that has reached a
|
|
163
|
+
* step holds an empty context rather than none.
|
|
164
|
+
*/
|
|
165
|
+
getRunContext(runId: string): Record<string, unknown> | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* The run's context, created on demand because the wire is also built on
|
|
168
|
+
* paths that skip `attachRunContext`.
|
|
169
|
+
*/
|
|
170
|
+
private contextForRun;
|
|
171
|
+
decorateRunWire(wire: PikkuRawWire, context: {
|
|
158
172
|
runId: string;
|
|
159
173
|
workflowMeta: any;
|
|
160
174
|
workflowWire: PikkuWorkflowWire;
|
|
@@ -5,7 +5,7 @@ import { closeWireServices } from '../../utils.js';
|
|
|
5
5
|
import { PikkuError, addError } from '../../errors/error-handler.js';
|
|
6
6
|
import { InMemoryWorkflowService } from '../../services/in-memory-workflow-service.js';
|
|
7
7
|
import { runScheduledTask } from '../scheduler/scheduler-runner.js';
|
|
8
|
-
import { WorkflowStepNameNotString
|
|
8
|
+
import { WorkflowStepNameNotString } from './workflow-errors.js';
|
|
9
9
|
import { resolveScenarioSurfaces, witnessesAgree } from './scenario-surface.js';
|
|
10
10
|
/**
|
|
11
11
|
* A workflow service with the scenario capability attached — the two lines
|
|
@@ -176,6 +176,10 @@ export class PikkuScenarioService {
|
|
|
176
176
|
// Scenario actors per run: live authenticated clients (cookie jars) are
|
|
177
177
|
// process-local by nature, so they ride this map, never the persisted wire.
|
|
178
178
|
runActors = new Map();
|
|
179
|
+
// What each run has accumulated so far — process-local like the actors above,
|
|
180
|
+
// so the body and its hooks share one object rather than reading it back off
|
|
181
|
+
// the persisted wire.
|
|
182
|
+
runContexts = new Map();
|
|
179
183
|
scenarioBrowserProvider;
|
|
180
184
|
scenarioEnvironment;
|
|
181
185
|
runSurface = 'default';
|
|
@@ -222,9 +226,35 @@ export class PikkuScenarioService {
|
|
|
222
226
|
if (actors) {
|
|
223
227
|
this.runActors.set(runId, actors);
|
|
224
228
|
}
|
|
229
|
+
if (workflowMeta.source === 'scenario') {
|
|
230
|
+
this.runContexts.set(runId, {});
|
|
231
|
+
}
|
|
225
232
|
}
|
|
226
233
|
detachRunContext(runId) {
|
|
227
234
|
this.runActors.delete(runId);
|
|
235
|
+
this.runContexts.delete(runId);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* What the run has accumulated.
|
|
239
|
+
*
|
|
240
|
+
* Undefined only for a run whose wire was never decorated — decoration calls
|
|
241
|
+
* `contextForRun` unconditionally, so a plain workflow that has reached a
|
|
242
|
+
* step holds an empty context rather than none.
|
|
243
|
+
*/
|
|
244
|
+
getRunContext(runId) {
|
|
245
|
+
return this.runContexts.get(runId);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The run's context, created on demand because the wire is also built on
|
|
249
|
+
* paths that skip `attachRunContext`.
|
|
250
|
+
*/
|
|
251
|
+
contextForRun(runId) {
|
|
252
|
+
let runContext = this.runContexts.get(runId);
|
|
253
|
+
if (!runContext) {
|
|
254
|
+
runContext = {};
|
|
255
|
+
this.runContexts.set(runId, runContext);
|
|
256
|
+
}
|
|
257
|
+
return runContext;
|
|
228
258
|
}
|
|
229
259
|
decorateRunWire(wire, context) {
|
|
230
260
|
wire.scenario =
|
|
@@ -367,6 +397,7 @@ export class PikkuScenarioService {
|
|
|
367
397
|
rpcService,
|
|
368
398
|
});
|
|
369
399
|
Object.assign(workflowWire, {
|
|
400
|
+
context: this.contextForRun(runId),
|
|
370
401
|
// Durable polling step: invoke an RPC (as an actor when options.as is
|
|
371
402
|
// set) until the predicate passes or `within` elapses. The whole poll is
|
|
372
403
|
// ONE recorded step, so replay returns the cached outcome.
|
|
@@ -451,12 +482,36 @@ export class PikkuScenarioService {
|
|
|
451
482
|
}
|
|
452
483
|
}, options);
|
|
453
484
|
},
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
485
|
+
expectScore: async (stepName, agentRunId, scorerName, options) => {
|
|
486
|
+
this.engine.verifyStepName(stepName);
|
|
487
|
+
return await this.engine.inlineStep(runId, stepName, async () => {
|
|
488
|
+
const rpcName = 'pikkuScenarioGradeRun';
|
|
489
|
+
const data = {
|
|
490
|
+
runId: agentRunId,
|
|
491
|
+
scorer: scorerName,
|
|
492
|
+
...(options?.reference !== undefined
|
|
493
|
+
? { reference: options.reference }
|
|
494
|
+
: {}),
|
|
495
|
+
};
|
|
496
|
+
const grade = options?.actor
|
|
497
|
+
? await options.actor.invoke(rpcName, data)
|
|
498
|
+
: await rpcService.rpcWithWire(rpcName, data, {});
|
|
499
|
+
// A scorer that graded is a scorer that answered, so an unstated
|
|
500
|
+
// bound still fails a zero rather than passing anything at all.
|
|
501
|
+
const atLeast = options?.atLeast ?? 0.5;
|
|
502
|
+
const failed = grade.score < atLeast ||
|
|
503
|
+
(options?.atMost !== undefined && grade.score > options.atMost);
|
|
504
|
+
if (failed) {
|
|
505
|
+
const bound = options?.atMost !== undefined
|
|
506
|
+
? `between ${atLeast} and ${options.atMost}`
|
|
507
|
+
: `at least ${atLeast}`;
|
|
508
|
+
throw new Error(`[workflow] expectScore '${stepName}' expected '${scorerName}' to grade run ${agentRunId} ${bound}, got ${grade.score}` +
|
|
509
|
+
`${grade.reason ? `: ${grade.reason}` : ''}`);
|
|
510
|
+
}
|
|
511
|
+
return grade;
|
|
512
|
+
}, options);
|
|
513
|
+
},
|
|
514
|
+
// knowledge: decisions/internals/scenario-given-and-when-are-sugar-but-then-is-not.md
|
|
460
515
|
given: (stepName, stepFunc, data, options) => this.scenarioStep('given', scenarioStepContext(), stepName, stepFunc, data, options),
|
|
461
516
|
when: (stepName, stepFunc, data, options) => this.scenarioStep('when', scenarioStepContext(), stepName, stepFunc, data, options),
|
|
462
517
|
then: (stepName, stepFunc, data, options) => this.scenarioStep('then', scenarioStepContext(), stepName, stepFunc, data, options),
|
|
@@ -466,7 +521,7 @@ export class PikkuScenarioService {
|
|
|
466
521
|
});
|
|
467
522
|
}
|
|
468
523
|
async scenarioStep(phase, context, stepName, stepFunc, data, options) {
|
|
469
|
-
const { runId, workflowName, addonNamespace, workflowWire
|
|
524
|
+
const { runId, workflowName, addonNamespace, workflowWire } = context;
|
|
470
525
|
// Also the guard for `then` being a wire member: an accidental
|
|
471
526
|
// `await scenario` calls it with a resolve function, which lands here as a
|
|
472
527
|
// loud, named error instead of a silent hang.
|
|
@@ -486,11 +541,10 @@ export class PikkuScenarioService {
|
|
|
486
541
|
const resolution = resolveScenarioSurfaces(phase, declared, this.runSurface);
|
|
487
542
|
return await this.engine.inlineStep(runId, stepName, async () => {
|
|
488
543
|
const runOnSurface = async (surface) => {
|
|
544
|
+
// No `rpc` yet — runPikkuFunc attaches it lazily for the invocation.
|
|
489
545
|
const wire = {
|
|
490
546
|
workflow: workflowWire,
|
|
491
547
|
scenario: workflowWire,
|
|
492
|
-
rpc: rpcService?.wire?.rpc,
|
|
493
|
-
session: rpcService?.wire?.session,
|
|
494
548
|
pikkuUserId: workflowWire.pikkuUserId,
|
|
495
549
|
actors: this.runActors.get(runId),
|
|
496
550
|
scenarioStep: {
|