@wardby/cli 0.5.3 → 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/.env.example +33 -0
- package/README.md +25 -14
- package/deploy/local/docker-compose.quickstart-coding.yml +13 -0
- package/dist/claude-coding-worker/context.d.ts +22 -0
- package/dist/claude-coding-worker/context.js +92 -0
- package/dist/claude-coding-worker/driver.d.ts +27 -3
- package/dist/claude-coding-worker/driver.js +161 -20
- package/dist/claude-coding-worker/main.js +34 -6
- package/dist/claude-coding-worker/sdk.js +25 -5
- 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 +6 -2
- package/dist/cli-native-mode.d.ts +9 -0
- package/dist/cli-native-mode.js +20 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +161 -11
- package/dist/coding/claude-context.d.ts +45 -0
- package/dist/coding/claude-context.js +434 -0
- 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 +50 -118
- package/dist/coding/profile.js +51 -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 +292 -270
- package/dist/coding/protocol.js +322 -15
- 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 +16 -3
- package/dist/coding-worker/artifact.js +5 -3
- 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 +118 -38
- package/dist/coding-worker/errors.d.ts +1 -0
- package/dist/coding-worker/errors.js +32 -0
- package/dist/coding-worker/sdk.d.ts +6 -0
- package/dist/coding-worker/sdk.js +1 -0
- package/dist/coding-worker/skills.d.ts +23 -0
- package/dist/coding-worker/skills.js +117 -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 +13 -0
- package/dist/config/dependency-cache.d.ts +23 -0
- package/dist/config/dependency-cache.js +32 -0
- package/dist/config/github-allowed-accounts.d.ts +15 -0
- package/dist/config/github-allowed-accounts.js +36 -0
- package/dist/config/low-power.d.ts +12 -0
- package/dist/config/low-power.js +18 -0
- package/dist/config/mobile.d.ts +12 -0
- package/dist/config/mobile.js +18 -0
- package/dist/config/providers.d.ts +65 -3
- package/dist/config/providers.js +147 -11
- 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/db.d.ts +16 -6
- package/dist/core/db.js +12 -10
- 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 +53 -0
- package/dist/core/dispatch.js +167 -57
- package/dist/core/engine-native.js +10 -6
- 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 +67 -5
- package/dist/core/host-events.js +571 -37
- 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 +151 -20
- package/dist/core/issue-events.d.ts +1 -1
- package/dist/core/issue-events.js +16 -11
- package/dist/core/issue-status.d.ts +1 -1
- package/dist/core/issue-status.js +68 -29
- 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 +130 -0
- package/dist/core/merge-order-check.js +343 -0
- package/dist/core/notification-dispatcher.d.ts +70 -0
- package/dist/core/notification-dispatcher.js +368 -0
- package/dist/core/notification-templates.d.ts +19 -0
- package/dist/core/notification-templates.js +139 -0
- package/dist/core/notifications.d.ts +10 -0
- package/dist/core/notifications.js +38 -0
- package/dist/core/pg-auth.d.ts +22 -0
- package/dist/core/pg-auth.js +152 -0
- package/dist/core/power-composition.d.ts +16 -0
- package/dist/core/power-composition.js +37 -0
- package/dist/core/power-idle.d.ts +14 -0
- package/dist/core/power-idle.js +30 -0
- package/dist/core/power.d.ts +71 -0
- package/dist/core/power.js +202 -0
- package/dist/core/pull-request-state-sync.js +2 -2
- package/dist/core/reconciler.d.ts +8 -5
- package/dist/core/reconciler.js +37 -6
- package/dist/core/related-pull-requests.d.ts +59 -7
- package/dist/core/related-pull-requests.js +140 -25
- package/dist/core/reply-parts.d.ts +21 -0
- package/dist/core/reply-parts.js +73 -0
- package/dist/core/repo-access.d.ts +15 -0
- package/dist/core/repo-access.js +66 -0
- package/dist/core/review-fix.d.ts +38 -1
- package/dist/core/review-fix.js +209 -7
- package/dist/core/review-host-checks.d.ts +1 -1
- package/dist/core/review-host-tools.d.ts +23 -0
- package/dist/core/review-host-tools.js +156 -14
- 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 +384 -5
- package/dist/core/runner.js +1244 -372
- 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 +39 -0
- package/dist/core/secret-broker-config.js +112 -0
- 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/secrets.d.ts +39 -4
- package/dist/core/secrets.js +148 -40
- package/dist/core/stop-run.d.ts +46 -0
- package/dist/core/stop-run.js +61 -0
- package/dist/core/workflow-event-recorder.d.ts +14 -0
- package/dist/core/workflow-event-recorder.js +120 -0
- package/dist/core/workflow-events.d.ts +94 -0
- package/dist/core/workflow-events.js +48 -0
- package/dist/core/workflow-run-events.d.ts +18 -0
- package/dist/core/workflow-run-events.js +75 -0
- 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 +92 -3
- package/dist/generated/prisma/client.d.ts +92 -3
- package/dist/generated/prisma/commonInputTypes.d.ts +364 -54
- package/dist/generated/prisma/enums.d.ts +37 -0
- package/dist/generated/prisma/enums.js +31 -0
- package/dist/generated/prisma/internal/class.d.ts +132 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +1332 -142
- package/dist/generated/prisma/internal/prismaNamespace.js +227 -5
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +234 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +227 -5
- package/dist/generated/prisma/models/Agent.d.ts +464 -7
- package/dist/generated/prisma/models/AgentRepository.d.ts +42 -1
- package/dist/generated/prisma/models/CodingAgentProfile.d.ts +301 -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 +1841 -1
- package/dist/generated/prisma/models/DeferredReview.d.ts +78 -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 +1713 -0
- package/dist/generated/prisma/models/NativeGatewayCall.js +1 -0
- package/dist/generated/prisma/models/NativeGatewaySession.d.ts +1551 -0
- package/dist/generated/prisma/models/NativeGatewaySession.js +1 -0
- package/dist/generated/prisma/models/NativeWarmWorker.d.ts +1296 -0
- package/dist/generated/prisma/models/NativeWarmWorker.js +1 -0
- package/dist/generated/prisma/models/NotificationChannel.d.ts +1543 -0
- package/dist/generated/prisma/models/NotificationChannel.js +1 -0
- package/dist/generated/prisma/models/NotificationDelivery.d.ts +1502 -0
- package/dist/generated/prisma/models/NotificationDelivery.js +1 -0
- package/dist/generated/prisma/models/NotificationThread.d.ts +1090 -0
- package/dist/generated/prisma/models/NotificationThread.js +1 -0
- 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 +1619 -58
- package/dist/generated/prisma/models/RunBudgetEvent.d.ts +1211 -0
- package/dist/generated/prisma/models/RunBudgetEvent.js +1 -0
- package/dist/generated/prisma/models/RunHostCheck.d.ts +36 -1
- package/dist/generated/prisma/models/RunTranscript.d.ts +1339 -0
- package/dist/generated/prisma/models/RunTranscript.js +1 -0
- package/dist/generated/prisma/models/Secret.d.ts +37 -1
- package/dist/generated/prisma/models/SecretBrokerChange.d.ts +1101 -0
- package/dist/generated/prisma/models/SecretBrokerChange.js +1 -0
- package/dist/generated/prisma/models/WorkflowEvent.d.ts +1422 -0
- package/dist/generated/prisma/models/WorkflowEvent.js +1 -0
- package/dist/generated/prisma/models.d.ts +12 -0
- package/dist/help/build.js +4 -2
- package/dist/help/catalog.d.ts +1 -1
- package/dist/help/catalog.js +31 -6
- package/dist/help-index.json +2584 -146
- package/dist/import/create.js +49 -3
- package/dist/import/neutral-schema.d.ts +50 -277
- package/dist/import/neutral-schema.js +7 -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 +11 -2
- package/dist/mcp/auth/access.js +15 -1
- package/dist/mcp/auth/ownership.d.ts +7 -7
- package/dist/mcp/auth/repo-authorization.js +14 -0
- package/dist/mcp/auth/resource-server.d.ts +2 -1
- package/dist/mcp/auth/resource-server.js +7 -2
- package/dist/mcp/auth/self-hosted/browser.d.ts +1 -1
- package/dist/mcp/auth/self-hosted/browser.js +19 -6
- 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/context.d.ts +6 -0
- package/dist/mcp/host-events/github-ingress.d.ts +25 -1
- package/dist/mcp/host-events/github-ingress.js +70 -1
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.js +117 -20
- 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 +277 -24
- 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.d.ts +2 -0
- package/dist/mcp/tools/notification-channels.js +293 -0
- package/dist/mcp/tools/packages.d.ts +2 -0
- package/dist/mcp/tools/packages.js +195 -0
- package/dist/mcp/tools/power.d.ts +2 -0
- package/dist/mcp/tools/power.js +77 -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.d.ts +0 -6
- package/dist/mcp/tools/runs.js +41 -14
- package/dist/mcp/tools/scheduling.js +3 -1
- package/dist/mcp/tools/secret-broker-compat.d.ts +12 -0
- package/dist/mcp/tools/secret-broker-compat.js +23 -0
- package/dist/mcp/tools/secret-elicitation-form.d.ts +22 -2
- package/dist/mcp/tools/secret-elicitation-form.js +205 -10
- package/dist/mcp/tools/secret-elicitation-server.d.ts +6 -0
- package/dist/mcp/tools/secret-elicitation-server.js +10 -54
- package/dist/mcp/tools/secret-elicitation.d.ts +38 -3
- package/dist/mcp/tools/secret-elicitation.js +110 -12
- package/dist/mcp/tools/secrets.js +186 -9
- 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 +2 -2
- package/dist/mcp/tools/tools.js +47 -11
- 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/composition.d.ts +23 -0
- package/dist/native-worker/composition.js +77 -0
- package/dist/native-worker/docker-isolation.d.ts +65 -0
- package/dist/native-worker/docker-isolation.js +183 -0
- package/dist/native-worker/docker-launcher.d.ts +110 -0
- package/dist/native-worker/docker-launcher.js +297 -0
- package/dist/native-worker/gateway-server.d.ts +77 -0
- package/dist/native-worker/gateway-server.js +412 -0
- package/dist/native-worker/gateway.d.ts +70 -0
- package/dist/native-worker/gateway.js +263 -0
- package/dist/native-worker/http-server.d.ts +24 -0
- package/dist/native-worker/http-server.js +113 -0
- package/dist/native-worker/http-transport.d.ts +17 -0
- package/dist/native-worker/http-transport.js +88 -0
- package/dist/native-worker/kubernetes-isolation.d.ts +90 -0
- package/dist/native-worker/kubernetes-isolation.js +218 -0
- package/dist/native-worker/kubernetes-launcher.d.ts +106 -0
- package/dist/native-worker/kubernetes-launcher.js +375 -0
- package/dist/native-worker/launch.d.ts +62 -0
- package/dist/native-worker/launch.js +49 -0
- package/dist/native-worker/ledger.d.ts +125 -0
- package/dist/native-worker/ledger.js +245 -0
- package/dist/native-worker/loopback.d.ts +12 -0
- package/dist/native-worker/loopback.js +44 -0
- package/dist/native-worker/main.d.ts +8 -0
- package/dist/native-worker/main.js +85 -0
- package/dist/native-worker/protocol.d.ts +296 -0
- package/dist/native-worker/protocol.js +246 -0
- package/dist/native-worker/sandbox-executor.d.ts +83 -0
- package/dist/native-worker/sandbox-executor.js +284 -0
- 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 +29 -0
- package/dist/native-worker/stdio.js +189 -0
- package/dist/native-worker/warm-delivery.d.ts +16 -0
- package/dist/native-worker/warm-delivery.js +33 -0
- package/dist/native-worker/warm-pool-ledger.d.ts +39 -0
- package/dist/native-worker/warm-pool-ledger.js +73 -0
- package/dist/native-worker/warm-pool.d.ts +107 -0
- package/dist/native-worker/warm-pool.js +283 -0
- package/dist/native-worker/worker.d.ts +17 -0
- package/dist/native-worker/worker.js +141 -0
- package/dist/observability/metrics.js +6 -1
- package/dist/providers/auth/authorization-server.d.ts +3 -0
- package/dist/providers/auth/index.js +2 -0
- package/dist/providers/auth/self-hosted.d.ts +14 -2
- package/dist/providers/auth/self-hosted.js +54 -4
- package/dist/providers/chat/fake.d.ts +46 -0
- package/dist/providers/chat/fake.js +39 -0
- package/dist/providers/chat/index.d.ts +4 -0
- package/dist/providers/chat/index.js +8 -0
- package/dist/providers/chat/slack.d.ts +37 -0
- package/dist/providers/chat/slack.js +105 -0
- package/dist/providers/chat/types.d.ts +42 -0
- package/dist/providers/chat/types.js +19 -0
- 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 +36 -2
- package/dist/providers/engine/types.js +39 -0
- package/dist/providers/executor/composition.d.ts +31 -1
- package/dist/providers/executor/composition.js +81 -8
- package/dist/providers/executor/container.d.ts +385 -9
- package/dist/providers/executor/container.js +1234 -99
- 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 +91 -0
- package/dist/providers/executor/dbos.js +319 -26
- package/dist/providers/executor/deferred.d.ts +44 -0
- package/dist/providers/executor/deferred.js +100 -0
- 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 +39 -10
- package/dist/providers/executor/routing.js +77 -32
- package/dist/providers/executor/types.d.ts +25 -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 +29 -4
- package/dist/providers/jobs/fake-kubernetes-api.d.ts +23 -2
- package/dist/providers/jobs/fake-kubernetes-api.js +45 -1
- package/dist/providers/jobs/kubernetes-api.d.ts +25 -1
- package/dist/providers/jobs/kubernetes-api.js +17 -0
- package/dist/providers/jobs/kubernetes-client.d.ts +10 -1
- package/dist/providers/jobs/kubernetes-client.js +61 -3
- package/dist/providers/jobs/kubernetes-dry-run-fixture.d.ts +6 -1
- package/dist/providers/jobs/kubernetes-dry-run-fixture.js +6 -3
- package/dist/providers/jobs/kubernetes-isolation.d.ts +5 -1
- package/dist/providers/jobs/kubernetes-isolation.js +23 -1
- package/dist/providers/jobs/kubernetes-platform.d.ts +4 -1
- package/dist/providers/jobs/kubernetes-platform.js +38 -1
- package/dist/providers/jobs/kubernetes-preflight.d.ts +2 -1
- package/dist/providers/jobs/kubernetes-preflight.js +4 -2
- package/dist/providers/jobs/kubernetes.d.ts +42 -2
- package/dist/providers/jobs/kubernetes.js +178 -19
- package/dist/providers/jobs/metadata-probes.d.ts +11 -0
- package/dist/providers/jobs/metadata-probes.js +13 -0
- package/dist/providers/jobs/types.d.ts +42 -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 +39 -2
- package/dist/providers/review-host/github.js +274 -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 +157 -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 +246 -12
- package/dist/providers/vcs/github.js +521 -61
- 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 +21 -3
- package/dist/quickstart/coding-seed.js +283 -3
- package/dist/quickstart/images.d.ts +2 -0
- package/dist/quickstart/images.js +7 -1
- 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/brokered-fetch.d.ts +23 -0
- package/dist/sandbox/brokered-fetch.js +37 -0
- 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 +35 -0
- package/dist/sandbox/host-functions.js +150 -91
- package/dist/sandbox/prelude.js +7 -1
- package/dist/sandbox/run-in-sandbox.d.ts +19 -0
- package/dist/sandbox/run-in-sandbox.js +28 -10
- package/dist/sandbox/safe-fetch.d.ts +2 -0
- package/dist/sandbox/safe-fetch.js +3 -1
- package/dist/sandbox/secret-broker-sigv4.d.ts +2 -0
- package/dist/sandbox/secret-broker-sigv4.js +49 -0
- package/dist/sandbox/secret-broker.d.ts +34 -0
- package/dist/sandbox/secret-broker.js +161 -0
- package/dist/sandbox/tool-capabilities.d.ts +10 -30
- package/dist/sandbox/user-tool.d.ts +14 -0
- package/dist/sandbox/user-tool.js +32 -0
- package/dist/sandbox/zod-params.d.ts +37 -5
- package/dist/sandbox/zod-params.js +181 -26
- package/dist/serve.js +25 -0
- package/dist/viewer/api-schema.d.ts +372 -2454
- package/dist/viewer/api-schema.js +29 -0
- package/dist/viewer/build-schemas.js +10 -3
- package/dist/viewer/event-bus.d.ts +6 -0
- package/dist/viewer/event-bus.js +16 -7
- package/dist/viewer/graph.d.ts +5 -2
- package/dist/viewer/graph.js +7 -2
- package/dist/viewer/http.d.ts +0 -1
- package/dist/viewer/http.js +2 -2
- package/dist/viewer/infra.js +25 -2
- package/dist/viewer/limits.d.ts +4 -0
- package/dist/viewer/limits.js +4 -0
- package/dist/viewer/openapi.d.ts +15 -0
- package/dist/viewer/openapi.js +170 -0
- package/dist/wardby-bin.js +10 -0
- package/docs/README.md +7 -0
- package/docs/agent-recipes.md +114 -27
- package/docs/architecture-runtime.md +16 -1
- package/docs/code-review-agents.md +689 -45
- package/docs/coding-agent-setup.md +602 -12
- package/docs/coding-packages.md +1037 -92
- package/docs/coding-services.md +30 -13
- package/docs/coding-worker-byo-images.md +218 -6
- package/docs/coding-worker-isolation.md +173 -44
- package/docs/getting-started-gke.md +332 -129
- package/docs/getting-started-identity-provider.md +31 -11
- package/docs/getting-started.md +14 -4
- package/docs/jira-agents.md +22 -9
- 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 +731 -0
- package/docs/observability.md +4 -0
- package/docs/release-verification.md +9 -0
- package/docs/security-deployment.md +146 -14
- package/docs/slack-notifications.md +268 -0
- package/docs/tool-secrets.md +284 -0
- package/docs/viewer-api.md +46 -5
- package/docs/viewer-api.openapi.yml +1404 -0
- package/help/admin-viewer.md +29 -3
- package/help/agent-recipes.md +27 -0
- package/help/architecture-agent.md +11 -6
- package/help/brokered-secrets.md +79 -0
- package/help/build-claude-code-image.md +131 -0
- package/help/build-worker-image.md +6 -7
- package/help/builder-agent.md +19 -6
- package/help/code-review-agents.md +243 -10
- 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 +23 -9
- package/help/deployment-targets.md +25 -14
- package/help/errors/budget-exhausted.md +187 -0
- package/help/errors/budget-group-exhausted.md +5 -1
- package/help/errors/coding-provider-not-configured.md +2 -2
- 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/database-auth-invalid.md +28 -0
- 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 +29 -0
- package/help/errors/graph-incomplete.md +43 -0
- package/help/errors/graph-limit.md +43 -0
- package/help/errors/low-power-disabled.md +29 -0
- package/help/errors/low-power-scale-forbidden.md +35 -0
- package/help/errors/low-power-wake-timeout.md +30 -0
- package/help/errors/merge-conflict.md +49 -0
- package/help/errors/mobile-disabled.md +31 -0
- package/help/errors/native-sandbox-capacity.md +22 -0
- package/help/errors/native-sandbox-deadline-exceeded.md +19 -0
- package/help/errors/native-sandbox-docker-failed.md +20 -0
- package/help/errors/native-sandbox-gateway-error.md +20 -0
- package/help/errors/native-sandbox-gateway-unavailable.md +21 -0
- package/help/errors/native-sandbox-image-not-pinned.md +19 -0
- package/help/errors/native-sandbox-isolation-mismatch.md +20 -0
- package/help/errors/native-sandbox-launch-abandoned.md +21 -0
- package/help/errors/native-sandbox-network-unenforced.md +22 -0
- package/help/errors/native-sandbox-requires-catalog.md +31 -0
- package/help/errors/native-sandbox-unavailable.md +19 -0
- package/help/errors/native-sandbox-warm-delivery-failed.md +21 -0
- package/help/errors/native-sandbox-worker-exited.md +21 -0
- package/help/errors/native-sandbox-worker-lost.md +20 -0
- package/help/errors/native-sandbox-worker-unready.md +22 -0
- 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-broker-body-invalid.md +26 -0
- package/help/errors/secret-broker-changed.md +20 -0
- package/help/errors/secret-broker-config-invalid.md +30 -0
- package/help/errors/secret-broker-conflict.md +27 -0
- package/help/errors/secret-broker-destination-denied.md +28 -0
- package/help/errors/secret-broker-value-invalid.md +28 -0
- package/help/errors/secret-brokered.md +24 -0
- package/help/errors/secret-in-value.md +69 -0
- package/help/errors/secret-not-brokered.md +25 -0
- package/help/errors/slack-auth-failed.md +48 -0
- package/help/errors/slack-channel-unreachable.md +39 -0
- package/help/errors/slack-not-configured.md +33 -0
- package/help/errors/target-merge.md +40 -0
- package/help/fix-merge-conflicts.md +73 -0
- package/help/getting-started.md +4 -5
- package/help/github-app-setup.md +132 -0
- package/help/github.md +40 -1
- package/help/identity-and-access.md +7 -1
- package/help/jira.md +23 -6
- package/help/knowledge.md +16 -7
- package/help/local-repositories.md +3 -4
- package/help/low-power-mode.md +131 -0
- package/help/merge-order-check.md +122 -0
- package/help/mobile-app.md +54 -0
- package/help/native-capabilities.md +29 -1
- package/help/native-sandbox.md +150 -0
- package/help/observability.md +8 -0
- package/help/operating-agents.md +5 -0
- package/help/package-audit-mode.md +91 -0
- package/help/related-pull-requests.md +80 -16
- package/help/repo-instructions-and-skills.md +91 -0
- package/help/resume-runs-locally.md +131 -0
- package/help/review-fix-rounds.md +43 -1
- package/help/sharing-agents.md +59 -0
- package/help/slack-notifications.md +76 -0
- 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 +99 -7
- package/package.json +27 -13
- package/prisma/migrations/20261009000003_native_execution_mode/migration.sql +12 -0
- package/prisma/migrations/20261009000004_native_gateway_ledger/migration.sql +65 -0
- package/prisma/migrations/20261009000005_native_gateway_call_child_agent/migration.sql +5 -0
- package/prisma/migrations/20261009000006_run_deferred_start_stop/migration.sql +14 -0
- package/prisma/migrations/20261009000007_native_gateway_network_ready/migration.sql +5 -0
- package/prisma/migrations/20261010000001_workflow_notifications/migration.sql +99 -0
- package/prisma/migrations/20261011000001_native_gateway_session_status_index/migration.sql +2 -0
- package/prisma/migrations/20261012000001_native_warm_worker/migration.sql +32 -0
- package/prisma/migrations/20261013000001_coding_run_merge_order/migration.sql +2 -0
- package/prisma/migrations/20261013000001_secret_broker/migration.sql +17 -0
- package/prisma/migrations/20261013000002_deferred_review_request/migration.sql +4 -0
- package/prisma/migrations/20261014000000_repo_skills/migration.sql +15 -0
- package/prisma/migrations/20261015000001_coding_run_merge_order_index/migration.sql +2 -0
- package/prisma/migrations/20261015000002_no_change_rereview/migration.sql +2 -0
- 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 +631 -146
- package/dist/sandbox/generated/zod-to-json-schema.bundle.js +0 -5
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { DependencyCacheSessionState } from "../registry/store.js";
|
|
2
|
+
/**
|
|
3
|
+
* The value every snapshot row stores in its `policyHash` column, and the only
|
|
4
|
+
* value lookups match. The column and its unique index predate dropping the
|
|
5
|
+
* agent's package policy from the key (see key.ts for why), so they stay
|
|
6
|
+
* unchanged; rows written before carry a real policy hash, never match again,
|
|
7
|
+
* and age out through eviction.
|
|
8
|
+
*/
|
|
9
|
+
export declare const POLICY_ANY = "any";
|
|
10
|
+
/** The parts every snapshot of one project shares, whatever its lockfile. */
|
|
11
|
+
export interface SnapshotScope {
|
|
12
|
+
ecosystem: string;
|
|
13
|
+
repository: string;
|
|
14
|
+
projectPath: string;
|
|
15
|
+
workerImage: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SnapshotIdentity extends SnapshotScope {
|
|
18
|
+
lockHash: string;
|
|
19
|
+
}
|
|
20
|
+
export interface NewSnapshot extends SnapshotIdentity {
|
|
21
|
+
blobKey: string;
|
|
22
|
+
sha256: string;
|
|
23
|
+
sizeBytes: number;
|
|
24
|
+
archiveScanVersion: number | null;
|
|
25
|
+
archiveEntries: number | null;
|
|
26
|
+
unpackedBytes: number | null;
|
|
27
|
+
createdByRunId: string;
|
|
28
|
+
}
|
|
29
|
+
export interface SnapshotRow extends SnapshotIdentity {
|
|
30
|
+
id: string;
|
|
31
|
+
blobKey: string;
|
|
32
|
+
sha256: string;
|
|
33
|
+
sizeBytes: number;
|
|
34
|
+
archiveScanVersion: number | null;
|
|
35
|
+
archiveEntries: number | null;
|
|
36
|
+
unpackedBytes: number | null;
|
|
37
|
+
createdAt: Date;
|
|
38
|
+
lastUsedAt: Date;
|
|
39
|
+
createdByRunId: string | null;
|
|
40
|
+
}
|
|
41
|
+
/** What eviction needs of every snapshot. */
|
|
42
|
+
export type EvictionRow = Pick<SnapshotRow, "id" | "repository" | "blobKey" | "sizeBytes" | "createdAt" | "lastUsedAt">;
|
|
43
|
+
/** DependencySnapshot rows and the session fields the cache reads (Postgres in production). */
|
|
44
|
+
export interface DependencyCacheStore {
|
|
45
|
+
session(runId: string): Promise<DependencyCacheSessionState | null>;
|
|
46
|
+
/** Sets the session's sealedAt unless it is already set. */
|
|
47
|
+
seal(runId: string, now: Date): Promise<void>;
|
|
48
|
+
/** Like `seal`, but only for a run whose agent has the cache on (a model request's seal, ModelRequestSeal). */
|
|
49
|
+
sealForModelRequest(runId: string, now: Date): Promise<void>;
|
|
50
|
+
findByIdentity(identity: SnapshotIdentity): Promise<SnapshotRow | null>;
|
|
51
|
+
/** The most recent snapshot in the scope whose lockHash differs (ties broken by id), or null. */
|
|
52
|
+
findNearest(scope: SnapshotScope, excludeLockHash: string): Promise<SnapshotRow | null>;
|
|
53
|
+
/** Whether the run already created a snapshot for this project. */
|
|
54
|
+
hasUploaded(runId: string, ecosystem: string, projectPath: string): Promise<boolean>;
|
|
55
|
+
/** "exists" when a snapshot with the same identity (or blob key) is already stored. */
|
|
56
|
+
insert(snapshot: NewSnapshot): Promise<"inserted" | "exists">;
|
|
57
|
+
touch(id: string, now: Date): Promise<void>;
|
|
58
|
+
delete(id: string): Promise<void>;
|
|
59
|
+
/** Deletes the row only while it still points at `blobKey` (a re-upload may have replaced it); true when deleted. */
|
|
60
|
+
deleteIfBlob(id: string, blobKey: string): Promise<boolean>;
|
|
61
|
+
listForEviction(): Promise<EvictionRow[]>;
|
|
62
|
+
/** Runs `work` while holding the cluster-wide eviction lock; returns false (without running it) when another holder has it. */
|
|
63
|
+
withEvictionLock(work: () => Promise<void>): Promise<boolean>;
|
|
64
|
+
}
|
|
65
|
+
/** In-memory adapter for tests. `sessions` may be shared with a MemoryRegistryStore's `cacheSessions`. */
|
|
66
|
+
export declare class MemoryDependencyCacheStore implements DependencyCacheStore {
|
|
67
|
+
readonly sessions: Map<string, DependencyCacheSessionState>;
|
|
68
|
+
readonly rows: SnapshotRow[];
|
|
69
|
+
private evicting;
|
|
70
|
+
/** Runs whose agent has the cache off (sealForModelRequest leaves them alone). */
|
|
71
|
+
readonly cacheOff: Set<string>;
|
|
72
|
+
constructor(sessions?: Map<string, DependencyCacheSessionState>);
|
|
73
|
+
session(runId: string): Promise<DependencyCacheSessionState | null>;
|
|
74
|
+
seal(runId: string, now: Date): Promise<void>;
|
|
75
|
+
sealForModelRequest(runId: string, now: Date): Promise<void>;
|
|
76
|
+
findByIdentity(identity: SnapshotIdentity): Promise<SnapshotRow | null>;
|
|
77
|
+
findNearest(scope: SnapshotScope, excludeLockHash: string): Promise<SnapshotRow | null>;
|
|
78
|
+
hasUploaded(runId: string, ecosystem: string, projectPath: string): Promise<boolean>;
|
|
79
|
+
insert(snapshot: NewSnapshot): Promise<"inserted" | "exists">;
|
|
80
|
+
touch(id: string, now: Date): Promise<void>;
|
|
81
|
+
delete(id: string): Promise<void>;
|
|
82
|
+
deleteIfBlob(id: string, blobKey: string): Promise<boolean>;
|
|
83
|
+
listForEviction(): Promise<EvictionRow[]>;
|
|
84
|
+
withEvictionLock(work: () => Promise<void>): Promise<boolean>;
|
|
85
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* The value every snapshot row stores in its `policyHash` column, and the only
|
|
4
|
+
* value lookups match. The column and its unique index predate dropping the
|
|
5
|
+
* agent's package policy from the key (see key.ts for why), so they stay
|
|
6
|
+
* unchanged; rows written before carry a real policy hash, never match again,
|
|
7
|
+
* and age out through eviction.
|
|
8
|
+
*/
|
|
9
|
+
export const POLICY_ANY = "any";
|
|
10
|
+
const sameScope = (row, scope) => row.ecosystem === scope.ecosystem &&
|
|
11
|
+
row.repository === scope.repository &&
|
|
12
|
+
row.projectPath === scope.projectPath &&
|
|
13
|
+
row.workerImage === scope.workerImage;
|
|
14
|
+
/** In-memory adapter for tests. `sessions` may be shared with a MemoryRegistryStore's `cacheSessions`. */
|
|
15
|
+
export class MemoryDependencyCacheStore {
|
|
16
|
+
sessions;
|
|
17
|
+
rows = [];
|
|
18
|
+
evicting = false;
|
|
19
|
+
/** Runs whose agent has the cache off (sealForModelRequest leaves them alone). */
|
|
20
|
+
cacheOff = new Set();
|
|
21
|
+
constructor(sessions = new Map()) {
|
|
22
|
+
this.sessions = sessions;
|
|
23
|
+
}
|
|
24
|
+
async session(runId) {
|
|
25
|
+
const session = this.sessions.get(runId);
|
|
26
|
+
return session ? { ...session, lockHashes: [...session.lockHashes] } : null;
|
|
27
|
+
}
|
|
28
|
+
async seal(runId, now) {
|
|
29
|
+
const session = this.sessions.get(runId);
|
|
30
|
+
if (session && !session.sealedAt)
|
|
31
|
+
session.sealedAt = now;
|
|
32
|
+
}
|
|
33
|
+
async sealForModelRequest(runId, now) {
|
|
34
|
+
if (!this.cacheOff.has(runId))
|
|
35
|
+
await this.seal(runId, now);
|
|
36
|
+
}
|
|
37
|
+
async findByIdentity(identity) {
|
|
38
|
+
return this.rows.find((row) => sameScope(row, identity) && row.lockHash === identity.lockHash) ?? null;
|
|
39
|
+
}
|
|
40
|
+
async findNearest(scope, excludeLockHash) {
|
|
41
|
+
const candidates = this.rows
|
|
42
|
+
.filter((row) => sameScope(row, scope) && row.lockHash !== excludeLockHash)
|
|
43
|
+
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime() || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0));
|
|
44
|
+
return candidates[0] ?? null;
|
|
45
|
+
}
|
|
46
|
+
async hasUploaded(runId, ecosystem, projectPath) {
|
|
47
|
+
return this.rows.some((row) => row.createdByRunId === runId && row.ecosystem === ecosystem && row.projectPath === projectPath);
|
|
48
|
+
}
|
|
49
|
+
async insert(snapshot) {
|
|
50
|
+
if ((await this.findByIdentity(snapshot)) || this.rows.some((row) => row.blobKey === snapshot.blobKey))
|
|
51
|
+
return "exists";
|
|
52
|
+
const now = new Date();
|
|
53
|
+
this.rows.push({ ...snapshot, id: `c${randomUUID().replaceAll("-", "")}`, createdAt: now, lastUsedAt: now });
|
|
54
|
+
return "inserted";
|
|
55
|
+
}
|
|
56
|
+
async touch(id, now) {
|
|
57
|
+
const row = this.rows.find((candidate) => candidate.id === id);
|
|
58
|
+
if (row)
|
|
59
|
+
row.lastUsedAt = now;
|
|
60
|
+
}
|
|
61
|
+
async delete(id) {
|
|
62
|
+
const index = this.rows.findIndex((row) => row.id === id);
|
|
63
|
+
if (index >= 0)
|
|
64
|
+
this.rows.splice(index, 1);
|
|
65
|
+
}
|
|
66
|
+
async deleteIfBlob(id, blobKey) {
|
|
67
|
+
const index = this.rows.findIndex((row) => row.id === id && row.blobKey === blobKey);
|
|
68
|
+
if (index < 0)
|
|
69
|
+
return false;
|
|
70
|
+
this.rows.splice(index, 1);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
async listForEviction() {
|
|
74
|
+
return this.rows.map(({ id, repository, blobKey, sizeBytes, createdAt, lastUsedAt }) => ({
|
|
75
|
+
id,
|
|
76
|
+
repository,
|
|
77
|
+
blobKey,
|
|
78
|
+
sizeBytes,
|
|
79
|
+
createdAt,
|
|
80
|
+
lastUsedAt,
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
async withEvictionLock(work) {
|
|
84
|
+
if (this.evicting)
|
|
85
|
+
return false;
|
|
86
|
+
this.evicting = true;
|
|
87
|
+
try {
|
|
88
|
+
await work();
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
this.evicting = false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ModelPricing } from "../llm/pricing-core.js";
|
|
2
|
+
import type { PreviousReply, ProxyProtocol, ReservationBasis } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Anthropic's prompt cache lives 5 minutes from when a request is processed, not from when its reply
|
|
5
|
+
* finishes: a previous request sent longer ago than this says nothing about the cache.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CACHE_WINDOW_MS: number;
|
|
8
|
+
export declare const MIN_CACHED_SHARE = 0.5;
|
|
9
|
+
export type HoldFallback = "no_previous" | "model_changed" | "previous_estimated" | "previous_not_completed" | "no_request_bytes" | "cache_expired" | "body_shrank" | "low_cache_share";
|
|
10
|
+
export interface HoldEstimate {
|
|
11
|
+
holdUsd: number;
|
|
12
|
+
ceilingUsd: number;
|
|
13
|
+
basis: ReservationBasis;
|
|
14
|
+
fallback?: HoldFallback;
|
|
15
|
+
cachedTokens?: number;
|
|
16
|
+
uncachedTokens?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What identifies one conversation within a run (Claude Code runs several: the main one and its
|
|
20
|
+
* sub-agents). Anthropic: the first message without cache markers (the system prompt carries a
|
|
21
|
+
* per-version billing line). OpenAI: prompt_cache_key, else instructions + the first input item.
|
|
22
|
+
*/
|
|
23
|
+
export declare function conversationKey(protocol: ProxyProtocol, body: Record<string, unknown>): string | null;
|
|
24
|
+
export declare function estimateHold(input: {
|
|
25
|
+
protocol: ProxyProtocol;
|
|
26
|
+
model: string;
|
|
27
|
+
bodyBytes: number;
|
|
28
|
+
maxOutputTokens: number;
|
|
29
|
+
pricing: ModelPricing;
|
|
30
|
+
previous: PreviousReply | null;
|
|
31
|
+
now: Date;
|
|
32
|
+
}): HoldEstimate;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A model request's hold: what the proxy reserves against the run's budget before forwarding it.
|
|
3
|
+
* After a mostly cached reply in the same conversation, the part of the prompt the previous reply
|
|
4
|
+
* read from (or wrote to) the cache is priced at the cache-read rate; everything else, including
|
|
5
|
+
* what the body grew by (one token per byte), at the input + cache-write rates. Capped at the
|
|
6
|
+
* ceiling, today's worst case (the whole body as uncached input), which a reply may never exceed.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { estimateReservationUsd } from "./metering.js";
|
|
10
|
+
/**
|
|
11
|
+
* Anthropic's prompt cache lives 5 minutes from when a request is processed, not from when its reply
|
|
12
|
+
* finishes: a previous request sent longer ago than this says nothing about the cache.
|
|
13
|
+
*/
|
|
14
|
+
export const CACHE_WINDOW_MS = 5 * 60_000;
|
|
15
|
+
export const MIN_CACHED_SHARE = 0.5;
|
|
16
|
+
function withoutCacheControl(value) {
|
|
17
|
+
if (Array.isArray(value))
|
|
18
|
+
return value.map(withoutCacheControl);
|
|
19
|
+
if (!value || typeof value !== "object")
|
|
20
|
+
return value;
|
|
21
|
+
return Object.fromEntries(Object.entries(value)
|
|
22
|
+
.filter(([key]) => key !== "cache_control")
|
|
23
|
+
.map(([key, inner]) => [key, withoutCacheControl(inner)]));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* What identifies one conversation within a run (Claude Code runs several: the main one and its
|
|
27
|
+
* sub-agents). Anthropic: the first message without cache markers (the system prompt carries a
|
|
28
|
+
* per-version billing line). OpenAI: prompt_cache_key, else instructions + the first input item.
|
|
29
|
+
*/
|
|
30
|
+
export function conversationKey(protocol, body) {
|
|
31
|
+
let basis;
|
|
32
|
+
if (protocol === "anthropic-messages") {
|
|
33
|
+
const messages = body.messages;
|
|
34
|
+
if (!Array.isArray(messages) || messages.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
// Claude Code's first message can carry the date, so a conversation crossing midnight starts a
|
|
37
|
+
// new key (its next request falls back to the worst case once).
|
|
38
|
+
basis = ["anthropic", withoutCacheControl(messages[0])];
|
|
39
|
+
}
|
|
40
|
+
else if (typeof body.prompt_cache_key === "string" && body.prompt_cache_key) {
|
|
41
|
+
basis = ["openai-key", body.prompt_cache_key];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const input = body.input;
|
|
45
|
+
const first = typeof input === "string" ? input : Array.isArray(input) ? input[0] : undefined;
|
|
46
|
+
if (first === undefined)
|
|
47
|
+
return null;
|
|
48
|
+
basis = ["openai-first", body.instructions ?? null, first];
|
|
49
|
+
}
|
|
50
|
+
return createHash("sha256").update(JSON.stringify(basis)).digest("base64url");
|
|
51
|
+
}
|
|
52
|
+
export function estimateHold(input) {
|
|
53
|
+
const ceilingUsd = estimateReservationUsd(input.bodyBytes, input.maxOutputTokens, input.pricing);
|
|
54
|
+
const full = (fallback) => ({ holdUsd: ceilingUsd, ceilingUsd, basis: "full", fallback });
|
|
55
|
+
const previous = input.previous;
|
|
56
|
+
if (!previous)
|
|
57
|
+
return full("no_previous");
|
|
58
|
+
if (previous.model !== input.model)
|
|
59
|
+
return full("model_changed");
|
|
60
|
+
if (previous.costEstimated)
|
|
61
|
+
return full("previous_estimated");
|
|
62
|
+
if (previous.status !== "completed" || !previous.usage)
|
|
63
|
+
return full("previous_not_completed");
|
|
64
|
+
if (previous.requestBytes === null)
|
|
65
|
+
return full("no_request_bytes");
|
|
66
|
+
if (input.now.getTime() - previous.startedAt.getTime() > CACHE_WINDOW_MS)
|
|
67
|
+
return full("cache_expired");
|
|
68
|
+
if (input.bodyBytes < previous.requestBytes)
|
|
69
|
+
return full("body_shrank");
|
|
70
|
+
const usage = previous.usage;
|
|
71
|
+
const prevPrompt = usage.inputTokens + usage.cacheWriteTokens;
|
|
72
|
+
const cachedTokens = input.protocol === "anthropic-messages"
|
|
73
|
+
? usage.cachedInputTokens + usage.cacheWriteTokens
|
|
74
|
+
: usage.cachedInputTokens;
|
|
75
|
+
if (prevPrompt <= 0 || cachedTokens < prevPrompt * MIN_CACHED_SHARE)
|
|
76
|
+
return full("low_cache_share");
|
|
77
|
+
const uncachedTokens = prevPrompt + (input.bodyBytes - previous.requestBytes) - cachedTokens;
|
|
78
|
+
const { pricing } = input;
|
|
79
|
+
const cacheReadRate = pricing.cachedInputPerMTok ?? pricing.inputPerMTok;
|
|
80
|
+
const cacheWriteRate = pricing.cacheWritePerMTok ?? pricing.inputPerMTok;
|
|
81
|
+
const holdUsd = (cachedTokens * cacheReadRate +
|
|
82
|
+
uncachedTokens * (pricing.inputPerMTok + cacheWriteRate) +
|
|
83
|
+
input.maxOutputTokens * pricing.outputPerMTok) /
|
|
84
|
+
1_000_000;
|
|
85
|
+
return { holdUsd: Math.min(holdUsd, ceilingUsd), ceilingUsd, basis: "cached", cachedTokens, uncachedTokens };
|
|
86
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type ModelPricing } from "../llm/pricing-core.js";
|
|
2
|
+
import type { PreviousReply, ProxyUsage } from "./types.js";
|
|
3
|
+
export interface InterruptedFacts {
|
|
4
|
+
/** Anthropic message_start usage already read (inputTokens includes cache reads, not writes). */
|
|
5
|
+
readUsage?: {
|
|
6
|
+
inputTokens: number;
|
|
7
|
+
cachedInputTokens: number;
|
|
8
|
+
cacheWriteTokens: number;
|
|
9
|
+
};
|
|
10
|
+
/** Output tokens the upstream reported so far (Anthropic message_delta), if any. */
|
|
11
|
+
reportedOutputTokens?: number;
|
|
12
|
+
/** message_start's output count: a placeholder (usually 1), so only a floor, never the count. */
|
|
13
|
+
outputFloorTokens?: number;
|
|
14
|
+
/** A stream that failed before its response started: the provider generated no output. */
|
|
15
|
+
beforeResponse?: boolean;
|
|
16
|
+
/** UTF-8 bytes of output relayed to the client before the break: text, tool input, thinking. */
|
|
17
|
+
relayedOutputBytes: number;
|
|
18
|
+
/** The input of the request's own prompt, from its conversation's previous reply (previousInput). */
|
|
19
|
+
previous?: ProxyUsage;
|
|
20
|
+
/** UTF-8 bytes of the request body the proxy forwarded, when known. */
|
|
21
|
+
bodyBytes?: number;
|
|
22
|
+
/** Median outputTokens of the session's completed replies for the same model, if any. */
|
|
23
|
+
medianOutputTokens?: number;
|
|
24
|
+
/** The request's hold and the output tokens it reserved for. */
|
|
25
|
+
reservationUsd: number;
|
|
26
|
+
maxOutputTokens: number;
|
|
27
|
+
/** The request's worst case (its ceiling); the estimate never exceeds it. Defaults to the hold. */
|
|
28
|
+
ceilingUsd?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface InterruptedEstimate {
|
|
31
|
+
usage: ProxyUsage;
|
|
32
|
+
costUsd: number;
|
|
33
|
+
}
|
|
34
|
+
/** Output tokens for relayed text: ceil(bytes / 3), a deliberately high count. */
|
|
35
|
+
export declare function relayedOutputTokens(bytes: number): number;
|
|
36
|
+
/**
|
|
37
|
+
* Prompt tokens for request-body bytes in a settled estimate: ceil(bytes / 3), the same high count
|
|
38
|
+
* as the native gateway's byte estimate. Coding-agent bodies are mostly code, JSON and English,
|
|
39
|
+
* which tokenize at about 3.5 to 4.5 bytes a token, so a token per 3 bytes stays above the real
|
|
40
|
+
* count. Text that tokenizes tighter is mostly multi-byte UTF-8 (3 bytes a character, rarely more
|
|
41
|
+
* than a token each), and base64 images are billed by size, not bytes, so both still lean high.
|
|
42
|
+
* The hold itself still counts a token per byte (hold.ts): this is only the settled estimate.
|
|
43
|
+
*/
|
|
44
|
+
export declare function bodyInputTokens(bytes: number): number;
|
|
45
|
+
/**
|
|
46
|
+
* The input of a cut request from its conversation's previous reply: that reply's prompt and cache
|
|
47
|
+
* split, plus the body's growth since (bodyInputTokens) as uncached input (uncachedInput).
|
|
48
|
+
* Undefined when that reply can't stand for this prompt, as for the hold (hold.ts): another model,
|
|
49
|
+
* estimated or unfinished, an unknown or larger body, or a cache that had expired by the time the
|
|
50
|
+
* request was reserved. The estimate then prices the whole body as uncached input.
|
|
51
|
+
*/
|
|
52
|
+
export declare function previousInput(input: {
|
|
53
|
+
model: string;
|
|
54
|
+
bodyBytes: number | undefined;
|
|
55
|
+
previous: PreviousReply | null;
|
|
56
|
+
pricing: ModelPricing;
|
|
57
|
+
/** When the request was reserved: the hold's own clock. */
|
|
58
|
+
now: Date;
|
|
59
|
+
}): ProxyUsage | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* The best known cost of a reply that broke before its final usage (spec PR 1
|
|
62
|
+
* › 1b): usage already read, else the input from its conversation's previous
|
|
63
|
+
* reply (previousInput), else the whole body as uncached input
|
|
64
|
+
* (bodyInputTokens), else (body size unknown) the input part of the hold; plus
|
|
65
|
+
* the output seen so far. With no output seen, the model's median completed
|
|
66
|
+
* reply, or none while there is no completed reply (a deliberate rule: one cut
|
|
67
|
+
* must not book a whole reserved reply). A stream that failed before its
|
|
68
|
+
* response started generated none. Never more than the request's worst case.
|
|
69
|
+
*/
|
|
70
|
+
export declare function estimateInterrupted(facts: InterruptedFacts, pricing: ModelPricing): InterruptedEstimate;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { computeCost } from "../llm/pricing-core.js";
|
|
2
|
+
import { CACHE_WINDOW_MS } from "./hold.js";
|
|
3
|
+
/** Output tokens for relayed text: ceil(bytes / 3), a deliberately high count. */
|
|
4
|
+
export function relayedOutputTokens(bytes) {
|
|
5
|
+
return bytes > 0 ? Math.ceil(bytes / 3) : 0;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Prompt tokens for request-body bytes in a settled estimate: ceil(bytes / 3), the same high count
|
|
9
|
+
* as the native gateway's byte estimate. Coding-agent bodies are mostly code, JSON and English,
|
|
10
|
+
* which tokenize at about 3.5 to 4.5 bytes a token, so a token per 3 bytes stays above the real
|
|
11
|
+
* count. Text that tokenizes tighter is mostly multi-byte UTF-8 (3 bytes a character, rarely more
|
|
12
|
+
* than a token each), and base64 images are billed by size, not bytes, so both still lean high.
|
|
13
|
+
* The hold itself still counts a token per byte (hold.ts): this is only the settled estimate.
|
|
14
|
+
*/
|
|
15
|
+
export function bodyInputTokens(bytes) {
|
|
16
|
+
return bytes > 0 ? Math.ceil(bytes / 3) : 0;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* New prompt tokens as usage, at the higher of the model's fresh-input and cache-write rates: the
|
|
20
|
+
* provider may write them to its cache (Claude Code marks the latest message; OpenAI GPT-5.6 and
|
|
21
|
+
* later bill cache writes above input), or bill them as input.
|
|
22
|
+
*/
|
|
23
|
+
function uncachedInput(tokens, pricing) {
|
|
24
|
+
const written = (pricing.cacheWritePerMTok ?? pricing.inputPerMTok) > pricing.inputPerMTok;
|
|
25
|
+
return { inputTokens: written ? 0 : tokens, cacheWriteTokens: written ? tokens : 0 };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The input of a cut request from its conversation's previous reply: that reply's prompt and cache
|
|
29
|
+
* split, plus the body's growth since (bodyInputTokens) as uncached input (uncachedInput).
|
|
30
|
+
* Undefined when that reply can't stand for this prompt, as for the hold (hold.ts): another model,
|
|
31
|
+
* estimated or unfinished, an unknown or larger body, or a cache that had expired by the time the
|
|
32
|
+
* request was reserved. The estimate then prices the whole body as uncached input.
|
|
33
|
+
*/
|
|
34
|
+
export function previousInput(input) {
|
|
35
|
+
const { previous, bodyBytes } = input;
|
|
36
|
+
if (!previous || previous.model !== input.model || previous.costEstimated)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (previous.status !== "completed" || !previous.usage)
|
|
39
|
+
return undefined;
|
|
40
|
+
if (bodyBytes === undefined || previous.requestBytes === null || bodyBytes < previous.requestBytes)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (input.now.getTime() - previous.startedAt.getTime() > CACHE_WINDOW_MS)
|
|
43
|
+
return undefined;
|
|
44
|
+
const growth = uncachedInput(bodyInputTokens(bodyBytes - previous.requestBytes), input.pricing);
|
|
45
|
+
const usage = previous.usage;
|
|
46
|
+
return {
|
|
47
|
+
inputTokens: usage.inputTokens + growth.inputTokens,
|
|
48
|
+
cachedInputTokens: usage.cachedInputTokens,
|
|
49
|
+
cacheWriteTokens: usage.cacheWriteTokens + growth.cacheWriteTokens,
|
|
50
|
+
outputTokens: 0,
|
|
51
|
+
reasoningTokens: 0,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The best known cost of a reply that broke before its final usage (spec PR 1
|
|
56
|
+
* › 1b): usage already read, else the input from its conversation's previous
|
|
57
|
+
* reply (previousInput), else the whole body as uncached input
|
|
58
|
+
* (bodyInputTokens), else (body size unknown) the input part of the hold; plus
|
|
59
|
+
* the output seen so far. With no output seen, the model's median completed
|
|
60
|
+
* reply, or none while there is no completed reply (a deliberate rule: one cut
|
|
61
|
+
* must not book a whole reserved reply). A stream that failed before its
|
|
62
|
+
* response started generated none. Never more than the request's worst case.
|
|
63
|
+
*/
|
|
64
|
+
export function estimateInterrupted(facts, pricing) {
|
|
65
|
+
const relayed = relayedOutputTokens(facts.relayedOutputBytes);
|
|
66
|
+
const output = relayed > 0 || facts.beforeResponse ? relayed : (facts.medianOutputTokens ?? 0);
|
|
67
|
+
const clamp = (cost) => Math.max(0, Math.min(cost, facts.ceilingUsd ?? facts.reservationUsd));
|
|
68
|
+
if (facts.readUsage) {
|
|
69
|
+
const usage = {
|
|
70
|
+
...facts.readUsage,
|
|
71
|
+
outputTokens: facts.reportedOutputTokens ?? Math.max(facts.outputFloorTokens ?? 0, output),
|
|
72
|
+
reasoningTokens: 0,
|
|
73
|
+
};
|
|
74
|
+
return { usage, costUsd: clamp(computeCost(pricing, usage)) };
|
|
75
|
+
}
|
|
76
|
+
if (facts.previous) {
|
|
77
|
+
const usage = {
|
|
78
|
+
inputTokens: facts.previous.inputTokens,
|
|
79
|
+
cachedInputTokens: facts.previous.cachedInputTokens,
|
|
80
|
+
cacheWriteTokens: facts.previous.cacheWriteTokens,
|
|
81
|
+
outputTokens: output,
|
|
82
|
+
reasoningTokens: 0,
|
|
83
|
+
};
|
|
84
|
+
return { usage, costUsd: clamp(computeCost(pricing, usage)) };
|
|
85
|
+
}
|
|
86
|
+
if (facts.bodyBytes !== undefined) {
|
|
87
|
+
const usage = {
|
|
88
|
+
...uncachedInput(bodyInputTokens(facts.bodyBytes), pricing),
|
|
89
|
+
cachedInputTokens: 0,
|
|
90
|
+
outputTokens: output,
|
|
91
|
+
reasoningTokens: 0,
|
|
92
|
+
};
|
|
93
|
+
return { usage, costUsd: clamp(computeCost(pricing, usage)) };
|
|
94
|
+
}
|
|
95
|
+
const usage = {
|
|
96
|
+
inputTokens: 0,
|
|
97
|
+
cachedInputTokens: 0,
|
|
98
|
+
cacheWriteTokens: 0,
|
|
99
|
+
outputTokens: output,
|
|
100
|
+
reasoningTokens: 0,
|
|
101
|
+
};
|
|
102
|
+
const inputPart = facts.reservationUsd - (facts.maxOutputTokens * pricing.outputPerMTok) / 1_000_000;
|
|
103
|
+
return { usage, costUsd: clamp(inputPart + (usage.outputTokens * pricing.outputPerMTok) / 1_000_000) };
|
|
104
|
+
}
|
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
import { type CreateProxySessionInput, type ProxyLedger, type ProxyRequest, type ProxySession, type ProxyUsage, type ReserveProxyRequestInput, type ReserveProxyRequestResult } from "./types.js";
|
|
1
|
+
import { type PreviousReply, type CreateProxySessionInput, type ProxyLedger, type ProxyRefusalRecord, type ProxyRequest, type ProxySession, type ProxyUsage, type ReserveProxyRequestInput, type ReserveProxyRequestResult } from "./types.js";
|
|
2
2
|
/** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
|
|
3
3
|
export declare class MemoryProxyLedger implements ProxyLedger {
|
|
4
|
+
private readonly options;
|
|
4
5
|
private readonly sessions;
|
|
5
6
|
private readonly sessionByCapability;
|
|
6
7
|
private readonly requests;
|
|
7
8
|
private readonly requestBySessionKey;
|
|
9
|
+
private readonly startedAt;
|
|
10
|
+
constructor(options?: {
|
|
11
|
+
now?: () => Date;
|
|
12
|
+
});
|
|
8
13
|
createSession(input: CreateProxySessionInput): Promise<void>;
|
|
9
14
|
findSessionByCapabilityHash(capabilityHash: string): Promise<ProxySession | null>;
|
|
10
15
|
reserve(input: ReserveProxyRequestInput): Promise<ReserveProxyRequestResult>;
|
|
11
16
|
complete(requestId: string, usage: ProxyUsage, actualCostUsd: number, upstreamStatus: number): Promise<ProxyRequest>;
|
|
12
17
|
release(requestId: string, upstreamStatus: number): Promise<void>;
|
|
13
|
-
markUncertain(requestId: string, upstreamStatus?: number
|
|
18
|
+
markUncertain(requestId: string, upstreamStatus?: number, estimate?: {
|
|
19
|
+
usage: ProxyUsage;
|
|
20
|
+
costUsd: number;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
settlementHints(sessionId: string, model: string): Promise<{
|
|
23
|
+
medianOutputTokens?: number;
|
|
24
|
+
}>;
|
|
25
|
+
previousReply(sessionId: string, conversationKey: string): Promise<PreviousReply | null>;
|
|
14
26
|
cancelSession(sessionId: string): Promise<void>;
|
|
15
27
|
budgetExhausted(sessionId: string): Promise<boolean>;
|
|
28
|
+
budgetRefusal(sessionId: string): Promise<ProxyRefusalRecord | null>;
|
|
16
29
|
recordUpstreamFailure(sessionId: string, code: string): Promise<void>;
|
|
17
30
|
upstreamFailure(sessionId: string): Promise<string | null>;
|
|
18
31
|
getRequest(requestId: string): Promise<ProxyRequest | null>;
|
|
@@ -5,6 +5,7 @@ function cloneSession(session) {
|
|
|
5
5
|
allowedModels: [...session.allowedModels],
|
|
6
6
|
deadlineAt: new Date(session.deadlineAt),
|
|
7
7
|
budgetExhaustedAt: session.budgetExhaustedAt ? new Date(session.budgetExhaustedAt) : null,
|
|
8
|
+
budgetRefusal: session.budgetRefusal ? { ...session.budgetRefusal } : null,
|
|
8
9
|
upstreamFailure: session.upstreamFailure ?? null,
|
|
9
10
|
terms: session.terms
|
|
10
11
|
? { version: session.terms.version, entry: { ...session.terms.entry, efforts: [...session.terms.entry.efforts] } }
|
|
@@ -20,10 +21,15 @@ function cloneRequest(request) {
|
|
|
20
21
|
}
|
|
21
22
|
/** Deterministic contract adapter. Sharing one instance simulates a proxy restart. */
|
|
22
23
|
export class MemoryProxyLedger {
|
|
24
|
+
options;
|
|
23
25
|
sessions = new Map();
|
|
24
26
|
sessionByCapability = new Map();
|
|
25
27
|
requests = new Map();
|
|
26
28
|
requestBySessionKey = new Map();
|
|
29
|
+
startedAt = new Map();
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
this.options = options;
|
|
32
|
+
}
|
|
27
33
|
async createSession(input) {
|
|
28
34
|
if ([...this.sessions.values()].some((session) => session.runId === input.runId)) {
|
|
29
35
|
throw new Error("proxy_session_exists");
|
|
@@ -54,22 +60,47 @@ export class MemoryProxyLedger {
|
|
|
54
60
|
const existingId = this.requestBySessionKey.get(lookupKey);
|
|
55
61
|
if (existingId)
|
|
56
62
|
return { outcome: "duplicate", request: cloneRequest(this.requests.get(existingId)) };
|
|
57
|
-
let
|
|
63
|
+
let spent = 0;
|
|
64
|
+
let heldReserved = 0;
|
|
65
|
+
let heldUncertain = 0;
|
|
66
|
+
let done = 0;
|
|
58
67
|
for (const request of this.requests.values()) {
|
|
59
68
|
if (request.sessionId !== input.sessionId)
|
|
60
69
|
continue;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
70
|
+
// An uncertain request settled at an estimate counts at it; one without an estimate keeps its hold.
|
|
71
|
+
const settled = request.status === "completed" || (request.status === "uncertain" && request.costEstimated);
|
|
72
|
+
if (settled) {
|
|
73
|
+
spent += request.actualCostUsd;
|
|
74
|
+
done += 1;
|
|
75
|
+
}
|
|
76
|
+
else if (request.status === "reserved")
|
|
77
|
+
heldReserved += request.reservationUsd;
|
|
78
|
+
else if (request.status === "uncertain")
|
|
79
|
+
heldUncertain += request.reservationUsd;
|
|
65
80
|
}
|
|
81
|
+
const committedOrHeld = spent + heldReserved + heldUncertain;
|
|
66
82
|
if (committedOrHeld + input.reservationUsd >= session.budgetUsd) {
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
const details = {
|
|
84
|
+
budgetUsd: session.budgetUsd,
|
|
85
|
+
spentUsd: spent,
|
|
86
|
+
heldReservedUsd: heldReserved,
|
|
87
|
+
heldUncertainUsd: heldUncertain,
|
|
88
|
+
refusedHoldUsd: input.reservationUsd,
|
|
89
|
+
...(input.reservationBasis ? { refusedHoldBasis: input.reservationBasis } : {}),
|
|
90
|
+
...(input.ceilingUsd !== undefined ? { refusedHoldCeilingUsd: input.ceilingUsd } : {}),
|
|
91
|
+
model: input.model,
|
|
92
|
+
turn: done + 1,
|
|
93
|
+
};
|
|
94
|
+
if (!session.budgetExhaustedAt) {
|
|
95
|
+
session.budgetExhaustedAt = new Date(input.now);
|
|
96
|
+
session.budgetRefusal = { source: "proxy", ...details };
|
|
97
|
+
}
|
|
98
|
+
return { outcome: "budget_exhausted", details };
|
|
69
99
|
}
|
|
70
100
|
const request = { ...input, pricing: { ...input.pricing }, status: "reserved" };
|
|
71
101
|
this.requests.set(request.id, request);
|
|
72
102
|
this.requestBySessionKey.set(lookupKey, request.id);
|
|
103
|
+
this.startedAt.set(request.id, new Date(input.now));
|
|
73
104
|
return { outcome: "reserved", request: cloneRequest(request) };
|
|
74
105
|
}
|
|
75
106
|
async complete(requestId, usage, actualCostUsd, upstreamStatus) {
|
|
@@ -86,6 +117,7 @@ export class MemoryProxyLedger {
|
|
|
86
117
|
request.actualCostUsd = actualCostUsd;
|
|
87
118
|
request.usage = { ...usage };
|
|
88
119
|
request.upstreamStatus = upstreamStatus;
|
|
120
|
+
request.costEstimated = false;
|
|
89
121
|
return cloneRequest(request);
|
|
90
122
|
}
|
|
91
123
|
async release(requestId, upstreamStatus) {
|
|
@@ -95,12 +127,52 @@ export class MemoryProxyLedger {
|
|
|
95
127
|
request.status = "released";
|
|
96
128
|
request.upstreamStatus = upstreamStatus;
|
|
97
129
|
}
|
|
98
|
-
async markUncertain(requestId, upstreamStatus) {
|
|
130
|
+
async markUncertain(requestId, upstreamStatus, estimate) {
|
|
99
131
|
const request = this.requiredRequest(requestId);
|
|
100
132
|
if (request.status !== "reserved")
|
|
101
133
|
return;
|
|
102
134
|
request.status = "uncertain";
|
|
103
135
|
request.upstreamStatus = upstreamStatus;
|
|
136
|
+
if (estimate) {
|
|
137
|
+
request.actualCostUsd = estimate.costUsd;
|
|
138
|
+
request.usage = { ...estimate.usage };
|
|
139
|
+
request.costEstimated = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async settlementHints(sessionId, model) {
|
|
143
|
+
const outputs = [];
|
|
144
|
+
for (const request of this.requests.values()) {
|
|
145
|
+
if (request.sessionId !== sessionId || request.model !== model)
|
|
146
|
+
continue;
|
|
147
|
+
if (request.status !== "completed" || !request.usage)
|
|
148
|
+
continue;
|
|
149
|
+
outputs.push(request.usage.outputTokens);
|
|
150
|
+
}
|
|
151
|
+
outputs.sort((a, b) => a - b);
|
|
152
|
+
return {
|
|
153
|
+
// The lower middle for an even count, as Postgres's percentile_disc(0.5).
|
|
154
|
+
...(outputs.length > 0 ? { medianOutputTokens: outputs[Math.ceil(outputs.length / 2) - 1] } : {}),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
async previousReply(sessionId, conversationKey) {
|
|
158
|
+
let latest;
|
|
159
|
+
// Map iteration follows insertion order: the last match is the latest request.
|
|
160
|
+
for (const request of this.requests.values()) {
|
|
161
|
+
if (request.sessionId !== sessionId || request.conversationKey !== conversationKey)
|
|
162
|
+
continue;
|
|
163
|
+
if (request.status === "completed" || request.status === "uncertain")
|
|
164
|
+
latest = request;
|
|
165
|
+
}
|
|
166
|
+
if (!latest)
|
|
167
|
+
return null;
|
|
168
|
+
return {
|
|
169
|
+
model: latest.model,
|
|
170
|
+
status: latest.status,
|
|
171
|
+
costEstimated: latest.costEstimated === true,
|
|
172
|
+
...(latest.usage ? { usage: { ...latest.usage } } : {}),
|
|
173
|
+
requestBytes: latest.requestBytes ?? null,
|
|
174
|
+
startedAt: this.startedAt.get(latest.id) ?? new Date(0),
|
|
175
|
+
};
|
|
104
176
|
}
|
|
105
177
|
async cancelSession(sessionId) {
|
|
106
178
|
const session = this.sessions.get(sessionId);
|
|
@@ -110,6 +182,10 @@ export class MemoryProxyLedger {
|
|
|
110
182
|
async budgetExhausted(sessionId) {
|
|
111
183
|
return Boolean(this.sessions.get(sessionId)?.budgetExhaustedAt);
|
|
112
184
|
}
|
|
185
|
+
async budgetRefusal(sessionId) {
|
|
186
|
+
const refusal = this.sessions.get(sessionId)?.budgetRefusal;
|
|
187
|
+
return refusal ? { ...refusal } : null;
|
|
188
|
+
}
|
|
113
189
|
async recordUpstreamFailure(sessionId, code) {
|
|
114
190
|
const session = this.sessions.get(sessionId);
|
|
115
191
|
if (session)
|