@pikku/core 0.12.71 → 0.12.74
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 +848 -0
- package/dist/crypto-utils.d.ts +30 -5
- package/dist/crypto-utils.js +146 -41
- package/dist/dev/hot-reload.js +11 -30
- package/dist/dev/module-runner.d.ts +3 -7
- package/dist/dev/module-runner.js +4 -10
- package/dist/dev/reload-meta.d.ts +8 -20
- package/dist/dev/reload-meta.js +9 -29
- package/dist/errors/error-handler.d.ts +5 -30
- package/dist/errors/error-handler.js +16 -32
- package/dist/errors/errors.d.ts +32 -151
- package/dist/errors/errors.js +55 -157
- package/dist/function/abort-scope.d.ts +47 -0
- package/dist/function/abort-scope.js +63 -0
- package/dist/function/function-runner.js +40 -30
- package/dist/function/functions.types.d.ts +44 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/list.types.d.ts +12 -62
- package/dist/function/list.types.js +4 -25
- package/dist/handle-error.d.ts +0 -11
- package/dist/handle-error.js +6 -18
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/middleware/auth-apikey.d.ts +3 -18
- package/dist/middleware/auth-apikey.js +0 -17
- package/dist/middleware/auth-bearer.d.ts +6 -41
- package/dist/middleware/auth-bearer.js +3 -40
- package/dist/middleware/auth-cookie.d.ts +5 -27
- package/dist/middleware/auth-cookie.js +2 -26
- package/dist/middleware/cors.d.ts +7 -34
- package/dist/middleware/cors.js +7 -34
- package/dist/middleware/remote-auth.d.ts +3 -1
- package/dist/middleware/remote-auth.js +3 -2
- package/dist/middleware/telemetry.d.ts +8 -33
- package/dist/middleware/telemetry.js +2 -31
- package/dist/middleware-runner.d.ts +4 -55
- package/dist/middleware-runner.js +5 -74
- package/dist/permissions.d.ts +3 -44
- package/dist/permissions.js +19 -71
- package/dist/pikku-request.d.ts +0 -6
- package/dist/pikku-request.js +0 -6
- package/dist/pikku-state.d.ts +0 -26
- package/dist/pikku-state.js +2 -30
- package/dist/remote.d.ts +3 -5
- package/dist/remote.js +8 -7
- package/dist/schema.d.ts +7 -17
- package/dist/schema.js +30 -18
- package/dist/scopes.d.ts +4 -23
- package/dist/scopes.js +7 -48
- package/dist/services/ai-agent-runner-service.d.ts +20 -0
- package/dist/services/ai-embedding-service.d.ts +2 -25
- package/dist/services/audit-service.js +1 -2
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/gateway-service.d.ts +0 -15
- package/dist/services/http-personas.d.ts +80 -0
- package/dist/services/http-personas.js +233 -0
- package/dist/services/in-memory-queue-service.d.ts +0 -14
- package/dist/services/in-memory-queue-service.js +1 -15
- package/dist/services/in-memory-trigger-service.d.ts +0 -18
- package/dist/services/in-memory-trigger-service.js +1 -18
- package/dist/services/in-memory-workflow-service.d.ts +0 -16
- package/dist/services/in-memory-workflow-service.js +4 -33
- package/dist/services/index.d.ts +5 -6
- package/dist/services/index.js +2 -5
- package/dist/services/istanbul-coverage-service.d.ts +1 -5
- package/dist/services/istanbul-coverage-service.js +2 -8
- package/dist/services/jwt-service.d.ts +1 -16
- package/dist/services/local-content.d.ts +13 -2
- package/dist/services/local-content.js +40 -13
- package/dist/services/local-gateway-service.d.ts +0 -16
- package/dist/services/local-gateway-service.js +2 -17
- package/dist/services/local-secrets.d.ts +0 -4
- package/dist/services/local-secrets.js +0 -4
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +2 -37
- package/dist/services/meta-service.d.ts +23 -26
- package/dist/services/meta-service.js +22 -36
- package/dist/services/personas-service.d.ts +134 -0
- package/dist/services/personas-service.js +40 -0
- package/dist/services/pikku-user-id.js +0 -4
- package/dist/services/queue-webhook-service.d.ts +2 -36
- package/dist/services/queue-webhook-service.js +9 -41
- package/dist/services/scheduler-service.d.ts +1 -50
- package/dist/services/scheduler-service.js +0 -10
- package/dist/services/schema-service.d.ts +1 -24
- package/dist/services/scope-service.d.ts +49 -34
- package/dist/services/scoped-secret-service.d.ts +0 -4
- package/dist/services/scoped-secret-service.js +0 -4
- package/dist/services/secret-host-binding.d.ts +8 -0
- package/dist/services/secret-host-binding.js +36 -0
- package/dist/services/secret-service.d.ts +5 -33
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +21 -0
- package/dist/services/stub-tracker.d.ts +7 -18
- package/dist/services/stub-tracker.js +8 -18
- package/dist/services/system-role-guard.d.ts +33 -0
- package/dist/services/system-role-guard.js +38 -0
- package/dist/services/trigger-service.d.ts +0 -12
- package/dist/services/typed-secret-service.d.ts +0 -7
- package/dist/services/typed-secret-service.js +1 -7
- package/dist/services/v8-coverage-service.d.ts +2 -3
- package/dist/services/v8-coverage-service.js +1 -2
- package/dist/services/variables-service.d.ts +1 -8
- package/dist/services/webhook-service.d.ts +19 -63
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +0 -17
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +99 -219
- package/dist/types/core.types.js +0 -42
- package/dist/types/state.types.d.ts +4 -9
- package/dist/utils/hmac.d.ts +4 -10
- package/dist/utils/hmac.js +4 -10
- package/dist/utils/safe-fetch.d.ts +7 -35
- package/dist/utils/safe-fetch.js +13 -53
- package/dist/utils.d.ts +1 -6
- package/dist/utils.js +6 -15
- package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
- package/dist/wirings/actor-flow/index.d.ts +0 -9
- package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
- package/dist/wirings/actor-flow/run-conversation.js +14 -7
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
- package/dist/wirings/ai-agent/ai-agent-agui.js +34 -12
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
- package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
- package/dist/wirings/ai-agent/ai-agent-prepare.js +58 -131
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +49 -20
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +153 -63
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +84 -4
- package/dist/wirings/ai-agent/index.d.ts +6 -4
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.d.ts +39 -1
- package/dist/wirings/ai-agent/voice-input.js +46 -3
- package/dist/wirings/ai-agent/voice-output.d.ts +54 -1
- package/dist/wirings/ai-agent/voice-output.js +153 -50
- package/dist/wirings/channel/channel-common.d.ts +7 -20
- package/dist/wirings/channel/channel-common.js +7 -21
- package/dist/wirings/channel/channel-handler.js +25 -6
- package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
- package/dist/wirings/channel/channel-host-rpc.js +38 -0
- package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
- package/dist/wirings/channel/channel-middleware-runner.js +0 -12
- package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
- package/dist/wirings/channel/channel-rpc-registry.js +89 -0
- package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
- package/dist/wirings/channel/channel-rpc-responder.js +71 -0
- package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
- package/dist/wirings/channel/channel-rpc-service.js +106 -0
- package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
- package/dist/wirings/channel/channel-rpc-validators.js +30 -0
- package/dist/wirings/channel/channel-rpc.d.ts +5 -0
- package/dist/wirings/channel/channel-rpc.js +5 -0
- package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
- package/dist/wirings/channel/channel-rpc.types.js +50 -0
- package/dist/wirings/channel/channel-runner.d.ts +0 -4
- package/dist/wirings/channel/channel-runner.js +0 -14
- package/dist/wirings/channel/channel-store.d.ts +0 -10
- package/dist/wirings/channel/channel.types.d.ts +12 -1
- package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
- package/dist/wirings/channel/define-channel-routes.js +0 -20
- package/dist/wirings/channel/eventhub-service.d.ts +0 -18
- package/dist/wirings/channel/index.d.ts +4 -1
- package/dist/wirings/channel/index.js +2 -0
- package/dist/wirings/channel/local/local-channel-runner.js +3 -1
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
- package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
- package/dist/wirings/channel/log-channels.d.ts +0 -4
- package/dist/wirings/channel/log-channels.js +0 -4
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
- package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
- package/dist/wirings/cli/channel/cli-approval.js +81 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
- package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +20 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +121 -0
- package/dist/wirings/cli/channel/index.d.ts +4 -0
- package/dist/wirings/cli/channel/index.js +2 -0
- package/dist/wirings/cli/cli-runner.d.ts +20 -20
- package/dist/wirings/cli/cli-runner.js +28 -89
- package/dist/wirings/cli/cli.types.d.ts +14 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -10
- package/dist/wirings/cli/command-parser.js +10 -87
- package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
- package/dist/wirings/cli/define-cli-commands.js +1 -17
- package/dist/wirings/credential/credential.types.d.ts +0 -12
- package/dist/wirings/credential/define-credential.d.ts +48 -0
- package/dist/wirings/credential/define-credential.js +47 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/credential/index.js +1 -1
- package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
- package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
- package/dist/wirings/gateway/gateway-runner.js +8 -105
- package/dist/wirings/gateway/gateway.types.d.ts +7 -80
- package/dist/wirings/http/http-routes.d.ts +0 -63
- package/dist/wirings/http/http-routes.js +0 -63
- package/dist/wirings/http/http-runner.d.ts +1 -100
- package/dist/wirings/http/http-runner.js +12 -166
- package/dist/wirings/http/http.types.d.ts +16 -55
- package/dist/wirings/http/index.d.ts +2 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/http/log-http-routes.d.ts +0 -4
- package/dist/wirings/http/log-http-routes.js +0 -4
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +6 -36
- package/dist/wirings/http/pikku-fetch-http-request.js +56 -50
- package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
- package/dist/wirings/http/routers/path-to-regex.js +2 -13
- package/dist/wirings/http/web-request.d.ts +0 -8
- package/dist/wirings/http/web-request.js +25 -17
- package/dist/wirings/mcp/mcp-runner.d.ts +2 -0
- package/dist/wirings/mcp/mcp-runner.js +6 -16
- package/dist/wirings/mcp/mcp.types.d.ts +2 -35
- package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
- package/dist/wirings/oauth2/oauth2.types.js +0 -3
- package/dist/wirings/persona/define-personas.d.ts +28 -0
- package/dist/wirings/persona/define-personas.js +27 -0
- package/dist/wirings/persona/index.d.ts +21 -0
- package/dist/wirings/persona/index.js +17 -0
- package/dist/wirings/persona/persona-email.d.ts +37 -0
- package/dist/wirings/persona/persona-email.js +69 -0
- package/dist/wirings/persona/persona-environments.d.ts +45 -0
- package/dist/wirings/persona/persona-environments.js +81 -0
- package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
- package/dist/wirings/persona/persona-mailbox.js +53 -0
- package/dist/wirings/persona/persona.types.d.ts +125 -0
- package/dist/wirings/persona/persona.types.js +1 -0
- package/dist/wirings/persona/validate-personas.d.ts +53 -0
- package/dist/wirings/persona/validate-personas.js +94 -0
- package/dist/wirings/queue/index.d.ts +3 -0
- package/dist/wirings/queue/index.js +2 -3
- package/dist/wirings/queue/queue-identity.d.ts +28 -0
- package/dist/wirings/queue/queue-identity.js +102 -0
- package/dist/wirings/queue/queue-runner.d.ts +0 -19
- package/dist/wirings/queue/queue-runner.js +9 -30
- package/dist/wirings/queue/queue.types.d.ts +18 -89
- package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
- package/dist/wirings/queue/register-queue-helper.js +0 -11
- package/dist/wirings/queue/signed-queue-service.d.ts +16 -0
- package/dist/wirings/queue/signed-queue-service.js +42 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
- package/dist/wirings/queue/validate-worker-config.js +0 -14
- package/dist/wirings/role/define-system-role.d.ts +32 -0
- package/dist/wirings/role/define-system-role.js +31 -0
- package/dist/wirings/role/index.d.ts +3 -0
- package/dist/wirings/role/index.js +2 -0
- package/dist/wirings/role/role.types.d.ts +43 -0
- package/dist/wirings/role/role.types.js +1 -0
- package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
- package/dist/wirings/role/validate-role-definitions.js +71 -0
- package/dist/wirings/rpc/addon-runner.d.ts +0 -19
- package/dist/wirings/rpc/addon-runner.js +0 -51
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -12
- package/dist/wirings/rpc/remote-addon-auth.js +1 -9
- package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
- package/dist/wirings/rpc/rpc-runner.js +88 -105
- package/dist/wirings/rpc/rpc-types.d.ts +7 -6
- package/dist/wirings/rpc/wire-addon.d.ts +25 -0
- package/dist/wirings/rpc/wire-addon.js +62 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
- package/dist/wirings/rpc/wire-remote-addon.js +0 -8
- package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
- package/dist/wirings/scheduler/log-schedulers.js +0 -4
- package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
- package/dist/wirings/scheduler/scheduler-runner.js +0 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
- package/dist/wirings/scope/define-scope.d.ts +32 -0
- package/dist/wirings/scope/define-scope.js +31 -0
- package/dist/wirings/scope/index.d.ts +1 -1
- package/dist/wirings/scope/index.js +1 -1
- package/dist/wirings/scope/scope.types.d.ts +7 -9
- package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
- package/dist/wirings/scope/validate-scope-definitions.js +3 -21
- package/dist/wirings/secret/index.d.ts +1 -1
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +19 -15
- package/dist/wirings/secret/secret.types.js +1 -1
- package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
- package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
- package/dist/wirings/trigger/trigger-runner.js +1 -24
- package/dist/wirings/trigger/trigger.types.d.ts +1 -82
- package/dist/wirings/trigger/trigger.types.js +0 -34
- package/dist/wirings/variable/index.d.ts +1 -1
- package/dist/wirings/variable/index.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
- package/dist/wirings/variable/variable.types.d.ts +1 -13
- package/dist/wirings/variable/variable.types.js +1 -1
- package/dist/wirings/virtual-user/index.d.ts +27 -0
- package/dist/wirings/virtual-user/index.js +8 -0
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
- package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
- package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
- package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
- package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
- package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
- package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
- package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
- package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
- package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
- package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +5 -5
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
- package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
- package/dist/wirings/workflow/feature.d.ts +0 -19
- package/dist/wirings/workflow/feature.js +0 -19
- package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
- package/dist/wirings/workflow/graph/graph-node.js +0 -34
- package/dist/wirings/workflow/graph/graph-runner.js +6 -41
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
- package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
- package/dist/wirings/workflow/index.d.ts +5 -7
- package/dist/wirings/workflow/index.js +3 -17
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
- package/dist/wirings/workflow/pikku-scenario-service.js +204 -42
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
- package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
- package/dist/wirings/workflow/run-timeline.d.ts +0 -47
- package/dist/wirings/workflow/run-timeline.js +0 -22
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
- package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
- package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
- package/dist/wirings/workflow/scenario-poll.js +0 -12
- package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
- package/dist/wirings/workflow/scenario-prose.js +0 -18
- package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
- package/dist/wirings/workflow/scenario-step-guards.js +1 -14
- package/dist/wirings/workflow/scenario-step.types.d.ts +72 -6
- package/dist/wirings/workflow/scenario-step.types.js +5 -1
- package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
- package/dist/wirings/workflow/scenario-surface.js +56 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
- package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
- package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
- package/dist/wirings/workflow/workflow.types.d.ts +0 -197
- package/knowledge/decisions/index.md +19 -0
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
- package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
- package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
- package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
- package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
- package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
- package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
- package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
- package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
- package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
- package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
- package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
- package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
- package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
- package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
- package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
- package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +34 -0
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
- package/knowledge/decisions/internals/index.md +113 -0
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
- package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
- package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
- package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
- package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
- package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
- package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
- package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
- package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
- package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
- package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
- package/knowledge/decisions/security/index.md +55 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
- package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
- package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
- package/knowledge/index.md +24 -0
- package/knowledge/questions/index.md +15 -0
- package/package.json +4 -2
- package/run-tests.sh +0 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +283 -55
- package/src/data-classification.ts +1 -7
- package/src/dev/hot-reload.test.ts +0 -4
- package/src/dev/hot-reload.ts +11 -30
- package/src/dev/module-runner.ts +7 -32
- package/src/dev/reload-meta.ts +9 -29
- package/src/errors/error-handler.ts +20 -35
- package/src/errors/error.test.ts +30 -1
- package/src/errors/errors.ts +73 -157
- package/src/function/abort-scope.test.ts +97 -0
- package/src/function/abort-scope.ts +80 -0
- package/src/function/function-runner.test.ts +75 -7
- package/src/function/function-runner.ts +73 -30
- package/src/function/functions.types.ts +56 -136
- package/src/function/list.types.test.ts +3 -25
- package/src/function/list.types.ts +12 -62
- package/src/gopass-secrets-removed.test.ts +51 -0
- package/src/handle-error.test.ts +108 -1
- package/src/handle-error.ts +8 -18
- package/src/index.ts +60 -1
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +0 -3
- package/src/middleware/auth-bearer.ts +3 -40
- package/src/middleware/auth-cookie.test.ts +0 -6
- package/src/middleware/auth-cookie.ts +2 -26
- package/src/middleware/cors.test.ts +34 -0
- package/src/middleware/cors.ts +12 -33
- package/src/middleware/remote-auth.test.ts +24 -9
- package/src/middleware/remote-auth.ts +10 -2
- package/src/middleware/telemetry.ts +2 -31
- package/src/middleware-runner.test.ts +0 -2
- package/src/middleware-runner.ts +5 -74
- package/src/permissions.test.ts +30 -0
- package/src/permissions.ts +24 -74
- package/src/pikku-request.ts +0 -6
- package/src/pikku-state.ts +2 -30
- package/src/production-barrels-stay-lean.test.ts +110 -0
- package/src/remote.test.ts +172 -0
- package/src/remote.ts +17 -7
- package/src/schema.test.ts +103 -0
- package/src/schema.ts +35 -18
- package/src/scopes.ts +7 -48
- package/src/services/ai-agent-runner-service.ts +20 -0
- package/src/services/ai-embedding-service.ts +3 -25
- package/src/services/audit-service.ts +1 -2
- package/src/services/content-service.ts +1 -46
- package/src/services/credential-service.ts +3 -40
- package/src/services/credential-wire-service.test.ts +0 -2
- package/src/services/deployment-service.ts +3 -9
- package/src/services/gateway-service.ts +0 -15
- package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
- package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
- package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
- package/src/services/in-memory-queue-service.ts +1 -15
- package/src/services/in-memory-trigger-service.ts +1 -18
- package/src/services/in-memory-workflow-service.test.ts +0 -13
- package/src/services/in-memory-workflow-service.ts +4 -38
- package/src/services/index.ts +20 -15
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content.test.ts +159 -27
- package/src/services/local-content.ts +55 -23
- package/src/services/local-gateway-service.ts +2 -17
- package/src/services/local-secrets.ts +0 -4
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +2 -37
- package/src/services/meta-service.test.ts +1 -5
- package/src/services/meta-service.ts +41 -61
- package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
- package/src/services/pikku-user-id.ts +0 -4
- package/src/services/queue-webhook-service.ts +9 -41
- package/src/services/scheduler-service.ts +1 -50
- package/src/services/schema-service.ts +1 -24
- package/src/services/scope-service.ts +50 -34
- package/src/services/scoped-secret-service.ts +0 -4
- package/src/services/secret-host-binding.test.ts +138 -0
- package/src/services/secret-host-binding.ts +51 -0
- package/src/services/secret-service.ts +5 -33
- package/src/services/secretless.test.ts +54 -0
- package/src/services/secretless.ts +29 -0
- package/src/services/stub-tracker.ts +8 -18
- package/src/services/system-role-guard.test.ts +93 -0
- package/src/services/system-role-guard.ts +71 -0
- package/src/services/trigger-service.ts +0 -12
- package/src/services/typed-secret-service.ts +1 -7
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +19 -63
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +0 -26
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +116 -229
- package/src/types/state.types.ts +7 -9
- package/src/utils/hmac.ts +4 -10
- package/src/utils/safe-fetch.ts +13 -54
- package/src/utils.test.ts +11 -2
- package/src/utils.ts +6 -15
- package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
- package/src/wirings/actor-flow/index.ts +0 -9
- package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
- package/src/wirings/actor-flow/run-conversation.ts +19 -12
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +75 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +36 -17
- package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
- package/src/wirings/ai-agent/ai-agent-prepare.ts +82 -138
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
- package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
- package/src/wirings/ai-agent/ai-agent-runner.ts +67 -33
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +192 -75
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +85 -4
- package/src/wirings/ai-agent/index.ts +35 -3
- package/src/wirings/ai-agent/voice-input.test.ts +72 -7
- package/src/wirings/ai-agent/voice-input.ts +48 -3
- package/src/wirings/ai-agent/voice-output.test.ts +422 -0
- package/src/wirings/ai-agent/voice-output.ts +216 -56
- package/src/wirings/channel/channel-common.ts +15 -20
- package/src/wirings/channel/channel-handler.test.ts +50 -0
- package/src/wirings/channel/channel-handler.ts +32 -11
- package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
- package/src/wirings/channel/channel-host-rpc.ts +69 -0
- package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
- package/src/wirings/channel/channel-middleware-runner.ts +0 -12
- package/src/wirings/channel/channel-rpc-registry.ts +116 -0
- package/src/wirings/channel/channel-rpc-responder.ts +117 -0
- package/src/wirings/channel/channel-rpc-service.ts +146 -0
- package/src/wirings/channel/channel-rpc-validators.ts +65 -0
- package/src/wirings/channel/channel-rpc.test.ts +820 -0
- package/src/wirings/channel/channel-rpc.ts +5 -0
- package/src/wirings/channel/channel-rpc.types.ts +150 -0
- package/src/wirings/channel/channel-runner.ts +0 -14
- package/src/wirings/channel/channel-store.ts +0 -10
- package/src/wirings/channel/channel.types.ts +19 -8
- package/src/wirings/channel/define-channel-routes.ts +0 -20
- package/src/wirings/channel/eventhub-service.ts +0 -18
- package/src/wirings/channel/index.ts +35 -0
- package/src/wirings/channel/local/local-channel-handler.ts +3 -1
- package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
- package/src/wirings/channel/local/local-channel-runner.ts +3 -1
- package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
- package/src/wirings/channel/log-channels.ts +0 -4
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
- package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
- package/src/wirings/cli/channel/cli-approval.ts +135 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
- package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +155 -0
- package/src/wirings/cli/channel/index.ts +9 -0
- package/src/wirings/cli/cli-runner.test.ts +0 -1
- package/src/wirings/cli/cli-runner.ts +46 -88
- package/src/wirings/cli/cli.types.ts +14 -3
- package/src/wirings/cli/command-parser.test.ts +0 -4
- package/src/wirings/cli/command-parser.ts +11 -91
- package/src/wirings/cli/define-cli-commands.ts +1 -17
- package/src/wirings/credential/credential.types.ts +0 -12
- package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
- package/src/wirings/credential/index.ts +1 -1
- package/src/wirings/credential/validate-credential-definitions.ts +2 -4
- package/src/wirings/gateway/gateway-runner.test.ts +1 -21
- package/src/wirings/gateway/gateway-runner.ts +8 -110
- package/src/wirings/gateway/gateway.types.ts +7 -80
- package/src/wirings/http/http-routes.test.ts +0 -3
- package/src/wirings/http/http-routes.ts +0 -86
- package/src/wirings/http/http-runner.test.ts +0 -1
- package/src/wirings/http/http-runner.ts +12 -168
- package/src/wirings/http/http.types.ts +17 -62
- package/src/wirings/http/index.ts +5 -1
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +88 -7
- package/src/wirings/http/pikku-fetch-http-request.ts +74 -50
- package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
- package/src/wirings/http/routers/path-to-regex.ts +2 -13
- package/src/wirings/http/web-request.test.ts +33 -2
- package/src/wirings/http/web-request.ts +30 -17
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +40 -0
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- package/src/wirings/mcp/mcp.types.ts +7 -42
- package/src/wirings/oauth2/oauth2.types.ts +0 -30
- package/src/wirings/persona/define-personas.ts +29 -0
- package/src/wirings/persona/index.ts +62 -0
- package/src/wirings/persona/persona-email.ts +87 -0
- package/src/wirings/persona/persona-environments.test.ts +183 -0
- package/src/wirings/persona/persona-environments.ts +138 -0
- package/src/wirings/persona/persona-mailbox.ts +156 -0
- package/src/wirings/persona/persona.test.ts +220 -0
- package/src/wirings/persona/persona.types.ts +131 -0
- package/src/wirings/persona/validate-personas.ts +133 -0
- package/src/wirings/queue/index.ts +13 -3
- package/src/wirings/queue/queue-identity.test.ts +453 -0
- package/src/wirings/queue/queue-identity.ts +173 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +19 -89
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +59 -0
- package/src/wirings/queue/validate-worker-config.ts +2 -28
- package/src/wirings/role/define-system-role.ts +33 -0
- package/src/wirings/role/index.ts +13 -0
- package/src/wirings/role/role.test.ts +104 -0
- package/src/wirings/role/role.types.ts +47 -0
- package/src/wirings/role/validate-role-definitions.ts +93 -0
- package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
- package/src/wirings/rpc/addon-runner.ts +0 -56
- package/src/wirings/rpc/addon-scopes.test.ts +225 -0
- package/src/wirings/rpc/remote-addon-auth.ts +1 -13
- package/src/wirings/rpc/rpc-runner.test.ts +186 -2
- package/src/wirings/rpc/rpc-runner.ts +145 -127
- package/src/wirings/rpc/rpc-types.ts +11 -6
- package/src/wirings/rpc/wire-addon.test.ts +43 -1
- package/src/wirings/rpc/wire-addon.ts +99 -0
- package/src/wirings/rpc/wire-remote-addon.ts +9 -29
- package/src/wirings/scheduler/log-schedulers.ts +0 -4
- package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
- package/src/wirings/scheduler/scheduler-runner.ts +0 -2
- package/src/wirings/scheduler/scheduler.types.ts +1 -14
- package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
- package/src/wirings/scope/index.ts +1 -1
- package/src/wirings/scope/scope.test.ts +1 -2
- package/src/wirings/scope/scope.types.ts +7 -9
- package/src/wirings/scope/validate-scope-definitions.ts +3 -21
- package/src/wirings/secret/index.ts +1 -1
- package/src/wirings/secret/secret.types.ts +19 -15
- package/src/wirings/secret/validate-secret-definitions.ts +2 -4
- package/src/wirings/trigger/trigger-runner.ts +1 -27
- package/src/wirings/trigger/trigger.types.ts +1 -82
- package/src/wirings/variable/index.ts +1 -1
- package/src/wirings/variable/validate-variable-definitions.ts +2 -4
- package/src/wirings/variable/variable.types.ts +1 -13
- package/src/wirings/virtual-user/index.ts +76 -0
- package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
- package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
- package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
- package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
- package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
- package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
- package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
- package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
- package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +5 -4
- package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
- package/src/wirings/workflow/feature.ts +0 -19
- package/src/wirings/workflow/graph/graph-node.ts +0 -136
- package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
- package/src/wirings/workflow/graph/graph-runner.ts +6 -41
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
- package/src/wirings/workflow/index.ts +10 -44
- package/src/wirings/workflow/pikku-scenario-service.ts +235 -52
- package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
- package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
- package/src/wirings/workflow/run-timeline.test.ts +7 -19
- package/src/wirings/workflow/run-timeline.ts +0 -56
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
- package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
- package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
- package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
- package/src/wirings/workflow/scenario-poll.test.ts +0 -2
- package/src/wirings/workflow/scenario-poll.ts +0 -15
- package/src/wirings/workflow/scenario-prose.ts +0 -28
- package/src/wirings/workflow/scenario-service.test.ts +2 -9
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +159 -14
- package/src/wirings/workflow/scenario-step.types.ts +82 -6
- package/src/wirings/workflow/scenario-surface.test.ts +145 -0
- package/src/wirings/workflow/scenario-surface.ts +71 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
- package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
- package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
- package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
- package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
- package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
- package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
- package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
- package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
- package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
- package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
- package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
- package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
- package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
- package/src/wirings/workflow/workflow.types.ts +0 -203
- package/tsconfig.tsbuildinfo +1 -1
- package/src/middleware/timeout.ts +0 -22
- package/src/pikku-response.ts +0 -5
- package/src/services/gopass-secrets.ts +0 -78
- package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
- package/src/wirings/workflow/dsl/index.ts +0 -36
- package/src/wirings/workflow/graph/index.ts +0 -15
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { hasScopes } from '../../scopes.js';
|
|
2
|
+
/**
|
|
3
|
+
* Endpoint names that only read, by convention. Used when nobody annotated
|
|
4
|
+
* `readonly` — which in a real project is most of them.
|
|
5
|
+
*/
|
|
6
|
+
const READ_PREFIXES = [
|
|
7
|
+
'get',
|
|
8
|
+
'list',
|
|
9
|
+
'lookup',
|
|
10
|
+
'search',
|
|
11
|
+
'find',
|
|
12
|
+
'read',
|
|
13
|
+
'fetch',
|
|
14
|
+
'check',
|
|
15
|
+
'count',
|
|
16
|
+
'query',
|
|
17
|
+
'preview',
|
|
18
|
+
'describe',
|
|
19
|
+
'has',
|
|
20
|
+
'is',
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Whether a call only reads.
|
|
24
|
+
*
|
|
25
|
+
* An explicit annotation always wins. Without one, the name decides — because
|
|
26
|
+
* an unannotated function means "nobody said", not "safe", and silently
|
|
27
|
+
* treating 395 unannotated endpoints as read-only is how a virtual user
|
|
28
|
+
* deploys something. {@link catalogueClassification} reports how much of the
|
|
29
|
+
* catalogue rests on this guess so the gap is visible rather than assumed.
|
|
30
|
+
*/
|
|
31
|
+
export const isReadOnly = (entry) => {
|
|
32
|
+
if (typeof entry.readonly === 'boolean')
|
|
33
|
+
return entry.readonly;
|
|
34
|
+
const name = entry.name;
|
|
35
|
+
return READ_PREFIXES.some((prefix) => name.startsWith(prefix) &&
|
|
36
|
+
(name.length === prefix.length ||
|
|
37
|
+
name[prefix.length] === name[prefix.length]?.toUpperCase()));
|
|
38
|
+
};
|
|
39
|
+
/** How much of a catalogue's read/write split is annotation and how much is guess. */
|
|
40
|
+
export const catalogueClassification = (entries) => {
|
|
41
|
+
const annotated = entries.filter((entry) => typeof entry.readonly === 'boolean').length;
|
|
42
|
+
return {
|
|
43
|
+
total: entries.length,
|
|
44
|
+
annotated,
|
|
45
|
+
inferred: entries.length - annotated,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
/** One catalogue line: `name(inputKeys) -> outputKeys — description`. */
|
|
49
|
+
const renderEntry = (entry) => {
|
|
50
|
+
const inputs = (entry.inputKeys ?? []).join(',');
|
|
51
|
+
const outputs = (entry.outputKeys ?? []).join(',');
|
|
52
|
+
const description = entry.description
|
|
53
|
+
? ` — ${entry.description.split('\n')[0].slice(0, 120)}`
|
|
54
|
+
: '';
|
|
55
|
+
return `${entry.name}(${inputs})${outputs ? ` -> ${outputs}` : ''}${description}`;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The whole reachable API as one compact index, for the instructions.
|
|
59
|
+
*
|
|
60
|
+
* Every endpoint is listed rather than retrieved against. Measured on a 430-RPC
|
|
61
|
+
* project this is ~8k tokens, cached for the life of the run — cheaper than any
|
|
62
|
+
* retrieval step, and it hides nothing. A ranking function would make the
|
|
63
|
+
* virtual user only as adventurous as the ranking, which loses exactly the
|
|
64
|
+
* endpoints worth stumbling into.
|
|
65
|
+
*/
|
|
66
|
+
export const renderCatalogue = (entries) => entries.map(renderEntry).join('\n');
|
|
67
|
+
/**
|
|
68
|
+
* The entries a given user may reach: approval-gated calls dropped unless the
|
|
69
|
+
* run opted in, mutations dropped for a read-only disposition, and anything the
|
|
70
|
+
* actor's tier cannot satisfy dropped when the caller supplied one.
|
|
71
|
+
*
|
|
72
|
+
* This narrows *what is offered*, never what is enforced — the server is the
|
|
73
|
+
* only thing that decides who may call what, and a call this filter would have
|
|
74
|
+
* denied still going through is a finding rather than a bug in the filter.
|
|
75
|
+
*/
|
|
76
|
+
export const reachableCatalogue = (entries, { readOnly = false, allowApprovalRequired = false, scopes, } = {}) => entries.filter((entry) => {
|
|
77
|
+
if (entry.approvalRequired && !allowApprovalRequired)
|
|
78
|
+
return false;
|
|
79
|
+
if (readOnly && !isReadOnly(entry))
|
|
80
|
+
return false;
|
|
81
|
+
if (scopes && entry.scopes?.length) {
|
|
82
|
+
return hasScopes(entry.scopes, scopes);
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Endpoints this persona is *not* entitled to reach.
|
|
88
|
+
*
|
|
89
|
+
* The adversarial oracle. Withheld from the catalogue, so reaching one takes
|
|
90
|
+
* initiative — and a 2xx from one is the finding, because the server is the
|
|
91
|
+
* only thing that decides who may call what.
|
|
92
|
+
*/
|
|
93
|
+
export const unreachableCatalogue = (entries, scopes) => entries.filter((entry) => !!entry.scopes?.length && !hasScopes(entry.scopes, scopes));
|
|
94
|
+
/** Index a catalogue by name for the engine's lookups. */
|
|
95
|
+
export const catalogueIndex = (entries) => new Map(entries.map((entry) => [entry.name, entry]));
|
|
96
|
+
/**
|
|
97
|
+
* Find an entry by the name a model gave, forgiving the signature it just read.
|
|
98
|
+
*
|
|
99
|
+
* The catalogue renders as `name(inputs) -> outputs`, and a model that has the
|
|
100
|
+
* line in front of it will sometimes hand the whole line back — `whoAmI() ->
|
|
101
|
+
* userId,scopes` instead of `whoAmI`. Measured on a live run, 8 of 24 steps
|
|
102
|
+
* went that way and every one of them was answered with "there is no endpoint
|
|
103
|
+
* called that", which is true and useless.
|
|
104
|
+
*
|
|
105
|
+
* Forgiving it is not the same as guessing: an rpc name never contains a
|
|
106
|
+
* bracket, so everything from the first one is the signature the catalogue
|
|
107
|
+
* printed, and taking it off is unambiguous.
|
|
108
|
+
*/
|
|
109
|
+
export const catalogueLookup = (index, rpcName) => {
|
|
110
|
+
const exact = index.get(rpcName);
|
|
111
|
+
if (exact) {
|
|
112
|
+
return exact;
|
|
113
|
+
}
|
|
114
|
+
const [head] = rpcName.trim().split('(');
|
|
115
|
+
return head && head !== rpcName ? index.get(head.trim()) : undefined;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* What `describe` hands back: the full schemas, so the next call can be made
|
|
119
|
+
* correctly rather than guessed at.
|
|
120
|
+
*
|
|
121
|
+
* Guessing field names is unproductive fuzz — every 400 becomes a typo and
|
|
122
|
+
* nothing is learned from any of them. Reading the schema first is also what a
|
|
123
|
+
* person does, since the form tells them the fields. It makes a subsequent 400
|
|
124
|
+
* mean something: either the schema and the implementation disagree, or the
|
|
125
|
+
* misuse is genuine and worth seeing.
|
|
126
|
+
*/
|
|
127
|
+
export const describeEntry = (entry) => ({
|
|
128
|
+
name: entry.name,
|
|
129
|
+
description: entry.description,
|
|
130
|
+
readonly: isReadOnly(entry),
|
|
131
|
+
approvalRequired: entry.approvalRequired ?? false,
|
|
132
|
+
input: entry.inputSchema ?? { type: 'object', properties: {} },
|
|
133
|
+
output: entry.outputSchema ?? null,
|
|
134
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FunctionsMeta } from '../../types/core.types.js';
|
|
2
|
+
import type { WorkflowsMeta } from '../workflow/workflow.types.js';
|
|
3
|
+
import type { ApiCatalogueEntry, IntentSource } from './virtual-user.types.js';
|
|
4
|
+
/** A generated JSON schema, keyed by the name the function meta refers to. */
|
|
5
|
+
export type SchemaMap = Record<string, Record<string, unknown> | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* Every RPC a virtual user could reach, read off the meta a project already
|
|
8
|
+
* generates.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here is new authoring, which is the whole point: the scopes, the
|
|
11
|
+
* `readonly` flags, the approval gates and the schemas were written for other
|
|
12
|
+
* reasons, and a virtual user is another reader of them. A project that has
|
|
13
|
+
* never heard of virtual users already ships everything one needs.
|
|
14
|
+
*/
|
|
15
|
+
export declare const deriveCatalogue: (functions: FunctionsMeta, schemas?: SchemaMap) => ApiCatalogueEntry[];
|
|
16
|
+
/**
|
|
17
|
+
* The things a virtual user might want, read off the scenarios a project
|
|
18
|
+
* already declares.
|
|
19
|
+
*
|
|
20
|
+
* Only the prose survives the trip. A scenario knows which RPCs it calls and
|
|
21
|
+
* how their outputs feed each other, and none of that is passed on: finding
|
|
22
|
+
* the API is the behaviour under test, and a user handed the answer tests
|
|
23
|
+
* nothing. A step with no sentence to its name is dropped rather than
|
|
24
|
+
* described by its function name, which would leak exactly that answer.
|
|
25
|
+
*/
|
|
26
|
+
export declare const deriveIntents: (workflows: WorkflowsMeta, functions?: FunctionsMeta) => IntentSource[];
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { composeStepProse } from '../workflow/scenario-prose.js';
|
|
2
|
+
const topLevelKeys = (schema) => {
|
|
3
|
+
const properties = schema?.properties;
|
|
4
|
+
if (!properties || typeof properties !== 'object')
|
|
5
|
+
return undefined;
|
|
6
|
+
const keys = Object.keys(properties);
|
|
7
|
+
return keys.length ? keys : undefined;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Every RPC a virtual user could reach, read off the meta a project already
|
|
11
|
+
* generates.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here is new authoring, which is the whole point: the scopes, the
|
|
14
|
+
* `readonly` flags, the approval gates and the schemas were written for other
|
|
15
|
+
* reasons, and a virtual user is another reader of them. A project that has
|
|
16
|
+
* never heard of virtual users already ships everything one needs.
|
|
17
|
+
*/
|
|
18
|
+
export const deriveCatalogue = (functions, schemas = {}) => {
|
|
19
|
+
const entries = [];
|
|
20
|
+
for (const [name, meta] of Object.entries(functions ?? {})) {
|
|
21
|
+
// Scenario bodies and their steps are never network-callable — they are
|
|
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.
|
|
32
|
+
if (meta.scenario || meta.scenarioStep || meta.scenarioStepKind)
|
|
33
|
+
continue;
|
|
34
|
+
// `expose: true` is what puts a function on the rpc transport, and that is
|
|
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.
|
|
39
|
+
if (meta.expose !== true)
|
|
40
|
+
continue;
|
|
41
|
+
const inputSchema = meta.inputSchemaName
|
|
42
|
+
? schemas[meta.inputSchemaName]
|
|
43
|
+
: undefined;
|
|
44
|
+
const outputSchema = meta.outputSchemaName
|
|
45
|
+
? schemas[meta.outputSchemaName]
|
|
46
|
+
: undefined;
|
|
47
|
+
entries.push({
|
|
48
|
+
name,
|
|
49
|
+
description: meta.description ?? meta.summary ?? meta.title,
|
|
50
|
+
readonly: meta.readonly,
|
|
51
|
+
approvalRequired: meta.approvalRequired,
|
|
52
|
+
scopes: meta.scopes?.length ? [...new Set(meta.scopes)] : undefined,
|
|
53
|
+
tags: meta.tags?.length ? meta.tags : undefined,
|
|
54
|
+
inputKeys: topLevelKeys(inputSchema),
|
|
55
|
+
outputKeys: topLevelKeys(outputSchema),
|
|
56
|
+
inputSchema,
|
|
57
|
+
outputSchema,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return entries;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The same scenario, spelled either way.
|
|
64
|
+
*
|
|
65
|
+
* One scenario has two meta shapes and both reach this function: the runner
|
|
66
|
+
* hands over the inspector's DSL meta, where steps are a `steps[]` of
|
|
67
|
+
* `scenarioStep`s, while the console reads what was written to disk through
|
|
68
|
+
* `getWorkflowMeta()`, where the same steps are the graph's `nodes` and the
|
|
69
|
+
* scenario declares itself with `source` rather than `scenario`. Reading only
|
|
70
|
+
* the first shape is not a narrower reading — it is an empty one, and a screen
|
|
71
|
+
* built on it shows every user wanting nothing at all.
|
|
72
|
+
*/
|
|
73
|
+
const scenarioSteps = (meta) => {
|
|
74
|
+
if (meta.steps?.length) {
|
|
75
|
+
return meta.steps.flatMap((step) => step.type === 'scenarioStep'
|
|
76
|
+
? [{ stepFunc: step.stepFunc, phase: step.phase, actor: step.actor }]
|
|
77
|
+
: []);
|
|
78
|
+
}
|
|
79
|
+
// Insertion order is the order the CLI wrote the nodes in, which is the order
|
|
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.
|
|
83
|
+
return Object.values(meta.nodes ?? {}).flatMap((node) => {
|
|
84
|
+
const { rpcName, scenarioStepPhase, actor } = (node ?? {});
|
|
85
|
+
if (!rpcName || !scenarioStepPhase)
|
|
86
|
+
return [];
|
|
87
|
+
return [{ stepFunc: rpcName, phase: scenarioStepPhase, actor }];
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The things a virtual user might want, read off the scenarios a project
|
|
92
|
+
* already declares.
|
|
93
|
+
*
|
|
94
|
+
* Only the prose survives the trip. A scenario knows which RPCs it calls and
|
|
95
|
+
* how their outputs feed each other, and none of that is passed on: finding
|
|
96
|
+
* the API is the behaviour under test, and a user handed the answer tests
|
|
97
|
+
* nothing. A step with no sentence to its name is dropped rather than
|
|
98
|
+
* described by its function name, which would leak exactly that answer.
|
|
99
|
+
*/
|
|
100
|
+
export const deriveIntents = (workflows, functions = {}) => {
|
|
101
|
+
const intents = [];
|
|
102
|
+
for (const [name, meta] of Object.entries(workflows ?? {})) {
|
|
103
|
+
if (!meta.scenario && meta.source !== 'scenario')
|
|
104
|
+
continue;
|
|
105
|
+
// A quarantined scenario is one someone decided not to run. Driving real
|
|
106
|
+
// traffic with it would be a louder version of the same mistake.
|
|
107
|
+
if (meta.skip)
|
|
108
|
+
continue;
|
|
109
|
+
const steps = [];
|
|
110
|
+
for (const step of scenarioSteps(meta)) {
|
|
111
|
+
const stepMeta = functions[step.stepFunc];
|
|
112
|
+
const template = stepMeta?.scenarioStepTemplate;
|
|
113
|
+
const description = stepMeta?.description ?? stepMeta?.summary;
|
|
114
|
+
if (!template && !description)
|
|
115
|
+
continue;
|
|
116
|
+
steps.push(composeStepProse({
|
|
117
|
+
phase: step.phase,
|
|
118
|
+
// The template goes in unfilled, braces and all. A reporter fills its
|
|
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.
|
|
123
|
+
description: template ?? description ?? '',
|
|
124
|
+
actor: step.actor,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
intents.push({
|
|
128
|
+
id: name,
|
|
129
|
+
title: meta.title ?? meta.summary ?? name,
|
|
130
|
+
description: meta.description,
|
|
131
|
+
steps: steps.length ? steps : undefined,
|
|
132
|
+
tags: meta.tags?.length ? meta.tags : undefined,
|
|
133
|
+
personas: meta.actors?.length ? meta.actors : undefined,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return intents;
|
|
137
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { VirtualUserDisposition } from './virtual-user.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The dials a disposition turns. Everything here changes what the engine does;
|
|
4
|
+
* `instructions` is the only field the model ever sees, and it describes
|
|
5
|
+
* behaviour the dials cannot express on their own.
|
|
6
|
+
*/
|
|
7
|
+
export interface DispositionProfile {
|
|
8
|
+
/** Appended to the persona instructions. Behaviour, never identity. */
|
|
9
|
+
instructions: string;
|
|
10
|
+
/**
|
|
11
|
+
* Relative weights for the scheduler's four moves. `continue` dominating is
|
|
12
|
+
* what makes a run look like work rather than channel-surfing.
|
|
13
|
+
*/
|
|
14
|
+
moves: {
|
|
15
|
+
continue: number;
|
|
16
|
+
suspend: number;
|
|
17
|
+
resume: number;
|
|
18
|
+
abandon: number;
|
|
19
|
+
};
|
|
20
|
+
/** Sampling temperature for the model's own turns. */
|
|
21
|
+
temperature: number;
|
|
22
|
+
/** Chance of re-issuing the previous call unchanged — the double-click. */
|
|
23
|
+
repeatRate: number;
|
|
24
|
+
/** Chance of re-reading before acting instead of trusting memory. */
|
|
25
|
+
reReadRate: number;
|
|
26
|
+
/** Start with nothing remembered, whatever the caller seeded. */
|
|
27
|
+
emptyMemory: boolean;
|
|
28
|
+
/** Non-read calls are refused by the engine, not merely discouraged. */
|
|
29
|
+
readOnly: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* A 2xx is a finding rather than a success. The engine cannot know *whose*
|
|
32
|
+
* resource an id belongs to, so it flags the success and leaves ownership to
|
|
33
|
+
* the app's classifier — the honest split, since ownership is app knowledge.
|
|
34
|
+
*/
|
|
35
|
+
invertedOracle: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Per-user overrides for a disposition's dials.
|
|
39
|
+
*
|
|
40
|
+
* The six profiles below are starting points, not laws — the weights are a
|
|
41
|
+
* considered guess about how people behave, and your product is allowed to know
|
|
42
|
+
* better. A user that declares `disposition: 'careless'` with a higher
|
|
43
|
+
* `repeatRate` is still a careless user; it is the same behaviour tuned to a
|
|
44
|
+
* product where double-submits actually happen.
|
|
45
|
+
*
|
|
46
|
+
* `instructions` is the one field that appends rather than replaces. Everything
|
|
47
|
+
* else is a number the engine reads, so overriding it changes the run and
|
|
48
|
+
* nothing else; instructions are the model's sense of who it is, and letting a
|
|
49
|
+
* declaration replace them wholesale is how you end up with a `careless` user
|
|
50
|
+
* that is not careless — which makes the name, and every run labelled with it,
|
|
51
|
+
* a lie.
|
|
52
|
+
*/
|
|
53
|
+
export interface VirtualUserTuning {
|
|
54
|
+
/** Relative weights for the scheduler's moves. Merged over the profile's. */
|
|
55
|
+
moves?: Partial<DispositionProfile['moves']>;
|
|
56
|
+
temperature?: number;
|
|
57
|
+
repeatRate?: number;
|
|
58
|
+
reReadRate?: number;
|
|
59
|
+
emptyMemory?: boolean;
|
|
60
|
+
readOnly?: boolean;
|
|
61
|
+
invertedOracle?: boolean;
|
|
62
|
+
/** Extra behaviour, appended to the disposition's own instructions. */
|
|
63
|
+
instructions?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The profiles, keyed by disposition. `careless` is the one worth reading twice:
|
|
67
|
+
* it is not malice, it is an ordinary person being interrupted and impatient,
|
|
68
|
+
* and it is where most production bugs actually live.
|
|
69
|
+
*/
|
|
70
|
+
export declare const DISPOSITIONS: Readonly<Record<VirtualUserDisposition, DispositionProfile>>;
|
|
71
|
+
/**
|
|
72
|
+
* The profile for a disposition, defaulting to `realistic`, with any declared
|
|
73
|
+
* tuning merged over it.
|
|
74
|
+
*
|
|
75
|
+
* Every consumer resolves a profile through here — the engine, the CLI report
|
|
76
|
+
* and the console screen — so a tuned user reads as tuned everywhere rather
|
|
77
|
+
* than only behaving differently when it runs.
|
|
78
|
+
*/
|
|
79
|
+
export declare const dispositionProfile: (disposition?: VirtualUserDisposition, tuning?: VirtualUserTuning) => DispositionProfile;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const REALISTIC = {
|
|
2
|
+
instructions: [
|
|
3
|
+
'Work towards your current goal the way a competent user would.',
|
|
4
|
+
'Read an endpoint schema before you use it, and prefer values that a real person would plausibly enter.',
|
|
5
|
+
].join(' '),
|
|
6
|
+
moves: { continue: 88, suspend: 6, resume: 5, abandon: 1 },
|
|
7
|
+
temperature: 0.7,
|
|
8
|
+
repeatRate: 0,
|
|
9
|
+
reReadRate: 0.1,
|
|
10
|
+
emptyMemory: false,
|
|
11
|
+
readOnly: false,
|
|
12
|
+
invertedOracle: false,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The profiles, keyed by disposition. `careless` is the one worth reading twice:
|
|
16
|
+
* it is not malice, it is an ordinary person being interrupted and impatient,
|
|
17
|
+
* and it is where most production bugs actually live.
|
|
18
|
+
*/
|
|
19
|
+
export const DISPOSITIONS = {
|
|
20
|
+
realistic: REALISTIC,
|
|
21
|
+
careless: {
|
|
22
|
+
...REALISTIC,
|
|
23
|
+
instructions: [
|
|
24
|
+
'You are busy and easily distracted. You act on what you half-remember rather than checking first,',
|
|
25
|
+
'you sometimes submit the same thing twice because you are not sure it went through,',
|
|
26
|
+
'and you are comfortable entering odd-but-legal values — a very long name, an empty optional field, an emoji, a huge page size.',
|
|
27
|
+
'Stay within what the schema allows; you are careless, not malicious.',
|
|
28
|
+
].join(' '),
|
|
29
|
+
moves: { continue: 62, suspend: 18, resume: 12, abandon: 8 },
|
|
30
|
+
temperature: 1,
|
|
31
|
+
repeatRate: 0.18,
|
|
32
|
+
reReadRate: 0.03,
|
|
33
|
+
},
|
|
34
|
+
newcomer: {
|
|
35
|
+
...REALISTIC,
|
|
36
|
+
instructions: [
|
|
37
|
+
'This is your first time in this product. You know nothing about it and hold no ids or names in your head.',
|
|
38
|
+
'Find your way from whatever lists or lookups exist, and say plainly when there is no path forward from where you are.',
|
|
39
|
+
].join(' '),
|
|
40
|
+
moves: { continue: 80, suspend: 8, resume: 6, abandon: 6 },
|
|
41
|
+
temperature: 0.8,
|
|
42
|
+
reReadRate: 0.4,
|
|
43
|
+
emptyMemory: true,
|
|
44
|
+
},
|
|
45
|
+
stale: {
|
|
46
|
+
...REALISTIC,
|
|
47
|
+
instructions: [
|
|
48
|
+
'You used this product a while ago and are working from notes you took then.',
|
|
49
|
+
'Reach for the ids and names you already have rather than looking them up again — some of them are out of date, and finding out how the product tells you so is the point.',
|
|
50
|
+
].join(' '),
|
|
51
|
+
moves: { continue: 84, suspend: 8, resume: 6, abandon: 2 },
|
|
52
|
+
temperature: 0.7,
|
|
53
|
+
reReadRate: 0.02,
|
|
54
|
+
},
|
|
55
|
+
auditor: {
|
|
56
|
+
...REALISTIC,
|
|
57
|
+
instructions: [
|
|
58
|
+
'You are reconciling, not achieving. Pick one fact the product reports — a total, a count, a balance, a status —',
|
|
59
|
+
'and read it from every endpoint that claims to know it, then say whether they agree.',
|
|
60
|
+
'Report a disagreement precisely: which endpoints, which field, which two values.',
|
|
61
|
+
'Never change anything.',
|
|
62
|
+
].join(' '),
|
|
63
|
+
moves: { continue: 92, suspend: 4, resume: 4, abandon: 0 },
|
|
64
|
+
temperature: 0.4,
|
|
65
|
+
reReadRate: 0.5,
|
|
66
|
+
readOnly: true,
|
|
67
|
+
},
|
|
68
|
+
adversarial: {
|
|
69
|
+
...REALISTIC,
|
|
70
|
+
instructions: [
|
|
71
|
+
'You are testing whether this product actually enforces the boundaries it claims.',
|
|
72
|
+
'Try reaching resources that should not be yours, reusing identifiers you were given for one purpose in another,',
|
|
73
|
+
'and calling endpoints that look like they belong to someone with more authority than you.',
|
|
74
|
+
'You are probing authorization, not causing damage: never destroy data you can reach, and prefer reads over writes when either would prove the point.',
|
|
75
|
+
].join(' '),
|
|
76
|
+
moves: { continue: 70, suspend: 10, resume: 8, abandon: 12 },
|
|
77
|
+
temperature: 0.9,
|
|
78
|
+
reReadRate: 0.2,
|
|
79
|
+
invertedOracle: true,
|
|
80
|
+
},
|
|
81
|
+
// The only disposition that is not testing anything. It is doing the job, so
|
|
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.
|
|
85
|
+
accountable: {
|
|
86
|
+
...REALISTIC,
|
|
87
|
+
instructions: [
|
|
88
|
+
'You are doing this job for real. What you change stays changed, and every call you make is recorded against your name.',
|
|
89
|
+
'Work towards your goals as the person you are, using the tools you have been given.',
|
|
90
|
+
'Where a specialist agent exists for part of the work, hand that part to it rather than reconstructing it yourself.',
|
|
91
|
+
'When you are unsure whether something is wanted, stop and say what you would do and why, rather than doing it and reporting afterwards.',
|
|
92
|
+
'Never guess at an identifier, an amount or a recipient — read it from the product first.',
|
|
93
|
+
].join(' '),
|
|
94
|
+
moves: { continue: 94, suspend: 5, resume: 1, abandon: 0 },
|
|
95
|
+
temperature: 0.4,
|
|
96
|
+
repeatRate: 0,
|
|
97
|
+
reReadRate: 0.25,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The profile for a disposition, defaulting to `realistic`, with any declared
|
|
102
|
+
* tuning merged over it.
|
|
103
|
+
*
|
|
104
|
+
* Every consumer resolves a profile through here — the engine, the CLI report
|
|
105
|
+
* and the console screen — so a tuned user reads as tuned everywhere rather
|
|
106
|
+
* than only behaving differently when it runs.
|
|
107
|
+
*/
|
|
108
|
+
export const dispositionProfile = (disposition = 'realistic', tuning) => {
|
|
109
|
+
const base = DISPOSITIONS[disposition] ?? DISPOSITIONS.realistic;
|
|
110
|
+
if (!tuning) {
|
|
111
|
+
return base;
|
|
112
|
+
}
|
|
113
|
+
const { moves, instructions, ...dials } = tuning;
|
|
114
|
+
const profile = {
|
|
115
|
+
...base,
|
|
116
|
+
// An explicit `undefined` is someone spreading an optional value, not a
|
|
117
|
+
// request to unset a dial — spreading `dials` straight in would erase it.
|
|
118
|
+
...Object.fromEntries(Object.entries(dials).filter(([, value]) => value !== undefined)),
|
|
119
|
+
moves: {
|
|
120
|
+
...base.moves,
|
|
121
|
+
...Object.fromEntries(Object.entries(moves ?? {}).filter(([, value]) => value !== undefined)),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
if (instructions) {
|
|
125
|
+
profile.instructions = `${base.instructions} ${instructions}`;
|
|
126
|
+
}
|
|
127
|
+
return profile;
|
|
128
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { DispositionProfile } from './virtual-user-dispositions.js';
|
|
2
|
+
import type { VirtualUserRng } from './virtual-user-rng.js';
|
|
3
|
+
import type { IntentRecord, IntentSource, IntentStatus } from './virtual-user.types.js';
|
|
4
|
+
/** One intent as the stack tracks it. */
|
|
5
|
+
interface TrackedIntent {
|
|
6
|
+
id: string;
|
|
7
|
+
source: IntentSource;
|
|
8
|
+
status: IntentStatus;
|
|
9
|
+
steps: number[];
|
|
10
|
+
suspensions: number;
|
|
11
|
+
summary?: string;
|
|
12
|
+
}
|
|
13
|
+
/** The move the scheduler rolled for a tick. */
|
|
14
|
+
export type IntentMove = 'start' | 'continue' | 'suspend' | 'resume' | 'abandon';
|
|
15
|
+
/** What the stack scheduled: which intent is active, and how it got there. */
|
|
16
|
+
export interface ScheduledTick {
|
|
17
|
+
intent: TrackedIntent;
|
|
18
|
+
move: IntentMove;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The stack of things this user is in the middle of — and the whole of the
|
|
22
|
+
* engine's randomness.
|
|
23
|
+
*
|
|
24
|
+
* A real person does not run a flow end to end: they start something, get
|
|
25
|
+
* pulled away, do a bit of something else, come back to a world that moved
|
|
26
|
+
* underneath them, and sometimes never come back at all. Modelling that as a
|
|
27
|
+
* stack of partially-completed intents is what produces the bugs worth having —
|
|
28
|
+
* half-mutated state, a flow resumed against changed data, an invite accepted
|
|
29
|
+
* after the plan changed — none of which a scripted scenario can reach.
|
|
30
|
+
*
|
|
31
|
+
* Scheduling is the engine's job and the model's turns are not: the model
|
|
32
|
+
* decides what to do *within* the active intent, the stack decides which intent
|
|
33
|
+
* that is. Keeping the split there is what makes a run reproducible from a seed
|
|
34
|
+
* while the work inside it stays free.
|
|
35
|
+
*
|
|
36
|
+
* A feature is only where an intent comes from. Nothing here tracks whether one
|
|
37
|
+
* was "completed correctly", and the model is never told an intent boundary
|
|
38
|
+
* exists.
|
|
39
|
+
*/
|
|
40
|
+
export declare class IntentStack {
|
|
41
|
+
private readonly rng;
|
|
42
|
+
private readonly profile;
|
|
43
|
+
/** Cap on intents open at once, so a distractible user still finishes things. */
|
|
44
|
+
private readonly maxOpen;
|
|
45
|
+
private readonly tracked;
|
|
46
|
+
private readonly unstarted;
|
|
47
|
+
private active;
|
|
48
|
+
private counter;
|
|
49
|
+
constructor(sources: readonly IntentSource[], rng: VirtualUserRng, profile: DispositionProfile,
|
|
50
|
+
/** Cap on intents open at once, so a distractible user still finishes things. */
|
|
51
|
+
maxOpen?: number);
|
|
52
|
+
/**
|
|
53
|
+
* Pick the intent for this tick, or `null` when there is nothing left to do.
|
|
54
|
+
*
|
|
55
|
+
* The first tick always starts something; after that the four moves are
|
|
56
|
+
* weighted by the disposition, and a move that has nowhere to go degrades to
|
|
57
|
+
* `continue` rather than stalling the run.
|
|
58
|
+
*/
|
|
59
|
+
next(step: number): ScheduledTick | null;
|
|
60
|
+
/** Mark the active intent finished; the next tick schedules something else. */
|
|
61
|
+
complete(summary?: string): void;
|
|
62
|
+
/** Mark the active intent as one the user could not get through. */
|
|
63
|
+
stuck(reason?: string): void;
|
|
64
|
+
/** Every intent the run touched, in the order it first opened them. */
|
|
65
|
+
records(): IntentRecord[];
|
|
66
|
+
/** Prefer opening something new, falling back to picking a suspended one up. */
|
|
67
|
+
private startOrResume;
|
|
68
|
+
private resumeSuspended;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The intents a persona may be given: those whose source names them, plus every
|
|
72
|
+
* source that names nobody.
|
|
73
|
+
*
|
|
74
|
+
* This is a free lookup rather than new authoring — scenario meta already
|
|
75
|
+
* records which personas each scenario runs as.
|
|
76
|
+
*/
|
|
77
|
+
export declare const intentsForPersona: (sources: readonly IntentSource[], personaId: string) => IntentSource[];
|
|
78
|
+
export {};
|