@wardby/cli 0.6.0 → 0.7.0
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/deploy/local/docker-compose.quickstart-coding.yml +13 -0
- package/dist/claude-coding-worker/driver.d.ts +21 -3
- package/dist/claude-coding-worker/driver.js +125 -17
- package/dist/claude-coding-worker/main.js +34 -6
- package/dist/claude-coding-worker/sdk.js +12 -1
- package/dist/claude-coding-worker/tool-socket.d.ts +27 -0
- package/dist/claude-coding-worker/tool-socket.js +111 -0
- package/dist/claude-coding-worker/transcript.d.ts +18 -0
- package/dist/claude-coding-worker/transcript.js +77 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +1 -0
- package/dist/cli.js +24 -10
- package/dist/coding/continuation-wording.d.ts +35 -0
- package/dist/coding/continuation-wording.js +73 -0
- package/dist/coding/linked-issue-note.d.ts +23 -0
- package/dist/coding/linked-issue-note.js +47 -0
- package/dist/coding/merge-wording.d.ts +28 -0
- package/dist/coding/merge-wording.js +78 -0
- package/dist/coding/pr-description-note.d.ts +9 -0
- package/dist/coding/pr-description-note.js +32 -0
- package/dist/coding/profile.d.ts +46 -126
- package/dist/coding/profile.js +45 -4
- package/dist/coding/protected-path-wording.d.ts +8 -0
- package/dist/coding/protected-path-wording.js +1 -1
- package/dist/coding/protocol.d.ts +264 -346
- package/dist/coding/protocol.js +235 -12
- package/dist/coding/redact.d.ts +3 -0
- package/dist/coding/redact.js +12 -0
- package/dist/coding/registry/allowlist.d.ts +12 -0
- package/dist/coding/registry/allowlist.js +14 -1
- package/dist/coding/registry/audit-mode.d.ts +153 -0
- package/dist/coding/registry/audit-mode.js +304 -0
- package/dist/coding/registry/lockfile-shared.d.ts +36 -0
- package/dist/coding/registry/lockfile-shared.js +128 -0
- package/dist/coding/registry/lockfiles.js +1 -1
- package/dist/coding/registry/npm-lockfile-formats.d.ts +11 -0
- package/dist/coding/registry/npm-lockfile-formats.js +41 -0
- package/dist/coding/registry/npm-lockfile.d.ts +8 -4
- package/dist/coding/registry/npm-lockfile.js +4 -6
- package/dist/coding/registry/npm.js +78 -8
- package/dist/coding/registry/pnpm-lockfile.d.ts +17 -0
- package/dist/coding/registry/pnpm-lockfile.js +189 -0
- package/dist/coding/registry/pypi-plan.d.ts +50 -0
- package/dist/coding/registry/pypi-plan.js +406 -0
- package/dist/coding/registry/pypi-requirements.d.ts +58 -0
- package/dist/coding/registry/pypi-requirements.js +155 -0
- package/dist/coding/registry/pypi.d.ts +3 -27
- package/dist/coding/registry/pypi.js +40 -154
- package/dist/coding/registry/refusal-hints.d.ts +20 -0
- package/dist/coding/registry/refusal-hints.js +61 -0
- package/dist/coding/registry/refusal-wording.d.ts +11 -0
- package/dist/coding/registry/refusal-wording.js +56 -0
- package/dist/coding/registry/report.d.ts +70 -8
- package/dist/coding/registry/report.js +112 -5
- package/dist/coding/registry/types.d.ts +58 -8
- package/dist/coding/registry/yarn-lockfile.d.ts +30 -0
- package/dist/coding/registry/yarn-lockfile.js +367 -0
- package/dist/coding/services/catalog.d.ts +37 -351
- package/dist/coding/transcript/claude-code.d.ts +13 -0
- package/dist/coding/transcript/claude-code.js +273 -0
- package/dist/coding/transcript/download-protocol.d.ts +30 -0
- package/dist/coding/transcript/download-protocol.js +18 -0
- package/dist/coding/transcript/format.d.ts +20 -0
- package/dist/coding/transcript/format.js +32 -0
- package/dist/coding/transcript/recorder.d.ts +51 -0
- package/dist/coding/transcript/recorder.js +225 -0
- package/dist/coding/transcript/resume/checkout.d.ts +31 -0
- package/dist/coding/transcript/resume/checkout.js +203 -0
- package/dist/coding/transcript/resume/command.d.ts +17 -0
- package/dist/coding/transcript/resume/command.js +176 -0
- package/dist/coding/transcript/resume/download.d.ts +20 -0
- package/dist/coding/transcript/resume/download.js +153 -0
- package/dist/coding/transcript/resume/launch.d.ts +38 -0
- package/dist/coding/transcript/resume/launch.js +128 -0
- package/dist/coding/transcript/resume/session-file.d.ts +13 -0
- package/dist/coding/transcript/resume/session-file.js +79 -0
- package/dist/coding/transcript/resume/stand-in.d.ts +11 -0
- package/dist/coding/transcript/resume/stand-in.js +49 -0
- package/dist/coding-worker/artifact.d.ts +8 -3
- package/dist/coding-worker/artifact.js +3 -1
- package/dist/coding-worker/debug-trace.d.ts +6 -5
- package/dist/coding-worker/debug-trace.js +13 -18
- package/dist/coding-worker/dependency-cache.d.mts +229 -0
- package/dist/coding-worker/dependency-cache.mjs +2123 -0
- package/dist/coding-worker/driver.d.ts +4 -3
- package/dist/coding-worker/driver.js +116 -38
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +32 -0
- package/dist/coding-worker/task-note.d.ts +11 -0
- package/dist/coding-worker/task-note.js +13 -0
- package/dist/coding-worker/types.d.ts +11 -0
- package/dist/config/dependency-cache.d.ts +23 -0
- package/dist/config/dependency-cache.js +32 -0
- package/dist/config/providers.d.ts +12 -3
- package/dist/config/providers.js +55 -5
- package/dist/config/test-simulators.d.ts +82 -0
- package/dist/config/test-simulators.js +305 -0
- package/dist/core/async-context.d.ts +2 -0
- package/dist/core/async-context.js +12 -0
- package/dist/core/budget-events.d.ts +108 -0
- package/dist/core/budget-events.js +346 -0
- package/dist/core/budget-groups.d.ts +50 -1
- package/dist/core/budget-groups.js +236 -27
- package/dist/core/budget-stopped-head.d.ts +46 -0
- package/dist/core/budget-stopped-head.js +81 -0
- package/dist/core/budget-topup.d.ts +51 -0
- package/dist/core/budget-topup.js +156 -0
- package/dist/core/budget-wording.d.ts +16 -2
- package/dist/core/budget-wording.js +40 -2
- package/dist/core/coding-queue.d.ts +2 -1
- package/dist/core/coding-queue.js +7 -0
- package/dist/core/cron.d.ts +19 -1
- package/dist/core/cron.js +17 -0
- package/dist/core/datastores.js +1 -1
- package/dist/core/deferred-coding.d.ts +14 -0
- package/dist/core/deferred-coding.js +62 -0
- package/dist/core/delegation-child.d.ts +25 -0
- package/dist/core/delegation-child.js +37 -0
- package/dist/core/dispatch.d.ts +42 -0
- package/dist/core/dispatch.js +131 -56
- package/dist/core/engine-native.js +1 -1
- package/dist/core/error-code.d.ts +38 -0
- package/dist/core/error-code.js +168 -0
- package/dist/core/grants.d.ts +19 -6
- package/dist/core/grants.js +55 -6
- package/dist/core/host-events.d.ts +18 -2
- package/dist/core/host-events.js +284 -24
- package/dist/core/host-status.d.ts +85 -3
- package/dist/core/host-status.js +298 -20
- package/dist/core/issue-bridge.d.ts +50 -6
- package/dist/core/issue-bridge.js +124 -33
- package/dist/core/issue-events.d.ts +1 -1
- package/dist/core/issue-events.js +4 -10
- package/dist/core/issue-status.d.ts +1 -1
- package/dist/core/issue-status.js +54 -26
- package/dist/core/logger.d.ts +5 -0
- package/dist/core/logger.js +14 -1
- package/dist/core/lost-run-children.d.ts +6 -0
- package/dist/core/lost-run-children.js +32 -0
- package/dist/core/mark-ready.d.ts +34 -0
- package/dist/core/mark-ready.js +152 -0
- package/dist/core/markdown-code.d.ts +8 -0
- package/dist/core/markdown-code.js +107 -0
- package/dist/core/memory-tools.js +7 -0
- package/dist/core/merge-order-check.d.ts +2 -1
- package/dist/core/merge-order-check.js +8 -1
- package/dist/core/notification-templates.d.ts +1 -7
- package/dist/core/notification-templates.js +36 -2
- package/dist/core/pull-request-state-sync.js +2 -2
- package/dist/core/reconciler.d.ts +4 -3
- package/dist/core/reconciler.js +8 -1
- package/dist/core/related-pull-requests.d.ts +11 -3
- package/dist/core/related-pull-requests.js +27 -14
- package/dist/core/reply-parts.d.ts +21 -0
- package/dist/core/reply-parts.js +73 -0
- package/dist/core/review-fix.d.ts +1 -1
- package/dist/core/review-fix.js +2 -1
- package/dist/core/review-host-checks.d.ts +1 -1
- package/dist/core/review-host-tools.d.ts +3 -0
- package/dist/core/review-host-tools.js +99 -13
- package/dist/core/review-reads.d.ts +55 -0
- package/dist/core/review-reads.js +233 -0
- package/dist/core/run-status.d.ts +12 -0
- package/dist/core/run-status.js +12 -0
- package/dist/core/runner.d.ts +80 -34
- package/dist/core/runner.js +439 -144
- package/dist/core/schedule-start.d.ts +12 -0
- package/dist/core/schedule-start.js +14 -0
- package/dist/core/secret-broker-config.d.ts +10 -74
- package/dist/core/secret-guard.d.ts +46 -0
- package/dist/core/secret-guard.js +104 -0
- package/dist/core/secret-guarded-stores.d.ts +12 -0
- package/dist/core/secret-guarded-stores.js +41 -0
- package/dist/core/secret-spans.d.ts +50 -0
- package/dist/core/secret-spans.js +94 -0
- package/dist/core/stop-run.d.ts +46 -0
- package/dist/core/stop-run.js +61 -0
- package/dist/core/workflow-events.d.ts +14 -2
- package/dist/core/workflow-events.js +4 -0
- package/dist/core/workflow-run-events.d.ts +5 -3
- package/dist/core/workflow-run-events.js +43 -8
- package/dist/core/zod-json-schema.d.ts +4 -0
- package/dist/core/zod-json-schema.js +39 -0
- package/dist/core/zod3-window.d.ts +35 -0
- package/dist/core/zod3-window.js +124 -0
- package/dist/generated/prisma/browser.d.ts +34 -3
- package/dist/generated/prisma/client.d.ts +34 -3
- package/dist/generated/prisma/commonInputTypes.d.ts +220 -60
- package/dist/generated/prisma/enums.d.ts +10 -0
- package/dist/generated/prisma/enums.js +8 -0
- package/dist/generated/prisma/internal/class.d.ts +44 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +428 -9
- package/dist/generated/prisma/internal/prismaNamespace.js +92 -1
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +95 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +92 -1
- package/dist/generated/prisma/models/Agent.d.ts +106 -8
- package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +229 -1
- package/dist/generated/prisma/models/CodingProxyRequest.d.ts +207 -3
- package/dist/generated/prisma/models/CodingProxySession.d.ts +114 -1
- package/dist/generated/prisma/models/CodingRun.d.ts +1637 -1
- package/dist/generated/prisma/models/DependencySnapshot.d.ts +1668 -0
- package/dist/generated/prisma/models/DependencySnapshot.js +1 -0
- package/dist/generated/prisma/models/IssuePullRequest.d.ts +6 -2
- package/dist/generated/prisma/models/LocalReview.d.ts +40 -1
- package/dist/generated/prisma/models/NativeGatewayCall.d.ts +39 -1
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +35 -1
- package/dist/generated/prisma/models/RegistryAllowance.d.ts +41 -1
- package/dist/generated/prisma/models/RegistryApprovedVersion.d.ts +75 -1
- package/dist/generated/prisma/models/RegistryAuditRecord.d.ts +1364 -0
- package/dist/generated/prisma/models/RegistryAuditRecord.js +1 -0
- package/dist/generated/prisma/models/Run.d.ts +738 -2
- package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
- package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
- package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
- package/dist/generated/prisma/models/RunTranscript.js +1 -0
- package/dist/generated/prisma/models.d.ts +4 -0
- package/dist/help-index.json +1320 -69
- package/dist/import/create.js +32 -3
- package/dist/import/neutral-schema.d.ts +50 -281
- package/dist/import/neutral-schema.js +5 -4
- package/dist/knowledge/check.d.ts +1 -1
- package/dist/knowledge/cli.d.ts +11 -1
- package/dist/knowledge/cli.js +37 -4
- package/dist/knowledge/concept.d.ts +3 -19
- package/dist/knowledge/location.d.ts +31 -0
- package/dist/knowledge/location.js +78 -0
- package/dist/mcp/auth/access.d.ts +10 -2
- package/dist/mcp/auth/access.js +15 -1
- package/dist/mcp/auth/ownership.d.ts +7 -7
- package/dist/mcp/auth/self-hosted/credentials.d.ts +3 -3
- package/dist/mcp/auth/self-hosted/session.d.ts +2 -2
- package/dist/mcp/host-events/github-ingress.d.ts +2 -0
- package/dist/mcp/host-events/github-ingress.js +2 -1
- package/dist/mcp/index.d.ts +6 -0
- package/dist/mcp/index.js +58 -10
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +33 -14
- package/dist/mcp/tools/agents.d.ts +4 -0
- package/dist/mcp/tools/agents.js +198 -16
- package/dist/mcp/tools/datastore.js +17 -8
- package/dist/mcp/tools/grants.js +9 -3
- package/dist/mcp/tools/memory.js +11 -1
- package/dist/mcp/tools/notification-channels.js +2 -2
- package/dist/mcp/tools/packages.d.ts +2 -0
- package/dist/mcp/tools/packages.js +195 -0
- package/dist/mcp/tools/repositories.js +18 -5
- package/dist/mcp/tools/run-access.d.ts +16 -0
- package/dist/mcp/tools/run-access.js +25 -0
- package/dist/mcp/tools/run-transcript-download.d.ts +30 -0
- package/dist/mcp/tools/run-transcript-download.js +129 -0
- package/dist/mcp/tools/run-transcript.d.ts +19 -0
- package/dist/mcp/tools/run-transcript.js +70 -0
- package/dist/mcp/tools/runs.js +34 -12
- package/dist/mcp/tools/scheduling.js +3 -1
- package/dist/mcp/tools/secret-elicitation-form.js +5 -0
- package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
- package/dist/mcp/tools/secret-elicitation-server.js +10 -61
- package/dist/mcp/tools/secrets.js +2 -2
- package/dist/mcp/tools/stop-run.d.ts +2 -0
- package/dist/mcp/tools/stop-run.js +82 -0
- package/dist/mcp/tools/subagents.js +2 -2
- package/dist/mcp/tools/tools.d.ts +1 -1
- package/dist/mcp/tools/tools.js +25 -9
- package/dist/mcp/transport/stdio-link-host.d.ts +20 -0
- package/dist/mcp/transport/stdio-link-host.js +67 -0
- package/dist/mcp/transport/streamable-http.d.ts +13 -0
- package/dist/mcp/transport/streamable-http.js +41 -1
- package/dist/native-worker/docker-launcher.d.ts +38 -2
- package/dist/native-worker/docker-launcher.js +65 -5
- package/dist/native-worker/gateway-server.d.ts +41 -3
- package/dist/native-worker/gateway-server.js +124 -27
- package/dist/native-worker/gateway.d.ts +27 -1
- package/dist/native-worker/gateway.js +70 -4
- package/dist/native-worker/http-server.d.ts +3 -1
- package/dist/native-worker/http-server.js +11 -7
- package/dist/native-worker/http-transport.js +1 -1
- package/dist/native-worker/kubernetes-launcher.d.ts +7 -3
- package/dist/native-worker/kubernetes-launcher.js +43 -3
- package/dist/native-worker/launch.d.ts +18 -1
- package/dist/native-worker/launch.js +6 -1
- package/dist/native-worker/ledger.d.ts +18 -2
- package/dist/native-worker/ledger.js +57 -4
- package/dist/native-worker/loopback.js +3 -8
- package/dist/native-worker/main.d.ts +2 -1
- package/dist/native-worker/main.js +14 -3
- package/dist/native-worker/protocol.d.ts +129 -577
- package/dist/native-worker/protocol.js +47 -1
- package/dist/native-worker/sandbox-executor.d.ts +17 -2
- package/dist/native-worker/sandbox-executor.js +78 -4
- package/dist/native-worker/stderr-redaction.d.ts +77 -0
- package/dist/native-worker/stderr-redaction.js +237 -0
- package/dist/native-worker/stdio.d.ts +1 -1
- package/dist/native-worker/stdio.js +6 -5
- package/dist/native-worker/warm-pool.d.ts +2 -2
- package/dist/native-worker/warm-pool.js +4 -4
- package/dist/native-worker/worker.js +28 -2
- package/dist/observability/metrics.js +6 -1
- package/dist/providers/auth/self-hosted.d.ts +1 -1
- package/dist/providers/coding-proxy/dependency-cache/eviction.d.ts +29 -0
- package/dist/providers/coding-proxy/dependency-cache/eviction.js +87 -0
- package/dist/providers/coding-proxy/dependency-cache/key.d.ts +33 -0
- package/dist/providers/coding-proxy/dependency-cache/key.js +86 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.d.ts +18 -0
- package/dist/providers/coding-proxy/dependency-cache/model-request-seal.js +40 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.d.ts +25 -0
- package/dist/providers/coding-proxy/dependency-cache/prisma-store.js +131 -0
- package/dist/providers/coding-proxy/dependency-cache/service.d.ts +70 -0
- package/dist/providers/coding-proxy/dependency-cache/service.js +409 -0
- package/dist/providers/coding-proxy/dependency-cache/store.d.ts +85 -0
- package/dist/providers/coding-proxy/dependency-cache/store.js +95 -0
- package/dist/providers/coding-proxy/hold.d.ts +32 -0
- package/dist/providers/coding-proxy/hold.js +86 -0
- package/dist/providers/coding-proxy/interrupted.d.ts +70 -0
- package/dist/providers/coding-proxy/interrupted.js +104 -0
- package/dist/providers/coding-proxy/memory-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/memory-ledger.js +84 -8
- package/dist/providers/coding-proxy/metering.d.ts +16 -0
- package/dist/providers/coding-proxy/metering.js +27 -4
- package/dist/providers/coding-proxy/prisma-ledger.d.ts +15 -2
- package/dist/providers/coding-proxy/prisma-ledger.js +179 -67
- package/dist/providers/coding-proxy/proxy.d.ts +14 -1
- package/dist/providers/coding-proxy/proxy.js +166 -14
- package/dist/providers/coding-proxy/registry/audit.d.ts +53 -10
- package/dist/providers/coding-proxy/registry/audit.js +94 -17
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.d.ts +36 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse-worker.js +67 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.d.ts +16 -0
- package/dist/providers/coding-proxy/registry/lockfile-parse.js +110 -0
- package/dist/providers/coding-proxy/registry/plan.d.ts +9 -0
- package/dist/providers/coding-proxy/registry/plan.js +201 -48
- package/dist/providers/coding-proxy/registry/prisma-store.d.ts +11 -5
- package/dist/providers/coding-proxy/registry/prisma-store.js +120 -17
- package/dist/providers/coding-proxy/registry/service.d.ts +97 -16
- package/dist/providers/coding-proxy/registry/service.js +579 -112
- package/dist/providers/coding-proxy/registry/store.d.ts +84 -9
- package/dist/providers/coding-proxy/registry/store.js +54 -1
- package/dist/providers/coding-proxy/runtime.d.ts +4 -0
- package/dist/providers/coding-proxy/runtime.js +78 -16
- package/dist/providers/coding-proxy/server.d.ts +6 -1
- package/dist/providers/coding-proxy/server.js +45 -1
- package/dist/providers/coding-proxy/types.d.ts +65 -1
- package/dist/providers/datastore/types.d.ts +5 -0
- package/dist/providers/engine/types.d.ts +17 -2
- package/dist/providers/engine/types.js +17 -0
- package/dist/providers/executor/composition.d.ts +10 -3
- package/dist/providers/executor/composition.js +47 -7
- package/dist/providers/executor/container.d.ts +361 -8
- package/dist/providers/executor/container.js +1136 -91
- package/dist/providers/executor/dbos-status.d.ts +31 -0
- package/dist/providers/executor/dbos-status.js +64 -0
- package/dist/providers/executor/dbos.d.ts +50 -1
- package/dist/providers/executor/dbos.js +207 -20
- package/dist/providers/executor/deferred.d.ts +12 -24
- package/dist/providers/executor/deferred.js +10 -29
- package/dist/providers/executor/in-process.d.ts +9 -1
- package/dist/providers/executor/in-process.js +14 -4
- package/dist/providers/executor/linked-issue-reader.d.ts +16 -0
- package/dist/providers/executor/linked-issue-reader.js +30 -0
- package/dist/providers/executor/routing.d.ts +2 -0
- package/dist/providers/executor/routing.js +4 -0
- package/dist/providers/executor/types.d.ts +13 -0
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/issue-tracker/types.d.ts +17 -0
- package/dist/providers/issue-tracker/types.js +39 -1
- package/dist/providers/jobs/claude-tool-setup.d.ts +4 -0
- package/dist/providers/jobs/claude-tool-setup.js +5 -2
- package/dist/providers/jobs/docker-isolation.d.ts +8 -0
- package/dist/providers/jobs/docker-isolation.js +17 -0
- package/dist/providers/jobs/docker.d.ts +1 -0
- package/dist/providers/jobs/docker.js +27 -2
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +2 -0
- package/dist/providers/jobs/fake-kubernetes-api.js +3 -0
- package/dist/providers/jobs/kubernetes-api.d.ts +8 -0
- package/dist/providers/jobs/kubernetes-api.js +10 -0
- package/dist/providers/jobs/kubernetes-client.js +10 -1
- package/dist/providers/jobs/kubernetes-isolation.d.ts +2 -0
- package/dist/providers/jobs/kubernetes-isolation.js +17 -1
- package/dist/providers/jobs/kubernetes.d.ts +6 -1
- package/dist/providers/jobs/kubernetes.js +105 -16
- package/dist/providers/jobs/types.d.ts +33 -0
- package/dist/providers/jobs/types.js +13 -1
- package/dist/providers/llm/anthropic.js +5 -1
- package/dist/providers/llm/bedrock.d.ts +0 -12
- package/dist/providers/llm/bedrock.js +4 -0
- package/dist/providers/llm/claude-messages.d.ts +3 -1
- package/dist/providers/llm/claude-messages.js +4 -1
- package/dist/providers/llm/claude-provider.d.ts +2 -2
- package/dist/providers/llm/claude-provider.js +2 -2
- package/dist/providers/llm/openai.d.ts +2 -2
- package/dist/providers/llm/openai.js +6 -2
- package/dist/providers/llm/routing.d.ts +2 -2
- package/dist/providers/llm/routing.js +2 -2
- package/dist/providers/llm/types.d.ts +12 -2
- package/dist/providers/review-host/github-events.d.ts +9 -1
- package/dist/providers/review-host/github-events.js +34 -12
- package/dist/providers/review-host/github.d.ts +29 -2
- package/dist/providers/review-host/github.js +224 -29
- package/dist/providers/review-host/local.d.ts +8 -4
- package/dist/providers/review-host/local.js +49 -31
- package/dist/providers/review-host/patch-pages.d.ts +41 -0
- package/dist/providers/review-host/patch-pages.js +176 -0
- package/dist/providers/review-host/review-format.d.ts +19 -1
- package/dist/providers/review-host/review-format.js +38 -7
- package/dist/providers/review-host/types.d.ts +134 -2
- package/dist/providers/review-host/types.js +8 -0
- package/dist/providers/storage/gcs.d.ts +63 -0
- package/dist/providers/storage/gcs.js +69 -0
- package/dist/providers/storage/index.d.ts +15 -0
- package/dist/providers/storage/index.js +14 -0
- package/dist/providers/storage/local.d.ts +24 -0
- package/dist/providers/storage/local.js +92 -0
- package/dist/providers/storage/meter.d.ts +14 -0
- package/dist/providers/storage/meter.js +34 -0
- package/dist/providers/storage/s3.d.ts +41 -0
- package/dist/providers/storage/s3.js +107 -0
- package/dist/providers/storage/types.d.ts +37 -3
- package/dist/providers/storage/types.js +21 -4
- package/dist/providers/vcs/git.d.ts +33 -2
- package/dist/providers/vcs/git.js +324 -22
- package/dist/providers/vcs/github-remote.d.ts +26 -3
- package/dist/providers/vcs/github-remote.js +124 -14
- package/dist/providers/vcs/github.d.ts +214 -6
- package/dist/providers/vcs/github.js +447 -45
- package/dist/providers/vcs/index.js +8 -1
- package/dist/providers/vcs/pr-description.d.ts +127 -0
- package/dist/providers/vcs/pr-description.js +270 -0
- package/dist/providers/vcs/remote.d.ts +33 -1
- package/dist/providers/vcs/routing.d.ts +4 -2
- package/dist/providers/vcs/routing.js +6 -0
- package/dist/providers/vcs/types.d.ts +80 -3
- package/dist/quickstart/coding-seed.d.ts +14 -3
- package/dist/quickstart/coding-seed.js +213 -4
- package/dist/quickstart/reviewer-prompt.d.ts +1 -1
- package/dist/quickstart/reviewer-prompt.js +6 -6
- package/dist/quickstart-images.json +1 -1
- package/dist/sandbox/generated/zod.bundle.js +62 -1
- package/dist/sandbox/generated/zod3.bundle.js +5 -0
- package/dist/sandbox/host-functions.d.ts +1 -0
- package/dist/sandbox/host-functions.js +6 -11
- package/dist/sandbox/secret-broker.js +3 -4
- package/dist/sandbox/tool-capabilities.d.ts +10 -30
- package/dist/sandbox/zod-params.d.ts +37 -5
- package/dist/sandbox/zod-params.js +181 -26
- package/dist/serve.js +8 -1
- package/dist/viewer/api-schema.d.ts +349 -2627
- package/dist/viewer/api-schema.js +7 -0
- package/dist/viewer/build-schemas.js +6 -2
- package/dist/viewer/openapi.js +2 -4
- package/dist/wardby-bin.js +10 -0
- package/docs/agent-recipes.md +58 -20
- package/docs/code-review-agents.md +551 -41
- package/docs/coding-agent-setup.md +489 -7
- package/docs/coding-packages.md +1033 -90
- package/docs/coding-services.md +27 -12
- package/docs/coding-worker-byo-images.md +20 -0
- package/docs/coding-worker-isolation.md +105 -30
- package/docs/getting-started-gke.md +124 -137
- package/docs/getting-started-identity-provider.md +10 -1
- package/docs/getting-started.md +9 -0
- package/docs/jira-agents.md +17 -8
- package/docs/knowledge/blob-not-found-semantics.md +41 -0
- package/docs/knowledge/bounded-file-descriptor.md +52 -0
- package/docs/knowledge/delegation-admission-slots.md +52 -0
- package/docs/knowledge/http-dispatcher-bootstrap.md +61 -0
- package/docs/knowledge/import-rename-target.md +52 -0
- package/docs/knowledge/index.md +57 -0
- package/docs/knowledge/log.md +9 -0
- package/docs/knowledge/mcp-cancelled-task-precedence.md +41 -0
- package/docs/knowledge/mcp-http-prompt-discovery.md +41 -0
- package/docs/knowledge/mcp-schema-module-boundary.md +41 -0
- package/docs/knowledge/nullable-tool-uniqueness.md +52 -0
- package/docs/knowledge/overview-cli.md +74 -0
- package/docs/knowledge/overview-coding-proxy.md +72 -0
- package/docs/knowledge/overview-coding.md +72 -0
- package/docs/knowledge/overview-config.md +60 -0
- package/docs/knowledge/overview-core.md +72 -0
- package/docs/knowledge/overview-deploy.md +83 -0
- package/docs/knowledge/overview-mcp.md +61 -0
- package/docs/knowledge/overview-prisma.md +72 -0
- package/docs/knowledge/overview-providers.md +89 -0
- package/docs/knowledge/overview-sandbox.md +83 -0
- package/docs/knowledge/overview-surfaces.md +83 -0
- package/docs/knowledge/private-datastore-shared-boundary.md +54 -0
- package/docs/knowledge/proxy-settlement-projections.md +41 -0
- package/docs/knowledge/run-pricing-first-writer.md +43 -0
- package/docs/knowledge/schedule-claim-transaction.md +41 -0
- package/docs/knowledge/secret-entry-replica-contract.md +52 -0
- package/docs/knowledge/terminal-run-first-writer.md +41 -0
- package/docs/knowledge/transactional-agent-authorization.md +52 -0
- package/docs/knowledge/viewer-notify-write-isolation.md +30 -0
- package/docs/knowledge/warm-input-publication.md +30 -0
- package/docs/knowledge/workspace-staging-failure.md +54 -0
- package/docs/knowledge.md +54 -14
- package/docs/native-sandbox.md +119 -23
- package/docs/observability.md +4 -0
- package/docs/security-deployment.md +33 -2
- package/docs/slack-notifications.md +35 -19
- package/docs/tool-secrets.md +42 -10
- package/docs/viewer-api.openapi.yml +1 -1
- package/help/admin-viewer.md +24 -2
- package/help/architecture-agent.md +11 -6
- package/help/build-worker-image.md +3 -1
- package/help/builder-agent.md +19 -6
- package/help/code-review-agents.md +177 -6
- package/help/coding-packages.md +156 -6
- package/help/cost-attribution.md +9 -5
- package/help/creating-agents.md +14 -1
- package/help/dependency-cache.md +143 -0
- package/help/deploy-gke.md +15 -8
- package/help/errors/budget-exhausted.md +187 -0
- package/help/errors/budget-group-exhausted.md +5 -1
- package/help/errors/coding-stream-quota-exceeded.md +33 -0
- package/help/errors/coding-workspace-disk-exceeds-limit.md +39 -0
- package/help/errors/continuation-closed.md +9 -12
- package/help/errors/delegation-conflict.md +24 -0
- package/help/errors/file-list-truncated.md +45 -0
- package/help/errors/full-read-required.md +49 -0
- package/help/errors/github-account-not-allowed.md +4 -0
- package/help/errors/graph-incomplete.md +43 -0
- package/help/errors/graph-limit.md +43 -0
- package/help/errors/merge-conflict.md +49 -0
- package/help/errors/native-sandbox-gateway-error.md +20 -0
- package/help/errors/native-sandbox-launch-abandoned.md +21 -0
- package/help/errors/native-sandbox-worker-exited.md +3 -2
- package/help/errors/package-not-allowed-pending.md +52 -0
- package/help/errors/package-not-allowed.md +51 -0
- package/help/errors/package-refusals.md +43 -0
- package/help/errors/patch-cursor-malformed.md +31 -0
- package/help/errors/run-lost.md +39 -0
- package/help/errors/run-transcript-download.md +44 -0
- package/help/errors/secret-in-value.md +69 -0
- package/help/errors/target-merge.md +40 -0
- package/help/fix-merge-conflicts.md +73 -0
- package/help/github-app-setup.md +132 -0
- package/help/github.md +22 -0
- package/help/identity-and-access.md +2 -0
- package/help/jira.md +23 -6
- package/help/knowledge.md +16 -7
- package/help/local-repositories.md +1 -1
- package/help/low-power-mode.md +7 -1
- package/help/merge-order-check.md +5 -0
- package/help/native-capabilities.md +29 -1
- package/help/native-sandbox.md +15 -1
- package/help/operating-agents.md +5 -0
- package/help/package-audit-mode.md +91 -0
- package/help/related-pull-requests.md +10 -7
- package/help/resume-runs-locally.md +131 -0
- package/help/review-fix-rounds.md +33 -1
- package/help/sharing-agents.md +59 -0
- package/help/slack-notifications.md +19 -5
- package/help/status-comments.md +31 -0
- package/help/stop-run.md +58 -0
- package/help/troubleshooting/budgets.md +28 -0
- package/help/troubleshooting/coding-workers.md +78 -7
- package/package.json +17 -10
- package/prisma/migrations/20261016000000_registry_approved_accepted_advisories/migration.sql +3 -0
- package/prisma/migrations/20261016000001_mark_ready_when_passing/migration.sql +3 -0
- package/prisma/migrations/20261017000000_debug_trace_max_mb/migration.sql +4 -0
- package/prisma/migrations/20261018000000_dependency_cache/migration.sql +53 -0
- package/prisma/migrations/20261019000000_claude_max_output_tokens/migration.sql +5 -0
- package/prisma/migrations/20261021000000_pr_description_hash/migration.sql +4 -0
- package/prisma/migrations/20261022000000_dependency_snapshot_validation_metadata/migration.sql +4 -0
- package/prisma/migrations/20261023000000_package_audit_mode/migration.sql +27 -0
- package/prisma/migrations/20261024000000_budget_events/migration.sql +26 -0
- package/prisma/migrations/20261025000000_cache_aware_holds/migration.sql +9 -0
- package/prisma/migrations/20261026000000_budget_overrun/migration.sql +4 -0
- package/prisma/migrations/20261027000000_coding_run_request/migration.sql +1 -0
- package/prisma/migrations/20261028000000_native_gateway_review_reads/migration.sql +6 -0
- package/prisma/migrations/20261029000000_lead_survives_deploy/migration.sql +6 -0
- package/prisma/migrations/20261030000000_local_review_covered_sha/migration.sql +2 -0
- package/prisma/migrations/20261031000000_coding_run_budget_limit/migration.sql +9 -0
- package/prisma/migrations/20261101000000_run_transcripts/migration.sql +22 -0
- package/prisma/schema.prisma +311 -97
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
package/dist/core/runner.js
CHANGED
|
@@ -18,19 +18,24 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { createHash, randomBytes } from "node:crypto";
|
|
20
20
|
import { z } from "zod";
|
|
21
|
-
import {
|
|
21
|
+
import { Prisma } from "#prisma";
|
|
22
|
+
import { RunOwnershipLostError, STEPS_CHANGED_REASON, StepReplayMismatchError, runStepInline, } from "../providers/engine/types.js";
|
|
22
23
|
import { isLlmEffort } from "../providers/llm/types.js";
|
|
23
24
|
import { createPrivilegedHost } from "../sandbox/host-functions.js";
|
|
24
25
|
import { consoleRedactionValues } from "../sandbox/secret-broker.js";
|
|
25
26
|
import { runUserToolCall } from "../sandbox/user-tool.js";
|
|
26
|
-
import { runSandboxedEngine, SandboxRunCancelledError, } from "../native-worker/gateway.js";
|
|
27
|
+
import { logUnexpectedError, runSandboxedEngine, SandboxRunCancelledError, } from "../native-worker/gateway.js";
|
|
27
28
|
import { NATIVE_WORKER_PROTOCOL_VERSION } from "../native-worker/protocol.js";
|
|
28
29
|
import { asStringArray, asPrefixMap } from "../sandbox/tool-capabilities.js";
|
|
29
30
|
import { scopeDatastore } from "../providers/datastore/scoped.js";
|
|
30
31
|
import { buildSecretsAccessor, scopeSecretsAccessor } from "./secrets.js";
|
|
32
|
+
import { loadAgentSecretValues, maskNamedSecrets, POSTING_TOOL_NAMES, SECRET_CHECK_UNAVAILABLE_MESSAGE, WITHHELD_TEXT_NOTICE, } from "./secret-guard.js";
|
|
31
33
|
import { buildSharedDatastoreAccessor, scopeSharedDatastoreAccessor } from "./datastores.js";
|
|
32
34
|
import { effectiveBudgetForRun } from "./budget-groups.js";
|
|
35
|
+
import { stopChildrenOfLostRun } from "./lost-run-children.js";
|
|
33
36
|
import { createDelegationSiblings } from "./delegation-siblings.js";
|
|
37
|
+
import { findDelegationChild } from "./delegation-child.js";
|
|
38
|
+
import { DRIVABLE } from "./run-status.js";
|
|
34
39
|
import { createSerialGate } from "./serial-gate.js";
|
|
35
40
|
import { withRunHeartbeat } from "./run-heartbeat.js";
|
|
36
41
|
import { ContinuationRefusedError, dispatchRun } from "./dispatch.js";
|
|
@@ -40,6 +45,7 @@ import { DELEGATE_TOOL_PREFIX, duplicateToolNames } from "./tool-names.js";
|
|
|
40
45
|
import { SUBAGENT_MEMORY_GET_TOOL, PARENT_MEMORY_GET_TOOL, handleSubAgentMemoryGet, handleParentMemoryGet, } from "./subagent-memory-tools.js";
|
|
41
46
|
import { prisma as defaultDb } from "./db.js";
|
|
42
47
|
import { logger } from "./logger.js";
|
|
48
|
+
import { CHILD_RUN_FAILURE_CODES, declaredCodeOf } from "./error-code.js";
|
|
43
49
|
import { loadCodingConcurrencyConfig } from "../config/providers.js";
|
|
44
50
|
import { REVIEW_HOST_TOOL_DEFS, REVIEW_HOST_TOOL_NAMES, handleReviewHostTool, } from "./review-host-tools.js";
|
|
45
51
|
import { closeOpenHostCheck } from "./review-host-checks.js";
|
|
@@ -55,14 +61,17 @@ import { emitRunFinishedEvents } from "./workflow-run-events.js";
|
|
|
55
61
|
import { startReviewFixAfterReview } from "./review-fix.js";
|
|
56
62
|
import { updateRelatedPullRequests } from "./related-pull-requests.js";
|
|
57
63
|
import { syncMergeOrderChecksAfterRun } from "./merge-order-check.js";
|
|
64
|
+
import { markReadyAfterRun } from "./mark-ready.js";
|
|
58
65
|
import { startDeferredForRequest } from "./host-events.js";
|
|
59
66
|
import { recordNativeModelUsage } from "./model-usage.js";
|
|
60
67
|
import { pinNativeRunPricing } from "./run-pricing.js";
|
|
61
68
|
import { RoutingLlmProvider } from "../providers/llm/routing.js";
|
|
62
69
|
import { ModelUnavailableError } from "../providers/llm/catalog-types.js";
|
|
63
70
|
import { trackRun } from "./in-flight-runs.js";
|
|
71
|
+
import { ReviewReadLedger } from "./review-reads.js";
|
|
64
72
|
import { createRepoAccessGate, requiredLevel } from "./repo-access.js";
|
|
65
|
-
|
|
73
|
+
import { loadBudgetEvent, ownerBudgetSentence } from "./budget-events.js";
|
|
74
|
+
export const runnerLog = logger.child({ module: "runner" });
|
|
66
75
|
/**
|
|
67
76
|
* Sub-agent dispatch uses one synthetic tool per declared child, named by the
|
|
68
77
|
* boundName it's attached
|
|
@@ -145,7 +154,7 @@ const DelegateArgs = z
|
|
|
145
154
|
grantParentMemoryKeys: z.array(z.string()).optional(),
|
|
146
155
|
continuePriorRun: z.string().optional(),
|
|
147
156
|
mergeOrder: z
|
|
148
|
-
.number({
|
|
157
|
+
.number({ error: MERGE_ORDER_RANGE_MESSAGE })
|
|
149
158
|
.int(MERGE_ORDER_RANGE_MESSAGE)
|
|
150
159
|
.min(1, MERGE_ORDER_RANGE_MESSAGE)
|
|
151
160
|
.max(99, MERGE_ORDER_RANGE_MESSAGE)
|
|
@@ -325,18 +334,7 @@ function toIssueProjectLink(row) {
|
|
|
325
334
|
maxNewIssuesPerRun: row.maxNewIssuesPerRun ?? null,
|
|
326
335
|
};
|
|
327
336
|
}
|
|
328
|
-
|
|
329
|
-
* The two states a Run can still be driven out of. Every write `executeRun`
|
|
330
|
-
* makes is filtered on these: a durable executor can have two attempts of the
|
|
331
|
-
* same run in flight at once (a still-live original parked in a slow LLM step
|
|
332
|
-
* and an adopted attempt the reconciler resumed elsewhere), and whichever
|
|
333
|
-
* reaches a terminal state first must win. A conditional `updateMany` makes
|
|
334
|
-
* that a database-level CAS rather than a race — the loser's WHERE matches
|
|
335
|
-
* zero rows. It also stops a *later* attempt resurrecting a run the
|
|
336
|
-
* reconciler already reaped: a `lost` row stays `lost`. A step-level
|
|
337
|
-
* ownership loss writes nothing at all (RunOwnershipLostError).
|
|
338
|
-
*/
|
|
339
|
-
const DRIVABLE = ["pending", "running"];
|
|
337
|
+
// DRIVABLE (the two states a Run can still be driven out of) lives in run-status.ts.
|
|
340
338
|
/**
|
|
341
339
|
* Raised when a run's step boundary observed a cancellation (DbosExecutor's
|
|
342
340
|
* `stop`). `executeRun`'s backstop persists these as `cancelled` with the
|
|
@@ -370,6 +368,37 @@ async function finishRunClaimed(db, runId, data) {
|
|
|
370
368
|
const updated = await db.run.updateMany({ where: { id: runId, status: { in: [...DRIVABLE] } }, data });
|
|
371
369
|
return { run: await db.run.findUniqueOrThrow({ where: { id: runId } }), claimed: updated.count > 0 };
|
|
372
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* A step runner made to notice a stop. Before each step this reads the run's own row: once anything
|
|
373
|
+
* else has made it terminal (stop_run, an MCP task's cancel, a parent run's stop, the reconciler),
|
|
374
|
+
* the run stops at this boundary with a RunCancelledError. The terminal row is never rewritten
|
|
375
|
+
* (finishRunClaimed matches zero rows), so the stop keeps its reason. Inline runs need it because
|
|
376
|
+
* nothing else interrupts their steps. DbosExecutor wraps its own step runner in it too: DBOS stops
|
|
377
|
+
* only a workflow it was told to cancel, and stop() can name only the workflow the run records.
|
|
378
|
+
*/
|
|
379
|
+
export function stopAwareStep(db, runId, inner = runStepInline, options = {}) {
|
|
380
|
+
const check = async (name, own) => {
|
|
381
|
+
const read = db.run.findUnique({ where: { id: runId }, select: { status: true, executionWorkflowId: true } });
|
|
382
|
+
const row = options.failOpen ? await read.catch(() => null) : await read;
|
|
383
|
+
if (row?.executionWorkflowId && own && options.ownership?.forkedFrom(row.executionWorkflowId, own)) {
|
|
384
|
+
throw new RunOwnershipLostError(name);
|
|
385
|
+
}
|
|
386
|
+
if (row && !DRIVABLE.includes(row.status)) {
|
|
387
|
+
throw new RunCancelledError(`Run ${row.status}: stopped before step "${name}".`);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
// Each check waits for the one before it, so steps reach `inner` in the order they were called,
|
|
391
|
+
// as they did without a read in front: a durable runner numbers a step when it is called (DBOS
|
|
392
|
+
// assigns its function id then), and a replay of concurrent delegations matches steps by number.
|
|
393
|
+
let previous = Promise.resolve();
|
|
394
|
+
return async (name, fn) => {
|
|
395
|
+
const own = options.ownership?.workflowId();
|
|
396
|
+
const checked = previous.then(() => check(name, own));
|
|
397
|
+
previous = checked.catch(() => undefined);
|
|
398
|
+
await checked;
|
|
399
|
+
return inner(name, fn);
|
|
400
|
+
};
|
|
401
|
+
}
|
|
373
402
|
/**
|
|
374
403
|
* Why a sandbox-mode native run is not executed here. The runner only ever
|
|
375
404
|
* executes native runs in the control plane; a run whose snapshot says
|
|
@@ -399,12 +428,16 @@ export const CODING_CHILD_WAIT_GRACE_SEC = 60;
|
|
|
399
428
|
* a parent left waiting on a child that never finishes.
|
|
400
429
|
*/
|
|
401
430
|
export const SANDBOX_CHILD_WAIT_SEC = 60 * 60;
|
|
431
|
+
/** The leading snake_case code of an error message (`code: sentence`); messages can carry internals. */
|
|
402
432
|
/**
|
|
403
433
|
* What a coding sub-agent's run tells the parent run's model. A run refused
|
|
404
434
|
* over its services carries the host sentence (never the raw Run.error), so
|
|
405
|
-
* the parent can pass it on — for a mention, that is the requester.
|
|
435
|
+
* the parent can pass it on — for a mention, that is the requester. A failed
|
|
436
|
+
* run carries only its error code, so the parent can say why without seeing internals.
|
|
406
437
|
*/
|
|
407
|
-
export function codingChildResult(run, codingResult
|
|
438
|
+
export function codingChildResult(run, codingResult,
|
|
439
|
+
/** The child's recorded budget refusal (loadBudgetEvent), if any. */
|
|
440
|
+
budgetEvent) {
|
|
408
441
|
// Checked before the "refused" branch: a continuation whose PR closed
|
|
409
442
|
// before the run ever spent anything is stored as "refused" (a preflight
|
|
410
443
|
// refusal, container.ts), not "failed" -- but it is the same
|
|
@@ -415,6 +448,10 @@ export function codingChildResult(run, codingResult) {
|
|
|
415
448
|
: run.status === "refused"
|
|
416
449
|
? serviceRefusalSentence(run.error)
|
|
417
450
|
: null;
|
|
451
|
+
const errorCode = run.status === "failed" ? declaredCodeOf(run.error, CHILD_RUN_FAILURE_CODES) : undefined;
|
|
452
|
+
const budget = budgetEvent && (run.status === "budget_exhausted" || run.status === "refused")
|
|
453
|
+
? ownerBudgetSentence(budgetEvent.event, budgetEvent.agentName)
|
|
454
|
+
: undefined;
|
|
418
455
|
return JSON.stringify({
|
|
419
456
|
status: run.status,
|
|
420
457
|
finalText: run.finalText,
|
|
@@ -422,6 +459,8 @@ export function codingChildResult(run, codingResult) {
|
|
|
422
459
|
tokensIn: run.tokensIn,
|
|
423
460
|
tokensOut: run.tokensOut,
|
|
424
461
|
...(refusal ? { refusal } : {}),
|
|
462
|
+
...(errorCode ? { errorCode } : {}),
|
|
463
|
+
...(budget ? { budget } : {}),
|
|
425
464
|
...pullRequestOf(codingResult),
|
|
426
465
|
});
|
|
427
466
|
}
|
|
@@ -668,6 +707,18 @@ export async function loadNativeRun(options) {
|
|
|
668
707
|
throw err;
|
|
669
708
|
});
|
|
670
709
|
}
|
|
710
|
+
/**
|
|
711
|
+
* Every value of the secrets `names` (readable or brokered; a SigV4 secret's key and token alone
|
|
712
|
+
* too, the same set the in-process host redacts), as a redaction list. Rejects when ANY read
|
|
713
|
+
* fails: a list missing one secret would let that secret through, so a caller treats a rejection
|
|
714
|
+
* as "no list" and fails closed. A secret with no value contributes nothing.
|
|
715
|
+
*/
|
|
716
|
+
export async function readRedactionValues(accessor, names) {
|
|
717
|
+
const values = await Promise.all(names.map((secret) => accessor.resolve
|
|
718
|
+
? accessor.resolve(secret).then((e) => (e ? consoleRedactionValues(e) : []))
|
|
719
|
+
: accessor.get(secret).then((v) => (v === undefined ? [] : [v]))));
|
|
720
|
+
return values.flat().filter((value) => typeof value === "string");
|
|
721
|
+
}
|
|
671
722
|
/**
|
|
672
723
|
* One attempt's tool surface for a native run. `builtinHandler(name)` is the
|
|
673
724
|
* single source of truth for which names are trusted built-ins (memory,
|
|
@@ -683,6 +734,8 @@ export function createNativeRunTools(options) {
|
|
|
683
734
|
// jira_create_issue's per-run cap counter: shared by every tool call of this attempt (a resumed attempt
|
|
684
735
|
// starts a fresh one, floored by the run's recorded fingerprint creates).
|
|
685
736
|
const issueCreationCounters = new Map();
|
|
737
|
+
// What this attempt's review tools have read, for repo_publish_review's unread_files gate.
|
|
738
|
+
const reviewReads = options.reviewReads ?? new ReviewReadLedger();
|
|
686
739
|
// One per attempt: admits this run's delegations one at a time (see the delegate branch).
|
|
687
740
|
const delegationGate = createSerialGate();
|
|
688
741
|
// The children this attempt's delegations have running, and the sub-agents whose delegation is
|
|
@@ -690,7 +743,125 @@ export function createNativeRunTools(options) {
|
|
|
690
743
|
// place in the same-child and limit checks while the gate is open to the others.
|
|
691
744
|
const delegationSiblings = createDelegationSiblings();
|
|
692
745
|
const waitingDelegations = new Set();
|
|
693
|
-
|
|
746
|
+
/**
|
|
747
|
+
* Waits on a dispatched coding or sandbox-mode native child until it is terminal, its wait
|
|
748
|
+
* bound passes (it is then stopped), or this run is cancelled, and returns what the model sees.
|
|
749
|
+
* The bound is measured from the child's creation, so a re-executed delegate step (a resume, or
|
|
750
|
+
* a takeover under a new version) never extends how long this run waits for it.
|
|
751
|
+
*/
|
|
752
|
+
const awaitDelegatedChild = async (wait) => {
|
|
753
|
+
const { executor, childRunId, kind, boundName } = wait;
|
|
754
|
+
const startedAt = Date.now();
|
|
755
|
+
let boundMs;
|
|
756
|
+
if (kind === "coding") {
|
|
757
|
+
const codingRun = await db.codingRun.findUnique({
|
|
758
|
+
where: { runId: childRunId },
|
|
759
|
+
select: { timeoutSec: true },
|
|
760
|
+
});
|
|
761
|
+
const { queueTimeoutSec } = loadCodingConcurrencyConfig();
|
|
762
|
+
boundMs = (queueTimeoutSec + (codingRun?.timeoutSec ?? 0) + CODING_CHILD_WAIT_GRACE_SEC) * 1000;
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
boundMs = SANDBOX_CHILD_WAIT_SEC * 1000;
|
|
766
|
+
}
|
|
767
|
+
const elapsedMs = Math.max(0, Date.now() - wait.createdAtMs);
|
|
768
|
+
// Executor.start may resolve before the child is terminal, so wait on the row.
|
|
769
|
+
const waited = await waitForCodingChild({
|
|
770
|
+
db,
|
|
771
|
+
executor,
|
|
772
|
+
childRunId,
|
|
773
|
+
parentRunId: runId,
|
|
774
|
+
boundMs: Math.max(0, boundMs - elapsedMs),
|
|
775
|
+
});
|
|
776
|
+
wait.onSettled();
|
|
777
|
+
runnerLog.info({
|
|
778
|
+
runId,
|
|
779
|
+
childRunId,
|
|
780
|
+
boundName,
|
|
781
|
+
outcome: waited.kind === "terminal" ? waited.run.status : waited.kind,
|
|
782
|
+
durationMs: Date.now() - startedAt,
|
|
783
|
+
}, "delegation finished");
|
|
784
|
+
if (waited.kind === "timed_out") {
|
|
785
|
+
return JSON.stringify({
|
|
786
|
+
error: "subagent_wait_timed_out",
|
|
787
|
+
runId: childRunId,
|
|
788
|
+
message: kind === "coding"
|
|
789
|
+
? "The coding sub-agent did not finish within its queue timeout plus run timeout; it was stopped and produced no result."
|
|
790
|
+
: "The sandbox sub-agent did not finish in time; it was stopped and produced no result.",
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
if (waited.kind === "parent_cancelled") {
|
|
794
|
+
return JSON.stringify({
|
|
795
|
+
error: "parent_cancelled",
|
|
796
|
+
runId: childRunId,
|
|
797
|
+
message: kind === "coding"
|
|
798
|
+
? "This run was cancelled while waiting for the coding sub-agent; the sub-agent was stopped."
|
|
799
|
+
: "This run was cancelled while waiting for the sandbox sub-agent; the sub-agent was stopped.",
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
if (kind === "coding") {
|
|
803
|
+
const stored = await db.codingRun
|
|
804
|
+
.findUnique({ where: { runId: childRunId }, select: { result: true } })
|
|
805
|
+
.catch((err) => {
|
|
806
|
+
runnerLog.warn({ err, childRunId }, "could not read the coding sub-run's result");
|
|
807
|
+
return null;
|
|
808
|
+
});
|
|
809
|
+
return codingChildResult(waited.run, stored?.result, await loadBudgetEvent(db, childRunId));
|
|
810
|
+
}
|
|
811
|
+
return nativeChildResult(waited.run, wait.mergeOrderNote);
|
|
812
|
+
};
|
|
813
|
+
/**
|
|
814
|
+
* A re-executed delegate call whose child already exists (findDelegationChild): wait on it
|
|
815
|
+
* again rather than refuse it as a duplicate. A control-plane native child ran inline in the
|
|
816
|
+
* attempt that died, so nothing drives it any more: it is stopped (or its result returned, if
|
|
817
|
+
* it had finished) and no new child is started.
|
|
818
|
+
*/
|
|
819
|
+
const reattachDelegatedChild = async (child, boundName, argsJson) => {
|
|
820
|
+
const row = await db.run.findUniqueOrThrow({ where: { id: child.id } });
|
|
821
|
+
const childAgentRow = await db.agent.findUnique({ where: { id: row.agentId }, select: { kind: true } });
|
|
822
|
+
const parsedArgs = parseDelegateArgs(argsJson);
|
|
823
|
+
const mergeOrderNote = "args" in parsedArgs && parsedArgs.args.mergeOrder !== undefined ? MERGE_ORDER_IGNORED_NOTE : undefined;
|
|
824
|
+
const coding = childAgentRow?.kind === "coding";
|
|
825
|
+
if (!coding && row.nativeExecutionMode !== "sandbox") {
|
|
826
|
+
if (!DRIVABLE.includes(row.status))
|
|
827
|
+
return nativeChildResult(row, mergeOrderNote);
|
|
828
|
+
await providers.executor?.stop(child.id, "parent resumed without it").catch((err) => {
|
|
829
|
+
runnerLog.warn({ err, childRunId: child.id, runId }, "failed to stop an interrupted sub-agent run");
|
|
830
|
+
});
|
|
831
|
+
return JSON.stringify({
|
|
832
|
+
error: "subagent_interrupted",
|
|
833
|
+
message: "The sub-agent was interrupted by a restart and cannot be resumed; no new sub-agent run was started.",
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
if (!providers.executor) {
|
|
837
|
+
return coding
|
|
838
|
+
? JSON.stringify({
|
|
839
|
+
error: "coding_dispatch_unavailable",
|
|
840
|
+
message: "This execution context has no Executor wired in, so a coding-kind sub-agent cannot be dispatched.",
|
|
841
|
+
})
|
|
842
|
+
: JSON.stringify({
|
|
843
|
+
error: "sandbox_dispatch_unavailable",
|
|
844
|
+
message: "This execution context has no Executor wired in, so a sandbox-mode sub-agent cannot be dispatched.",
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
// Counted as a running sibling while it is waited on, as a fresh dispatch is.
|
|
848
|
+
const finishSibling = delegationSiblings.start();
|
|
849
|
+
try {
|
|
850
|
+
return await awaitDelegatedChild({
|
|
851
|
+
executor: providers.executor,
|
|
852
|
+
childRunId: child.id,
|
|
853
|
+
createdAtMs: child.createdAt.getTime(),
|
|
854
|
+
kind: coding ? "coding" : "native-sandbox",
|
|
855
|
+
boundName,
|
|
856
|
+
mergeOrderNote: coding ? undefined : mergeOrderNote,
|
|
857
|
+
onSettled: finishSibling,
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
finally {
|
|
861
|
+
finishSibling();
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
const unguardedBuiltinHandler = (name) => {
|
|
694
865
|
if (loaded.memoryEnabled && MEMORY_TOOL_NAMES.has(name)) {
|
|
695
866
|
return async (argsJson) => {
|
|
696
867
|
return handleMemoryTool(name, argsJson, loaded.agentId, providers.memory);
|
|
@@ -703,6 +874,7 @@ export function createNativeRunTools(options) {
|
|
|
703
874
|
agentId: loaded.agentId,
|
|
704
875
|
links: loaded.repositoryLinks,
|
|
705
876
|
hosts: reviewHosts,
|
|
877
|
+
reads: reviewReads,
|
|
706
878
|
db,
|
|
707
879
|
runCheck: check && !check.completedAt
|
|
708
880
|
? {
|
|
@@ -791,7 +963,9 @@ export function createNativeRunTools(options) {
|
|
|
791
963
|
};
|
|
792
964
|
}
|
|
793
965
|
if (name.startsWith(DELEGATE_TOOL_PREFIX)) {
|
|
794
|
-
return async (argsJson) => {
|
|
966
|
+
return async (argsJson, toolCallId) => {
|
|
967
|
+
// An empty id (an adapter that had none) is no key: every such call would share it.
|
|
968
|
+
const callId = toolCallId || undefined;
|
|
795
969
|
const boundName = name.slice(DELEGATE_TOOL_PREFIX.length);
|
|
796
970
|
const edge = loaded.subAgentEdges.find((e) => e.boundName === boundName);
|
|
797
971
|
if (!edge) {
|
|
@@ -800,8 +974,36 @@ export function createNativeRunTools(options) {
|
|
|
800
974
|
message: `No sub-agent is bound to name "${boundName}".`,
|
|
801
975
|
});
|
|
802
976
|
}
|
|
977
|
+
// A re-executed delegate step (a resume, or a takeover under a new version) finds the
|
|
978
|
+
// child this very call created and waits on it again, instead of refusing it as a duplicate.
|
|
979
|
+
const existingChild = await findDelegationChild(db, runId, edge.childAgentId, callId);
|
|
980
|
+
if (existingChild) {
|
|
981
|
+
runnerLog.info({ runId, childRunId: existingChild.id, boundName }, "delegation re-attached");
|
|
982
|
+
return reattachDelegatedChild(existingChild, boundName, argsJson);
|
|
983
|
+
}
|
|
803
984
|
let release = await delegationGate.acquire();
|
|
804
985
|
let finishSibling = () => { };
|
|
986
|
+
/**
|
|
987
|
+
* A child create that lost the (parentRunId, parentCallId) unique key to another execution of
|
|
988
|
+
* this same delegate step (a stalled owner overlapping an adopted attempt): wait on the child
|
|
989
|
+
* that execution created, as a re-executed step does. A key held by no child of this agent
|
|
990
|
+
* (an id colliding with another sub-agent's call) is the model's to see, never a run failure.
|
|
991
|
+
*/
|
|
992
|
+
const afterDelegationKeyConflict = async (err) => {
|
|
993
|
+
if (!(err instanceof Prisma.PrismaClientKnownRequestError && err.code === "P2002"))
|
|
994
|
+
throw err;
|
|
995
|
+
release();
|
|
996
|
+
const raced = await findDelegationChild(db, runId, edge.childAgentId, callId);
|
|
997
|
+
if (raced) {
|
|
998
|
+
runnerLog.info({ runId, childRunId: raced.id, boundName }, "delegation re-attached after a concurrent create");
|
|
999
|
+
return reattachDelegatedChild(raced, boundName, argsJson);
|
|
1000
|
+
}
|
|
1001
|
+
runnerLog.warn({ err, runId, boundName }, "delegation child create hit a unique key held by no child of this agent");
|
|
1002
|
+
return JSON.stringify({
|
|
1003
|
+
error: "delegation_conflict",
|
|
1004
|
+
message: "The sub-agent run could not be created: its call id is already used by another sub-agent run.",
|
|
1005
|
+
});
|
|
1006
|
+
};
|
|
805
1007
|
try {
|
|
806
1008
|
// At most maxDelegationsPerRun dispatches per run (default one: a
|
|
807
1009
|
// classifier deciding plan-vs-implement commits to exactly one child),
|
|
@@ -839,6 +1041,7 @@ export function createNativeRunTools(options) {
|
|
|
839
1041
|
while (delegationSiblings.inFlight > 0) {
|
|
840
1042
|
// Taken before the budget read, so a sibling that finishes during it still wakes this wait.
|
|
841
1043
|
const finishes = delegationSiblings.finishes;
|
|
1044
|
+
// What dispatch will reserve: a coding child's base too, its overrun is never reserved.
|
|
842
1045
|
const { exhaustedBy } = await effectiveBudgetForRun(db, childAgent, new Date(), runId);
|
|
843
1046
|
const remainingMs = deadline - Date.now();
|
|
844
1047
|
if (!exhaustedBy || remainingMs <= 0)
|
|
@@ -898,6 +1101,7 @@ export function createNativeRunTools(options) {
|
|
|
898
1101
|
continuesCodingRunId: args.continuePriorRun,
|
|
899
1102
|
mergeOrder: args.mergeOrder,
|
|
900
1103
|
parentRunId: runId,
|
|
1104
|
+
parentCallId: callId,
|
|
901
1105
|
// The child's result flows back into this run, which the
|
|
902
1106
|
// triggerer sees, so the child is visible to them too.
|
|
903
1107
|
triggeredById: existingRun.triggeredById,
|
|
@@ -917,7 +1121,7 @@ export function createNativeRunTools(options) {
|
|
|
917
1121
|
// a pull request another deployment opened, say) is the model's to
|
|
918
1122
|
// report, not a reason to fail the whole run.
|
|
919
1123
|
if (!(err instanceof ContinuationRefusedError))
|
|
920
|
-
|
|
1124
|
+
return await afterDelegationKeyConflict(err);
|
|
921
1125
|
return JSON.stringify({
|
|
922
1126
|
error: "continuation_refused",
|
|
923
1127
|
message: `${err.message} No sub-agent run was started. Do not open a new pull request in its place: ` +
|
|
@@ -928,49 +1132,16 @@ export function createNativeRunTools(options) {
|
|
|
928
1132
|
return JSON.stringify({ error: "dispatch_failed", message: "The sub-agent run could not be created." });
|
|
929
1133
|
}
|
|
930
1134
|
const childRunId = dispatched.run.id;
|
|
931
|
-
const startedAt = Date.now();
|
|
932
1135
|
runnerLog.info({ runId, childRunId, boundName, kind: "coding" }, "delegation started");
|
|
933
|
-
|
|
934
|
-
where: { runId: childRunId },
|
|
935
|
-
select: { timeoutSec: true },
|
|
936
|
-
});
|
|
937
|
-
const { queueTimeoutSec } = loadCodingConcurrencyConfig();
|
|
938
|
-
const waited = await waitForCodingChild({
|
|
939
|
-
db,
|
|
1136
|
+
return await awaitDelegatedChild({
|
|
940
1137
|
executor: providers.executor,
|
|
941
1138
|
childRunId,
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
});
|
|
945
|
-
finishSibling();
|
|
946
|
-
runnerLog.info({
|
|
947
|
-
runId,
|
|
948
|
-
childRunId,
|
|
1139
|
+
createdAtMs: dispatched.run.startedAt.getTime(),
|
|
1140
|
+
kind: "coding",
|
|
949
1141
|
boundName,
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
}, "delegation finished");
|
|
953
|
-
if (waited.kind === "timed_out") {
|
|
954
|
-
return JSON.stringify({
|
|
955
|
-
error: "subagent_wait_timed_out",
|
|
956
|
-
runId: childRunId,
|
|
957
|
-
message: "The coding sub-agent did not finish within its queue timeout plus run timeout; it was stopped and produced no result.",
|
|
958
|
-
});
|
|
959
|
-
}
|
|
960
|
-
if (waited.kind === "parent_cancelled") {
|
|
961
|
-
return JSON.stringify({
|
|
962
|
-
error: "parent_cancelled",
|
|
963
|
-
runId: childRunId,
|
|
964
|
-
message: "This run was cancelled while waiting for the coding sub-agent; the sub-agent was stopped.",
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
const stored = await db.codingRun
|
|
968
|
-
.findUnique({ where: { runId: childRunId }, select: { result: true } })
|
|
969
|
-
.catch((err) => {
|
|
970
|
-
runnerLog.warn({ err, childRunId }, "could not read the coding sub-run's result");
|
|
971
|
-
return null;
|
|
1142
|
+
mergeOrderNote: undefined,
|
|
1143
|
+
onSettled: finishSibling,
|
|
972
1144
|
});
|
|
973
|
-
return codingChildResult(waited.run, stored?.result);
|
|
974
1145
|
}
|
|
975
1146
|
const taskOverride = delegationTaskOverride(args);
|
|
976
1147
|
// mergeOrder is a coding-only concept (it orders CodingRuns within a merge); a native
|
|
@@ -988,73 +1159,64 @@ export function createNativeRunTools(options) {
|
|
|
988
1159
|
message: "This execution context has no Executor wired in, so a sandbox-mode sub-agent cannot be dispatched.",
|
|
989
1160
|
});
|
|
990
1161
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1162
|
+
let dispatched;
|
|
1163
|
+
try {
|
|
1164
|
+
dispatched = await dispatchRun({
|
|
1165
|
+
db,
|
|
1166
|
+
executor: providers.executor,
|
|
1167
|
+
selfDefects: { db, issueTrackers },
|
|
1168
|
+
agentId: edge.childAgentId,
|
|
1169
|
+
trigger: "subagent",
|
|
1170
|
+
taskOverride,
|
|
1171
|
+
grantedParentMemoryKeys: args.grantParentMemoryKeys ?? [],
|
|
1172
|
+
parentRunId: runId,
|
|
1173
|
+
parentCallId: callId,
|
|
1174
|
+
triggeredById: existingRun.triggeredById,
|
|
1175
|
+
awaitExecution: true,
|
|
1176
|
+
onPersisted: (persistedRun) => {
|
|
1177
|
+
if (persistedRun.status !== "refused" && persistedRun.status !== "failed") {
|
|
1178
|
+
finishSibling = delegationSiblings.start();
|
|
1179
|
+
}
|
|
1180
|
+
release();
|
|
1181
|
+
},
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
catch (err) {
|
|
1185
|
+
return await afterDelegationKeyConflict(err);
|
|
1186
|
+
}
|
|
1009
1187
|
if (!dispatched) {
|
|
1010
1188
|
return JSON.stringify({ error: "dispatch_failed", message: "The sub-agent run could not be created." });
|
|
1011
1189
|
}
|
|
1012
1190
|
const childRunId = dispatched.run.id;
|
|
1013
|
-
const startedAt = Date.now();
|
|
1014
1191
|
runnerLog.info({ runId, childRunId, boundName, kind: "native-sandbox" }, "delegation started");
|
|
1015
|
-
|
|
1016
|
-
const waited = await waitForCodingChild({
|
|
1017
|
-
db,
|
|
1192
|
+
return await awaitDelegatedChild({
|
|
1018
1193
|
executor: providers.executor,
|
|
1019
1194
|
childRunId,
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
});
|
|
1023
|
-
finishSibling();
|
|
1024
|
-
runnerLog.info({
|
|
1025
|
-
runId,
|
|
1026
|
-
childRunId,
|
|
1195
|
+
createdAtMs: dispatched.run.startedAt.getTime(),
|
|
1196
|
+
kind: "native-sandbox",
|
|
1027
1197
|
boundName,
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1198
|
+
mergeOrderNote,
|
|
1199
|
+
onSettled: finishSibling,
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
let childRun;
|
|
1203
|
+
try {
|
|
1204
|
+
childRun = await db.run.create({
|
|
1205
|
+
data: {
|
|
1206
|
+
agentId: edge.childAgentId,
|
|
1207
|
+
trigger: "subagent",
|
|
1208
|
+
parentRunId: runId,
|
|
1209
|
+
parentCallId: callId,
|
|
1210
|
+
grantedParentMemoryKeys: args.grantParentMemoryKeys ?? [],
|
|
1211
|
+
taskOverride,
|
|
1212
|
+
triggeredById: existingRun.triggeredById,
|
|
1213
|
+
nativeExecutionMode: childAgent.nativeExecutionMode,
|
|
1214
|
+
},
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
catch (err) {
|
|
1218
|
+
return await afterDelegationKeyConflict(err);
|
|
1046
1219
|
}
|
|
1047
|
-
const childRun = await db.run.create({
|
|
1048
|
-
data: {
|
|
1049
|
-
agentId: edge.childAgentId,
|
|
1050
|
-
trigger: "subagent",
|
|
1051
|
-
parentRunId: runId,
|
|
1052
|
-
grantedParentMemoryKeys: args.grantParentMemoryKeys ?? [],
|
|
1053
|
-
taskOverride,
|
|
1054
|
-
triggeredById: existingRun.triggeredById,
|
|
1055
|
-
nativeExecutionMode: childAgent.nativeExecutionMode,
|
|
1056
|
-
},
|
|
1057
|
-
});
|
|
1058
1220
|
finishSibling = delegationSiblings.start();
|
|
1059
1221
|
// The child row exists: admit the next delegation while this child runs.
|
|
1060
1222
|
release();
|
|
@@ -1081,6 +1243,26 @@ export function createNativeRunTools(options) {
|
|
|
1081
1243
|
}
|
|
1082
1244
|
return undefined;
|
|
1083
1245
|
};
|
|
1246
|
+
/**
|
|
1247
|
+
* The only route to a built-in tool, in both execution modes (the in-process loop and the native
|
|
1248
|
+
* gateway's builtin.call). A tool that posts model-written text to a host, and a delegate_to_*
|
|
1249
|
+
* call (its task text becomes the child run's stored task), has every attached secret's value
|
|
1250
|
+
* masked in its arguments first; when the secrets cannot be read the call is refused and
|
|
1251
|
+
* neither the host nor a child run is reached. (The native gateway serves delegate_to_* through
|
|
1252
|
+
* durableDelegate, which masks the same way.)
|
|
1253
|
+
*/
|
|
1254
|
+
const builtinHandler = (name) => {
|
|
1255
|
+
const handler = unguardedBuiltinHandler(name);
|
|
1256
|
+
if (!handler || !(POSTING_TOOL_NAMES.has(name) || name.startsWith(DELEGATE_TOOL_PREFIX)))
|
|
1257
|
+
return handler;
|
|
1258
|
+
return async (argsJson, toolCallId) => {
|
|
1259
|
+
const masked = await maskModelWrittenArgs({ db, secrets: providers.secrets, agentId: loaded.agentId, runId }, name, argsJson);
|
|
1260
|
+
if (masked === undefined) {
|
|
1261
|
+
return JSON.stringify({ error: "secret_check_unavailable", message: SECRET_CHECK_UNAVAILABLE_MESSAGE });
|
|
1262
|
+
}
|
|
1263
|
+
return handler(masked, toolCallId);
|
|
1264
|
+
};
|
|
1265
|
+
};
|
|
1084
1266
|
/**
|
|
1085
1267
|
* The privileged host for one call of the user tool `name`, scoped to that attachment's
|
|
1086
1268
|
* consented capabilities. Undefined for a name that is not an attached user tool. In-process it
|
|
@@ -1101,17 +1283,15 @@ export function createNativeRunTools(options) {
|
|
|
1101
1283
|
const tool = toolsByName.get(name);
|
|
1102
1284
|
return tool ? scopedHost(name, tool, signal, redactSecretValues) : undefined;
|
|
1103
1285
|
};
|
|
1104
|
-
/**
|
|
1286
|
+
/**
|
|
1287
|
+
* Every secret value the user tool `name` may use (readable or brokered), for console redaction
|
|
1288
|
+
* by a stateless gateway. Rejects when any read fails (readRedactionValues).
|
|
1289
|
+
*/
|
|
1105
1290
|
const readableSecretValues = async (name) => {
|
|
1106
1291
|
const tool = toolsByName.get(name);
|
|
1107
1292
|
if (!tool)
|
|
1108
1293
|
return [];
|
|
1109
|
-
|
|
1110
|
-
const values = await Promise.all(tool.allowedSecrets.map((secret) => (scoped.resolve
|
|
1111
|
-
? scoped.resolve(secret).then((e) => (e ? consoleRedactionValues(e) : []))
|
|
1112
|
-
: scoped.get(secret).then((v) => (v === undefined ? [] : [v]))).catch(() => [])));
|
|
1113
|
-
// A SigV4 secret's key and token alone, too: the same set the in-process host redacts.
|
|
1114
|
-
return values.flat().filter((value) => typeof value === "string");
|
|
1294
|
+
return readRedactionValues(scopeSecretsAccessor(secretsAccessor, tool.allowedSecrets), tool.allowedSecrets);
|
|
1115
1295
|
};
|
|
1116
1296
|
const runUserTool = async (name, argsJson) => {
|
|
1117
1297
|
const tool = toolsByName.get(name);
|
|
@@ -1123,9 +1303,9 @@ export function createNativeRunTools(options) {
|
|
|
1123
1303
|
}
|
|
1124
1304
|
return runUserToolCall(tool, argsJson, (signal) => scopedHost(name, tool, signal));
|
|
1125
1305
|
};
|
|
1126
|
-
const runSandboxTool = async (name, argsJson) => {
|
|
1306
|
+
const runSandboxTool = async (name, argsJson, callId) => {
|
|
1127
1307
|
const builtin = builtinHandler(name);
|
|
1128
|
-
return builtin ? builtin(argsJson) : runUserTool(name, argsJson);
|
|
1308
|
+
return builtin ? builtin(argsJson, callId) : runUserTool(name, argsJson);
|
|
1129
1309
|
};
|
|
1130
1310
|
return { toolsByName, builtinHandler, privilegedHostFor, readableSecretValues, runUserTool, runSandboxTool };
|
|
1131
1311
|
}
|
|
@@ -1135,11 +1315,13 @@ export function createNativeRunTools(options) {
|
|
|
1135
1315
|
* tree's shared budget (computeRunTreeSpend) then counts a running parent's spend so far, as it
|
|
1136
1316
|
* already does for coding runs, whose proxy ledger writes their totals live. Best-effort: a
|
|
1137
1317
|
* failed write only delays what observers see, and finishRun writes the final totals anyway.
|
|
1318
|
+
* A cancelled run takes them too: a stop lands mid-step, and that step's spend is real, while the
|
|
1319
|
+
* cancelled run's terminal write (failNativeRun) records no totals of its own.
|
|
1138
1320
|
*/
|
|
1139
1321
|
export async function recordNativeRunProgress(db, runId, progress) {
|
|
1140
1322
|
try {
|
|
1141
1323
|
await db.run.updateMany({
|
|
1142
|
-
where: { id: runId, status: "running" },
|
|
1324
|
+
where: { id: runId, status: { in: ["running", "cancelled"] } },
|
|
1143
1325
|
data: {
|
|
1144
1326
|
turns: progress.turns,
|
|
1145
1327
|
tokensIn: progress.usage.tokensIn,
|
|
@@ -1153,6 +1335,35 @@ export async function recordNativeRunProgress(db, runId, progress) {
|
|
|
1153
1335
|
runnerLog.warn({ err, runId }, "failed to record run progress");
|
|
1154
1336
|
}
|
|
1155
1337
|
}
|
|
1338
|
+
/**
|
|
1339
|
+
* `texts` with every value of every secret attached to the run's agent masked, for a terminal
|
|
1340
|
+
* write: the stored row is what get_run, the viewer, host and issue status comments and run
|
|
1341
|
+
* notifications all read. Fails closed: when the secrets cannot be read, every non-null text is
|
|
1342
|
+
* replaced by WITHHELD_TEXT_NOTICE (the log line carries no text and no error message). A pure
|
|
1343
|
+
* function of the stored secrets, so a durable replay writes the same row.
|
|
1344
|
+
*/
|
|
1345
|
+
async function maskRunTexts(ctx, texts) {
|
|
1346
|
+
const entries = Object.entries(texts);
|
|
1347
|
+
if (!entries.some(([, text]) => typeof text === "string" && text.length > 0))
|
|
1348
|
+
return texts;
|
|
1349
|
+
let mask;
|
|
1350
|
+
try {
|
|
1351
|
+
const row = await ctx.db.run.findUnique({ where: { id: ctx.runId }, select: { agentId: true } });
|
|
1352
|
+
if (!row)
|
|
1353
|
+
throw new Error("run not found");
|
|
1354
|
+
const named = await loadAgentSecretValues(ctx.db, ctx.providers.secrets, row.agentId);
|
|
1355
|
+
mask = (text) => maskNamedSecrets(text, named);
|
|
1356
|
+
}
|
|
1357
|
+
catch (err) {
|
|
1358
|
+
runnerLog.warn({
|
|
1359
|
+
runId: ctx.runId,
|
|
1360
|
+
event: "run_text_secret_check_failed",
|
|
1361
|
+
errorName: err instanceof Error ? err.name : typeof err,
|
|
1362
|
+
}, "could not read the agent's secrets to check the run's final text and error; storing the withheld notice");
|
|
1363
|
+
mask = () => WITHHELD_TEXT_NOTICE;
|
|
1364
|
+
}
|
|
1365
|
+
return Object.fromEntries(entries.map(([key, text]) => [key, typeof text === "string" && text.length > 0 ? mask(text) : text]));
|
|
1366
|
+
}
|
|
1156
1367
|
/** Everything after the terminal write, shared by the normal and backstop paths. */
|
|
1157
1368
|
async function settleFinishedNativeRun(ctx, finished, claimed) {
|
|
1158
1369
|
const { runId, db, providers, reviewHosts, repoAccess, issueTrackers } = ctx;
|
|
@@ -1192,17 +1403,22 @@ async function settleFinishedNativeRun(ctx, finished, claimed) {
|
|
|
1192
1403
|
// host reads). Only for a tree root that delegated. Not gated on `claimed`: the sync is
|
|
1193
1404
|
// idempotent (an unchanged check writes nothing). Never throws.
|
|
1194
1405
|
await syncMergeOrderChecksAfterRun({ db, hosts: reviewHosts }, finished);
|
|
1406
|
+
// A reviewer run's end may be the last thing a pull request waited for: mark it ready for review
|
|
1407
|
+
// when its builder link opted in (#287). Last, so nothing above waits on its host reads; idempotent
|
|
1408
|
+
// (claimed once per pull request); no host reads unless a link opted in. Never throws.
|
|
1409
|
+
await markReadyAfterRun({ db, hosts: reviewHosts, log: runnerLog }, runId);
|
|
1195
1410
|
return finished;
|
|
1196
1411
|
}
|
|
1197
1412
|
/** The terminal write for an engine result, then its usage, host/issue status, and follow-ups. */
|
|
1198
1413
|
export async function finishNativeRun(ctx, model, result) {
|
|
1414
|
+
const texts = await maskRunTexts(ctx, { error: result.error ?? null, finalText: result.finalText || null });
|
|
1199
1415
|
const { run: finished, claimed } = await finishRunClaimed(ctx.db, ctx.runId, {
|
|
1200
1416
|
status: result.status,
|
|
1201
1417
|
tokensIn: result.usage.tokensIn,
|
|
1202
1418
|
tokensOut: result.usage.tokensOut,
|
|
1203
1419
|
costUsd: result.usage.costUsd,
|
|
1204
|
-
error:
|
|
1205
|
-
finalText:
|
|
1420
|
+
error: texts.error,
|
|
1421
|
+
finalText: texts.finalText,
|
|
1206
1422
|
turns: result.turns,
|
|
1207
1423
|
finishedAt: new Date(),
|
|
1208
1424
|
});
|
|
@@ -1212,11 +1428,24 @@ export async function finishNativeRun(ctx, model, result) {
|
|
|
1212
1428
|
}
|
|
1213
1429
|
/** The backstop terminal write for a run that threw. A cancellation is not a failure: it carries the operator's own reason. */
|
|
1214
1430
|
export async function failNativeRun(ctx, err) {
|
|
1431
|
+
const { error } = await maskRunTexts(ctx, { error: err instanceof Error ? err.message : String(err) });
|
|
1215
1432
|
const { run: finished, claimed } = await finishRunClaimed(ctx.db, ctx.runId, {
|
|
1216
1433
|
status: err instanceof RunCancelledError || err instanceof SandboxRunCancelledError ? "cancelled" : "failed",
|
|
1217
|
-
error
|
|
1434
|
+
error,
|
|
1435
|
+
finishedAt: new Date(),
|
|
1436
|
+
});
|
|
1437
|
+
return settleFinishedNativeRun(ctx, finished, claimed);
|
|
1438
|
+
}
|
|
1439
|
+
/** The terminal write for a run that cannot continue (it ends `lost` with `reason`), then the same settle path. */
|
|
1440
|
+
export async function loseNativeRun(ctx, reason) {
|
|
1441
|
+
const { error } = await maskRunTexts(ctx, { error: reason });
|
|
1442
|
+
const { run: finished, claimed } = await finishRunClaimed(ctx.db, ctx.runId, {
|
|
1443
|
+
status: "lost",
|
|
1444
|
+
error,
|
|
1218
1445
|
finishedAt: new Date(),
|
|
1219
1446
|
});
|
|
1447
|
+
if (claimed)
|
|
1448
|
+
await stopChildrenOfLostRun(ctx.db, ctx.providers.executor, ctx.runId);
|
|
1220
1449
|
return settleFinishedNativeRun(ctx, finished, claimed);
|
|
1221
1450
|
}
|
|
1222
1451
|
/** Where a run stands for the native gateway: still drivable, cancelled (its task), or otherwise ended. */
|
|
@@ -1250,6 +1479,25 @@ export function sandboxWorkerInput(runId, loaded, tools) {
|
|
|
1250
1479
|
pricing: { ...loaded.pricing.entry, efforts: [...loaded.pricing.entry.efforts] },
|
|
1251
1480
|
};
|
|
1252
1481
|
}
|
|
1482
|
+
/**
|
|
1483
|
+
* A tool call's model-written arguments with every secret value attached to the agent masked, or
|
|
1484
|
+
* undefined (logged by error name only) when the secrets cannot be read and the call must be refused.
|
|
1485
|
+
*/
|
|
1486
|
+
async function maskModelWrittenArgs(ctx, tool, argsJson) {
|
|
1487
|
+
try {
|
|
1488
|
+
const named = await loadAgentSecretValues(ctx.db, ctx.secrets, ctx.agentId);
|
|
1489
|
+
return maskNamedSecrets(argsJson, named);
|
|
1490
|
+
}
|
|
1491
|
+
catch (err) {
|
|
1492
|
+
runnerLog.warn({
|
|
1493
|
+
runId: ctx.runId,
|
|
1494
|
+
tool,
|
|
1495
|
+
event: "post_secret_check_failed",
|
|
1496
|
+
errorName: err instanceof Error ? err.name : typeof err,
|
|
1497
|
+
}, "could not read the agent's secrets to check a posted text; refusing the call");
|
|
1498
|
+
return undefined;
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1253
1501
|
/** Long-poll window: well under common proxy and load-balancer idle timeouts. */
|
|
1254
1502
|
export const DELEGATION_POLL_WINDOW_MS = 20_000;
|
|
1255
1503
|
/**
|
|
@@ -1308,13 +1556,24 @@ export async function durableDelegate(ctx, callId, name, argsJson) {
|
|
|
1308
1556
|
if (!childRunId && state?.childAgentId === edge.childAgentId) {
|
|
1309
1557
|
// A replica that died between dispatching the child and recording it left the child row:
|
|
1310
1558
|
// adopt it rather than refusing this very delegation as a duplicate.
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1559
|
+
childRunId = (await findDelegationChild(db, runId, edge.childAgentId, callId))?.id ?? null;
|
|
1560
|
+
// Recorded, so later calls wait on it by id.
|
|
1561
|
+
if (childRunId) {
|
|
1562
|
+
await ledger.setDelegation(sessionId, callId, { status: "pending", childAgentId: edge.childAgentId, childRunId });
|
|
1563
|
+
}
|
|
1316
1564
|
}
|
|
1317
1565
|
if (!childRunId) {
|
|
1566
|
+
// About to create a child: its task is model-written and stored, so mask the parent's secret
|
|
1567
|
+
// values first. Only here, never on a poll of an existing child (a transient secret-read
|
|
1568
|
+
// failure must not orphan a running child). Recorded as the call's result, which also completes a waiting row; the model's retry comes with a new callId.
|
|
1569
|
+
const maskedArgsJson = await maskModelWrittenArgs({ db, secrets: providers.secrets, agentId: loaded.agentId, runId }, name, argsJson);
|
|
1570
|
+
if (maskedArgsJson === undefined) {
|
|
1571
|
+
return finish(JSON.stringify({ error: "secret_check_unavailable", message: SECRET_CHECK_UNAVAILABLE_MESSAGE }));
|
|
1572
|
+
}
|
|
1573
|
+
const maskedArgs = parseDelegateArgs(maskedArgsJson);
|
|
1574
|
+
if ("refusal" in maskedArgs)
|
|
1575
|
+
return finish(maskedArgs.refusal);
|
|
1576
|
+
const dispatchArgs = maskedArgs.args;
|
|
1318
1577
|
const limit = loaded.maxDelegationsPerRun ?? 1;
|
|
1319
1578
|
const refusalNow = async (reader) => {
|
|
1320
1579
|
const prior = await reader.run.findMany({ where: { parentRunId: runId }, select: { agentId: true } });
|
|
@@ -1356,9 +1615,17 @@ export async function durableDelegate(ctx, callId, name, argsJson) {
|
|
|
1356
1615
|
agentId: edge.childAgentId,
|
|
1357
1616
|
trigger: "subagent",
|
|
1358
1617
|
...(coding
|
|
1359
|
-
? {
|
|
1360
|
-
|
|
1618
|
+
? {
|
|
1619
|
+
codingTask: dispatchArgs.task,
|
|
1620
|
+
continuesCodingRunId: dispatchArgs.continuePriorRun,
|
|
1621
|
+
mergeOrder: dispatchArgs.mergeOrder,
|
|
1622
|
+
}
|
|
1623
|
+
: {
|
|
1624
|
+
taskOverride: delegationTaskOverride(dispatchArgs),
|
|
1625
|
+
grantedParentMemoryKeys: dispatchArgs.grantParentMemoryKeys ?? [],
|
|
1626
|
+
}),
|
|
1361
1627
|
parentRunId: runId,
|
|
1628
|
+
parentCallId: callId,
|
|
1362
1629
|
// The child's result flows back into this run, which the triggerer sees, so the child is visible to them too.
|
|
1363
1630
|
triggeredById: existingRun.triggeredById,
|
|
1364
1631
|
beforePersist: async (tx) => {
|
|
@@ -1370,12 +1637,21 @@ export async function durableDelegate(ctx, callId, name, argsJson) {
|
|
|
1370
1637
|
});
|
|
1371
1638
|
}
|
|
1372
1639
|
catch (err) {
|
|
1373
|
-
if (
|
|
1374
|
-
|
|
1640
|
+
if (err instanceof ContinuationRefusedError) {
|
|
1641
|
+
return finish(JSON.stringify({
|
|
1642
|
+
error: "continuation_refused",
|
|
1643
|
+
message: `${err.message} No sub-agent run was started. Do not open a new pull request in its place: ` +
|
|
1644
|
+
"tell the requester that this wardby deployment cannot continue that pull request's branch.",
|
|
1645
|
+
}));
|
|
1646
|
+
}
|
|
1647
|
+
// Recorded as the call's result, so the model can report it and a retried callId never
|
|
1648
|
+
// dispatches twice. Only the leading code is exposed: messages can carry internals.
|
|
1649
|
+
const code = declaredCodeOf(err);
|
|
1650
|
+
const values = await ctx.secretValues?.().catch(() => undefined);
|
|
1651
|
+
logUnexpectedError(runnerLog, err, values, "delegation dispatch failed", { runId, boundName });
|
|
1375
1652
|
return finish(JSON.stringify({
|
|
1376
|
-
error: "
|
|
1377
|
-
message:
|
|
1378
|
-
"tell the requester that this wardby deployment cannot continue that pull request's branch.",
|
|
1653
|
+
error: "dispatch_failed",
|
|
1654
|
+
message: `The sub-agent run could not be created${code ? ` (${code})` : ""}.`,
|
|
1379
1655
|
}));
|
|
1380
1656
|
}
|
|
1381
1657
|
if (!dispatched) {
|
|
@@ -1403,7 +1679,7 @@ export async function durableDelegate(ctx, callId, name, argsJson) {
|
|
|
1403
1679
|
const stored = await db.codingRun
|
|
1404
1680
|
.findUnique({ where: { runId: childRunId }, select: { result: true } })
|
|
1405
1681
|
.catch(() => null);
|
|
1406
|
-
return finish(codingChildResult(child, stored?.result));
|
|
1682
|
+
return finish(codingChildResult(child, stored?.result, await loadBudgetEvent(db, childRunId)));
|
|
1407
1683
|
}
|
|
1408
1684
|
if (now() - startedAt >= boundMs) {
|
|
1409
1685
|
await executor.stop(childRunId, "sub-agent wait timed out").catch((err) => {
|
|
@@ -1505,8 +1781,17 @@ export async function createSandboxSession(options) {
|
|
|
1505
1781
|
sessionId: session.id,
|
|
1506
1782
|
capability,
|
|
1507
1783
|
input: { ...input, gateway: { url: options.gatewayUrl, capability } },
|
|
1784
|
+
secretValues: () => userToolSecretValues(tools, Object.keys(input.userTools)),
|
|
1508
1785
|
};
|
|
1509
1786
|
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Every secret value the sandbox run's user tools `names` may read (readable or brokered): what its
|
|
1789
|
+
* worker can be handed, so what the gateway checks its cause codes against and a launcher masks
|
|
1790
|
+
* from the worker's output tail. Rejects when any read fails (readRedactionValues).
|
|
1791
|
+
*/
|
|
1792
|
+
export async function userToolSecretValues(tools, names) {
|
|
1793
|
+
return (await Promise.all(names.map((name) => tools.readableSecretValues(name)))).flat();
|
|
1794
|
+
}
|
|
1510
1795
|
/** Run.executionBackend for a sandbox-mode run whose worker is (or was) launched. */
|
|
1511
1796
|
export const NATIVE_SANDBOX_BACKEND = "native-sandbox";
|
|
1512
1797
|
/** The stored form of a sandbox capability: never the token itself. */
|
|
@@ -1539,13 +1824,18 @@ async function executeTrackedRun(runId, providers, db, onText, step) {
|
|
|
1539
1824
|
? (providers.repoAccess ?? createRepoAccessGate({ db, hosts: reviewHosts }))
|
|
1540
1825
|
: undefined;
|
|
1541
1826
|
const issueTrackers = configuredIssueTrackers(providers.issueTrackers);
|
|
1827
|
+
// Inline execution checks for a stop before every step (stopAwareStep); a durable executor passes
|
|
1828
|
+
// its own step runner, which does its own check (DbosExecutor wraps it in stopAwareStep too).
|
|
1829
|
+
if (step === runStepInline)
|
|
1830
|
+
step = stopAwareStep(db, runId);
|
|
1542
1831
|
// Fails a run that ends before its engine starts, closing what its trigger opened (the review
|
|
1543
1832
|
// check, the host and issue status comments) exactly as the normal and catch paths below do.
|
|
1544
1833
|
// Deliberately no self-defect: every caller is a configuration state, not this run's defect (an
|
|
1545
1834
|
// admin disabled or removed the model, or this deployment has no coding or native sandbox
|
|
1546
1835
|
// executor), and filing would open one defect per affected agent rather than describe a failure
|
|
1547
1836
|
// of that agent.
|
|
1548
|
-
const finishEarly = async (
|
|
1837
|
+
const finishEarly = async (reason) => {
|
|
1838
|
+
const { error } = await maskRunTexts({ runId, db, providers }, { error: reason });
|
|
1549
1839
|
const finished = await finishRun(db, runId, { status: "failed", error, finishedAt: new Date() });
|
|
1550
1840
|
await closeOpenHostCheck(db, finished, reviewHosts);
|
|
1551
1841
|
await completeHostStatus(db, finished, reviewHosts);
|
|
@@ -1601,6 +1891,7 @@ async function executeTrackedRun(runId, providers, db, onText, step) {
|
|
|
1601
1891
|
ctx: { providers: { llm }, onText, onProgress },
|
|
1602
1892
|
builtinHandler: tools.builtinHandler,
|
|
1603
1893
|
privilegedHostFor: tools.privilegedHostFor,
|
|
1894
|
+
readableSecretValues: tools.readableSecretValues,
|
|
1604
1895
|
drivability: () => runDrivability(db, runId),
|
|
1605
1896
|
launcher: providers.nativeSandbox,
|
|
1606
1897
|
});
|
|
@@ -1634,6 +1925,10 @@ async function executeTrackedRun(runId, providers, db, onText, step) {
|
|
|
1634
1925
|
logRunOwnershipLost(runId, err);
|
|
1635
1926
|
throw err;
|
|
1636
1927
|
}
|
|
1928
|
+
// A replay that no longer matches its record (a run recorded by a release whose steps differ)
|
|
1929
|
+
// cannot continue: it ends lost, not failed, through the same settle path.
|
|
1930
|
+
if (err instanceof StepReplayMismatchError)
|
|
1931
|
+
return loseNativeRun(finishContext, STEPS_CHANGED_REASON);
|
|
1637
1932
|
return failNativeRun(finishContext, err);
|
|
1638
1933
|
}
|
|
1639
1934
|
}
|