@vercel/factory 0.0.13 → 0.0.15
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/README.md +307 -1
- package/dist/agent-routes.d.mts +69 -0
- package/dist/agent-routes.mjs +64 -0
- package/dist/agent-routes.mjs.map +1 -0
- package/dist/api-contracts.d.mts +1749 -0
- package/dist/api-contracts.mjs +118 -0
- package/dist/api-contracts.mjs.map +1 -0
- package/dist/api-images.d.mts +30 -0
- package/dist/api-images.mjs +28 -0
- package/dist/api-images.mjs.map +1 -0
- package/dist/api-task-graph.mjs +57 -0
- package/dist/api-task-graph.mjs.map +1 -0
- package/dist/api.d.mts +77 -0
- package/dist/api.mjs +1087 -0
- package/dist/api.mjs.map +1 -0
- package/dist/approval-access.d.mts +39 -0
- package/dist/approval-access.mjs +62 -0
- package/dist/approval-access.mjs.map +1 -0
- package/dist/approval-contracts.d.mts +692 -0
- package/dist/approval-contracts.mjs +27 -0
- package/dist/approval-contracts.mjs.map +1 -0
- package/dist/approval.d.mts +49 -0
- package/dist/approval.mjs +39 -0
- package/dist/approval.mjs.map +1 -0
- package/dist/blob/artifacts.d.mts +37 -0
- package/dist/blob/artifacts.mjs +45 -0
- package/dist/blob/artifacts.mjs.map +1 -0
- package/dist/blob/index.d.mts +44 -8
- package/dist/blob/index.mjs +159 -35
- package/dist/blob/index.mjs.map +1 -1
- package/dist/budget.d.mts +108 -0
- package/dist/budget.mjs +141 -0
- package/dist/budget.mjs.map +1 -0
- package/dist/budgets.d.mts +4 -0
- package/dist/budgets.mjs +4 -0
- package/dist/build-factory.d.mts +6 -4
- package/dist/build-factory.mjs +2 -1
- package/dist/build-factory.mjs.map +1 -1
- package/dist/change-verification/brief.d.mts +9 -0
- package/dist/change-verification/brief.mjs +13 -0
- package/dist/change-verification/brief.mjs.map +1 -0
- package/dist/change-verification/dispatch.d.mts +24 -0
- package/dist/change-verification/dispatch.mjs +45 -0
- package/dist/change-verification/dispatch.mjs.map +1 -0
- package/dist/change-verification/eve-tool.d.mts +60 -0
- package/dist/change-verification/eve-tool.mjs +101 -0
- package/dist/change-verification/eve-tool.mjs.map +1 -0
- package/dist/changes/eve-record-change.d.mts +56 -0
- package/dist/changes/eve-record-change.mjs +97 -0
- package/dist/changes/eve-record-change.mjs.map +1 -0
- package/dist/changes/presentation.d.mts +14 -0
- package/dist/changes.d.mts +23 -0
- package/dist/changes.mjs +29 -0
- package/dist/changes.mjs.map +1 -0
- package/dist/client-events.d.mts +18 -0
- package/dist/client-events.mjs +41 -0
- package/dist/client-events.mjs.map +1 -0
- package/dist/client-stream.d.mts +28 -0
- package/dist/client-stream.mjs +204 -0
- package/dist/client-stream.mjs.map +1 -0
- package/dist/client-transcript.d.mts +41 -0
- package/dist/client-transcript.mjs +229 -0
- package/dist/client-transcript.mjs.map +1 -0
- package/dist/client.d.mts +234 -0
- package/dist/client.mjs +258 -0
- package/dist/client.mjs.map +1 -0
- package/dist/code-review/contracts.d.mts +26 -0
- package/dist/code-review/eve-post-review.d.mts +70 -0
- package/dist/code-review/eve-post-review.mjs +183 -0
- package/dist/code-review/eve-post-review.mjs.map +1 -0
- package/dist/code-review/eve-review-comments.d.mts +64 -0
- package/dist/code-review/eve-review-comments.mjs +159 -0
- package/dist/code-review/eve-review-comments.mjs.map +1 -0
- package/dist/code-review/github-contracts.d.mts +10 -0
- package/dist/code-review/github-reporter.d.mts +44 -0
- package/dist/code-review/github-reporter.mjs +260 -0
- package/dist/code-review/github-reporter.mjs.map +1 -0
- package/dist/code-review/preparation.d.mts +34 -0
- package/dist/code-review/preparation.mjs +23 -0
- package/dist/code-review/preparation.mjs.map +1 -0
- package/dist/code-review/stall.d.mts +17 -0
- package/dist/code-review/stall.mjs +30 -0
- package/dist/code-review/stall.mjs.map +1 -0
- package/dist/code-review.d.mts +6 -0
- package/dist/code-review.mjs +5 -0
- package/dist/communication.d.mts +9 -0
- package/dist/communication.mjs +9 -0
- package/dist/connectors/github.d.mts +26 -0
- package/dist/connectors/github.mjs +55 -0
- package/dist/connectors/github.mjs.map +1 -0
- package/dist/connectors/index.d.mts +35 -2
- package/dist/connectors/index.mjs +4 -26
- package/dist/connectors/index.mjs.map +1 -1
- package/dist/connectors/outbox.d.mts +34 -0
- package/dist/connectors/outbox.mjs +50 -0
- package/dist/connectors/outbox.mjs.map +1 -0
- package/dist/connectors/slack-approval-blocks.mjs +136 -0
- package/dist/connectors/slack-approval-blocks.mjs.map +1 -0
- package/dist/connectors/slack-approvals.d.mts +29 -0
- package/dist/connectors/slack-approvals.mjs +346 -0
- package/dist/connectors/slack-approvals.mjs.map +1 -0
- package/dist/connectors/slack.d.mts +35 -41
- package/dist/connectors/slack.mjs +13 -69
- package/dist/connectors/slack.mjs.map +1 -1
- package/dist/deepsec/eve-tool.d.mts +110 -0
- package/dist/deepsec/eve-tool.mjs +164 -0
- package/dist/deepsec/eve-tool.mjs.map +1 -0
- package/dist/deepsec/finding.d.mts +84 -0
- package/dist/deepsec/finding.mjs +56 -0
- package/dist/deepsec/finding.mjs.map +1 -0
- package/dist/deepsec.d.mts +3 -0
- package/dist/delivery-metrics/metrics.d.mts +93 -0
- package/dist/delivery-metrics/metrics.mjs +200 -0
- package/dist/delivery-metrics/metrics.mjs.map +1 -0
- package/dist/delivery-metrics.d.mts +2 -0
- package/dist/delivery-metrics.mjs +2 -0
- package/dist/dispatch.d.mts +81 -0
- package/dist/dispatch.mjs +140 -0
- package/dist/dispatch.mjs.map +1 -0
- package/dist/errors.d.mts +15 -0
- package/dist/errors.mjs +38 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/eve/index.d.mts +143 -1561
- package/dist/eve/index.mjs +244 -1063
- package/dist/eve/index.mjs.map +1 -1
- package/dist/eve/invoke.d.mts +144 -0
- package/dist/eve/invoke.mjs +241 -0
- package/dist/eve/invoke.mjs.map +1 -0
- package/dist/eve/session-client.d.mts +68 -0
- package/dist/eve/session-client.mjs +131 -0
- package/dist/eve/session-client.mjs.map +1 -0
- package/dist/eve/task-execution.mjs +18 -0
- package/dist/eve/task-execution.mjs.map +1 -0
- package/dist/eve/task-session.d.mts +87 -0
- package/dist/eve/task-session.mjs +203 -0
- package/dist/eve/task-session.mjs.map +1 -0
- package/dist/eve/transcript.d.mts +37 -0
- package/dist/eve/transcript.mjs +65 -0
- package/dist/eve/transcript.mjs.map +1 -0
- package/dist/execution-public.d.mts +8 -0
- package/dist/execution-public.mjs +7 -0
- package/dist/execution.d.mts +75 -0
- package/dist/execution.mjs +153 -0
- package/dist/execution.mjs.map +1 -0
- package/dist/finding-remediation/admission.d.mts +51 -0
- package/dist/finding-remediation/admission.mjs +87 -0
- package/dist/finding-remediation/admission.mjs.map +1 -0
- package/dist/finding-remediation/brief.d.mts +14 -0
- package/dist/finding-remediation/brief.mjs +25 -0
- package/dist/finding-remediation/brief.mjs.map +1 -0
- package/dist/finding-remediation/eve-tool.d.mts +29 -0
- package/dist/finding-remediation/eve-tool.mjs +34 -0
- package/dist/finding-remediation/eve-tool.mjs.map +1 -0
- package/dist/findings/fingerprint.d.mts +14 -0
- package/dist/findings/fingerprint.mjs +28 -0
- package/dist/findings/fingerprint.mjs.map +1 -0
- package/dist/findings.d.mts +6 -0
- package/dist/findings.mjs +6 -0
- package/dist/github-app.d.mts +54 -0
- package/dist/github-app.mjs +121 -0
- package/dist/github-app.mjs.map +1 -0
- package/dist/github-publication.d.mts +198 -0
- package/dist/github-publication.mjs +429 -0
- package/dist/github-publication.mjs.map +1 -0
- package/dist/github-transfer.d.mts +72 -0
- package/dist/github-transfer.mjs +125 -0
- package/dist/github-transfer.mjs.map +1 -0
- package/dist/github.d.mts +406 -2
- package/dist/github.mjs +250 -37
- package/dist/github.mjs.map +1 -1
- package/dist/image-input.d.mts +51 -0
- package/dist/image-input.mjs +63 -0
- package/dist/image-input.mjs.map +1 -0
- package/dist/index.d.mts +14 -314
- package/dist/index.mjs +14 -1124
- package/dist/intake-contracts.d.mts +56 -0
- package/dist/intake-contracts.mjs +33 -0
- package/dist/intake-contracts.mjs.map +1 -0
- package/dist/integrations/deepsec.d.mts +4 -0
- package/dist/integrations/deepsec.mjs +3 -0
- package/dist/integrations/github.d.mts +11 -0
- package/dist/integrations/github.mjs +9 -0
- package/dist/integrations/slack.d.mts +3 -0
- package/dist/integrations/slack.mjs +3 -0
- package/dist/integrations/vercel.d.mts +3 -0
- package/dist/integrations/vercel.mjs +3 -0
- package/dist/merge-resolution/contracts.d.mts +17 -0
- package/dist/merge-resolution/contracts.mjs +19 -0
- package/dist/merge-resolution/contracts.mjs.map +1 -0
- package/dist/merge-resolution/eve-tools.d.mts +46 -0
- package/dist/merge-resolution/eve-tools.mjs +117 -0
- package/dist/merge-resolution/eve-tools.mjs.map +1 -0
- package/dist/multi-repository-changes/coordination.d.mts +49 -0
- package/dist/multi-repository-changes/coordination.mjs +115 -0
- package/dist/multi-repository-changes/coordination.mjs.map +1 -0
- package/dist/planning/cancellation.mjs +82 -0
- package/dist/planning/cancellation.mjs.map +1 -0
- package/dist/planning/configuration.d.mts +23 -0
- package/dist/planning/configuration.mjs +56 -0
- package/dist/planning/configuration.mjs.map +1 -0
- package/dist/planning/contracts.d.mts +136 -0
- package/dist/planning/contracts.mjs +42 -0
- package/dist/planning/contracts.mjs.map +1 -0
- package/dist/planning/dependencies.mjs +44 -0
- package/dist/planning/dependencies.mjs.map +1 -0
- package/dist/planning/effects.mjs +122 -0
- package/dist/planning/effects.mjs.map +1 -0
- package/dist/planning/reconcile.mjs +273 -0
- package/dist/planning/reconcile.mjs.map +1 -0
- package/dist/planning/runtime.d.mts +27 -0
- package/dist/planning/runtime.mjs +25 -0
- package/dist/planning/runtime.mjs.map +1 -0
- package/dist/planning/state.mjs +92 -0
- package/dist/planning/state.mjs.map +1 -0
- package/dist/planning/turns.mjs +262 -0
- package/dist/planning/turns.mjs.map +1 -0
- package/dist/planning/validation.mjs +106 -0
- package/dist/planning/validation.mjs.map +1 -0
- package/dist/postgres/index.d.mts +7 -1
- package/dist/postgres/index.mjs +7 -3
- package/dist/postgres/index.mjs.map +1 -1
- package/dist/presets/software-development/approval.d.mts +14 -0
- package/dist/presets/software-development/approval.mjs +21 -0
- package/dist/presets/software-development/approval.mjs.map +1 -0
- package/dist/presets/software-development/deepsec-brief.d.mts +8 -0
- package/dist/presets/software-development/deepsec-brief.mjs +14 -0
- package/dist/presets/software-development/deepsec-brief.mjs.map +1 -0
- package/dist/presets/software-development/dispatch.d.mts +53 -0
- package/dist/presets/software-development/dispatch.mjs +66 -0
- package/dist/presets/software-development/dispatch.mjs.map +1 -0
- package/dist/presets/software-development/eve-delegation-policy.d.mts +7 -0
- package/dist/presets/software-development/eve-delegation-policy.mjs +34 -0
- package/dist/presets/software-development/eve-delegation-policy.mjs.map +1 -0
- package/dist/presets/software-development/eve.d.mts +18 -0
- package/dist/presets/software-development/eve.mjs +19 -0
- package/dist/presets/software-development/eve.mjs.map +1 -0
- package/dist/presets/software-development/finish-task-policy.d.mts +7 -0
- package/dist/presets/software-development/finish-task-policy.mjs +9 -0
- package/dist/presets/software-development/finish-task-policy.mjs.map +1 -0
- package/dist/presets/software-development/recovery.d.mts +32 -0
- package/dist/presets/software-development/recovery.mjs +120 -0
- package/dist/presets/software-development/recovery.mjs.map +1 -0
- package/dist/presets/software-development/task-communication.d.mts +23 -0
- package/dist/presets/software-development/task-communication.mjs +120 -0
- package/dist/presets/software-development/task-communication.mjs.map +1 -0
- package/dist/presets/software-development.d.mts +9 -0
- package/dist/presets/software-development.mjs +9 -0
- package/dist/pull-requests/contracts.d.mts +72 -0
- package/dist/pull-requests/eve-fetch.d.mts +57 -0
- package/dist/pull-requests/eve-fetch.mjs +151 -0
- package/dist/pull-requests/eve-fetch.mjs.map +1 -0
- package/dist/pull-requests/github-label-manager.d.mts +27 -0
- package/dist/pull-requests/github-label-manager.mjs +40 -0
- package/dist/pull-requests/github-label-manager.mjs.map +1 -0
- package/dist/pull-requests/github-publisher.d.mts +53 -0
- package/dist/pull-requests/github-publisher.mjs +345 -0
- package/dist/pull-requests/github-publisher.mjs.map +1 -0
- package/dist/pull-requests.d.mts +5 -0
- package/dist/pull-requests.mjs +4 -0
- package/dist/receipts.d.mts +4 -0
- package/dist/receipts.mjs +3 -0
- package/dist/repositories.d.mts +18 -0
- package/dist/repositories.mjs +33 -0
- package/dist/repositories.mjs.map +1 -0
- package/dist/sandbox/command.d.mts +18 -0
- package/dist/sandbox/execution-abort.d.mts +16 -0
- package/dist/sandbox/execution-abort.mjs +49 -0
- package/dist/sandbox/execution-abort.mjs.map +1 -0
- package/dist/sandbox/execution-environment.d.mts +25 -0
- package/dist/sandbox/execution-run-ledger.d.mts +115 -0
- package/dist/sandbox/execution-run-ledger.mjs +209 -0
- package/dist/sandbox/execution-run-ledger.mjs.map +1 -0
- package/dist/sandbox/execution.d.mts +54 -0
- package/dist/sandbox/execution.mjs +228 -0
- package/dist/sandbox/execution.mjs.map +1 -0
- package/dist/sandbox/harness-runner.d.mts +79 -0
- package/dist/sandbox/harness-runner.mjs +162 -0
- package/dist/sandbox/harness-runner.mjs.map +1 -0
- package/dist/sandbox/index.d.mts +9 -0
- package/dist/sandbox/index.mjs +7 -0
- package/dist/sandbox/task-environment.d.mts +50 -0
- package/dist/sandbox/task-environment.mjs +140 -0
- package/dist/sandbox/task-environment.mjs.map +1 -0
- package/dist/sandbox/workspace.d.mts +29 -0
- package/dist/sandbox/workspace.mjs +28 -0
- package/dist/sandbox/workspace.mjs.map +1 -0
- package/dist/schema/agent-route.d.mts +22 -0
- package/dist/schema/agent-route.mjs +15 -0
- package/dist/schema/agent-route.mjs.map +1 -0
- package/dist/schema/answer.d.mts +23 -0
- package/dist/schema/answer.mjs +21 -0
- package/dist/schema/answer.mjs.map +1 -0
- package/dist/schema/budget.d.mts +38 -0
- package/dist/schema/budget.mjs +30 -0
- package/dist/schema/budget.mjs.map +1 -0
- package/dist/schema/catalog.mjs +72 -0
- package/dist/schema/catalog.mjs.map +1 -0
- package/dist/schema/change.d.mts +117 -0
- package/dist/schema/change.mjs +68 -0
- package/dist/schema/change.mjs.map +1 -0
- package/dist/schema/common.d.mts +33 -0
- package/dist/{id-DwCihQr4.mjs → schema/common.mjs} +7 -14
- package/dist/schema/common.mjs.map +1 -0
- package/dist/schema/communication.d.mts +52 -0
- package/dist/schema/communication.mjs +35 -0
- package/dist/schema/communication.mjs.map +1 -0
- package/dist/schema/execution.d.mts +101 -0
- package/dist/schema/execution.mjs +86 -0
- package/dist/schema/execution.mjs.map +1 -0
- package/dist/schema/factory-config.d.mts +95 -0
- package/dist/schema/factory-config.mjs +60 -0
- package/dist/schema/factory-config.mjs.map +1 -0
- package/dist/schema/finding.d.mts +125 -0
- package/dist/schema/finding.mjs +67 -0
- package/dist/schema/finding.mjs.map +1 -0
- package/dist/schema/id.d.mts +43 -0
- package/dist/schema/id.mjs +32 -0
- package/dist/schema/id.mjs.map +1 -0
- package/dist/schema/outbox.d.mts +240 -0
- package/dist/schema/outbox.mjs +53 -0
- package/dist/schema/outbox.mjs.map +1 -0
- package/dist/schema/question-route.mjs +16 -0
- package/dist/schema/question-route.mjs.map +1 -0
- package/dist/schema/receipt.d.mts +81 -0
- package/dist/schema/receipt.mjs +94 -0
- package/dist/schema/receipt.mjs.map +1 -0
- package/dist/schema/repository.d.mts +26 -0
- package/dist/schema/repository.mjs +25 -0
- package/dist/schema/repository.mjs.map +1 -0
- package/dist/schema/session.d.mts +135 -0
- package/dist/schema/session.mjs +53 -0
- package/dist/schema/session.mjs.map +1 -0
- package/dist/schema/signal.d.mts +105 -0
- package/dist/schema/signal.mjs +81 -0
- package/dist/schema/signal.mjs.map +1 -0
- package/dist/schema/stored-session.mjs +10 -0
- package/dist/schema/stored-session.mjs.map +1 -0
- package/dist/schema/stored-task.mjs +20 -0
- package/dist/schema/stored-task.mjs.map +1 -0
- package/dist/schema/task-effect.d.mts +39 -0
- package/dist/schema/task-effect.mjs +29 -0
- package/dist/schema/task-effect.mjs.map +1 -0
- package/dist/schema/task-graph.d.mts +3134 -0
- package/dist/schema/task-graph.mjs +97 -0
- package/dist/schema/task-graph.mjs.map +1 -0
- package/dist/schema/task-message.d.mts +254 -0
- package/dist/schema/task-message.mjs +189 -0
- package/dist/schema/task-message.mjs.map +1 -0
- package/dist/schema/task.d.mts +272 -0
- package/dist/schema/task.mjs +199 -0
- package/dist/schema/task.mjs.map +1 -0
- package/dist/schema/transcript.d.mts +170 -0
- package/dist/schema/transcript.mjs +86 -0
- package/dist/schema/transcript.mjs.map +1 -0
- package/dist/schema/transitions.d.mts +50 -0
- package/dist/schema/transitions.mjs +303 -0
- package/dist/schema/transitions.mjs.map +1 -0
- package/dist/schema/work.d.mts +101 -0
- package/dist/schema/work.mjs +102 -0
- package/dist/schema/work.mjs.map +1 -0
- package/dist/signal-triage.d.mts +20 -0
- package/dist/signal-triage.mjs +85 -0
- package/dist/signal-triage.mjs.map +1 -0
- package/dist/signals.d.mts +19 -0
- package/dist/signals.mjs +19 -0
- package/dist/signals.mjs.map +1 -0
- package/dist/stall.d.mts +38 -0
- package/dist/stall.mjs +79 -0
- package/dist/stall.mjs.map +1 -0
- package/dist/storage.d.mts +4 -0
- package/dist/storage.mjs +4 -0
- package/dist/store/driver.d.mts +65 -0
- package/dist/store/driver.mjs +42 -0
- package/dist/store/driver.mjs.map +1 -0
- package/dist/store/engine.d.mts +485 -0
- package/dist/store/engine.mjs +2175 -0
- package/dist/store/engine.mjs.map +1 -0
- package/dist/store/memory.d.mts +7 -0
- package/dist/store/memory.mjs +52 -0
- package/dist/store/memory.mjs.map +1 -0
- package/dist/store/task-effects.d.mts +38 -0
- package/dist/store/task-effects.mjs +118 -0
- package/dist/store/task-effects.mjs.map +1 -0
- package/dist/store/task-graphs.d.mts +60 -0
- package/dist/store/task-graphs.mjs +212 -0
- package/dist/store/task-graphs.mjs.map +1 -0
- package/dist/store/task-messages.d.mts +136 -0
- package/dist/store/task-messages.mjs +475 -0
- package/dist/store/task-messages.mjs.map +1 -0
- package/dist/store/task-work.d.mts +65 -0
- package/dist/store/task-work.mjs +134 -0
- package/dist/store/task-work.mjs.map +1 -0
- package/dist/store/work-notifications.d.mts +19 -0
- package/dist/store/work-notifications.mjs +48 -0
- package/dist/store/work-notifications.mjs.map +1 -0
- package/dist/sweep.d.mts +57 -0
- package/dist/sweep.mjs +143 -0
- package/dist/sweep.mjs.map +1 -0
- package/dist/task-communication.d.mts +35 -0
- package/dist/task-communication.mjs +47 -0
- package/dist/task-communication.mjs.map +1 -0
- package/dist/task-graph-view.d.mts +264 -0
- package/dist/task-graph-view.mjs +17 -0
- package/dist/task-graph-view.mjs.map +1 -0
- package/dist/task-message-processing.d.mts +60 -0
- package/dist/task-message-processing.mjs +200 -0
- package/dist/task-message-processing.mjs.map +1 -0
- package/dist/task-protocols.d.mts +80 -0
- package/dist/task-protocols.mjs +47 -0
- package/dist/task-protocols.mjs.map +1 -0
- package/dist/tasks.d.mts +17 -0
- package/dist/tasks.mjs +17 -0
- package/dist/vercel-git.d.mts +21 -0
- package/dist/vercel-git.mjs +112 -0
- package/dist/vercel-git.mjs.map +1 -0
- package/dist/vercel.d.mts +33 -2
- package/dist/vercel.mjs +48 -3
- package/dist/vercel.mjs.map +1 -1
- package/dist/work-triage/eve-tool.d.mts +29 -0
- package/dist/work-triage/eve-tool.mjs +32 -0
- package/dist/work-triage/eve-tool.mjs.map +1 -0
- package/dist/work-triage/find-existing-work.d.mts +32 -0
- package/dist/work-triage/find-existing-work.mjs +31 -0
- package/dist/work-triage/find-existing-work.mjs.map +1 -0
- package/dist/work-triage/github.d.mts +15 -0
- package/dist/work-triage/github.mjs +14 -0
- package/dist/work-triage/github.mjs.map +1 -0
- package/dist/work-triage.d.mts +3 -0
- package/dist/work-triage.mjs +3 -0
- package/dist/workflows.d.mts +48 -0
- package/dist/workflows.mjs +86 -0
- package/dist/workflows.mjs.map +1 -0
- package/dist/workspace-diff-assembly.d.mts +33 -0
- package/dist/workspace-diff-assembly.mjs +95 -0
- package/dist/workspace-diff-assembly.mjs.map +1 -0
- package/dist/workspace-diff.d.mts +90 -0
- package/dist/workspace-diff.mjs +61 -0
- package/dist/workspace-diff.mjs.map +1 -0
- package/dist/workspace-snapshot.d.mts +26 -0
- package/dist/workspace-snapshot.mjs +80 -0
- package/dist/workspace-snapshot.mjs.map +1 -0
- package/package.json +129 -40
- package/dist/approval-CwhTP1XB.mjs +0 -269
- package/dist/approval-CwhTP1XB.mjs.map +0 -1
- package/dist/change-CzEAoFVE.mjs +0 -620
- package/dist/change-CzEAoFVE.mjs.map +0 -1
- package/dist/dispatch-B77cuPxh.d.mts +0 -713
- package/dist/driver-BJutB0PE.d.mts +0 -34
- package/dist/driver-Bbd25rNM.mjs +0 -23
- package/dist/driver-Bbd25rNM.mjs.map +0 -1
- package/dist/factory-config-BJcjsPKl.mjs +0 -86
- package/dist/factory-config-BJcjsPKl.mjs.map +0 -1
- package/dist/factory-config-D2yU3G0c.d.mts +0 -58
- package/dist/github-DXsxboUL.d.mts +0 -271
- package/dist/id-DwCihQr4.mjs.map +0 -1
- package/dist/index-Cy4jfXh5.d.mts +0 -67
- package/dist/index.mjs.map +0 -1
- package/dist/signal-CHVEmzvI.d.mts +0 -59
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { JsonValue } from "../schema/work.mjs";
|
|
2
|
+
import { ExecutionReference } from "../schema/task.mjs";
|
|
3
|
+
import "../workflows.mjs";
|
|
4
|
+
import { MillisecondClock } from "../schema/common.mjs";
|
|
5
|
+
import { CodingExecutionRequest, ExecutionLaunchKey, ExecutionResult } from "../schema/execution.mjs";
|
|
6
|
+
import { BlobClient } from "../blob/index.mjs";
|
|
7
|
+
import { HarnessTurnUsage } from "./harness-runner.mjs";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
//#region src/sandbox/execution-run-ledger.d.ts
|
|
10
|
+
declare const runRecordSchema: z.ZodObject<{
|
|
11
|
+
key: z.ZodType<`factory-task:task_${string}:${number}`, string, z.core.$ZodTypeInternals<`factory-task:task_${string}:${number}`, string>>;
|
|
12
|
+
request: z.ZodObject<{
|
|
13
|
+
repository: z.ZodObject<{
|
|
14
|
+
slug: z.ZodType<`${string}/${string}`, string, z.core.$ZodTypeInternals<`${string}/${string}`, string>>;
|
|
15
|
+
baseSha: z.ZodString;
|
|
16
|
+
}, z.core.$strict>;
|
|
17
|
+
harness: z.ZodEnum<{
|
|
18
|
+
"claude-code": "claude-code";
|
|
19
|
+
codex: "codex";
|
|
20
|
+
fx: "fx";
|
|
21
|
+
pi: "pi";
|
|
22
|
+
}>;
|
|
23
|
+
prompt: z.ZodString;
|
|
24
|
+
allowedConstructs: z.ZodReadonly<z.ZodArray<z.ZodString>>;
|
|
25
|
+
environment: z.ZodObject<{
|
|
26
|
+
snapshotId: z.ZodOptional<z.ZodString>;
|
|
27
|
+
timeoutMs: z.ZodNumber;
|
|
28
|
+
}, z.core.$strict>;
|
|
29
|
+
limits: z.ZodObject<{
|
|
30
|
+
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
maxCostUsd: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
taskId: z.ZodType<`task_${string}`, string, z.core.$ZodTypeInternals<`task_${string}`, string>>;
|
|
34
|
+
attempt: z.ZodNumber;
|
|
35
|
+
}, z.core.$strict>;
|
|
36
|
+
execution: z.ZodObject<{
|
|
37
|
+
provider: z.ZodString;
|
|
38
|
+
sessionId: z.ZodString;
|
|
39
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
40
|
+
harness: z.ZodOptional<z.ZodString>;
|
|
41
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, z.core.$strict>;
|
|
43
|
+
harnessSessionId: z.ZodString;
|
|
44
|
+
model: z.ZodString;
|
|
45
|
+
reportSchema: z.ZodCustom<JsonValue, JsonValue>;
|
|
46
|
+
createdAtMs: z.ZodNumber;
|
|
47
|
+
launched: z.ZodBoolean;
|
|
48
|
+
startedAtMs: z.ZodOptional<z.ZodNumber>;
|
|
49
|
+
promptedAtMs: z.ZodOptional<z.ZodNumber>;
|
|
50
|
+
resumeState: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
51
|
+
turns: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
52
|
+
inputTokens: z.ZodNumber;
|
|
53
|
+
noCacheInputTokens: z.ZodNumber;
|
|
54
|
+
cacheReadTokens: z.ZodNumber;
|
|
55
|
+
cacheWriteTokens: z.ZodNumber;
|
|
56
|
+
outputTokens: z.ZodNumber;
|
|
57
|
+
complete: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
}, z.core.$strict>>>;
|
|
59
|
+
lostUsage: z.ZodOptional<z.ZodBoolean>;
|
|
60
|
+
result: z.ZodOptional<z.ZodType<ExecutionResult, unknown, z.core.$ZodTypeInternals<ExecutionResult, unknown>>>;
|
|
61
|
+
}, z.core.$strict>;
|
|
62
|
+
/** Durable identity, continuation, usage, and terminal result for one sandbox execution. */
|
|
63
|
+
type RunRecord = z.infer<typeof runRecordSchema>;
|
|
64
|
+
/** A run record paired with the ETag required for its next confirmed CAS update. */
|
|
65
|
+
interface RunSnapshot {
|
|
66
|
+
record: RunRecord;
|
|
67
|
+
etag: string;
|
|
68
|
+
}
|
|
69
|
+
/** Workflow-owned outcome fields combined with observed execution identity and usage at finalize time. */
|
|
70
|
+
type WithoutObservedExecution<Result extends ExecutionResult> = Result extends ExecutionResult ? Omit<Result, "execution" | "usage"> : never;
|
|
71
|
+
/** Workflow-owned outcome fields before observed execution identity and usage are attached. */
|
|
72
|
+
type ExecutionOutcome = WithoutObservedExecution<ExecutionResult>;
|
|
73
|
+
/** Durable state, clock, and model pricing used to construct an execution ledger. */
|
|
74
|
+
interface ExecutionRunLedgerOptions {
|
|
75
|
+
state: BlobClient;
|
|
76
|
+
now?: MillisecondClock;
|
|
77
|
+
calculateCostUsd?(model: string, turns: readonly HarnessTurnUsage[]): number | undefined;
|
|
78
|
+
}
|
|
79
|
+
/** Immutable admission arguments for one stable sandbox execution key. */
|
|
80
|
+
interface AdmitExecutionRunInput {
|
|
81
|
+
request: CodingExecutionRequest;
|
|
82
|
+
key: ExecutionLaunchKey;
|
|
83
|
+
model: string;
|
|
84
|
+
environmentId: string;
|
|
85
|
+
reportSchema?: unknown;
|
|
86
|
+
}
|
|
87
|
+
/** Identifies the prompt acceptance to persist for one admitted execution run. */
|
|
88
|
+
interface MarkExecutionRunPromptedInput {
|
|
89
|
+
readonly base: RunSnapshot;
|
|
90
|
+
readonly resumeState: unknown;
|
|
91
|
+
readonly origin: "this-driver" | "recovered";
|
|
92
|
+
}
|
|
93
|
+
/** Identifies the first measured turn to persist for one admitted execution run. */
|
|
94
|
+
interface RecordExecutionRunTurnInput {
|
|
95
|
+
readonly base: RunSnapshot;
|
|
96
|
+
readonly turn: HarnessTurnUsage;
|
|
97
|
+
readonly resumeState: unknown;
|
|
98
|
+
readonly origin: "this-driver" | "recovered";
|
|
99
|
+
}
|
|
100
|
+
/** CAS-backed operations for one sandbox execution's admission and continuation state. */
|
|
101
|
+
interface ExecutionRunLedger {
|
|
102
|
+
usage(record: RunRecord): ExecutionResult["usage"];
|
|
103
|
+
read(execution: ExecutionReference): Promise<RunSnapshot | null>;
|
|
104
|
+
admit(input: AdmitExecutionRunInput): Promise<RunSnapshot>;
|
|
105
|
+
markLaunched(base: RunSnapshot, resumeState: unknown): Promise<RunSnapshot>;
|
|
106
|
+
markPrompted(input: MarkExecutionRunPromptedInput): Promise<RunSnapshot>;
|
|
107
|
+
recordTurn(input: RecordExecutionRunTurnInput): Promise<RunSnapshot>;
|
|
108
|
+
finalize(base: RunSnapshot, outcome: ExecutionOutcome): Promise<ExecutionResult>;
|
|
109
|
+
pending(): Promise<readonly ExecutionReference[]>;
|
|
110
|
+
}
|
|
111
|
+
/** Create a CAS-backed ledger for idempotent execution admission, continuation, and finalization. */
|
|
112
|
+
declare function createExecutionRunLedger(input: ExecutionRunLedgerOptions): ExecutionRunLedger;
|
|
113
|
+
//#endregion
|
|
114
|
+
export { AdmitExecutionRunInput, ExecutionOutcome, ExecutionRunLedger, ExecutionRunLedgerOptions, MarkExecutionRunPromptedInput, RecordExecutionRunTurnInput, RunRecord, RunSnapshot, createExecutionRunLedger };
|
|
115
|
+
//# sourceMappingURL=execution-run-ledger.d.mts.map
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { jsonValueSchema } from "../schema/work.mjs";
|
|
2
|
+
import { executionReferenceSchema } from "../schema/task.mjs";
|
|
3
|
+
import { codingExecutionRequestSchema, executionLaunchKeySchema, executionResultSchema } from "../schema/execution.mjs";
|
|
4
|
+
import { ExecutionLaunchPendingError } from "../dispatch.mjs";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { isDeepStrictEqual } from "node:util";
|
|
8
|
+
//#region src/sandbox/execution-run-ledger.ts
|
|
9
|
+
const turnUsageSchema = z.strictObject({
|
|
10
|
+
inputTokens: z.number().int().nonnegative(),
|
|
11
|
+
noCacheInputTokens: z.number().int().nonnegative(),
|
|
12
|
+
cacheReadTokens: z.number().int().nonnegative(),
|
|
13
|
+
cacheWriteTokens: z.number().int().nonnegative(),
|
|
14
|
+
outputTokens: z.number().int().nonnegative(),
|
|
15
|
+
complete: z.boolean().optional()
|
|
16
|
+
});
|
|
17
|
+
const runRecordSchema = z.strictObject({
|
|
18
|
+
key: executionLaunchKeySchema,
|
|
19
|
+
request: codingExecutionRequestSchema,
|
|
20
|
+
execution: executionReferenceSchema,
|
|
21
|
+
harnessSessionId: z.string().min(1),
|
|
22
|
+
model: z.string().min(1),
|
|
23
|
+
reportSchema: jsonValueSchema,
|
|
24
|
+
createdAtMs: z.number().int().nonnegative(),
|
|
25
|
+
launched: z.boolean(),
|
|
26
|
+
startedAtMs: z.number().int().nonnegative().optional(),
|
|
27
|
+
/** Set durably right after the prompt was accepted by the runtime. */
|
|
28
|
+
promptedAtMs: z.number().int().nonnegative().optional(),
|
|
29
|
+
resumeState: jsonValueSchema.optional(),
|
|
30
|
+
turns: z.array(turnUsageSchema).readonly(),
|
|
31
|
+
/** Unobserved spend makes cost permanently unknown, even if later usage is measured. */
|
|
32
|
+
lostUsage: z.boolean().optional(),
|
|
33
|
+
result: executionResultSchema.optional()
|
|
34
|
+
});
|
|
35
|
+
const sameJson = (left, right) => isDeepStrictEqual(left === void 0 ? void 0 : JSON.parse(JSON.stringify(left)), right === void 0 ? void 0 : JSON.parse(JSON.stringify(right)));
|
|
36
|
+
const asStoredJson = (value) => JSON.parse(JSON.stringify(value ?? null));
|
|
37
|
+
const runPrefix = "factory-executions/";
|
|
38
|
+
/** Create a CAS-backed ledger for idempotent execution admission, continuation, and finalization. */
|
|
39
|
+
function createExecutionRunLedger(input) {
|
|
40
|
+
const { state } = input;
|
|
41
|
+
const now = input.now ?? Date.now;
|
|
42
|
+
const runPath = (sessionId) => `${runPrefix}${sessionId}/run`;
|
|
43
|
+
async function readRun(sessionId) {
|
|
44
|
+
const stored = await state.read({ pathname: runPath(sessionId) });
|
|
45
|
+
if (!stored) return null;
|
|
46
|
+
return {
|
|
47
|
+
record: runRecordSchema.parse(JSON.parse(stored.body)),
|
|
48
|
+
etag: stored.etag
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function writeRun(record, etag) {
|
|
52
|
+
await state.write({
|
|
53
|
+
pathname: runPath(record.execution.sessionId),
|
|
54
|
+
body: JSON.stringify(record),
|
|
55
|
+
overwrite: etag !== void 0,
|
|
56
|
+
...etag === void 0 ? {} : { ifMatch: etag }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function persistRun(base, apply, verify) {
|
|
60
|
+
try {
|
|
61
|
+
await writeRun(apply(base.record), base.etag);
|
|
62
|
+
} catch {}
|
|
63
|
+
let current = await readRun(base.record.execution.sessionId);
|
|
64
|
+
if (current && !current.record.result && !verify(current.record)) {
|
|
65
|
+
try {
|
|
66
|
+
await writeRun(apply(current.record), current.etag);
|
|
67
|
+
} catch {}
|
|
68
|
+
current = await readRun(base.record.execution.sessionId);
|
|
69
|
+
}
|
|
70
|
+
if (current && (current.record.result || verify(current.record))) return current;
|
|
71
|
+
throw new Error("Execution state could not be persisted; drive again with the same reference");
|
|
72
|
+
}
|
|
73
|
+
function usage(record) {
|
|
74
|
+
const totals = {
|
|
75
|
+
inputTokens: record.turns.reduce((sum, turn) => sum + turn.inputTokens, 0),
|
|
76
|
+
outputTokens: record.turns.reduce((sum, turn) => sum + turn.outputTokens, 0)
|
|
77
|
+
};
|
|
78
|
+
const costUsd = record.lostUsage !== true && (!record.launched || record.turns.length > 0) ? input.calculateCostUsd?.(record.model, record.turns) : void 0;
|
|
79
|
+
return {
|
|
80
|
+
computeMs: Math.max(0, now() - (record.startedAtMs ?? record.createdAtMs)),
|
|
81
|
+
...totals,
|
|
82
|
+
...costUsd === void 0 ? {} : { costUsd }
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
usage,
|
|
87
|
+
async read(execution) {
|
|
88
|
+
const stored = await readRun(execution.sessionId);
|
|
89
|
+
return stored && sameJson(stored.record.execution, execution) ? stored : null;
|
|
90
|
+
},
|
|
91
|
+
async admit(input) {
|
|
92
|
+
const request = codingExecutionRequestSchema.parse(input.request);
|
|
93
|
+
if (input.key !== `factory-task:${request.taskId}:${request.attempt}`) throw new Error("Execution key must be derived from the request's Task and attempt");
|
|
94
|
+
const sessionId = createHash("sha256").update(input.key).digest("hex");
|
|
95
|
+
const execution = executionReferenceSchema.parse({
|
|
96
|
+
provider: "vercel-sandbox",
|
|
97
|
+
sessionId,
|
|
98
|
+
environmentId: input.environmentId,
|
|
99
|
+
harness: request.harness
|
|
100
|
+
});
|
|
101
|
+
const reportSchema = jsonValueSchema.parse(asStoredJson(input.reportSchema ?? {}));
|
|
102
|
+
const matches = (record) => sameJson(record.request, request) && record.model === input.model && sameJson(record.reportSchema, reportSchema) && sameJson(record.execution, execution);
|
|
103
|
+
const existing = await readRun(sessionId);
|
|
104
|
+
if (existing) {
|
|
105
|
+
if (!matches(existing.record)) throw new Error("Launch key is already bound to a different execution request");
|
|
106
|
+
return existing;
|
|
107
|
+
}
|
|
108
|
+
const record = {
|
|
109
|
+
key: input.key,
|
|
110
|
+
request,
|
|
111
|
+
execution,
|
|
112
|
+
model: input.model,
|
|
113
|
+
reportSchema,
|
|
114
|
+
harnessSessionId: `factory-${sessionId.slice(0, 24)}`,
|
|
115
|
+
createdAtMs: now(),
|
|
116
|
+
launched: false,
|
|
117
|
+
turns: []
|
|
118
|
+
};
|
|
119
|
+
let writeError;
|
|
120
|
+
try {
|
|
121
|
+
await writeRun(record);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
writeError = error;
|
|
124
|
+
}
|
|
125
|
+
let stored;
|
|
126
|
+
try {
|
|
127
|
+
stored = await readRun(sessionId);
|
|
128
|
+
} catch (cause) {
|
|
129
|
+
throw new ExecutionLaunchPendingError("Execution admission requires recovery with its original key", { cause });
|
|
130
|
+
}
|
|
131
|
+
if (!stored) {
|
|
132
|
+
if (writeError) throw writeError;
|
|
133
|
+
throw new ExecutionLaunchPendingError("Execution admission could not be confirmed");
|
|
134
|
+
}
|
|
135
|
+
if (!matches(stored.record)) throw new Error("Launch key is already bound to a different execution request");
|
|
136
|
+
return stored;
|
|
137
|
+
},
|
|
138
|
+
markLaunched(base, resumeState) {
|
|
139
|
+
const normalized = jsonValueSchema.parse(asStoredJson(resumeState));
|
|
140
|
+
return persistRun(base, (record) => record.launched ? record : {
|
|
141
|
+
...record,
|
|
142
|
+
launched: true,
|
|
143
|
+
resumeState: normalized,
|
|
144
|
+
startedAtMs: now()
|
|
145
|
+
}, (record) => record.launched);
|
|
146
|
+
},
|
|
147
|
+
markPrompted({ base, resumeState, origin }) {
|
|
148
|
+
if (!base.record.launched) throw new Error("The execution must be launched before recording a prompt");
|
|
149
|
+
const normalized = jsonValueSchema.parse(asStoredJson(resumeState));
|
|
150
|
+
return persistRun(base, (record) => record.promptedAtMs !== void 0 ? record : {
|
|
151
|
+
...record,
|
|
152
|
+
promptedAtMs: now(),
|
|
153
|
+
resumeState: normalized,
|
|
154
|
+
...origin === "recovered" || record.lostUsage ? { lostUsage: true } : {}
|
|
155
|
+
}, (record) => record.promptedAtMs !== void 0);
|
|
156
|
+
},
|
|
157
|
+
recordTurn({ base, turn, resumeState, origin }) {
|
|
158
|
+
if (!base.record.launched) throw new Error("The execution must be launched before recording a turn");
|
|
159
|
+
const normalized = jsonValueSchema.parse(asStoredJson(resumeState));
|
|
160
|
+
const measured = turnUsageSchema.parse(turn);
|
|
161
|
+
return persistRun(base, (record) => record.turns.length > 0 ? record : {
|
|
162
|
+
...record,
|
|
163
|
+
promptedAtMs: record.promptedAtMs ?? now(),
|
|
164
|
+
turns: [measured],
|
|
165
|
+
resumeState: normalized,
|
|
166
|
+
...origin === "recovered" || record.lostUsage ? { lostUsage: true } : {}
|
|
167
|
+
}, (record) => record.turns.length > 0 && record.promptedAtMs !== void 0);
|
|
168
|
+
},
|
|
169
|
+
async finalize(base, outcome) {
|
|
170
|
+
if (base.record.result) return base.record.result;
|
|
171
|
+
const record = base.record;
|
|
172
|
+
const observed = usage(record);
|
|
173
|
+
const cancelledUsage = record.launched ? observed : {
|
|
174
|
+
computeMs: 0,
|
|
175
|
+
costUsd: 0
|
|
176
|
+
};
|
|
177
|
+
const result = executionResultSchema.parse({
|
|
178
|
+
...outcome,
|
|
179
|
+
execution: record.execution,
|
|
180
|
+
usage: outcome.status === "cancelled" ? cancelledUsage : observed
|
|
181
|
+
});
|
|
182
|
+
try {
|
|
183
|
+
await writeRun({
|
|
184
|
+
...record,
|
|
185
|
+
result
|
|
186
|
+
}, base.etag);
|
|
187
|
+
} catch {
|
|
188
|
+
const latest = await readRun(record.execution.sessionId);
|
|
189
|
+
if (latest?.record.result) return latest.record.result;
|
|
190
|
+
throw new Error("Execution result could not be recorded; retry with the same key");
|
|
191
|
+
}
|
|
192
|
+
const confirmed = await readRun(record.execution.sessionId);
|
|
193
|
+
if (confirmed?.record.result) return confirmed.record.result;
|
|
194
|
+
throw new Error("Execution result could not be recorded; retry with the same key");
|
|
195
|
+
},
|
|
196
|
+
async pending() {
|
|
197
|
+
const references = [];
|
|
198
|
+
for (const path of await state.listPaths({ prefix: runPrefix })) {
|
|
199
|
+
const stored = await readRun(path.slice(19).split("/")[0]);
|
|
200
|
+
if (stored && !stored.record.result) references.push(stored.record.execution);
|
|
201
|
+
}
|
|
202
|
+
return references;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
export { createExecutionRunLedger };
|
|
208
|
+
|
|
209
|
+
//# sourceMappingURL=execution-run-ledger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-run-ledger.mjs","names":[],"sources":["../../src/sandbox/execution-run-ledger.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport { ExecutionLaunchPendingError } from \"../dispatch\";\nimport type { MillisecondClock } from \"../schema/common\";\nimport {\n codingExecutionRequestSchema,\n executionLaunchKeySchema,\n executionResultSchema,\n type CodingExecutionRequest,\n type ExecutionLaunchKey,\n type ExecutionResult,\n} from \"../schema/execution\";\nimport { executionReferenceSchema, type ExecutionReference } from \"../schema/task\";\nimport { jsonValueSchema } from \"../schema/work\";\nimport type { BlobClient } from \"../blob/index\";\nimport type { HarnessTurnUsage } from \"./harness-runner\";\n\nconst turnUsageSchema = z.strictObject({\n inputTokens: z.number().int().nonnegative(),\n noCacheInputTokens: z.number().int().nonnegative(),\n cacheReadTokens: z.number().int().nonnegative(),\n cacheWriteTokens: z.number().int().nonnegative(),\n outputTokens: z.number().int().nonnegative(),\n complete: z.boolean().optional(),\n});\n\nconst runRecordSchema = z.strictObject({\n key: executionLaunchKeySchema,\n request: codingExecutionRequestSchema,\n execution: executionReferenceSchema,\n harnessSessionId: z.string().min(1),\n model: z.string().min(1),\n reportSchema: jsonValueSchema,\n createdAtMs: z.number().int().nonnegative(),\n launched: z.boolean(),\n startedAtMs: z.number().int().nonnegative().optional(),\n /** Set durably right after the prompt was accepted by the runtime. */\n promptedAtMs: z.number().int().nonnegative().optional(),\n resumeState: jsonValueSchema.optional(),\n turns: z.array(turnUsageSchema).readonly(),\n /** Unobserved spend makes cost permanently unknown, even if later usage is measured. */\n lostUsage: z.boolean().optional(),\n result: executionResultSchema.optional(),\n});\n\n/** Durable identity, continuation, usage, and terminal result for one sandbox execution. */\nexport type RunRecord = z.infer<typeof runRecordSchema>;\n\nconst sameJson = (left: unknown, right: unknown) =>\n isDeepStrictEqual(\n left === undefined ? undefined : JSON.parse(JSON.stringify(left)),\n right === undefined ? undefined : JSON.parse(JSON.stringify(right)),\n );\n// SDK values can carry non-plain properties; validate their persisted JSON form.\nconst asStoredJson = (value: unknown) => JSON.parse(JSON.stringify(value ?? null)) as unknown;\n\n/** A run record paired with the ETag required for its next confirmed CAS update. */\nexport interface RunSnapshot {\n record: RunRecord;\n etag: string;\n}\n\n/** Workflow-owned outcome fields combined with observed execution identity and usage at finalize time. */\ntype WithoutObservedExecution<Result extends ExecutionResult> = Result extends ExecutionResult\n ? Omit<Result, \"execution\" | \"usage\">\n : never;\n\n/** Workflow-owned outcome fields before observed execution identity and usage are attached. */\nexport type ExecutionOutcome = WithoutObservedExecution<ExecutionResult>;\nconst runPrefix = \"factory-executions/\";\n\n/** Durable state, clock, and model pricing used to construct an execution ledger. */\nexport interface ExecutionRunLedgerOptions {\n state: BlobClient;\n now?: MillisecondClock;\n calculateCostUsd?(model: string, turns: readonly HarnessTurnUsage[]): number | undefined;\n}\n\n/** Immutable admission arguments for one stable sandbox execution key. */\nexport interface AdmitExecutionRunInput {\n request: CodingExecutionRequest;\n key: ExecutionLaunchKey;\n model: string;\n environmentId: string;\n reportSchema?: unknown;\n}\n\n/** Identifies the prompt acceptance to persist for one admitted execution run. */\nexport interface MarkExecutionRunPromptedInput {\n readonly base: RunSnapshot;\n readonly resumeState: unknown;\n readonly origin: \"this-driver\" | \"recovered\";\n}\n\n/** Identifies the first measured turn to persist for one admitted execution run. */\nexport interface RecordExecutionRunTurnInput {\n readonly base: RunSnapshot;\n readonly turn: HarnessTurnUsage;\n readonly resumeState: unknown;\n readonly origin: \"this-driver\" | \"recovered\";\n}\n\n/** CAS-backed operations for one sandbox execution's admission and continuation state. */\nexport interface ExecutionRunLedger {\n usage(record: RunRecord): ExecutionResult[\"usage\"];\n read(execution: ExecutionReference): Promise<RunSnapshot | null>;\n admit(input: AdmitExecutionRunInput): Promise<RunSnapshot>;\n markLaunched(base: RunSnapshot, resumeState: unknown): Promise<RunSnapshot>;\n markPrompted(input: MarkExecutionRunPromptedInput): Promise<RunSnapshot>;\n recordTurn(input: RecordExecutionRunTurnInput): Promise<RunSnapshot>;\n finalize(base: RunSnapshot, outcome: ExecutionOutcome): Promise<ExecutionResult>;\n pending(): Promise<readonly ExecutionReference[]>;\n}\n\n/** Create a CAS-backed ledger for idempotent execution admission, continuation, and finalization. */\nexport function createExecutionRunLedger(input: ExecutionRunLedgerOptions): ExecutionRunLedger {\n const { state } = input;\n const now = input.now ?? Date.now;\n const runPath = (sessionId: string) => `${runPrefix}${sessionId}/run`;\n async function readRun(sessionId: string): Promise<{ record: RunRecord; etag: string } | null> {\n const stored = await state.read({ pathname: runPath(sessionId) });\n if (!stored) return null;\n return { record: runRecordSchema.parse(JSON.parse(stored.body)), etag: stored.etag };\n }\n\n async function writeRun(record: RunRecord, etag?: string): Promise<void> {\n await state.write({\n pathname: runPath(record.execution.sessionId),\n body: JSON.stringify(record),\n overwrite: etag !== undefined,\n ...(etag === undefined ? {} : { ifMatch: etag }),\n });\n }\n\n // A lost write response is ambiguous; confirm durable state before the next provider effect.\n async function persistRun(\n base: { record: RunRecord; etag: string },\n apply: (record: RunRecord) => RunRecord,\n verify: (record: RunRecord) => boolean,\n ): Promise<{ record: RunRecord; etag: string }> {\n try {\n await writeRun(apply(base.record), base.etag);\n } catch {\n // Confirmed or retried below.\n }\n let current = await readRun(base.record.execution.sessionId);\n if (current && !current.record.result && !verify(current.record)) {\n try {\n await writeRun(apply(current.record), current.etag);\n } catch {\n // Confirmed below.\n }\n current = await readRun(base.record.execution.sessionId);\n }\n if (current && (current.record.result || verify(current.record))) return current;\n throw new Error(\"Execution state could not be persisted; drive again with the same reference\");\n }\n\n function usage(record: RunRecord): ExecutionResult[\"usage\"] {\n const totals = {\n inputTokens: record.turns.reduce((sum, turn) => sum + turn.inputTokens, 0),\n outputTokens: record.turns.reduce((sum, turn) => sum + turn.outputTokens, 0),\n };\n const costUsd =\n record.lostUsage !== true && (!record.launched || record.turns.length > 0)\n ? input.calculateCostUsd?.(record.model, record.turns)\n : undefined;\n return {\n computeMs: Math.max(0, now() - (record.startedAtMs ?? record.createdAtMs)),\n ...totals,\n ...(costUsd === undefined ? {} : { costUsd }),\n };\n }\n\n return {\n usage,\n async read(execution: ExecutionReference): Promise<RunSnapshot | null> {\n const stored = await readRun(execution.sessionId);\n return stored && sameJson(stored.record.execution, execution) ? stored : null;\n },\n async admit(input: AdmitExecutionRunInput): Promise<RunSnapshot> {\n const request = codingExecutionRequestSchema.parse(input.request);\n if (input.key !== `factory-task:${request.taskId}:${request.attempt}`)\n throw new Error(\"Execution key must be derived from the request's Task and attempt\");\n const sessionId = createHash(\"sha256\").update(input.key).digest(\"hex\");\n const execution = executionReferenceSchema.parse({\n provider: \"vercel-sandbox\",\n sessionId,\n environmentId: input.environmentId,\n harness: request.harness,\n });\n const reportSchema = jsonValueSchema.parse(asStoredJson(input.reportSchema ?? {}));\n const matches = (record: RunRecord) =>\n sameJson(record.request, request) &&\n record.model === input.model &&\n sameJson(record.reportSchema, reportSchema) &&\n sameJson(record.execution, execution);\n const existing = await readRun(sessionId);\n if (existing) {\n if (!matches(existing.record))\n throw new Error(\"Launch key is already bound to a different execution request\");\n return existing;\n }\n const record: RunRecord = {\n key: input.key,\n request,\n execution,\n model: input.model,\n reportSchema,\n harnessSessionId: `factory-${sessionId.slice(0, 24)}`,\n createdAtMs: now(),\n launched: false,\n turns: [],\n };\n let writeError: unknown;\n try {\n await writeRun(record);\n } catch (error) {\n writeError = error;\n }\n let stored: RunSnapshot | null;\n try {\n stored = await readRun(sessionId);\n } catch (cause) {\n throw new ExecutionLaunchPendingError(\n \"Execution admission requires recovery with its original key\",\n { cause },\n );\n }\n if (!stored) {\n if (writeError) throw writeError;\n throw new ExecutionLaunchPendingError(\"Execution admission could not be confirmed\");\n }\n if (!matches(stored.record))\n throw new Error(\"Launch key is already bound to a different execution request\");\n return stored;\n },\n markLaunched(base: RunSnapshot, resumeState: unknown): Promise<RunSnapshot> {\n const normalized = jsonValueSchema.parse(asStoredJson(resumeState));\n return persistRun(\n base,\n (record) =>\n record.launched\n ? record\n : {\n ...record,\n launched: true,\n resumeState: normalized,\n startedAtMs: now(),\n },\n (record) => record.launched,\n );\n },\n markPrompted({\n base,\n resumeState,\n origin,\n }: MarkExecutionRunPromptedInput): Promise<RunSnapshot> {\n if (!base.record.launched)\n throw new Error(\"The execution must be launched before recording a prompt\");\n const normalized = jsonValueSchema.parse(asStoredJson(resumeState));\n return persistRun(\n base,\n (record) =>\n record.promptedAtMs !== undefined\n ? record\n : {\n ...record,\n promptedAtMs: now(),\n resumeState: normalized,\n ...(origin === \"recovered\" || record.lostUsage ? { lostUsage: true } : {}),\n },\n (record) => record.promptedAtMs !== undefined,\n );\n },\n recordTurn({\n base,\n turn,\n resumeState,\n origin,\n }: RecordExecutionRunTurnInput): Promise<RunSnapshot> {\n if (!base.record.launched)\n throw new Error(\"The execution must be launched before recording a turn\");\n const normalized = jsonValueSchema.parse(asStoredJson(resumeState));\n const measured = turnUsageSchema.parse(turn);\n return persistRun(\n base,\n (record) =>\n record.turns.length > 0\n ? record\n : {\n ...record,\n promptedAtMs: record.promptedAtMs ?? now(),\n turns: [measured],\n resumeState: normalized,\n ...(origin === \"recovered\" || record.lostUsage ? { lostUsage: true } : {}),\n },\n (record) => record.turns.length > 0 && record.promptedAtMs !== undefined,\n );\n },\n async finalize(base: RunSnapshot, outcome: ExecutionOutcome): Promise<ExecutionResult> {\n if (base.record.result) return base.record.result;\n const record = base.record;\n const observed = usage(record);\n const cancelledUsage = record.launched ? observed : { computeMs: 0, costUsd: 0 };\n const result = executionResultSchema.parse({\n ...outcome,\n execution: record.execution,\n usage: outcome.status === \"cancelled\" ? cancelledUsage : observed,\n });\n try {\n await writeRun({ ...record, result }, base.etag);\n } catch {\n const latest = await readRun(record.execution.sessionId);\n if (latest?.record.result) return latest.record.result;\n throw new Error(\"Execution result could not be recorded; retry with the same key\");\n }\n const confirmed = await readRun(record.execution.sessionId);\n if (confirmed?.record.result) return confirmed.record.result;\n throw new Error(\"Execution result could not be recorded; retry with the same key\");\n },\n async pending(): Promise<readonly ExecutionReference[]> {\n const references: ExecutionReference[] = [];\n for (const path of await state.listPaths({ prefix: runPrefix })) {\n const stored = await readRun(path.slice(runPrefix.length).split(\"/\")[0]!);\n if (stored && !stored.record.result) references.push(stored.record.execution);\n }\n return references;\n },\n };\n}\n"],"mappings":";;;;;;;;AAkBA,MAAM,kBAAkB,EAAE,aAAa;CACrC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CAC1C,oBAAoB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CACjD,iBAAiB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CAC9C,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CAC/C,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CAC3C,UAAU,EAAE,QAAQ,CAAC,CAAC,SAAS;AACjC,CAAC;AAED,MAAM,kBAAkB,EAAE,aAAa;CACrC,KAAK;CACL,SAAS;CACT,WAAW;CACX,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAClC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACvB,cAAc;CACd,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CAC1C,UAAU,EAAE,QAAQ;CACpB,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS;;CAErD,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS;CACtD,aAAa,gBAAgB,SAAS;CACtC,OAAO,EAAE,MAAM,eAAe,CAAC,CAAC,SAAS;;CAEzC,WAAW,EAAE,QAAQ,CAAC,CAAC,SAAS;CAChC,QAAQ,sBAAsB,SAAS;AACzC,CAAC;AAKD,MAAM,YAAY,MAAe,UAC/B,kBACE,SAAS,KAAA,IAAY,KAAA,IAAY,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,GAChE,UAAU,KAAA,IAAY,KAAA,IAAY,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC,CACpE;AAEF,MAAM,gBAAgB,UAAmB,KAAK,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC;AAejF,MAAM,YAAY;;AA8ClB,SAAgB,yBAAyB,OAAsD;CAC7F,MAAM,EAAE,UAAU;CAClB,MAAM,MAAM,MAAM,OAAO,KAAK;CAC9B,MAAM,WAAW,cAAsB,GAAG,YAAY,UAAU;CAChE,eAAe,QAAQ,WAAwE;EAC7F,MAAM,SAAS,MAAM,MAAM,KAAK,EAAE,UAAU,QAAQ,SAAS,EAAE,CAAC;EAChE,IAAI,CAAC,QAAQ,OAAO;EACpB,OAAO;GAAE,QAAQ,gBAAgB,MAAM,KAAK,MAAM,OAAO,IAAI,CAAC;GAAG,MAAM,OAAO;EAAK;CACrF;CAEA,eAAe,SAAS,QAAmB,MAA8B;EACvE,MAAM,MAAM,MAAM;GAChB,UAAU,QAAQ,OAAO,UAAU,SAAS;GAC5C,MAAM,KAAK,UAAU,MAAM;GAC3B,WAAW,SAAS,KAAA;GACpB,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,KAAK;EAChD,CAAC;CACH;CAGA,eAAe,WACb,MACA,OACA,QAC8C;EAC9C,IAAI;GACF,MAAM,SAAS,MAAM,KAAK,MAAM,GAAG,KAAK,IAAI;EAC9C,QAAQ,CAER;EACA,IAAI,UAAU,MAAM,QAAQ,KAAK,OAAO,UAAU,SAAS;EAC3D,IAAI,WAAW,CAAC,QAAQ,OAAO,UAAU,CAAC,OAAO,QAAQ,MAAM,GAAG;GAChE,IAAI;IACF,MAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,QAAQ,IAAI;GACpD,QAAQ,CAER;GACA,UAAU,MAAM,QAAQ,KAAK,OAAO,UAAU,SAAS;EACzD;EACA,IAAI,YAAY,QAAQ,OAAO,UAAU,OAAO,QAAQ,MAAM,IAAI,OAAO;EACzE,MAAM,IAAI,MAAM,6EAA6E;CAC/F;CAEA,SAAS,MAAM,QAA6C;EAC1D,MAAM,SAAS;GACb,aAAa,OAAO,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,aAAa,CAAC;GACzE,cAAc,OAAO,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,cAAc,CAAC;EAC7E;EACA,MAAM,UACJ,OAAO,cAAc,SAAS,CAAC,OAAO,YAAY,OAAO,MAAM,SAAS,KACpE,MAAM,mBAAmB,OAAO,OAAO,OAAO,KAAK,IACnD,KAAA;EACN,OAAO;GACL,WAAW,KAAK,IAAI,GAAG,IAAI,KAAK,OAAO,eAAe,OAAO,YAAY;GACzE,GAAG;GACH,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;EAC7C;CACF;CAEA,OAAO;EACL;EACA,MAAM,KAAK,WAA4D;GACrE,MAAM,SAAS,MAAM,QAAQ,UAAU,SAAS;GAChD,OAAO,UAAU,SAAS,OAAO,OAAO,WAAW,SAAS,IAAI,SAAS;EAC3E;EACA,MAAM,MAAM,OAAqD;GAC/D,MAAM,UAAU,6BAA6B,MAAM,MAAM,OAAO;GAChE,IAAI,MAAM,QAAQ,gBAAgB,QAAQ,OAAO,GAAG,QAAQ,WAC1D,MAAM,IAAI,MAAM,mEAAmE;GACrF,MAAM,YAAY,WAAW,QAAQ,CAAC,CAAC,OAAO,MAAM,GAAG,CAAC,CAAC,OAAO,KAAK;GACrE,MAAM,YAAY,yBAAyB,MAAM;IAC/C,UAAU;IACV;IACA,eAAe,MAAM;IACrB,SAAS,QAAQ;GACnB,CAAC;GACD,MAAM,eAAe,gBAAgB,MAAM,aAAa,MAAM,gBAAgB,CAAC,CAAC,CAAC;GACjF,MAAM,WAAW,WACf,SAAS,OAAO,SAAS,OAAO,KAChC,OAAO,UAAU,MAAM,SACvB,SAAS,OAAO,cAAc,YAAY,KAC1C,SAAS,OAAO,WAAW,SAAS;GACtC,MAAM,WAAW,MAAM,QAAQ,SAAS;GACxC,IAAI,UAAU;IACZ,IAAI,CAAC,QAAQ,SAAS,MAAM,GAC1B,MAAM,IAAI,MAAM,8DAA8D;IAChF,OAAO;GACT;GACA,MAAM,SAAoB;IACxB,KAAK,MAAM;IACX;IACA;IACA,OAAO,MAAM;IACb;IACA,kBAAkB,WAAW,UAAU,MAAM,GAAG,EAAE;IAClD,aAAa,IAAI;IACjB,UAAU;IACV,OAAO,CAAC;GACV;GACA,IAAI;GACJ,IAAI;IACF,MAAM,SAAS,MAAM;GACvB,SAAS,OAAO;IACd,aAAa;GACf;GACA,IAAI;GACJ,IAAI;IACF,SAAS,MAAM,QAAQ,SAAS;GAClC,SAAS,OAAO;IACd,MAAM,IAAI,4BACR,+DACA,EAAE,MAAM,CACV;GACF;GACA,IAAI,CAAC,QAAQ;IACX,IAAI,YAAY,MAAM;IACtB,MAAM,IAAI,4BAA4B,4CAA4C;GACpF;GACA,IAAI,CAAC,QAAQ,OAAO,MAAM,GACxB,MAAM,IAAI,MAAM,8DAA8D;GAChF,OAAO;EACT;EACA,aAAa,MAAmB,aAA4C;GAC1E,MAAM,aAAa,gBAAgB,MAAM,aAAa,WAAW,CAAC;GAClE,OAAO,WACL,OACC,WACC,OAAO,WACH,SACA;IACE,GAAG;IACH,UAAU;IACV,aAAa;IACb,aAAa,IAAI;GACnB,IACL,WAAW,OAAO,QACrB;EACF;EACA,aAAa,EACX,MACA,aACA,UACsD;GACtD,IAAI,CAAC,KAAK,OAAO,UACf,MAAM,IAAI,MAAM,0DAA0D;GAC5E,MAAM,aAAa,gBAAgB,MAAM,aAAa,WAAW,CAAC;GAClE,OAAO,WACL,OACC,WACC,OAAO,iBAAiB,KAAA,IACpB,SACA;IACE,GAAG;IACH,cAAc,IAAI;IAClB,aAAa;IACb,GAAI,WAAW,eAAe,OAAO,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;GAC1E,IACL,WAAW,OAAO,iBAAiB,KAAA,CACtC;EACF;EACA,WAAW,EACT,MACA,MACA,aACA,UACoD;GACpD,IAAI,CAAC,KAAK,OAAO,UACf,MAAM,IAAI,MAAM,wDAAwD;GAC1E,MAAM,aAAa,gBAAgB,MAAM,aAAa,WAAW,CAAC;GAClE,MAAM,WAAW,gBAAgB,MAAM,IAAI;GAC3C,OAAO,WACL,OACC,WACC,OAAO,MAAM,SAAS,IAClB,SACA;IACE,GAAG;IACH,cAAc,OAAO,gBAAgB,IAAI;IACzC,OAAO,CAAC,QAAQ;IAChB,aAAa;IACb,GAAI,WAAW,eAAe,OAAO,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;GAC1E,IACL,WAAW,OAAO,MAAM,SAAS,KAAK,OAAO,iBAAiB,KAAA,CACjE;EACF;EACA,MAAM,SAAS,MAAmB,SAAqD;GACrF,IAAI,KAAK,OAAO,QAAQ,OAAO,KAAK,OAAO;GAC3C,MAAM,SAAS,KAAK;GACpB,MAAM,WAAW,MAAM,MAAM;GAC7B,MAAM,iBAAiB,OAAO,WAAW,WAAW;IAAE,WAAW;IAAG,SAAS;GAAE;GAC/E,MAAM,SAAS,sBAAsB,MAAM;IACzC,GAAG;IACH,WAAW,OAAO;IAClB,OAAO,QAAQ,WAAW,cAAc,iBAAiB;GAC3D,CAAC;GACD,IAAI;IACF,MAAM,SAAS;KAAE,GAAG;KAAQ;IAAO,GAAG,KAAK,IAAI;GACjD,QAAQ;IACN,MAAM,SAAS,MAAM,QAAQ,OAAO,UAAU,SAAS;IACvD,IAAI,QAAQ,OAAO,QAAQ,OAAO,OAAO,OAAO;IAChD,MAAM,IAAI,MAAM,iEAAiE;GACnF;GACA,MAAM,YAAY,MAAM,QAAQ,OAAO,UAAU,SAAS;GAC1D,IAAI,WAAW,OAAO,QAAQ,OAAO,UAAU,OAAO;GACtD,MAAM,IAAI,MAAM,iEAAiE;EACnF;EACA,MAAM,UAAkD;GACtD,MAAM,aAAmC,CAAC;GAC1C,KAAK,MAAM,QAAQ,MAAM,MAAM,UAAU,EAAE,QAAQ,UAAU,CAAC,GAAG;IAC/D,MAAM,SAAS,MAAM,QAAQ,KAAK,MAAM,EAAgB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EAAG;IACxE,IAAI,UAAU,CAAC,OAAO,OAAO,QAAQ,WAAW,KAAK,OAAO,OAAO,SAAS;GAC9E;GACA,OAAO;EACT;CACF;AACF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ExecutionReference } from "../schema/task.mjs";
|
|
2
|
+
import { MillisecondClock } from "../schema/common.mjs";
|
|
3
|
+
import { CodingExecutionRequest, ExecutionLaunchKey, ExecutionResult } from "../schema/execution.mjs";
|
|
4
|
+
import { BlobClient } from "../blob/index.mjs";
|
|
5
|
+
import { ExecutionAdapter } from "../execution.mjs";
|
|
6
|
+
import { ConfiguredHarnessRunner, HarnessTurnUsage, SandboxHandle } from "./harness-runner.mjs";
|
|
7
|
+
import { ExecutionEnvironment } from "./execution-environment.mjs";
|
|
8
|
+
import { ExecutionOutcome } from "./execution-run-ledger.mjs";
|
|
9
|
+
//#region src/sandbox/execution.d.ts
|
|
10
|
+
/** Context used to construct the immutable prompt for an admitted sandbox execution. */
|
|
11
|
+
interface SandboxExecutionPromptContext {
|
|
12
|
+
request: CodingExecutionRequest;
|
|
13
|
+
reportSchema: unknown;
|
|
14
|
+
sandbox: SandboxHandle;
|
|
15
|
+
}
|
|
16
|
+
/** Context used to validate and extract artifacts after a sandbox turn completes. */
|
|
17
|
+
interface SandboxExecutionOutcomeContext {
|
|
18
|
+
request: CodingExecutionRequest;
|
|
19
|
+
sandbox: SandboxHandle;
|
|
20
|
+
}
|
|
21
|
+
/** Configures durable state, harnesses, environments, prompts, evidence, and usage pricing. */
|
|
22
|
+
interface SandboxExecutionOptions {
|
|
23
|
+
state: BlobClient;
|
|
24
|
+
harnesses: Partial<Record<CodingExecutionRequest["harness"], ConfiguredHarnessRunner>>;
|
|
25
|
+
environment: ExecutionEnvironment;
|
|
26
|
+
buildPrompt(context: SandboxExecutionPromptContext): string;
|
|
27
|
+
extractOutcome(context: SandboxExecutionOutcomeContext): Promise<ExecutionOutcome>;
|
|
28
|
+
calculateCostUsd?(model: string, turns: readonly HarnessTurnUsage[]): number | undefined;
|
|
29
|
+
sandboxTimeoutMarginMs?: number;
|
|
30
|
+
now?: MillisecondClock;
|
|
31
|
+
}
|
|
32
|
+
/** Coding request, stable launch key, and optional report contract for sandbox admission. */
|
|
33
|
+
interface StartSandboxExecutionInput {
|
|
34
|
+
request: CodingExecutionRequest;
|
|
35
|
+
launchKey: ExecutionLaunchKey;
|
|
36
|
+
context?: SandboxExecutionStartContext;
|
|
37
|
+
}
|
|
38
|
+
/** Optional report contract associated with one sandbox execution launch. */
|
|
39
|
+
interface SandboxExecutionStartContext {
|
|
40
|
+
reportSchema: unknown;
|
|
41
|
+
}
|
|
42
|
+
/** Execution adapter with explicit serial driving and pending-run discovery for sandbox work. */
|
|
43
|
+
interface SandboxExecutionAdapter extends ExecutionAdapter {
|
|
44
|
+
start(input: StartSandboxExecutionInput): Promise<ExecutionReference>;
|
|
45
|
+
/** Serialize calls per execution; ledger CAS does not fence provider effects. */
|
|
46
|
+
drive(execution: ExecutionReference): Promise<ExecutionResult>;
|
|
47
|
+
/** Launch keys with admitted but unfinished runs, for drivers and drills. */
|
|
48
|
+
pending(): Promise<readonly ExecutionReference[]>;
|
|
49
|
+
}
|
|
50
|
+
/** Create a durable execution adapter that runs configured harnesses in Task-scoped sandboxes. */
|
|
51
|
+
declare function createSandboxExecutionAdapter(options: SandboxExecutionOptions): SandboxExecutionAdapter;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { SandboxExecutionAdapter, SandboxExecutionOptions, SandboxExecutionOutcomeContext, SandboxExecutionPromptContext, SandboxExecutionStartContext, StartSandboxExecutionInput, createSandboxExecutionAdapter };
|
|
54
|
+
//# sourceMappingURL=execution.d.mts.map
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { codingExecutionRequestSchema, executionResultSchema } from "../schema/execution.mjs";
|
|
2
|
+
import { ExecutionLaunchPendingError } from "../dispatch.mjs";
|
|
3
|
+
import { ExecutionTimeoutError, withExecutionAbort } from "./execution-abort.mjs";
|
|
4
|
+
import { createExecutionRunLedger } from "./execution-run-ledger.mjs";
|
|
5
|
+
//#region src/sandbox/execution.ts
|
|
6
|
+
const defaultSandboxTimeoutMarginMs = 3e5;
|
|
7
|
+
const bounded = (reason) => reason.slice(0, 2e3);
|
|
8
|
+
/** Create a durable execution adapter that runs configured harnesses in Task-scoped sandboxes. */
|
|
9
|
+
function createSandboxExecutionAdapter(options) {
|
|
10
|
+
const now = options.now ?? Date.now;
|
|
11
|
+
const ledger = createExecutionRunLedger({
|
|
12
|
+
state: options.state,
|
|
13
|
+
now,
|
|
14
|
+
...options.calculateCostUsd ? { calculateCostUsd: options.calculateCostUsd } : {}
|
|
15
|
+
});
|
|
16
|
+
function configuredHarness(harness) {
|
|
17
|
+
const configured = options.harnesses[harness];
|
|
18
|
+
if (!configured || !configured.model.trim()) throw new Error(`Execution harness ${harness} has no configured runner and model`);
|
|
19
|
+
return configured;
|
|
20
|
+
}
|
|
21
|
+
const keyOf = (record) => ({
|
|
22
|
+
taskId: record.request.taskId,
|
|
23
|
+
attempt: record.request.attempt
|
|
24
|
+
});
|
|
25
|
+
const sandboxTimeout = (request) => request.environment.timeoutMs + (options.sandboxTimeoutMarginMs ?? defaultSandboxTimeoutMarginMs);
|
|
26
|
+
async function extract(sandbox, record) {
|
|
27
|
+
const request = record.request;
|
|
28
|
+
const failed = (reason) => ({
|
|
29
|
+
status: "failed",
|
|
30
|
+
artifacts: [],
|
|
31
|
+
reason: bounded(reason)
|
|
32
|
+
});
|
|
33
|
+
const usage = ledger.usage(record);
|
|
34
|
+
const { maxCostUsd, maxTokens } = request.limits;
|
|
35
|
+
if (maxCostUsd !== void 0 && usage.costUsd !== void 0 && usage.costUsd > maxCostUsd) return failed(`Execution spent $${usage.costUsd}, exceeding its maxCostUsd of $${maxCostUsd}`);
|
|
36
|
+
if (maxTokens !== void 0 && (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0) > maxTokens) return failed(`Execution used ${(usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)} tokens, exceeding its maxTokens of ${maxTokens}`);
|
|
37
|
+
return options.extractOutcome({
|
|
38
|
+
sandbox,
|
|
39
|
+
request
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Best-effort idempotent environment shutdown; ambiguity propagates for retry. */
|
|
43
|
+
async function stopEnvironment(record) {
|
|
44
|
+
const sandbox = await options.environment.find(keyOf(record));
|
|
45
|
+
if (sandbox) await options.environment.stop(sandbox.sandbox);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
async start({ request, launchKey, context }) {
|
|
49
|
+
const parsed = codingExecutionRequestSchema.parse(request);
|
|
50
|
+
const configured = configuredHarness(parsed.harness);
|
|
51
|
+
const keyParts = {
|
|
52
|
+
taskId: parsed.taskId,
|
|
53
|
+
attempt: parsed.attempt
|
|
54
|
+
};
|
|
55
|
+
const stored = await ledger.admit({
|
|
56
|
+
request: parsed,
|
|
57
|
+
key: launchKey,
|
|
58
|
+
model: configured.model,
|
|
59
|
+
environmentId: options.environment.name(keyParts),
|
|
60
|
+
reportSchema: context?.reportSchema
|
|
61
|
+
});
|
|
62
|
+
if (stored.record.launched || stored.record.result) return stored.record.execution;
|
|
63
|
+
try {
|
|
64
|
+
await options.environment.ensure(keyParts, {
|
|
65
|
+
timeoutMs: sandboxTimeout(parsed),
|
|
66
|
+
request: parsed
|
|
67
|
+
});
|
|
68
|
+
} catch (cause) {
|
|
69
|
+
throw new ExecutionLaunchPendingError("Execution environment provisioning is unresolved; recover with the original key", { cause });
|
|
70
|
+
}
|
|
71
|
+
return stored.record.execution;
|
|
72
|
+
},
|
|
73
|
+
async inspect(execution) {
|
|
74
|
+
const stored = await ledger.read(execution);
|
|
75
|
+
if (!stored) return { status: "expired" };
|
|
76
|
+
if (stored.record.result) return {
|
|
77
|
+
status: "finished",
|
|
78
|
+
result: stored.record.result
|
|
79
|
+
};
|
|
80
|
+
const sandbox = await options.environment.find(keyOf(stored.record));
|
|
81
|
+
if (!sandbox || sandbox.liveness === "terminal") return { status: "expired" };
|
|
82
|
+
if (sandbox.liveness !== "live") throw new Error("Execution environment is transitioning; inspect again shortly");
|
|
83
|
+
return { status: "active" };
|
|
84
|
+
},
|
|
85
|
+
async stop(execution) {
|
|
86
|
+
const stored = await ledger.read(execution);
|
|
87
|
+
if (!stored) return executionResultSchema.parse({
|
|
88
|
+
status: "cancelled",
|
|
89
|
+
execution,
|
|
90
|
+
artifacts: [],
|
|
91
|
+
usage: { computeMs: 0 },
|
|
92
|
+
reason: "No admitted execution matches this reference; its cost is unknown"
|
|
93
|
+
});
|
|
94
|
+
const { record } = stored;
|
|
95
|
+
if (record.result) {
|
|
96
|
+
await stopEnvironment(record);
|
|
97
|
+
return record.result;
|
|
98
|
+
}
|
|
99
|
+
await stopEnvironment(record);
|
|
100
|
+
return ledger.finalize(stored, {
|
|
101
|
+
status: "cancelled",
|
|
102
|
+
artifacts: [],
|
|
103
|
+
reason: record.launched ? record.turns.length > 0 ? "Execution was stopped after its completed turn was recorded" : "Execution was stopped after launch; unfinished turn cost is unknown" : "Execution was stopped before its prompt was sent"
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
async drive(execution) {
|
|
107
|
+
const admitted = await ledger.read(execution);
|
|
108
|
+
if (!admitted) throw new Error("No admitted execution matches this reference");
|
|
109
|
+
let stored = admitted;
|
|
110
|
+
if (stored.record.result) return stored.record.result;
|
|
111
|
+
const request = stored.record.request;
|
|
112
|
+
const configured = configuredHarness(request.harness);
|
|
113
|
+
if (configured.model !== stored.record.model) throw new Error("Execution model changed; restore its admitted harness configuration");
|
|
114
|
+
let sandbox;
|
|
115
|
+
if (!stored.record.launched) {
|
|
116
|
+
const observed = await options.environment.ensure(keyOf(stored.record), {
|
|
117
|
+
timeoutMs: sandboxTimeout(request),
|
|
118
|
+
request
|
|
119
|
+
});
|
|
120
|
+
if (observed.liveness !== "live") throw new Error("Execution environment is not live");
|
|
121
|
+
sandbox = observed.sandbox;
|
|
122
|
+
} else {
|
|
123
|
+
const found = await options.environment.find(keyOf(stored.record));
|
|
124
|
+
if (!found || found.liveness === "terminal") return ledger.finalize(stored, {
|
|
125
|
+
status: "failed",
|
|
126
|
+
artifacts: [],
|
|
127
|
+
reason: "Execution environment expired before a result was extracted; replacement requires a new attempt"
|
|
128
|
+
});
|
|
129
|
+
if (found.liveness !== "live") throw new Error("Execution environment is transitioning; drive again shortly");
|
|
130
|
+
sandbox = found.sandbox;
|
|
131
|
+
}
|
|
132
|
+
const remainingMs = Math.max(0, request.environment.timeoutMs - (now() - (stored.record.startedAtMs ?? now())));
|
|
133
|
+
try {
|
|
134
|
+
return await withExecutionAbort({
|
|
135
|
+
timeoutMs: remainingMs,
|
|
136
|
+
isStopped: async () => {
|
|
137
|
+
const latest = await ledger.read(execution);
|
|
138
|
+
if (!latest) throw new Error("The admitted execution disappeared");
|
|
139
|
+
return latest.record.result !== void 0;
|
|
140
|
+
},
|
|
141
|
+
run: async (abortSignal) => {
|
|
142
|
+
if (remainingMs === 0) throw new ExecutionTimeoutError();
|
|
143
|
+
let observedFlip = false;
|
|
144
|
+
if (!stored.record.launched) {
|
|
145
|
+
const session = await configured.runner.open({
|
|
146
|
+
sandbox,
|
|
147
|
+
sessionId: stored.record.harnessSessionId,
|
|
148
|
+
abortSignal
|
|
149
|
+
});
|
|
150
|
+
stored = await ledger.markLaunched(stored, await session.detach());
|
|
151
|
+
if (stored.record.result) return stored.record.result;
|
|
152
|
+
observedFlip = true;
|
|
153
|
+
}
|
|
154
|
+
let turn;
|
|
155
|
+
let promptedHere = false;
|
|
156
|
+
if (stored.record.promptedAtMs === void 0 && stored.record.turns.length === 0) {
|
|
157
|
+
const session = await configured.runner.open({
|
|
158
|
+
sandbox,
|
|
159
|
+
sessionId: stored.record.harnessSessionId,
|
|
160
|
+
resumeFrom: stored.record.resumeState,
|
|
161
|
+
abortSignal
|
|
162
|
+
});
|
|
163
|
+
const prompt = options.buildPrompt({
|
|
164
|
+
request,
|
|
165
|
+
reportSchema: stored.record.reportSchema,
|
|
166
|
+
sandbox
|
|
167
|
+
});
|
|
168
|
+
const foreignFlip = !observedFlip;
|
|
169
|
+
try {
|
|
170
|
+
const inflight = await session.beginPrompt(prompt);
|
|
171
|
+
stored = await ledger.markPrompted({
|
|
172
|
+
base: stored,
|
|
173
|
+
resumeState: inflight,
|
|
174
|
+
origin: foreignFlip ? "recovered" : "this-driver"
|
|
175
|
+
});
|
|
176
|
+
promptedHere = true;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (!(error instanceof Error && /unfinished turn/iu.test(error.message))) throw error;
|
|
179
|
+
turn = await session.continueTurn();
|
|
180
|
+
stored = await ledger.recordTurn({
|
|
181
|
+
base: stored,
|
|
182
|
+
turn: turn.usage,
|
|
183
|
+
resumeState: await session.detach(),
|
|
184
|
+
origin: "recovered"
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (stored.record.result) return stored.record.result;
|
|
188
|
+
}
|
|
189
|
+
if (turn === void 0 && stored.record.turns.length === 0) {
|
|
190
|
+
const session = await configured.runner.open({
|
|
191
|
+
sandbox,
|
|
192
|
+
sessionId: stored.record.harnessSessionId,
|
|
193
|
+
resumeFrom: stored.record.resumeState,
|
|
194
|
+
abortSignal
|
|
195
|
+
});
|
|
196
|
+
turn = await session.continueTurn();
|
|
197
|
+
stored = await ledger.recordTurn({
|
|
198
|
+
base: stored,
|
|
199
|
+
turn: turn.usage,
|
|
200
|
+
resumeState: await session.detach(),
|
|
201
|
+
origin: promptedHere ? "this-driver" : "recovered"
|
|
202
|
+
});
|
|
203
|
+
if (stored.record.result) return stored.record.result;
|
|
204
|
+
}
|
|
205
|
+
const result = await extract(sandbox, stored.record);
|
|
206
|
+
abortSignal.throwIfAborted();
|
|
207
|
+
return ledger.finalize(stored, result);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
} catch (error) {
|
|
211
|
+
const latest = await ledger.read(execution);
|
|
212
|
+
if (latest?.record.result) return latest.record.result;
|
|
213
|
+
if (!(error instanceof ExecutionTimeoutError) || !latest) throw error;
|
|
214
|
+
await stopEnvironment(latest.record);
|
|
215
|
+
return ledger.finalize(latest, {
|
|
216
|
+
status: "failed",
|
|
217
|
+
artifacts: [],
|
|
218
|
+
reason: error.message
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
pending: ledger.pending
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
226
|
+
export { createSandboxExecutionAdapter };
|
|
227
|
+
|
|
228
|
+
//# sourceMappingURL=execution.mjs.map
|