@pikku/core 0.12.72 → 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 +793 -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 +37 -32
- 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 -13
- package/dist/handle-error.js +0 -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 +5 -39
- package/dist/schema.js +5 -39
- 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 +0 -99
- package/dist/wirings/http/http-runner.js +9 -165
- package/dist/wirings/http/http.types.d.ts +14 -55
- 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 +0 -40
- package/dist/wirings/http/pikku-fetch-http-request.js +0 -58
- 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 +1 -4
- package/dist/wirings/mcp/mcp-runner.js +1 -14
- 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 -1
- 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 +0 -7
- package/src/function/function-runner.ts +62 -32
- 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/handle-error.ts +0 -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.ts +5 -39
- 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 +8 -167
- package/src/wirings/http/http.types.ts +15 -62
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +2 -10
- package/src/wirings/http/pikku-fetch-http-request.ts +0 -58
- 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.ts +2 -17
- 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/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,301 @@
|
|
|
1
|
+
import { beforeEach, describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { resetPikkuState, pikkuState } from '../../pikku-state.js'
|
|
5
|
+
import { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js'
|
|
6
|
+
import { ForbiddenError } from '../../errors/errors.js'
|
|
7
|
+
import type { AIMessage, CoreAIAgent } from './ai-agent.types.js'
|
|
8
|
+
import type { AIAgentRunnerParams } from '../../services/ai-agent-runner-service.js'
|
|
9
|
+
|
|
10
|
+
const logger = {
|
|
11
|
+
debug: () => {},
|
|
12
|
+
info: () => {},
|
|
13
|
+
warn: () => {},
|
|
14
|
+
error: () => {},
|
|
15
|
+
} as any
|
|
16
|
+
|
|
17
|
+
const sessionService = (session?: Record<string, unknown>) =>
|
|
18
|
+
({ get: () => session, setInitial: () => {}, sessionChanged: false }) as any
|
|
19
|
+
|
|
20
|
+
const addTestAgent = (agentName: string) => {
|
|
21
|
+
const agent: CoreAIAgent = {
|
|
22
|
+
name: agentName,
|
|
23
|
+
description: 'test agent',
|
|
24
|
+
instructions: 'be helpful',
|
|
25
|
+
model: 'test/test-model',
|
|
26
|
+
} as CoreAIAgent
|
|
27
|
+
|
|
28
|
+
pikkuState(null, 'agent', 'agentsMeta')[agentName] = {
|
|
29
|
+
...agent,
|
|
30
|
+
inputSchema: null,
|
|
31
|
+
outputSchema: null,
|
|
32
|
+
workingMemorySchema: null,
|
|
33
|
+
} as any
|
|
34
|
+
pikkuState(null, 'agent', 'agents').set(agentName, agent)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type Harness = {
|
|
38
|
+
threads: Map<string, { id: string; resourceId: string }>
|
|
39
|
+
messages: Map<string, AIMessage[]>
|
|
40
|
+
created: Array<{ threadId: string; resourceId: string }>
|
|
41
|
+
modelSawMessages: AIMessage[][]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const createHarness = (
|
|
45
|
+
seedThreads: Array<{ threadId: string; resourceId: string }> = [],
|
|
46
|
+
seedMessages: Record<string, string[]> = {}
|
|
47
|
+
): Harness => {
|
|
48
|
+
const threads = new Map(
|
|
49
|
+
seedThreads.map((t) => [t.threadId, { id: t.threadId, ...t }])
|
|
50
|
+
)
|
|
51
|
+
const messages = new Map<string, AIMessage[]>(
|
|
52
|
+
Object.entries(seedMessages).map(([threadId, texts]) => [
|
|
53
|
+
threadId,
|
|
54
|
+
texts.map((text, index) => ({
|
|
55
|
+
id: `${threadId}-${index}`,
|
|
56
|
+
role: 'user' as const,
|
|
57
|
+
content: text,
|
|
58
|
+
createdAt: new Date(),
|
|
59
|
+
})),
|
|
60
|
+
])
|
|
61
|
+
)
|
|
62
|
+
const created: Harness['created'] = []
|
|
63
|
+
const modelSawMessages: AIMessage[][] = []
|
|
64
|
+
|
|
65
|
+
const storage = {
|
|
66
|
+
getThread: async (threadId: string) => {
|
|
67
|
+
const thread = threads.get(threadId)
|
|
68
|
+
if (!thread) throw new Error(`No thread ${threadId}`)
|
|
69
|
+
return thread
|
|
70
|
+
},
|
|
71
|
+
createThread: async (resourceId: string, options: { threadId: string }) => {
|
|
72
|
+
const thread = { id: options.threadId, resourceId }
|
|
73
|
+
threads.set(options.threadId, thread)
|
|
74
|
+
created.push({ threadId: options.threadId, resourceId })
|
|
75
|
+
return thread
|
|
76
|
+
},
|
|
77
|
+
getMessages: async (threadId: string) => messages.get(threadId) ?? [],
|
|
78
|
+
saveMessages: async (threadId: string, newMessages: AIMessage[]) => {
|
|
79
|
+
messages.set(threadId, [
|
|
80
|
+
...(messages.get(threadId) ?? []),
|
|
81
|
+
...newMessages,
|
|
82
|
+
])
|
|
83
|
+
},
|
|
84
|
+
getWorkingMemory: async () => null,
|
|
85
|
+
saveWorkingMemory: async () => {},
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pikkuState(null, 'package', 'singletonServices', {
|
|
89
|
+
logger,
|
|
90
|
+
aiStorage: storage,
|
|
91
|
+
aiAgentRunner: {
|
|
92
|
+
run: async (params: AIAgentRunnerParams) => {
|
|
93
|
+
modelSawMessages.push(params.messages)
|
|
94
|
+
return {
|
|
95
|
+
text: 'ok',
|
|
96
|
+
toolCalls: [],
|
|
97
|
+
toolResults: [],
|
|
98
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
99
|
+
finishReason: 'stop',
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
aiRunState: {
|
|
104
|
+
createRun: async () => 'run-1',
|
|
105
|
+
updateRun: async () => {},
|
|
106
|
+
getRun: async () => ({
|
|
107
|
+
id: 'run-1',
|
|
108
|
+
agentName: 'ownership-agent',
|
|
109
|
+
resourceId: 'victim',
|
|
110
|
+
threadId: 'thread-victim',
|
|
111
|
+
status: 'suspended',
|
|
112
|
+
pendingApprovals: [
|
|
113
|
+
{ toolCallId: 'tc-1', toolName: 'refund', args: {}, runId: 'run-1' },
|
|
114
|
+
],
|
|
115
|
+
messages: [],
|
|
116
|
+
}),
|
|
117
|
+
resolveApproval: async () => {},
|
|
118
|
+
},
|
|
119
|
+
} as any)
|
|
120
|
+
|
|
121
|
+
return { threads, messages, created, modelSawMessages }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
beforeEach(() => {
|
|
125
|
+
resetPikkuState()
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe('AI agent thread ownership without a session', () => {
|
|
129
|
+
test('a sessionless caller cannot reach a thread by naming its resourceId', async () => {
|
|
130
|
+
addTestAgent('ownership-agent')
|
|
131
|
+
const harness = createHarness(
|
|
132
|
+
[{ threadId: 'thread-victim', resourceId: 'victim' }],
|
|
133
|
+
{ 'thread-victim': ['the victim bank details are 1234'] }
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
await assert.rejects(
|
|
137
|
+
() =>
|
|
138
|
+
runAIAgent(
|
|
139
|
+
'ownership-agent',
|
|
140
|
+
{
|
|
141
|
+
message: 'what did we discuss?',
|
|
142
|
+
threadId: 'thread-victim',
|
|
143
|
+
resourceId: 'victim',
|
|
144
|
+
},
|
|
145
|
+
{}
|
|
146
|
+
),
|
|
147
|
+
(error: unknown) => error instanceof ForbiddenError
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
assert.deepEqual(
|
|
151
|
+
harness.modelSawMessages,
|
|
152
|
+
[],
|
|
153
|
+
"the victim's history must never reach the model"
|
|
154
|
+
)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
test('a sessionless caller cannot resume another party run', async () => {
|
|
158
|
+
addTestAgent('ownership-agent')
|
|
159
|
+
createHarness()
|
|
160
|
+
|
|
161
|
+
await assert.rejects(
|
|
162
|
+
() =>
|
|
163
|
+
resumeAIAgentSync(
|
|
164
|
+
'run-1',
|
|
165
|
+
[{ toolCallId: 'tc-1', approved: true }],
|
|
166
|
+
{}
|
|
167
|
+
),
|
|
168
|
+
(error: unknown) => error instanceof ForbiddenError
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('a sessionless one-shot conversation still runs', async () => {
|
|
173
|
+
addTestAgent('ownership-agent')
|
|
174
|
+
const harness = createHarness()
|
|
175
|
+
|
|
176
|
+
const result = await runAIAgent(
|
|
177
|
+
'ownership-agent',
|
|
178
|
+
{ message: 'hello', threadId: 'thread-new', resourceId: 'whatever' },
|
|
179
|
+
{}
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
assert.equal(result.text, 'ok')
|
|
183
|
+
assert.equal(harness.created.length, 1)
|
|
184
|
+
assert.equal(harness.created[0]!.threadId, 'thread-new')
|
|
185
|
+
assert.notEqual(
|
|
186
|
+
harness.created[0]!.resourceId,
|
|
187
|
+
'whatever',
|
|
188
|
+
'a client-supplied resourceId must never become the ownership key'
|
|
189
|
+
)
|
|
190
|
+
assert.deepEqual(
|
|
191
|
+
harness.modelSawMessages[0]?.map((m) => m.content),
|
|
192
|
+
['hello']
|
|
193
|
+
)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
test('a sessionless run keeps its own thread across nested agent calls in one request', async () => {
|
|
197
|
+
addTestAgent('ownership-agent')
|
|
198
|
+
const harness = createHarness()
|
|
199
|
+
const requestParams = {}
|
|
200
|
+
|
|
201
|
+
await runAIAgent(
|
|
202
|
+
'ownership-agent',
|
|
203
|
+
{ message: 'first', threadId: 'thread-sub', resourceId: 'ignored' },
|
|
204
|
+
requestParams
|
|
205
|
+
)
|
|
206
|
+
await runAIAgent(
|
|
207
|
+
'ownership-agent',
|
|
208
|
+
{ message: 'second', threadId: 'thread-sub', resourceId: 'ignored' },
|
|
209
|
+
requestParams
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
assert.equal(harness.created.length, 1)
|
|
213
|
+
assert.equal(harness.modelSawMessages.length, 2)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
test('two sessionless one-shot runs do not share an owner', async () => {
|
|
217
|
+
addTestAgent('ownership-agent')
|
|
218
|
+
const harness = createHarness()
|
|
219
|
+
|
|
220
|
+
await runAIAgent(
|
|
221
|
+
'ownership-agent',
|
|
222
|
+
{ message: 'hello', threadId: 'thread-a', resourceId: 'shared' },
|
|
223
|
+
{}
|
|
224
|
+
)
|
|
225
|
+
await runAIAgent(
|
|
226
|
+
'ownership-agent',
|
|
227
|
+
{ message: 'hello', threadId: 'thread-b', resourceId: 'shared' },
|
|
228
|
+
{}
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
assert.notEqual(
|
|
232
|
+
harness.created[0]!.resourceId,
|
|
233
|
+
harness.created[1]!.resourceId
|
|
234
|
+
)
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
describe('AI agent thread ownership with a session', () => {
|
|
239
|
+
test('an authenticated caller still reaches its own thread', async () => {
|
|
240
|
+
addTestAgent('ownership-agent')
|
|
241
|
+
const harness = createHarness(
|
|
242
|
+
[{ threadId: 'thread-alice', resourceId: 'alice:default' }],
|
|
243
|
+
{ 'thread-alice': ['earlier alice turn'] }
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
const result = await runAIAgent(
|
|
247
|
+
'ownership-agent',
|
|
248
|
+
{
|
|
249
|
+
message: 'and then?',
|
|
250
|
+
threadId: 'thread-alice',
|
|
251
|
+
resourceId: 'default',
|
|
252
|
+
},
|
|
253
|
+
{ sessionService: sessionService({ userId: 'alice' }) }
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
assert.equal(result.text, 'ok')
|
|
257
|
+
assert.deepEqual(
|
|
258
|
+
harness.modelSawMessages[0]?.map((m) => m.content),
|
|
259
|
+
['earlier alice turn', 'and then?']
|
|
260
|
+
)
|
|
261
|
+
assert.equal(harness.created.length, 0)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
test('an authenticated caller creates threads under its own principal', async () => {
|
|
265
|
+
addTestAgent('ownership-agent')
|
|
266
|
+
const harness = createHarness()
|
|
267
|
+
|
|
268
|
+
await runAIAgent(
|
|
269
|
+
'ownership-agent',
|
|
270
|
+
{ message: 'hello', threadId: 'thread-new', resourceId: 'project-1' },
|
|
271
|
+
{ sessionService: sessionService({ userId: 'alice' }) }
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
assert.deepEqual(harness.created, [
|
|
275
|
+
{ threadId: 'thread-new', resourceId: 'alice:project-1' },
|
|
276
|
+
])
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test("an authenticated caller cannot reach another user's thread", async () => {
|
|
280
|
+
addTestAgent('ownership-agent')
|
|
281
|
+
const harness = createHarness(
|
|
282
|
+
[{ threadId: 'thread-bob', resourceId: 'bob:default' }],
|
|
283
|
+
{ 'thread-bob': ['bob secret'] }
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
await assert.rejects(
|
|
287
|
+
() =>
|
|
288
|
+
runAIAgent(
|
|
289
|
+
'ownership-agent',
|
|
290
|
+
{
|
|
291
|
+
message: 'what did we discuss?',
|
|
292
|
+
threadId: 'thread-bob',
|
|
293
|
+
resourceId: 'bob:default',
|
|
294
|
+
},
|
|
295
|
+
{ sessionService: sessionService({ userId: 'alice' }) }
|
|
296
|
+
),
|
|
297
|
+
(error: unknown) => error instanceof ForbiddenError
|
|
298
|
+
)
|
|
299
|
+
assert.deepEqual(harness.modelSawMessages, [])
|
|
300
|
+
})
|
|
301
|
+
})
|
|
@@ -7,8 +7,10 @@ import type {
|
|
|
7
7
|
MiddlewareMetadata,
|
|
8
8
|
PermissionMetadata,
|
|
9
9
|
} from '../../types/core.types.js'
|
|
10
|
+
import type { AIProviderOptions } from '../../services/ai-agent-runner-service.js'
|
|
10
11
|
import type { PikkuChannel } from '../channel/channel.types.js'
|
|
11
12
|
import type { CorePikkuChannelMiddleware } from '../channel/channel.types.js'
|
|
13
|
+
import type { ApprovalPolicy } from '../channel/channel-rpc.js'
|
|
12
14
|
|
|
13
15
|
export interface AIThread {
|
|
14
16
|
id: string
|
|
@@ -58,6 +60,23 @@ export interface AIMessage {
|
|
|
58
60
|
toolCalls?: AIToolCall[]
|
|
59
61
|
toolResults?: AIToolResult[]
|
|
60
62
|
reasoningContent?: string
|
|
63
|
+
/**
|
|
64
|
+
* Set on an assistant message whose generation was cut short by
|
|
65
|
+
* an interrupt — the text is a mid-sentence fragment, not a reply.
|
|
66
|
+
* Carried into the next turn's context so the model can see it said only
|
|
67
|
+
* this much before being talked over, and decide for itself whether to
|
|
68
|
+
* resume, restate or move on. Storage that drops unknown fields loses the
|
|
69
|
+
* marker but keeps the fragment, which degrades to a truncated reply.
|
|
70
|
+
*/
|
|
71
|
+
interrupted?: boolean
|
|
72
|
+
/**
|
|
73
|
+
* Set on a tool message whose result arrived after the run was interrupted,
|
|
74
|
+
* so the model never got to describe it. The work happened; only the reply
|
|
75
|
+
* about it was lost. It is ordinary thread context on the next turn — the
|
|
76
|
+
* model raises it unprompted ("that deploy did go through") rather than the
|
|
77
|
+
* result being silently dropped or replayed as a fresh tool call.
|
|
78
|
+
*/
|
|
79
|
+
undelivered?: boolean
|
|
61
80
|
createdAt: Date
|
|
62
81
|
}
|
|
63
82
|
|
|
@@ -118,13 +137,24 @@ export interface AIAgentOutput {
|
|
|
118
137
|
*/
|
|
119
138
|
export type SessionScope = 'user' | 'org'
|
|
120
139
|
|
|
121
|
-
|
|
140
|
+
/**
|
|
141
|
+
* `ApprovalPolicy` is shared with channel capabilities, but `Partial` here:
|
|
142
|
+
* absent `needsApproval` means "do not ask", which is safe because a tool is
|
|
143
|
+
* written by whoever runs the server it executes on. A capability runs on
|
|
144
|
+
* someone else's machine, so it requires the field instead.
|
|
145
|
+
*/
|
|
146
|
+
export interface AIAgentToolDef extends Partial<ApprovalPolicy> {
|
|
122
147
|
name: string
|
|
123
148
|
description: string
|
|
124
149
|
inputSchema: Record<string, unknown>
|
|
125
150
|
execute: (input: unknown) => Promise<unknown>
|
|
126
|
-
|
|
127
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Mirrors the pikku function's `readonly` flag. A read that gets interrupted
|
|
153
|
+
* is discarded rather than reported: nothing changed, and by the next turn
|
|
154
|
+
* the data may be stale anyway — re-reading is cheaper than explaining a
|
|
155
|
+
* result the user never asked to hear about.
|
|
156
|
+
*/
|
|
157
|
+
readonly?: boolean
|
|
128
158
|
/**
|
|
129
159
|
* Set only by the framework on sub-agent delegating tools. Such a tool may
|
|
130
160
|
* legitimately return an `__approvalRequired` marker to forward a nested
|
|
@@ -152,6 +182,27 @@ export interface PikkuAIMiddlewareHooks<
|
|
|
152
182
|
event: AIStreamEvent
|
|
153
183
|
allEvents: readonly AIStreamEvent[]
|
|
154
184
|
state: State
|
|
185
|
+
/**
|
|
186
|
+
* Push an event into the stream *after* this call has returned.
|
|
187
|
+
*
|
|
188
|
+
* Returning events blocks the stream until the hook resolves, which is
|
|
189
|
+
* right for anything derived from the event and wrong for anything slow.
|
|
190
|
+
* Speech is the motivating case: awaiting a text-to-speech call before
|
|
191
|
+
* returning the text delta stalls the reader at every full stop and
|
|
192
|
+
* serialises synthesis behind playback. Return the text immediately,
|
|
193
|
+
* start the slow work, and `emit` its result when it lands.
|
|
194
|
+
*
|
|
195
|
+
* Ordering among emitted events is the caller's problem — chain them if
|
|
196
|
+
* it matters — and a hook that emits must make sure anything still
|
|
197
|
+
* outstanding has landed before it lets `done` through.
|
|
198
|
+
*/
|
|
199
|
+
emit: (event: AIStreamEvent) => Promise<void>
|
|
200
|
+
/**
|
|
201
|
+
* Aborts when the run is interrupted. Pass it to any provider call the
|
|
202
|
+
* hook makes: work started for a reply the user has already talked over
|
|
203
|
+
* is billed but never heard.
|
|
204
|
+
*/
|
|
205
|
+
signal?: AbortSignal
|
|
155
206
|
}
|
|
156
207
|
) =>
|
|
157
208
|
| Promise<AIStreamEvent | AIStreamEvent[] | null>
|
|
@@ -232,8 +283,19 @@ export type CoreAIAgent<
|
|
|
232
283
|
description: string
|
|
233
284
|
summary?: string
|
|
234
285
|
errors?: string[]
|
|
286
|
+
/**
|
|
287
|
+
* The three fields below are the system prompt. `buildInstructions` joins
|
|
288
|
+
* whichever are set with a blank line, always in this order — role, then
|
|
289
|
+
* personality, then goal — and appends the tool-usage rules if the agent has
|
|
290
|
+
* tools. Nothing checks them against each other: the split is there to keep a
|
|
291
|
+
* prompt legible, and text put in the wrong one still reaches the model.
|
|
292
|
+
*
|
|
293
|
+
* Who the agent is. 'You are a support engineer triaging inbound bugs.'
|
|
294
|
+
*/
|
|
235
295
|
role?: string
|
|
296
|
+
/** How it should sound: tone, vocabulary, how much it says at a time. */
|
|
236
297
|
personality?: string
|
|
298
|
+
/** What it is for — the only one of the three that is required. */
|
|
237
299
|
goal: string
|
|
238
300
|
model: string
|
|
239
301
|
temperature?: number
|
|
@@ -246,6 +308,16 @@ export type CoreAIAgent<
|
|
|
246
308
|
memory?: AIAgentMemoryConfig
|
|
247
309
|
maxSteps?: number
|
|
248
310
|
toolChoice?: 'auto' | 'required' | 'none'
|
|
311
|
+
/**
|
|
312
|
+
* Per-provider model settings, keyed by provider id and passed through
|
|
313
|
+
* untouched — for anything only one vendor offers, which the fields above
|
|
314
|
+
* deliberately do not try to unify.
|
|
315
|
+
*
|
|
316
|
+
* `{ openai: { reasoningEffort: 'minimal' } }` is the one that matters for
|
|
317
|
+
* voice: on gpt-5-mini it measured 0.9s to first token against 2.5s at the
|
|
318
|
+
* default, and a spoken reply is waited through rather than skimmed.
|
|
319
|
+
*/
|
|
320
|
+
providerOptions?: AIProviderOptions
|
|
249
321
|
input?: unknown
|
|
250
322
|
output?: unknown
|
|
251
323
|
tags?: string[]
|
|
@@ -368,6 +440,15 @@ export type AIStreamEvent =
|
|
|
368
440
|
reason: 'rpc-missing'
|
|
369
441
|
missingRpcs: string[]
|
|
370
442
|
}
|
|
443
|
+
| {
|
|
444
|
+
type: 'interrupted'
|
|
445
|
+
runId: string
|
|
446
|
+
/** The truncated assistant text at the moment generation stopped. */
|
|
447
|
+
text: string
|
|
448
|
+
reason: 'speech' | 'user' | 'timeout'
|
|
449
|
+
agent?: string
|
|
450
|
+
session?: string
|
|
451
|
+
}
|
|
371
452
|
| { type: 'done' }
|
|
372
453
|
|
|
373
454
|
export interface AIStreamChannel extends PikkuChannel<unknown, AIStreamEvent> {}
|
|
@@ -402,7 +483,7 @@ export interface AgentRunState {
|
|
|
402
483
|
agentName: string
|
|
403
484
|
threadId: string
|
|
404
485
|
resourceId: string
|
|
405
|
-
status: 'running' | 'suspended' | 'completed' | 'failed'
|
|
486
|
+
status: 'running' | 'suspended' | 'completed' | 'failed' | 'interrupted'
|
|
406
487
|
errorMessage?: string
|
|
407
488
|
suspendReason?: 'approval' | 'credential' | 'rpc-missing'
|
|
408
489
|
missingRpcs?: string[]
|
|
@@ -3,12 +3,44 @@ export {
|
|
|
3
3
|
agentStream,
|
|
4
4
|
agentResume,
|
|
5
5
|
agentApprove,
|
|
6
|
+
agentInterrupt,
|
|
6
7
|
} from './ai-agent-helpers.js'
|
|
7
8
|
export { wrapChannelWithAGUI, type AGUIEvent } from './ai-agent-agui.js'
|
|
8
9
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js'
|
|
9
|
-
export {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
export {
|
|
11
|
+
streamAIAgent,
|
|
12
|
+
resumeAIAgent,
|
|
13
|
+
interruptAIAgent,
|
|
14
|
+
} from './ai-agent-stream.js'
|
|
15
|
+
export {
|
|
16
|
+
voiceInput,
|
|
17
|
+
readsAsNonSpeech,
|
|
18
|
+
NoSpeechDetectedError,
|
|
19
|
+
} from './voice-input.js'
|
|
20
|
+
export {
|
|
21
|
+
voiceOutput,
|
|
22
|
+
unspeakableScripts,
|
|
23
|
+
voiceForText,
|
|
24
|
+
type SpeakableScripts,
|
|
25
|
+
} from './voice-output.js'
|
|
26
|
+
export {
|
|
27
|
+
AgentInterruptedError,
|
|
28
|
+
awaitPendingInterruptNote,
|
|
29
|
+
getInFlightTools,
|
|
30
|
+
isAbortError,
|
|
31
|
+
isRunInterruptible,
|
|
32
|
+
persistOrphanedToolResults,
|
|
33
|
+
registerInterruptibleRun,
|
|
34
|
+
signalRunInterrupt,
|
|
35
|
+
trackInterruptNote,
|
|
36
|
+
trackToolExecution,
|
|
37
|
+
} from './ai-agent-interrupt.js'
|
|
38
|
+
export type {
|
|
39
|
+
AgentInterruption,
|
|
40
|
+
AgentInterruptResult,
|
|
41
|
+
InterruptibleRunHandle,
|
|
42
|
+
OrphanedToolResult,
|
|
43
|
+
} from './ai-agent-interrupt.js'
|
|
12
44
|
export {
|
|
13
45
|
type RunAIAgentParams,
|
|
14
46
|
type StreamAIAgentOptions,
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { describe, test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
voiceInput,
|
|
6
|
+
readsAsNonSpeech,
|
|
7
|
+
NoSpeechDetectedError,
|
|
8
|
+
} from './voice-input.js'
|
|
5
9
|
import type { AIContentPart, AIMessage } from './ai-agent.types.js'
|
|
6
10
|
|
|
7
|
-
/**
|
|
8
|
-
* A runner whose `transcribe` reads instance state through `this`, mirroring the
|
|
9
|
-
* real `VercelAIAgentRunner` where `transcribe` calls `this.getModel(...)`. If
|
|
10
|
-
* the middleware grabs the method as a bare reference the receiver is lost and
|
|
11
|
-
* `this` is undefined — which is exactly the regression this guards.
|
|
12
|
-
*/
|
|
13
11
|
class ThisDependentRunner {
|
|
14
12
|
private readonly transcript = 'the transcribed spoken words'
|
|
15
13
|
|
|
@@ -87,4 +85,71 @@ describe('voiceInput', () => {
|
|
|
87
85
|
/voiceInput requires a transcription model/
|
|
88
86
|
)
|
|
89
87
|
})
|
|
88
|
+
|
|
89
|
+
test('a turn with no speech in it never reaches the model', async () => {
|
|
90
|
+
// The failure this prevents: the user says nothing, the model answers
|
|
91
|
+
// anyway, and what it answers is a guess about audio it could not hear.
|
|
92
|
+
// An ASR that returns '' on non-speech is what makes this checkable — see
|
|
93
|
+
// readsAsNonSpeech for why nothing subtler than '' survived contact.
|
|
94
|
+
const silent = {
|
|
95
|
+
async transcribe() {
|
|
96
|
+
return { text: '', segments: [], warnings: [] }
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
const mw = voiceInput({
|
|
100
|
+
model: 'deepinfra/nvidia/Nemotron-3.5-ASR-Streaming-Multilingual-0.6b',
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
await assert.rejects(
|
|
104
|
+
() =>
|
|
105
|
+
mw.modifyInput!({ aiAgentRunner: silent } as any, {
|
|
106
|
+
messages: [audioMessage()],
|
|
107
|
+
instructions: 'sys',
|
|
108
|
+
}),
|
|
109
|
+
NoSpeechDetectedError
|
|
110
|
+
)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('a transcript is passed through exactly as the provider wrote it', async () => {
|
|
114
|
+
// No reassembly, no trimming, no filtering — whatever the model heard is
|
|
115
|
+
// what the agent is asked about.
|
|
116
|
+
const spaced = {
|
|
117
|
+
async transcribe() {
|
|
118
|
+
return {
|
|
119
|
+
text: ' spacing the provider chose ',
|
|
120
|
+
segments: [],
|
|
121
|
+
warnings: [],
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
const mw = voiceInput({ model: 'mock/asr' })
|
|
126
|
+
|
|
127
|
+
const result = await mw.modifyInput!({ aiAgentRunner: spaced } as any, {
|
|
128
|
+
messages: [audioMessage()],
|
|
129
|
+
instructions: 'sys',
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const parts = result.messages.at(-1)!.content as AIContentPart[]
|
|
133
|
+
assert.equal(
|
|
134
|
+
(parts[0] as { text: string }).text,
|
|
135
|
+
' spacing the provider chose '
|
|
136
|
+
)
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
describe('readsAsNonSpeech', () => {
|
|
141
|
+
test('only an empty transcript counts as nothing said', () => {
|
|
142
|
+
assert.equal(readsAsNonSpeech({ text: '' }), true)
|
|
143
|
+
assert.equal(readsAsNonSpeech({ text: ' ' }), true)
|
|
144
|
+
assert.equal(readsAsNonSpeech({}), true)
|
|
145
|
+
assert.equal(readsAsNonSpeech({ text: 'add milk to the list' }), false)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
test('a short or low-confidence-looking transcript is still speech', () => {
|
|
149
|
+
// The gate that used to live here would have been tempted by these. "Yes"
|
|
150
|
+
// is the single most important word in an approval flow, and dropping it
|
|
151
|
+
// because it is brief or quiet is far worse than keeping a stray one.
|
|
152
|
+
assert.equal(readsAsNonSpeech({ text: 'yes' }), false)
|
|
153
|
+
assert.equal(readsAsNonSpeech({ text: 'Thank you.' }), false)
|
|
154
|
+
})
|
|
90
155
|
})
|
|
@@ -14,6 +14,46 @@ function base64ToUint8Array(base64: string): Uint8Array {
|
|
|
14
14
|
|
|
15
15
|
const MAX_AUDIO_SIZE = 50 * 1024 * 1024
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Raised when every audio part in a turn turned out to be non-speech.
|
|
19
|
+
*
|
|
20
|
+
* Distinct from a transcription failure, because the response is different: a
|
|
21
|
+
* failure is worth reporting, whereas this is the microphone doing its job on a
|
|
22
|
+
* pause. A voice loop should catch it and go back to listening without running
|
|
23
|
+
* the agent — answering a hallucinated sentence is worse than answering nothing.
|
|
24
|
+
*/
|
|
25
|
+
export class NoSpeechDetectedError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super('No speech was detected in the audio.')
|
|
28
|
+
this.name = 'NoSpeechDetectedError'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Whether nothing usable was said — an empty transcript, and nothing cleverer
|
|
34
|
+
* than that.
|
|
35
|
+
*
|
|
36
|
+
* There was a confidence gate here once, and it is worth recording why it is
|
|
37
|
+
* gone. Whisper is trained on subtitles, so audio it cannot parse comes back
|
|
38
|
+
* not as nothing but as stock filler appended to real speech: "Hello, my name
|
|
39
|
+
* is Yasir. Thank you." where only the first sentence was spoken. The obvious
|
|
40
|
+
* defence is to drop low-confidence segments, and it does not work. Measured on
|
|
41
|
+
* a real turn, the invented "Thank you." scored `avg_logprob` -0.52 against
|
|
42
|
+
* -0.30 for the genuine sentence beside it, and `no_speech_prob` read 0.000 for
|
|
43
|
+
* both. Whisper is *confident* when it invents, because the text it invents is
|
|
44
|
+
* high-probability text. No threshold separates those two numbers, and one set
|
|
45
|
+
* low enough to try would take real quiet speech with it.
|
|
46
|
+
*
|
|
47
|
+
* The fix belongs at the model, not behind it: an ASR that is not a
|
|
48
|
+
* subtitle-trained autoregressive decoder returns an empty string on non-speech
|
|
49
|
+
* and there is nothing left to filter. Hence this reduces to asking whether
|
|
50
|
+
* anything came back at all — which is a property every provider reports
|
|
51
|
+
* honestly, unlike per-segment confidence (Nemotron, for one, hardcodes
|
|
52
|
+
* `avg_logprob` to 0.0).
|
|
53
|
+
*/
|
|
54
|
+
export const readsAsNonSpeech = (result: { text?: string }): boolean =>
|
|
55
|
+
!(result.text ?? '').trim()
|
|
56
|
+
|
|
17
57
|
async function fetchAsUint8Array(
|
|
18
58
|
url: string,
|
|
19
59
|
allowedAudioHosts?: string[]
|
|
@@ -57,9 +97,6 @@ export const voiceInput = (config?: {
|
|
|
57
97
|
)
|
|
58
98
|
if (!hasAudio) return { messages, instructions }
|
|
59
99
|
|
|
60
|
-
// Process parts in order, replacing each audio part with its transcription
|
|
61
|
-
// in place. Sequential, so no unbounded parallel downloads/transcriptions
|
|
62
|
-
// and original content ordering is preserved.
|
|
63
100
|
const updatedContent: AIContentPart[] = []
|
|
64
101
|
for (const p of parts) {
|
|
65
102
|
if (!(p.type === 'file' && p.mediaType?.startsWith('audio/'))) {
|
|
@@ -87,9 +124,17 @@ export const voiceInput = (config?: {
|
|
|
87
124
|
}
|
|
88
125
|
: {}),
|
|
89
126
|
})
|
|
127
|
+
// Dropped when nothing was said: an empty text part is still a turn the
|
|
128
|
+
// model will answer, and what it answers is a guess about what it could
|
|
129
|
+
// not hear.
|
|
130
|
+
if (readsAsNonSpeech(result)) continue
|
|
90
131
|
updatedContent.push({ type: 'text' as const, text: result.text })
|
|
91
132
|
}
|
|
92
133
|
|
|
134
|
+
// Every part was audio, and none of it was speech. There is nothing left
|
|
135
|
+
// to send, and a message with no content is not a question.
|
|
136
|
+
if (updatedContent.length === 0) throw new NoSpeechDetectedError()
|
|
137
|
+
|
|
93
138
|
return {
|
|
94
139
|
messages: [
|
|
95
140
|
...messages.slice(0, -1),
|