@pikku/core 0.12.72 → 0.12.77
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 +1171 -0
- package/dist/column-form.d.ts +32 -0
- package/dist/column-form.js +42 -0
- package/dist/crypto-utils.d.ts +43 -7
- package/dist/crypto-utils.js +163 -42
- package/dist/data-classification.d.ts +44 -0
- 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 +57 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/index.d.ts +1 -1
- 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 +11 -5
- package/dist/index.js +7 -2
- 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 +5 -41
- 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 +4 -3
- 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 +9 -8
- 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/secret-value.d.ts +56 -0
- package/dist/secret-value.js +46 -0
- 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.d.ts +74 -4
- package/dist/services/audit-service.js +8 -7
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/credential-wire-service.d.ts +5 -0
- package/dist/services/credential-wire-service.js +9 -1
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/email-service.d.ts +2 -1
- 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 +8 -9
- package/dist/services/index.js +3 -6
- 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-request-handler.d.ts +29 -0
- package/dist/services/local-content-request-handler.js +176 -0
- 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 +4 -7
- package/dist/services/local-secrets.js +7 -7
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +22 -40
- 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 +10 -42
- 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 +4 -7
- 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 +12 -35
- 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 +5 -11
- 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 +21 -64
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +6 -23
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +120 -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 +46 -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 +65 -132
- 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 +63 -22
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +180 -64
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +124 -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 +59 -1
- package/dist/wirings/ai-agent/voice-input.js +90 -12
- package/dist/wirings/ai-agent/voice-output.d.ts +69 -1
- package/dist/wirings/ai-agent/voice-output.js +162 -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 +38 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +129 -0
- package/dist/wirings/cli/channel/index.d.ts +5 -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 +32 -0
- package/dist/wirings/persona/define-personas.js +31 -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 +136 -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 +103 -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 +20 -90
- 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 +17 -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 +3 -13
- package/dist/wirings/rpc/remote-addon-auth.js +7 -11
- 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 +30 -0
- package/dist/wirings/virtual-user/index.js +10 -0
- package/dist/wirings/virtual-user/prepare-virtual-user-run.d.ts +54 -0
- package/dist/wirings/virtual-user/prepare-virtual-user-run.js +49 -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-run-store.d.ts +90 -0
- package/dist/wirings/virtual-user/virtual-user-run-store.js +1 -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 +19 -15
- 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 -43
- 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 +1 -19
- 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 +84 -12
- 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 +5 -195
- 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/a-virtual-user-run-is-not-a-workflow-and-not-a-queued-job.md +48 -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-column-form-is-an-axis-of-its-own.md +84 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +41 -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 +117 -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/one-project-shape-check-two-validators.md +53 -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/scenarios-live-in-files-named-for-them.md +48 -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/validate-checks-personas-through-a-shared-module.md +43 -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 +6 -2
- package/run-tests.sh +0 -0
- package/src/column-form.test.ts +97 -0
- package/src/column-form.ts +58 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +306 -59
- package/src/data-classification.ts +45 -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 +95 -138
- package/src/function/index.ts +1 -0
- 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 +84 -3
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +3 -5
- package/src/middleware/auth-bearer.ts +5 -41
- 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 +26 -10
- package/src/middleware/remote-auth.ts +11 -3
- 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 +173 -0
- package/src/remote.ts +18 -8
- package/src/schema.ts +5 -39
- package/src/scopes.ts +7 -48
- package/src/secret-value.test.ts +204 -0
- package/src/secret-value.ts +111 -0
- 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 +88 -11
- 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/credential-wire-service.ts +9 -1
- package/src/services/deployment-service.ts +3 -9
- package/src/services/email-service.ts +3 -1
- 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 +23 -18
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content-request-handler.test.ts +202 -0
- package/src/services/local-content-request-handler.ts +267 -0
- 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.test.ts +20 -5
- package/src/services/local-secrets.ts +15 -11
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +31 -46
- 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.test.ts +2 -1
- package/src/services/queue-webhook-service.ts +10 -42
- 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 +4 -7
- 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 +12 -35
- 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 +12 -14
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +23 -64
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +6 -32
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +137 -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 +91 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +49 -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 +89 -139
- 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 +85 -35
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +224 -76
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +130 -5
- package/src/wirings/ai-agent/index.ts +37 -3
- package/src/wirings/ai-agent/voice-input.test.ts +137 -7
- package/src/wirings/ai-agent/voice-input.ts +96 -12
- package/src/wirings/ai-agent/voice-output.test.ts +512 -0
- package/src/wirings/ai-agent/voice-output.ts +243 -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 +185 -0
- package/src/wirings/cli/channel/index.ts +13 -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 +33 -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 +142 -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 +454 -0
- package/src/wirings/queue/queue-identity.ts +176 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +25 -90
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +60 -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 +9 -16
- package/src/wirings/rpc/rpc-runner.test.ts +192 -6
- 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 +88 -0
- package/src/wirings/virtual-user/prepare-virtual-user-run.test.ts +115 -0
- package/src/wirings/virtual-user/prepare-virtual-user-run.ts +95 -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-run-store.ts +98 -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 +19 -20
- 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 -61
- 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.test.ts +5 -7
- package/src/wirings/workflow/scenario-prose.ts +1 -29
- package/src/wirings/workflow/scenario-service.test.ts +2 -10
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +163 -19
- package/src/wirings/workflow/scenario-step.types.ts +94 -12
- package/src/wirings/workflow/scenario-surface.test.ts +146 -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 +5 -201
- package/tsconfig.tsbuildinfo +1 -1
- package/tsconfig.type-tests.json +12 -0
- 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
|
@@ -6,118 +6,72 @@ import { verifyScopes } from '../../scopes.js';
|
|
|
6
6
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
7
7
|
import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js';
|
|
8
8
|
import { randomUUID } from './ai-agent-utils.js';
|
|
9
|
+
import { awaitPendingInterruptNote } from './ai-agent-interrupt.js';
|
|
9
10
|
import { streamAIAgent } from './ai-agent-stream.js';
|
|
10
11
|
import { runAIAgent } from './ai-agent-runner.js';
|
|
11
12
|
import { resolveNamespace, ContextAwareRPCService, } from '../../wirings/rpc/rpc-runner.js';
|
|
12
13
|
import { getOrCreatePackageSingletonServices } from '../../wirings/rpc/addon-runner.js';
|
|
13
14
|
import { resolveMemoryServices, loadContextMessages, trimMessages, } from './ai-agent-memory.js';
|
|
14
15
|
import { resolveModelConfig } from './ai-agent-model-config.js';
|
|
15
|
-
|
|
16
|
-
* The ownership key for a thread/run: the trusted principal (the authenticated
|
|
17
|
-
* `session.userId` for `'user'` scope, or `session.orgId` for `'org'` scope)
|
|
18
|
-
* composed with the client-supplied `resourceId` as a sub-partition —
|
|
19
|
-
* `principal:resourceId`. Because the principal is always the prefix, a client
|
|
20
|
-
* `resourceId` can sub-divide within the caller's own boundary but can never
|
|
21
|
-
* widen access to another user's or org's threads.
|
|
22
|
-
*
|
|
23
|
-
* Idempotent: a value that is already within the caller's namespace (top-level
|
|
24
|
-
* re-entry, sub-agent recursion, or resume, which all pass an already-composite
|
|
25
|
-
* `resourceId`) is returned unchanged rather than double-composed.
|
|
26
|
-
*
|
|
27
|
-
* `'org'` scope with no session org throws {@link ForbiddenError} — falling back
|
|
28
|
-
* to a bare/shared key would leak across organizations. Sessionless `'user'`
|
|
29
|
-
* wirings have no trusted principal and fall back to the requested `resourceId`
|
|
30
|
-
* as a best-effort partition key.
|
|
31
|
-
*/
|
|
32
|
-
export function resolveOwnerResourceId(params, sessionScope, requestedResourceId) {
|
|
16
|
+
export function resolveSessionPrincipal(params, sessionScope) {
|
|
33
17
|
const session = params.sessionService?.get();
|
|
34
|
-
let principal;
|
|
35
18
|
if ((sessionScope ?? 'user') === 'org') {
|
|
36
19
|
if (!session?.orgId) {
|
|
37
20
|
throw new ForbiddenError('This agent is org-scoped but the session has no organization');
|
|
38
21
|
}
|
|
39
|
-
|
|
22
|
+
return session.orgId;
|
|
40
23
|
}
|
|
41
|
-
|
|
42
|
-
|
|
24
|
+
return session?.userId;
|
|
25
|
+
}
|
|
26
|
+
export function resolveOwnerResourceId(params, sessionScope, requestedResourceId) {
|
|
27
|
+
const principal = resolveSessionPrincipal(params, sessionScope);
|
|
28
|
+
if (!principal) {
|
|
29
|
+
params.anonymousOwnerResourceId ??= `anon-${randomUUID()}`;
|
|
30
|
+
return params.anonymousOwnerResourceId;
|
|
43
31
|
}
|
|
44
|
-
if (!principal)
|
|
45
|
-
return requestedResourceId;
|
|
46
32
|
if (requestedResourceId === principal ||
|
|
47
33
|
requestedResourceId.startsWith(`${principal}:`)) {
|
|
48
34
|
return requestedResourceId;
|
|
49
35
|
}
|
|
50
36
|
return `${principal}:${requestedResourceId}`;
|
|
51
37
|
}
|
|
52
|
-
|
|
38
|
+
export function assertResourcePrincipalOwner(params, sessionScope, storedResourceId, kind) {
|
|
39
|
+
const principal = resolveSessionPrincipal(params, sessionScope);
|
|
40
|
+
if (!principal || !isOwnedByPrincipal(storedResourceId, principal)) {
|
|
41
|
+
throw new ForbiddenError(`Not authorized to access this ${kind}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
53
44
|
export function agentSessionScope(agentName) {
|
|
54
45
|
return resolveAgent(agentName).agent.sessionScope ?? 'user';
|
|
55
46
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Enforce that a stored thread/run belongs to the caller's owner resource,
|
|
58
|
-
* throwing {@link ForbiddenError} (without echoing the id, to avoid an
|
|
59
|
-
* existence oracle) on a mismatch.
|
|
60
|
-
*/
|
|
61
47
|
export function assertResourceOwner(ownerResourceId, storedResourceId, kind) {
|
|
62
48
|
if (storedResourceId !== ownerResourceId) {
|
|
63
49
|
throw new ForbiddenError(`Not authorized to access this ${kind}`);
|
|
64
50
|
}
|
|
65
51
|
}
|
|
66
|
-
/** A session's trusted principals, in the order they may be read as. */
|
|
67
52
|
export function sessionPrincipals(session) {
|
|
68
53
|
return [session?.userId, session?.orgId].filter((principal) => Boolean(principal));
|
|
69
54
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Whether `storedResourceId` belongs to `principal` under the composition
|
|
72
|
-
* {@link resolveOwnerResourceId} performs — either the bare principal or one of
|
|
73
|
-
* its `principal:` sub-partitions. The `:` is required so that `alice` does not
|
|
74
|
-
* match a `alice-evil:…` lookalike.
|
|
75
|
-
*/
|
|
76
55
|
export function isOwnedByPrincipal(storedResourceId, principal) {
|
|
77
56
|
return (storedResourceId === principal ||
|
|
78
57
|
storedResourceId.startsWith(`${principal}:`));
|
|
79
58
|
}
|
|
80
|
-
/**
|
|
81
|
-
* The `owners` constraint to pass to `AgentRunService.listThreads` for a caller.
|
|
82
|
-
*
|
|
83
|
-
* Returns `undefined` — not `[]` — for a session with no principal, because an
|
|
84
|
-
* empty list means "match nothing" whereas a sessionless deployment (agent
|
|
85
|
-
* `no-auth`) has no ownership model to constrain by. Keeping that carve-out here
|
|
86
|
-
* rather than at each call site stops it from being re-derived inconsistently.
|
|
87
|
-
*/
|
|
88
59
|
export function threadOwnerConstraint(session) {
|
|
89
|
-
|
|
90
|
-
return principals.length > 0 ? principals : undefined;
|
|
60
|
+
return sessionPrincipals(session);
|
|
91
61
|
}
|
|
92
|
-
/**
|
|
93
|
-
* Whether a stored thread/run may be read by the caller. Shaped as a predicate
|
|
94
|
-
* so it can back a `pikkuPermission` — authorization belongs in a function's
|
|
95
|
-
* `permissions` field, never in its body.
|
|
96
|
-
*
|
|
97
|
-
* Unlike {@link assertResourceOwner}, which compares against a single composed
|
|
98
|
-
* owner key on the run path, this guards the thread-management reads where the
|
|
99
|
-
* caller supplies only a `threadId` — so ownership has to be derived from the
|
|
100
|
-
* session rather than from the request.
|
|
101
|
-
*
|
|
102
|
-
* A session with no principal means the deployment opted out of authorization
|
|
103
|
-
* (agent `no-auth`), so there is no ownership model to enforce and access is not
|
|
104
|
-
* gated — mirroring {@link resolveOwnerResourceId}'s sessionless fallback to a
|
|
105
|
-
* bare resourceId.
|
|
106
|
-
*/
|
|
107
62
|
export function canAccessThread(storedResourceId, session) {
|
|
108
63
|
const principals = sessionPrincipals(session);
|
|
109
64
|
if (principals.length === 0)
|
|
110
|
-
return
|
|
65
|
+
return false;
|
|
111
66
|
return principals.some((principal) => isOwnedByPrincipal(storedResourceId, principal));
|
|
112
67
|
}
|
|
68
|
+
export const APPROVAL_REQUIRED = Symbol('pikku.ai.approvalRequired');
|
|
113
69
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* so `checkForApprovals` trusts the brand rather than the `__approvalRequired`
|
|
118
|
-
* string key to decide an approval must be surfaced.
|
|
70
|
+
* In-process brand proving a credential request was produced by pikku itself and
|
|
71
|
+
* not by tool output an attacker can influence. Never serialized — a value that
|
|
72
|
+
* has crossed a JSON boundary has lost the brand and is treated as untrusted.
|
|
119
73
|
*/
|
|
120
|
-
export const
|
|
74
|
+
export const CREDENTIAL_REQUIRED = Symbol('pikku.ai.credentialRequired');
|
|
121
75
|
export class ToolApprovalRequired extends PikkuError {
|
|
122
76
|
toolCallId;
|
|
123
77
|
toolName;
|
|
@@ -154,10 +108,6 @@ export class ToolCredentialRequired extends PikkuError {
|
|
|
154
108
|
this.connectUrl = connectUrl;
|
|
155
109
|
}
|
|
156
110
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Given a list of tool names (e.g. ["oauth-api:getProfile"]),
|
|
159
|
-
* returns the wire OAuth credentials required by their addons.
|
|
160
|
-
*/
|
|
161
111
|
export function getAddonCredentialRequirements(toolNames) {
|
|
162
112
|
const requirements = new Map();
|
|
163
113
|
for (const toolName of toolNames) {
|
|
@@ -211,26 +161,6 @@ export const resolveAgent = (agentName) => {
|
|
|
211
161
|
}
|
|
212
162
|
throw new Error(`AI agent not found: ${agentName}`);
|
|
213
163
|
};
|
|
214
|
-
/**
|
|
215
|
-
* Enforces an agent's own authorization before it runs: session presence
|
|
216
|
-
* (`auth`), then `scopes`, then `permissions`.
|
|
217
|
-
*
|
|
218
|
-
* The ordering mirrors the function runner — scopes are an AND gate checked
|
|
219
|
-
* first, so they can only ever narrow access, and a missing scope short-circuits
|
|
220
|
-
* before any permission function does I/O.
|
|
221
|
-
*
|
|
222
|
-
* `auth` follows `pikkuSessionlessFunc` rather than `pikkuFunc`: a session is
|
|
223
|
-
* required only when `auth: true` is set explicitly. An agent is normally
|
|
224
|
-
* reached from a function that has already enforced its own auth, and agents are
|
|
225
|
-
* also run from genuinely sessionless contexts (crons, queue workers), so
|
|
226
|
-
* requiring a session by default would reject those without adding a meaningful
|
|
227
|
-
* gate. `scopes` and `permissions` are always enforced when declared.
|
|
228
|
-
*
|
|
229
|
-
* Globals are evaluated here too (via {@link runPermissions}) rather than being
|
|
230
|
-
* assumed to have already run: an agent is reachable from entry points that do
|
|
231
|
-
* not go through the function runner, and re-evaluating an AND gate of
|
|
232
|
-
* side-effect-free predicates is idempotent.
|
|
233
|
-
*/
|
|
234
164
|
export async function assertAgentAuthorized(agent, params, packageName) {
|
|
235
165
|
const session = params.sessionService
|
|
236
166
|
? await params.sessionService.get()
|
|
@@ -322,31 +252,13 @@ export function createScopedChannel(parent, agentName, session) {
|
|
|
322
252
|
setState: (s) => parent.setState(s),
|
|
323
253
|
getState: () => parent.getState(),
|
|
324
254
|
clearState: () => parent.clearState(),
|
|
255
|
+
remote: (funcName, data) => parent.remote(funcName, data),
|
|
325
256
|
};
|
|
326
257
|
}
|
|
327
|
-
/**
|
|
328
|
-
* Build the run input for a delegated sub-agent.
|
|
329
|
-
*
|
|
330
|
-
* `context` is the PARENT run's identifier block (the "Current context" text
|
|
331
|
-
* with organizationId, project/stage ids). A sub-agent's tool-call schema only
|
|
332
|
-
* carries { message, session }, so unless the sub-agent inherits the parent's
|
|
333
|
-
* context it never sees the authoritative ids — it depends on the model
|
|
334
|
-
* re-typing them into `message`, which weak models botch, causing
|
|
335
|
-
* schema/permission rejections and retry loops. Forwarding it here is the
|
|
336
|
-
* regression this seam guards.
|
|
337
|
-
*/
|
|
338
258
|
export function buildSubAgentRunInput(message, threadId, resourceId, parentContext) {
|
|
339
259
|
return { message, threadId, resourceId, context: parentContext };
|
|
340
260
|
}
|
|
341
|
-
export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares, agentMode,
|
|
342
|
-
// The parent run's `context` (the "Current context" identifier block). A
|
|
343
|
-
// delegated sub-agent's tool-call input schema only carries { message,
|
|
344
|
-
// session }, so without inheriting this the sub-agent never sees the
|
|
345
|
-
// authoritative ids (organizationId, project/stage ids) — it depends on the
|
|
346
|
-
// model re-typing them into `message`, which weak models botch, causing
|
|
347
|
-
// schema/permission rejections and retry loops. Forward it so the sub-agent
|
|
348
|
-
// gets the same context block in its instructions.
|
|
349
|
-
parentContext) {
|
|
261
|
+
export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, aiMiddlewares, agentMode, parentContext) {
|
|
350
262
|
const singletonServices = getSingletonServices();
|
|
351
263
|
const tools = [];
|
|
352
264
|
const missingRpcs = [];
|
|
@@ -354,7 +266,22 @@ parentContext) {
|
|
|
354
266
|
const meta = pikkuState(packageName, 'agent', 'agentsMeta')[agentName];
|
|
355
267
|
if (!meta)
|
|
356
268
|
return { tools, missingRpcs };
|
|
357
|
-
|
|
269
|
+
/**
|
|
270
|
+
* A tool's description is what the model is told it does, and the main thing
|
|
271
|
+
* it chooses between tools on. It does not survive into the meta registered at
|
|
272
|
+
* boot: `description` is classed as a verbose field, so the bundled copy has
|
|
273
|
+
* it stripped and `fnMeta.description` is always undefined — every tool was
|
|
274
|
+
* being offered under its own bare name regardless of what its author wrote.
|
|
275
|
+
*
|
|
276
|
+
* `getFunctionsMeta` reads the verbose file and falls back to the minimal one,
|
|
277
|
+
* recovering the authored description wherever the generated `.pikku`
|
|
278
|
+
* directory is readable. Where it is not — no `metaService`, or a deployment
|
|
279
|
+
* shipping only the stripped copy — tools fall back to their name, which is
|
|
280
|
+
* what they did before this lookup existed.
|
|
281
|
+
*/
|
|
282
|
+
const describedFunctions = await singletonServices.metaService
|
|
283
|
+
?.getFunctionsMeta()
|
|
284
|
+
.catch(() => undefined);
|
|
358
285
|
const session = params.sessionService
|
|
359
286
|
? await params.sessionService.get()
|
|
360
287
|
: null;
|
|
@@ -389,10 +316,6 @@ parentContext) {
|
|
|
389
316
|
missingRpcs.push(toolName);
|
|
390
317
|
continue;
|
|
391
318
|
}
|
|
392
|
-
// Filter out tools the user doesn't have auth for. The `pikkuAuth` brand
|
|
393
|
-
// only survives on the live permission objects in the function config, so
|
|
394
|
-
// the check reads those rather than the metadata (whose by-name registry
|
|
395
|
-
// is never populated, which would let every gated tool through).
|
|
396
319
|
if (fnMeta.permissions?.length) {
|
|
397
320
|
if (!session)
|
|
398
321
|
continue;
|
|
@@ -415,7 +338,6 @@ parentContext) {
|
|
|
415
338
|
}
|
|
416
339
|
const needsApproval = approvalPolicy === 'all' ||
|
|
417
340
|
(approvalPolicy === 'explicit' && fnMeta?.approvalRequired);
|
|
418
|
-
// Build approvalDescriptionFn if the function has an approvalDescription configured
|
|
419
341
|
let approvalDescriptionFn;
|
|
420
342
|
if (needsApproval && pikkuFuncId) {
|
|
421
343
|
const funcConfig = pikkuState(resolvedPkg, 'function', 'functions').get(pikkuFuncId);
|
|
@@ -445,10 +367,13 @@ parentContext) {
|
|
|
445
367
|
}
|
|
446
368
|
tools.push({
|
|
447
369
|
name: toolName.replaceAll('@', '_').replaceAll(':', '__'),
|
|
448
|
-
description:
|
|
370
|
+
description: describedFunctions?.[pikkuFuncId]?.description ||
|
|
371
|
+
fnMeta?.description ||
|
|
372
|
+
toolName,
|
|
449
373
|
inputSchema,
|
|
450
374
|
needsApproval: needsApproval || undefined,
|
|
451
375
|
approvalDescriptionFn,
|
|
376
|
+
readonly: fnMeta?.readonly || undefined,
|
|
452
377
|
execute: async (toolInput) => {
|
|
453
378
|
const wire = params.sessionService
|
|
454
379
|
? { ...createMiddlewareSessionWireProps(params.sessionService) }
|
|
@@ -467,8 +392,6 @@ parentContext) {
|
|
|
467
392
|
singletonServices.logger.warn(`Sub-agent '${subAgentName}' not found in agent registry`);
|
|
468
393
|
continue;
|
|
469
394
|
}
|
|
470
|
-
// Filter out sub-agents the user doesn't have auth for, reading the live
|
|
471
|
-
// agent config for the same reason the tool path does.
|
|
472
395
|
if (subMeta.permissions?.length) {
|
|
473
396
|
if (!session)
|
|
474
397
|
continue;
|
|
@@ -513,8 +436,6 @@ parentContext) {
|
|
|
513
436
|
input: message,
|
|
514
437
|
});
|
|
515
438
|
const subChannel = createScopedChannel(channel, subAgentName, session);
|
|
516
|
-
// In supervise mode, suppress sub-agent text from reaching the client.
|
|
517
|
-
// Approvals still flow through normally.
|
|
518
439
|
const effectiveChannel = isDelegate
|
|
519
440
|
? subChannel
|
|
520
441
|
: {
|
|
@@ -545,7 +466,6 @@ parentContext) {
|
|
|
545
466
|
});
|
|
546
467
|
return resultText;
|
|
547
468
|
}
|
|
548
|
-
// No stream context: sub-agent runs non-streaming
|
|
549
469
|
const result = await runAIAgent(subAgentName, buildSubAgentRunInput(message, threadId, resourceId, parentContext), params, agentSessionMap);
|
|
550
470
|
if (result.status === 'suspended' &&
|
|
551
471
|
result.pendingApprovals?.length) {
|
|
@@ -610,11 +530,6 @@ parentContext) {
|
|
|
610
530
|
});
|
|
611
531
|
}
|
|
612
532
|
}
|
|
613
|
-
// A tool's execute() can throw (bad input, RPC failure, DB error, ...). The AI
|
|
614
|
-
// SDK catches that at the tool-call boundary and turns it into a conversational
|
|
615
|
-
// "tool error" reply — without this, the exception never reaches pikku's own
|
|
616
|
-
// logger, so a failing tool is undiagnosable server-side. Log unconditionally,
|
|
617
|
-
// even when no aiMiddleware afterToolCall hook is registered to see it.
|
|
618
533
|
for (const tool of tools) {
|
|
619
534
|
const originalExecute = tool.execute;
|
|
620
535
|
tool.execute = async (toolInput) => {
|
|
@@ -622,6 +537,13 @@ parentContext) {
|
|
|
622
537
|
return await originalExecute(toolInput);
|
|
623
538
|
}
|
|
624
539
|
catch (err) {
|
|
540
|
+
if (err?.payload?.error === 'missing_credential') {
|
|
541
|
+
return {
|
|
542
|
+
[CREDENTIAL_REQUIRED]: true,
|
|
543
|
+
__credentialRequired: true,
|
|
544
|
+
...err.payload,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
625
547
|
singletonServices.logger.error(`AI agent tool '${tool.name}' threw during execute()`, err);
|
|
626
548
|
throw err;
|
|
627
549
|
}
|
|
@@ -726,6 +648,11 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
|
|
|
726
648
|
}
|
|
727
649
|
let messages = [];
|
|
728
650
|
if (storage) {
|
|
651
|
+
// A tool whose run was interrupted may still be writing its result to this
|
|
652
|
+
// thread. In voice the next turn lands within a second or two, so without
|
|
653
|
+
// this the model would load context that is missing the very thing it is
|
|
654
|
+
// about to be asked about.
|
|
655
|
+
await awaitPendingInterruptNote(threadId);
|
|
729
656
|
messages = await storage.getMessages(threadId, {
|
|
730
657
|
lastN: memoryConfig?.lastMessages ?? 20,
|
|
731
658
|
});
|
|
@@ -733,7 +660,13 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
|
|
|
733
660
|
const contextMessages = await loadContextMessages(memoryConfig, storage, input, workingMemoryJsonSchema);
|
|
734
661
|
const userContent = input.attachments?.length
|
|
735
662
|
? [
|
|
736
|
-
|
|
663
|
+
// Omitted when there is nothing to say. An attachment on its own is a
|
|
664
|
+
// real turn — a spoken one carries audio and no text at all — and an
|
|
665
|
+
// empty text part alongside it is a part providers are entitled to
|
|
666
|
+
// reject, for a caller who never wrote one.
|
|
667
|
+
...(input.message
|
|
668
|
+
? [{ type: 'text', text: input.message }]
|
|
669
|
+
: []),
|
|
737
670
|
...input.attachments.map((a) => ({
|
|
738
671
|
type: a.type,
|
|
739
672
|
data: a.data,
|
|
@@ -758,7 +691,6 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
|
|
|
758
691
|
instructions = `${instructions}\n\nCurrent context (use these identifiers directly in tool calls — do not ask the user for them):\n${input.context}`;
|
|
759
692
|
}
|
|
760
693
|
const resolved = resolveModelConfig(resolvedName, agent);
|
|
761
|
-
// Per-request overrides
|
|
762
694
|
if (input.model) {
|
|
763
695
|
resolved.model = resolveModelConfig(resolvedName, {
|
|
764
696
|
...agent,
|
|
@@ -777,6 +709,7 @@ export async function prepareAgentRun(agentName, input, params, agentSessionMap,
|
|
|
777
709
|
tools,
|
|
778
710
|
maxSteps: 1,
|
|
779
711
|
toolChoice: agent.toolChoice ?? 'auto',
|
|
712
|
+
providerOptions: agent.providerOptions,
|
|
780
713
|
outputSchema,
|
|
781
714
|
};
|
|
782
715
|
return {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { CoreAIAgent } from './ai-agent.types.js';
|
|
2
2
|
import type { AIRunStateService } from '../../services/ai-run-state-service.js';
|
|
3
|
+
import { type RunAIAgentParams } from './ai-agent-prepare.js';
|
|
3
4
|
export declare const addAIAgent: (agentName: string, agent: CoreAIAgent<any, any>, packageName?: string | null) => void;
|
|
4
5
|
export declare function approveAIAgent(aiRunState: AIRunStateService, runId: string, approvals: {
|
|
5
6
|
toolCallId: string;
|
|
6
7
|
approved: boolean;
|
|
7
|
-
}[], expectedAgentName?: string): Promise<{
|
|
8
|
+
}[], expectedAgentName?: string, params?: RunAIAgentParams): Promise<{
|
|
8
9
|
status: 'resumed' | 'suspended';
|
|
9
10
|
runId: string;
|
|
10
11
|
approved: string[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pikkuState } from '../../pikku-state.js';
|
|
2
|
+
import { agentSessionScope, assertAgentAuthorized, assertResourcePrincipalOwner, resolveAgent, } from './ai-agent-prepare.js';
|
|
2
3
|
export const addAIAgent = (agentName, agent, packageName = null) => {
|
|
3
4
|
const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta');
|
|
4
5
|
const agentMeta = agentsMeta[agentName];
|
|
@@ -12,17 +13,20 @@ export const addAIAgent = (agentName, agent, packageName = null) => {
|
|
|
12
13
|
}
|
|
13
14
|
agents.set(agentName, agent);
|
|
14
15
|
};
|
|
15
|
-
export async function approveAIAgent(aiRunState, runId, approvals, expectedAgentName) {
|
|
16
|
+
export async function approveAIAgent(aiRunState, runId, approvals, expectedAgentName, params = {}) {
|
|
16
17
|
if (!aiRunState)
|
|
17
18
|
throw new Error('AIRunStateService not available');
|
|
18
19
|
const run = await aiRunState.getRun(runId);
|
|
19
20
|
if (!run)
|
|
20
21
|
throw new Error('Run not found: ' + runId);
|
|
22
|
+
assertResourcePrincipalOwner(params, agentSessionScope(run.agentName), run.resourceId, 'run');
|
|
21
23
|
if (expectedAgentName && run.agentName !== expectedAgentName) {
|
|
22
24
|
throw new Error(`Run ${runId} belongs to agent '${run.agentName}', not '${expectedAgentName}'`);
|
|
23
25
|
}
|
|
24
26
|
if (run.status !== 'suspended')
|
|
25
27
|
throw new Error('Run is not suspended: ' + run.status);
|
|
28
|
+
const { agent, packageName } = resolveAgent(run.agentName);
|
|
29
|
+
await assertAgentAuthorized(agent, params, packageName);
|
|
26
30
|
const approvedIds = new Set(approvals.filter((a) => a.approved).map((a) => a.toolCallId));
|
|
27
31
|
const rejectedIds = new Set(approvals.filter((a) => !a.approved).map((a) => a.toolCallId));
|
|
28
32
|
const remaining = (run.pendingApprovals ?? []).filter((p) => !approvedIds.has(p.toolCallId) && !rejectedIds.has(p.toolCallId));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { saveMessages, resolveMemoryServices, loadContextMessages, trimMessages, getWorkingMemoryMiddleware, } from './ai-agent-memory.js';
|
|
2
|
-
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope,
|
|
2
|
+
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope, assertResourcePrincipalOwner, assertAgentAuthorized, } from './ai-agent-prepare.js';
|
|
3
3
|
import { checkForApprovals, appendStepMessages } from './ai-agent-stream.js';
|
|
4
|
+
import { AgentInterruptedError, isAbortError, persistOrphanedToolResults, registerInterruptibleRun, trackInterruptNote, trackToolExecution, } from './ai-agent-interrupt.js';
|
|
4
5
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
5
6
|
import { resolveModelConfig } from './ai-agent-model-config.js';
|
|
6
7
|
import { AIProviderNotConfiguredError } from '../../errors/errors.js';
|
|
@@ -72,6 +73,8 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
72
73
|
}),
|
|
73
74
|
...(agent.aiMiddleware ?? []),
|
|
74
75
|
];
|
|
76
|
+
// One bag per run, shared by every middleware — see PikkuAIMiddlewareHooks.
|
|
77
|
+
const sharedNotes = {};
|
|
75
78
|
let modifiedMessages = runnerParams.messages;
|
|
76
79
|
let modifiedInstructions = runnerParams.instructions;
|
|
77
80
|
for (const mw of aiMiddlewares) {
|
|
@@ -79,6 +82,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
79
82
|
const result = await mw.modifyInput(singletonServices, {
|
|
80
83
|
messages: modifiedMessages,
|
|
81
84
|
instructions: modifiedInstructions,
|
|
85
|
+
shared: sharedNotes,
|
|
82
86
|
});
|
|
83
87
|
modifiedMessages = result.messages;
|
|
84
88
|
modifiedInstructions = result.instructions;
|
|
@@ -86,6 +90,12 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
86
90
|
}
|
|
87
91
|
runnerParams.messages = modifiedMessages;
|
|
88
92
|
runnerParams.instructions = modifiedInstructions;
|
|
93
|
+
// History records what the model was asked, which for a spoken turn is the
|
|
94
|
+
// transcript rather than the base64 audio that arrived — see the same note on
|
|
95
|
+
// the streaming path. Identity-checked, because a middleware may legitimately
|
|
96
|
+
// replace the message list with something unrelated to this turn.
|
|
97
|
+
const lastModified = modifiedMessages[modifiedMessages.length - 1];
|
|
98
|
+
const persistedUserMessage = lastModified?.id === userMessage.id ? lastModified : userMessage;
|
|
89
99
|
const runId = await aiRunState.createRun({
|
|
90
100
|
agentName,
|
|
91
101
|
threadId,
|
|
@@ -95,6 +105,13 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
95
105
|
createdAt: new Date(),
|
|
96
106
|
updatedAt: new Date(),
|
|
97
107
|
});
|
|
108
|
+
// Registered on the same terms as `streamAIAgent`. A run created here is
|
|
109
|
+
// visible to `interruptAIAgent` through `aiRunState` either way, so skipping
|
|
110
|
+
// this would leave that call finding the run, passing the ownership check and
|
|
111
|
+
// then failing to stop it — reported as if it were running on another host.
|
|
112
|
+
const interruptHandle = registerInterruptibleRun(runId);
|
|
113
|
+
runnerParams.abortSignal = interruptHandle.signal;
|
|
114
|
+
runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
|
|
98
115
|
try {
|
|
99
116
|
const accumulatedSteps = [];
|
|
100
117
|
const totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
@@ -146,7 +163,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
146
163
|
});
|
|
147
164
|
if (stepResult.toolCalls.length === 0)
|
|
148
165
|
break;
|
|
149
|
-
const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools
|
|
166
|
+
const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools);
|
|
150
167
|
if (approvalsNeeded.length > 0) {
|
|
151
168
|
for (const approval of approvalsNeeded) {
|
|
152
169
|
const toolDef = runnerParams.tools.find((t) => t.name === approval.toolName);
|
|
@@ -154,9 +171,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
154
171
|
try {
|
|
155
172
|
approval.reason = await toolDef.approvalDescriptionFn(approval.args);
|
|
156
173
|
}
|
|
157
|
-
catch {
|
|
158
|
-
// If description generation fails, continue without it
|
|
159
|
-
}
|
|
174
|
+
catch { }
|
|
160
175
|
}
|
|
161
176
|
}
|
|
162
177
|
const pendingApprovals = approvalsNeeded.map((a) => a.agentRunId
|
|
@@ -175,7 +190,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
175
190
|
args: a.args,
|
|
176
191
|
});
|
|
177
192
|
const completedStepsForSave = accumulatedSteps.slice(0, -1);
|
|
178
|
-
await saveMessages(storage, threadId, input.resourceId, memoryConfig,
|
|
193
|
+
await saveMessages(storage, threadId, input.resourceId, memoryConfig, persistedUserMessage, { text: '', steps: completedStepsForSave });
|
|
179
194
|
if (storage) {
|
|
180
195
|
await storage.saveMessages(threadId, [
|
|
181
196
|
{
|
|
@@ -236,7 +251,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
236
251
|
outputMessages = modResult.messages;
|
|
237
252
|
}
|
|
238
253
|
}
|
|
239
|
-
await saveMessages(storage, threadId, input.resourceId, memoryConfig,
|
|
254
|
+
await saveMessages(storage, threadId, input.resourceId, memoryConfig, persistedUserMessage, {
|
|
240
255
|
...result,
|
|
241
256
|
text: outputText,
|
|
242
257
|
uiSpec: structuredOutput.uiSpec,
|
|
@@ -255,6 +270,18 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
255
270
|
};
|
|
256
271
|
}
|
|
257
272
|
catch (error) {
|
|
273
|
+
// An interrupt is not a failure, so it skips the `onError` hooks and never
|
|
274
|
+
// becomes an `errorMessage`. Unlike the streaming path there is no partial
|
|
275
|
+
// reply to hand back — nothing was delivered — so the caller gets a typed
|
|
276
|
+
// throw it can tell apart from a provider outage instead of a result.
|
|
277
|
+
const interruption = interruptHandle.interruption;
|
|
278
|
+
if (interruption || isAbortError(error)) {
|
|
279
|
+
await aiRunState.updateRun(runId, { status: 'interrupted' });
|
|
280
|
+
if (storage) {
|
|
281
|
+
trackInterruptNote(threadId, persistOrphanedToolResults(interruptHandle, storage, threadId));
|
|
282
|
+
}
|
|
283
|
+
throw new AgentInterruptedError(runId, interruption ?? { reason: 'user' });
|
|
284
|
+
}
|
|
258
285
|
for (const mw of aiMiddlewares) {
|
|
259
286
|
if (mw.onError) {
|
|
260
287
|
try {
|
|
@@ -264,9 +291,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
264
291
|
messages: runnerParams.messages,
|
|
265
292
|
});
|
|
266
293
|
}
|
|
267
|
-
catch {
|
|
268
|
-
// onError hooks must not affect error flow
|
|
269
|
-
}
|
|
294
|
+
catch { }
|
|
270
295
|
}
|
|
271
296
|
}
|
|
272
297
|
await aiRunState.updateRun(runId, {
|
|
@@ -275,6 +300,9 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
275
300
|
});
|
|
276
301
|
throw error;
|
|
277
302
|
}
|
|
303
|
+
finally {
|
|
304
|
+
interruptHandle.release();
|
|
305
|
+
}
|
|
278
306
|
}
|
|
279
307
|
export async function resumeAIAgentSync(runId, approvals, params, expectedAgentName) {
|
|
280
308
|
const singletonServices = getSingletonServices();
|
|
@@ -285,7 +313,7 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
285
313
|
const run = await aiRunState.getRun(runId);
|
|
286
314
|
if (!run)
|
|
287
315
|
throw new Error(`No run found for runId ${runId}`);
|
|
288
|
-
|
|
316
|
+
assertResourcePrincipalOwner(params, agentSessionScope(run.agentName), run.resourceId, 'run');
|
|
289
317
|
if (expectedAgentName && run.agentName !== expectedAgentName) {
|
|
290
318
|
throw new Error(`Run ${runId} belongs to agent '${run.agentName}', not '${expectedAgentName}'`);
|
|
291
319
|
}
|
|
@@ -293,9 +321,6 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
293
321
|
throw new Error(`Run ${runId} is not suspended (status: ${run.status})`);
|
|
294
322
|
}
|
|
295
323
|
const { agent, packageName, resolvedName } = resolveAgent(run.agentName);
|
|
296
|
-
// Resuming re-runs the agent, so it re-runs the agent's gate. Run ownership
|
|
297
|
-
// alone is not enough: a grant revoked while the run was suspended must stop
|
|
298
|
-
// the caller from approving its pending tool calls.
|
|
299
324
|
await assertAgentAuthorized(agent, params, packageName);
|
|
300
325
|
const { storage } = resolveMemoryServices(agent, singletonServices);
|
|
301
326
|
const memoryConfig = agent.memory;
|
|
@@ -328,7 +353,6 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
328
353
|
const rawArgs = typeof pending.args === 'string'
|
|
329
354
|
? JSON.parse(pending.args)
|
|
330
355
|
: pending.args;
|
|
331
|
-
// Strip null values recursively — LLMs send null for optional fields but Zod expects undefined
|
|
332
356
|
const toolArgs = stripNulls(rawArgs) ?? {};
|
|
333
357
|
try {
|
|
334
358
|
const toolResult = await matchingTool.execute(toolArgs);
|
|
@@ -401,6 +425,8 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
401
425
|
}),
|
|
402
426
|
...(agent.aiMiddleware ?? []),
|
|
403
427
|
];
|
|
428
|
+
// One bag per run, shared by every middleware — see PikkuAIMiddlewareHooks.
|
|
429
|
+
const sharedNotes = {};
|
|
404
430
|
let modifiedMessages = trimmedMessages;
|
|
405
431
|
let modifiedInstructions = instructions;
|
|
406
432
|
for (const mw of aiMiddlewares) {
|
|
@@ -408,6 +434,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
408
434
|
const result = await mw.modifyInput(singletonServices, {
|
|
409
435
|
messages: modifiedMessages,
|
|
410
436
|
instructions: modifiedInstructions,
|
|
437
|
+
shared: sharedNotes,
|
|
411
438
|
});
|
|
412
439
|
modifiedMessages = result.messages;
|
|
413
440
|
modifiedInstructions = result.instructions;
|
|
@@ -424,11 +451,18 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
424
451
|
tools: resumeTools,
|
|
425
452
|
maxSteps: 1,
|
|
426
453
|
toolChoice: (agent.toolChoice ?? 'auto'),
|
|
454
|
+
providerOptions: agent.providerOptions,
|
|
427
455
|
outputSchema: meta?.outputSchema
|
|
428
456
|
? pikkuState(packageName, 'misc', 'schemas').get(meta.outputSchema)
|
|
429
457
|
: undefined,
|
|
430
458
|
agentId: run.agentName,
|
|
431
459
|
};
|
|
460
|
+
// A resumed run keeps its original runId, so the handle registered for the
|
|
461
|
+
// first leg is long gone — an approval that kicks off more generation has to
|
|
462
|
+
// be interruptible on its own terms.
|
|
463
|
+
const interruptHandle = registerInterruptibleRun(run.runId);
|
|
464
|
+
runnerParams.abortSignal = interruptHandle.signal;
|
|
465
|
+
runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
|
|
432
466
|
try {
|
|
433
467
|
const accumulatedSteps = [];
|
|
434
468
|
const totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
@@ -465,7 +499,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
465
499
|
});
|
|
466
500
|
if (stepResult.toolCalls.length === 0)
|
|
467
501
|
break;
|
|
468
|
-
const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools
|
|
502
|
+
const approvalsNeeded = checkForApprovals(stepResult, runnerParams.tools);
|
|
469
503
|
if (approvalsNeeded.length > 0) {
|
|
470
504
|
for (const approval of approvalsNeeded) {
|
|
471
505
|
const toolDef = runnerParams.tools.find((t) => t.name === approval.toolName);
|
|
@@ -473,9 +507,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
473
507
|
try {
|
|
474
508
|
approval.reason = await toolDef.approvalDescriptionFn(approval.args);
|
|
475
509
|
}
|
|
476
|
-
catch {
|
|
477
|
-
// ignore
|
|
478
|
-
}
|
|
510
|
+
catch { }
|
|
479
511
|
}
|
|
480
512
|
}
|
|
481
513
|
const pendingApprovals = approvalsNeeded.map((a) => a.agentRunId
|
|
@@ -574,6 +606,14 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
574
606
|
};
|
|
575
607
|
}
|
|
576
608
|
catch (error) {
|
|
609
|
+
const interruption = interruptHandle.interruption;
|
|
610
|
+
if (interruption || isAbortError(error)) {
|
|
611
|
+
await aiRunState.updateRun(run.runId, { status: 'interrupted' });
|
|
612
|
+
if (storage) {
|
|
613
|
+
trackInterruptNote(run.threadId, persistOrphanedToolResults(interruptHandle, storage, run.threadId));
|
|
614
|
+
}
|
|
615
|
+
throw new AgentInterruptedError(run.runId, interruption ?? { reason: 'user' });
|
|
616
|
+
}
|
|
577
617
|
for (const mw of aiMiddlewares) {
|
|
578
618
|
if (mw.onError) {
|
|
579
619
|
try {
|
|
@@ -583,9 +623,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
583
623
|
messages: runnerParams.messages,
|
|
584
624
|
});
|
|
585
625
|
}
|
|
586
|
-
catch {
|
|
587
|
-
// ignore
|
|
588
|
-
}
|
|
626
|
+
catch { }
|
|
589
627
|
}
|
|
590
628
|
}
|
|
591
629
|
await aiRunState.updateRun(run.runId, {
|
|
@@ -594,4 +632,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
594
632
|
});
|
|
595
633
|
throw error;
|
|
596
634
|
}
|
|
635
|
+
finally {
|
|
636
|
+
interruptHandle.release();
|
|
637
|
+
}
|
|
597
638
|
}
|