humanish 0.106.1 → 0.107.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/AGENTS.md +4 -4
- package/ARCHITECTURE.md +17 -16
- package/CHANGELOG.md +14 -0
- package/CONTEXT.md +42 -39
- package/CONTRIBUTING.md +8 -8
- package/README.md +8 -3
- package/dist/actors/codex/app-server-client.js +2 -1
- package/dist/actors/codex/app-server-trace.d.ts +0 -1
- package/dist/actors/codex/app-server-trace.js +1 -3
- package/dist/actors/codex/app-server.js +2 -1
- package/dist/actors/codex/protocol-compat.d.ts +27 -0
- package/dist/actors/codex/protocol-compat.js +357 -0
- package/dist/actors/codex/protocol-contract.d.ts +61 -0
- package/dist/actors/codex/protocol-contract.js +471 -0
- package/dist/actors/codex/qualified-versions.d.ts +30 -3
- package/dist/actors/codex/qualified-versions.js +50 -5
- package/dist/actors/codex/restricted-executable.d.ts +24 -0
- package/dist/actors/codex/restricted-executable.js +97 -22
- package/dist/actors/codex/restricted-launch.d.ts +7 -1
- package/dist/actors/codex/restricted-launch.js +42 -3
- package/dist/actors/codex/restricted-notifications.d.ts +101 -0
- package/dist/actors/codex/restricted-notifications.js +277 -0
- package/dist/actors/codex/restricted-participant.d.ts +30 -0
- package/dist/actors/codex/restricted-participant.js +60 -2
- package/dist/actors/codex/restricted-policy.d.ts +9 -1
- package/dist/actors/codex/restricted-session.d.ts +14 -1
- package/dist/actors/codex/restricted-session.js +50 -17
- package/dist/actors/codex/restricted-transport.d.ts +29 -0
- package/dist/actors/codex/restricted-transport.js +139 -27
- package/dist/actors/codex/restricted-turn.d.ts +19 -4
- package/dist/actors/codex/restricted-turn.js +43 -30
- package/dist/actors/computer-use/actor.d.ts +1 -1
- package/dist/actors/computer-use/actor.js +4 -4
- package/dist/actors/computer-use/loop/backstop.js +1 -1
- package/dist/actors/computer-use/loop/ending.d.ts +2 -2
- package/dist/actors/computer-use/loop/ending.js +2 -2
- package/dist/actors/computer-use/loop/spend.d.ts +1 -1
- package/dist/actors/computer-use/loop/spend.js +3 -3
- package/dist/actors/computer-use/loop/trace.js +2 -2
- package/dist/actors/computer-use/loop/types.d.ts +14 -5
- package/dist/actors/computer-use/loop.js +4 -4
- package/dist/actors/computer-use/openai-provider.d.ts +1 -1
- package/dist/actors/computer-use/openai-provider.js +2 -2
- package/dist/actors/contract.d.ts +9 -7
- package/dist/actors/local-agent/cli.js +1 -1
- package/dist/actors/scripted-browser/actor.d.ts +2 -2
- package/dist/actors/scripted-browser/journey.js +15 -4
- package/dist/actors/scripted-browser/steps.js +18 -0
- package/dist/actors/scripted-browser/types.d.ts +11 -1
- package/dist/actors/stop-conditions.js +1 -3
- package/dist/analysis/automatic-completion.d.ts +13 -8
- package/dist/analysis/automatic-completion.js +14 -8
- package/dist/analysis/automatic-config.d.ts +1 -1
- package/dist/analysis/automatic-config.js +2 -2
- package/dist/analysis/automatic.d.ts +10 -4
- package/dist/analysis/automatic.js +17 -13
- package/dist/analysis/diagnostics.d.ts +23 -0
- package/dist/analysis/diagnostics.js +112 -0
- package/dist/analysis/evidence-sources.js +2 -2
- package/dist/analysis/evidence.js +6 -6
- package/dist/analysis/execute.d.ts +7 -1
- package/dist/analysis/execute.js +39 -12
- package/dist/analysis/job.d.ts +8 -5
- package/dist/analysis/job.js +15 -14
- package/dist/analysis/load.d.ts +1 -1
- package/dist/analysis/load.js +5 -5
- package/dist/analysis/provider.d.ts +9 -1
- package/dist/analysis/restricted-codex.d.ts +2 -0
- package/dist/analysis/restricted-codex.js +10 -1
- package/dist/analysis/service.d.ts +2 -0
- package/dist/analysis/service.js +31 -12
- package/dist/analysis/sharing.d.ts +2 -2
- package/dist/analysis/sharing.js +5 -5
- package/dist/analysis/store-executions.d.ts +5 -5
- package/dist/analysis/store-executions.js +12 -12
- package/dist/analysis/store.d.ts +4 -4
- package/dist/analysis/store.js +13 -13
- package/dist/cli/commands/analysis-signals.d.ts +2 -1
- package/dist/cli/commands/analysis-signals.js +4 -1
- package/dist/cli/commands/analyze.js +4 -2
- package/dist/cli/commands/comms.js +8 -1
- package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
- package/dist/cli/commands/lab-route-computer-use.js +26 -14
- package/dist/cli/commands/lab-route-preview.d.ts +1 -3
- package/dist/cli/commands/lab-route-preview.js +3 -4
- package/dist/cli/commands/lab-route-run.d.ts +6 -4
- package/dist/cli/commands/lab-route-run.js +6 -2
- package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
- package/dist/cli/commands/lab-route-scripted.js +0 -1
- package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
- package/dist/cli/commands/lab-route-shared-world.js +0 -1
- package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
- package/dist/cli/commands/lab-route-terminal.js +0 -1
- package/dist/cli/commands/lab-run.js +76 -45
- package/dist/cli/commands/lab-scorer.d.ts +0 -2
- package/dist/cli/commands/lab.js +12 -6
- package/dist/cli/commands/observe.js +22 -0
- package/dist/cli/commands/run-signals.d.ts +30 -0
- package/dist/cli/commands/run-signals.js +146 -0
- package/dist/cli/commands/runs.js +10 -8
- package/dist/cli/commands/watch.js +12 -10
- package/dist/cli/doctor.d.ts +3 -0
- package/dist/cli/doctor.js +10 -2
- package/dist/cli/io.d.ts +5 -4
- package/dist/cli/io.js +12 -8
- package/dist/cli/program.js +3 -3
- package/dist/cli/renamed-options.d.ts +11 -0
- package/dist/cli/renamed-options.js +18 -0
- package/dist/cli/telemetry.d.ts +2 -2
- package/dist/cli/telemetry.js +1 -1
- package/dist/comms/capture-surface.d.ts +1 -1
- package/dist/comms/catch-host.d.ts +1 -1
- package/dist/comms/connections.js +4 -4
- package/dist/comms/external-evidence.d.ts +27 -0
- package/dist/comms/external-evidence.js +93 -0
- package/dist/comms/lease-store.js +7 -7
- package/dist/comms/types.js +1 -1
- package/dist/evidence/browser-hygiene.d.ts +1 -1
- package/dist/evidence/browser-hygiene.js +1 -1
- package/dist/evidence/redaction.js +1 -1
- package/dist/evidence/secret-scrub.d.ts +9 -0
- package/dist/evidence/secret-scrub.js +96 -0
- package/dist/feedback/draft.js +7 -9
- package/dist/feedback/export-bundle.js +4 -4
- package/dist/feedback/export.js +9 -9
- package/dist/feedback/feedback.d.ts +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.js +3 -6
- package/dist/keys/key-resolution.d.ts +3 -1
- package/dist/keys/key-resolution.js +18 -16
- package/dist/lab/adapter-extension.d.ts +28 -6
- package/dist/lab/adapter-extension.js +65 -126
- package/dist/lab/adapter-scorer-loader.d.ts +25 -5
- package/dist/lab/adapter-scorer-loader.js +24 -0
- package/dist/lab/composition-rules.js +20 -20
- package/dist/lab/config.js +28 -26
- package/dist/lab/device-presets.d.ts +2 -2
- package/dist/lab/discover.js +1 -3
- package/dist/lab/doctor.d.ts +44 -9
- package/dist/lab/doctor.js +149 -41
- package/dist/lab/init-plan.js +1 -3
- package/dist/lab/keys.js +1 -1
- package/dist/lab/lab-deps.d.ts +85 -0
- package/dist/lab/lab-deps.js +4 -0
- package/dist/lab/parse/actors.js +8 -7
- package/dist/lab/parse/comms.js +3 -2
- package/dist/lab/parse/execution.js +3 -2
- package/dist/lab/parse/subject-state.js +2 -1
- package/dist/lab/parse/subject.js +2 -1
- package/dist/lab/parse/values.d.ts +0 -1
- package/dist/lab/parse/values.js +0 -3
- package/dist/lab/persona-resolve.d.ts +3 -3
- package/dist/lab/persona-resolve.js +4 -4
- package/dist/lab/persona.js +1 -3
- package/dist/lab/plan-base.d.ts +0 -2
- package/dist/lab/plan-base.js +6 -4
- package/dist/lab/plan-participants.d.ts +5 -5
- package/dist/lab/plan-participants.js +2 -2
- package/dist/lab/plan-types.d.ts +22 -4
- package/dist/lab/plan.d.ts +3 -11
- package/dist/lab/plan.js +18 -42
- package/dist/lab/preflight-result.js +0 -2
- package/dist/lab/preflight.d.ts +0 -3
- package/dist/lab/preflight.js +1 -1
- package/dist/lab/requirements.d.ts +20 -0
- package/dist/lab/requirements.js +54 -0
- package/dist/lab/route-inputs.d.ts +23 -12
- package/dist/lab/route-inputs.js +48 -51
- package/dist/lab/routing.d.ts +19 -24
- package/dist/lab/routing.js +14 -47
- package/dist/lab/run-lab-events.d.ts +6 -11
- package/dist/lab/run-lab-events.js +3 -11
- package/dist/lab/run-lab-homes.d.ts +64 -0
- package/dist/lab/run-lab-homes.js +3 -0
- package/dist/lab/run-lab-options.d.ts +12 -66
- package/dist/lab/run-lab-options.js +45 -275
- package/dist/lab/summary.d.ts +9 -4
- package/dist/lab/summary.js +15 -8
- package/dist/lab/types.d.ts +132 -132
- package/dist/lab/validation.d.ts +15 -15
- package/dist/lab/validation.js +28 -28
- package/dist/lab/warnings.js +20 -19
- package/dist/observer/artifact.d.ts +1 -1
- package/dist/observer/artifact.js +3 -3
- package/dist/observer/data.js +2 -2
- package/dist/observer/render.js +2 -2
- package/dist/observer/run-routes.d.ts +1 -1
- package/dist/observer/run-routes.js +5 -5
- package/dist/observer/serve.d.ts +17 -0
- package/dist/observer/serve.js +34 -3
- package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
- package/dist/routes/computer-use/bundle-parts.js +10 -3
- package/dist/routes/computer-use/bundle.d.ts +4 -11
- package/dist/routes/computer-use/bundle.js +9 -15
- package/dist/routes/computer-use/diagnostics.d.ts +1 -1
- package/dist/routes/computer-use/diagnostics.js +1 -1
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
- package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
- package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
- package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
- package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
- package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
- package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
- package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
- package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
- package/dist/routes/computer-use/external-comms.d.ts +4 -4
- package/dist/routes/computer-use/external-comms.js +19 -43
- package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
- package/dist/routes/computer-use/fanout-bundle.js +25 -29
- package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
- package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
- package/dist/routes/computer-use/in-process-desktop.js +3 -9
- package/dist/routes/computer-use/live-flush.d.ts +7 -5
- package/dist/routes/computer-use/live-flush.js +19 -27
- package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +12 -11
- package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
- package/dist/routes/computer-use/local-tree-pack.js +4 -5
- package/dist/routes/computer-use/local-vm.d.ts +11 -8
- package/dist/routes/computer-use/local-vm.js +39 -66
- package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
- package/dist/routes/computer-use/participant-desktop.js +5 -25
- package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
- package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
- package/dist/routes/computer-use/participant-facts.d.ts +7 -1
- package/dist/routes/computer-use/participant-facts.js +12 -1
- package/dist/routes/computer-use/participant-model.d.ts +19 -11
- package/dist/routes/computer-use/participant-model.js +49 -25
- package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
- package/dist/routes/computer-use/participant-prompt.js +4 -4
- package/dist/routes/computer-use/participant-runs.d.ts +6 -6
- package/dist/routes/computer-use/participant-runs.js +8 -8
- package/dist/routes/computer-use/plan.d.ts +21 -29
- package/dist/routes/computer-use/plan.js +52 -60
- package/dist/routes/computer-use/preflight.d.ts +3 -5
- package/dist/routes/computer-use/preflight.js +20 -16
- package/dist/routes/computer-use/rerun-selection.js +10 -6
- package/dist/routes/computer-use/result.d.ts +1 -1
- package/dist/routes/computer-use/result.js +40 -30
- package/dist/routes/computer-use/route.d.ts +3 -4
- package/dist/routes/computer-use/route.js +21 -19
- package/dist/routes/computer-use/self-report.d.ts +2 -2
- package/dist/routes/computer-use/self-report.js +4 -4
- package/dist/routes/computer-use/setup.d.ts +8 -14
- package/dist/routes/computer-use/setup.js +96 -72
- package/dist/routes/computer-use/single-bundle.d.ts +8 -11
- package/dist/routes/computer-use/single-bundle.js +20 -25
- package/dist/routes/computer-use/subject-projection.d.ts +5 -7
- package/dist/routes/computer-use/subject-projection.js +20 -19
- package/dist/routes/computer-use/types.d.ts +169 -210
- package/dist/routes/computer-use/types.js +13 -5
- package/dist/routes/preview.js +0 -1
- package/dist/routes/scripted/bundle.d.ts +3 -6
- package/dist/routes/scripted/bundle.js +11 -16
- package/dist/routes/scripted/plan.d.ts +5 -7
- package/dist/routes/scripted/plan.js +6 -4
- package/dist/routes/scripted/result.d.ts +4 -1
- package/dist/routes/scripted/result.js +10 -6
- package/dist/routes/scripted/route.js +10 -11
- package/dist/routes/scripted/scenario.d.ts +1 -1
- package/dist/routes/scripted/scenario.js +1 -1
- package/dist/routes/scripted/setup.d.ts +3 -2
- package/dist/routes/scripted/setup.js +22 -21
- package/dist/routes/scripted/subject.d.ts +8 -3
- package/dist/routes/scripted/subject.js +9 -5
- package/dist/routes/scripted/surface-records.js +1 -1
- package/dist/routes/scripted/surface-sessions.d.ts +2 -2
- package/dist/routes/scripted/surface-sessions.js +4 -4
- package/dist/routes/scripted/types.d.ts +19 -36
- package/dist/routes/scripted/types.js +1 -2
- package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
- package/dist/routes/shared-world/bundle.d.ts +2 -2
- package/dist/routes/shared-world/bundle.js +22 -26
- package/dist/routes/shared-world/checkpoints.d.ts +4 -4
- package/dist/routes/shared-world/checkpoints.js +4 -4
- package/dist/routes/shared-world/comms.d.ts +5 -4
- package/dist/routes/shared-world/comms.js +28 -41
- package/dist/routes/shared-world/external-public.d.ts +5 -5
- package/dist/routes/shared-world/external-public.js +19 -20
- package/dist/routes/shared-world/handoff.d.ts +4 -4
- package/dist/routes/shared-world/handoff.js +50 -50
- package/dist/routes/shared-world/lobby-code.d.ts +5 -5
- package/dist/routes/shared-world/lobby-code.js +13 -13
- package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
- package/dist/routes/shared-world/{seats.js → participant-specs.js} +43 -48
- package/dist/routes/shared-world/plan.d.ts +2 -6
- package/dist/routes/shared-world/plan.js +1 -2
- package/dist/routes/shared-world/provenance.d.ts +4 -4
- package/dist/routes/shared-world/provenance.js +4 -4
- package/dist/routes/shared-world/provisioned.d.ts +3 -2
- package/dist/routes/shared-world/provisioned.js +46 -40
- package/dist/routes/shared-world/result.js +31 -19
- package/dist/routes/shared-world/route.js +37 -41
- package/dist/routes/shared-world/setup.d.ts +5 -4
- package/dist/routes/shared-world/setup.js +12 -14
- package/dist/routes/shared-world/types.d.ts +53 -126
- package/dist/routes/shared-world/types.js +2 -2
- package/dist/routes/terminal/adapter.d.ts +8 -8
- package/dist/routes/terminal/adapter.js +28 -125
- package/dist/routes/terminal/bundle.d.ts +7 -12
- package/dist/routes/terminal/bundle.js +24 -34
- package/dist/routes/terminal/credentials.d.ts +2 -2
- package/dist/routes/terminal/credentials.js +16 -16
- package/dist/routes/terminal/dry-run.d.ts +1 -1
- package/dist/routes/terminal/dry-run.js +9 -11
- package/dist/routes/terminal/encoding.d.ts +1 -1
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +6 -6
- package/dist/routes/terminal/ledger.js +9 -9
- package/dist/routes/terminal/live-finish.d.ts +1 -2
- package/dist/routes/terminal/live-finish.js +21 -20
- package/dist/routes/terminal/live-sandbox.d.ts +3 -2
- package/dist/routes/terminal/live-sandbox.js +20 -20
- package/dist/routes/terminal/participant-text.d.ts +23 -0
- package/dist/routes/terminal/participant-text.js +165 -0
- package/dist/routes/terminal/plan.d.ts +2 -6
- package/dist/routes/terminal/plan.js +13 -9
- package/dist/routes/terminal/recorder.d.ts +6 -1
- package/dist/routes/terminal/recorder.js +12 -4
- package/dist/routes/terminal/result.js +4 -4
- package/dist/routes/terminal/route.js +26 -26
- package/dist/routes/terminal/runtime.d.ts +3 -2
- package/dist/routes/terminal/runtime.js +3 -3
- package/dist/routes/terminal/sandbox.d.ts +3 -3
- package/dist/routes/terminal/sandbox.js +9 -9
- package/dist/routes/terminal/session.js +16 -14
- package/dist/routes/terminal/token-usage.js +5 -5
- package/dist/routes/terminal/trace.d.ts +5 -8
- package/dist/routes/terminal/trace.js +9 -64
- package/dist/routes/terminal/types.d.ts +85 -93
- package/dist/routes/terminal/types.js +9 -4
- package/dist/run/active-runs.d.ts +13 -0
- package/dist/run/active-runs.js +12 -0
- package/dist/run/bundle-shape.d.ts +2 -1
- package/dist/run/bundle-shape.js +4 -4
- package/dist/run/bundle.d.ts +63 -56
- package/dist/run/bundle.js +9 -8
- package/dist/run/cost-summary.js +3 -2
- package/dist/run/costs.d.ts +6 -6
- package/dist/run/costs.js +10 -10
- package/dist/run/detail.d.ts +5 -5
- package/dist/run/detail.js +6 -6
- package/dist/run/dry-run.js +5 -12
- package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
- package/dist/run/{study-files.js → evidence-files.js} +5 -5
- package/dist/run/feedback-shape.js +1 -1
- package/dist/run/judge.d.ts +16 -4
- package/dist/run/judge.js +24 -7
- package/dist/run/locate.d.ts +2 -0
- package/dist/run/locate.js +3 -1
- package/dist/run/outcomes.d.ts +3 -3
- package/dist/run/outcomes.js +3 -3
- package/dist/run/participant-records.d.ts +2 -2
- package/dist/run/participant-records.js +2 -2
- package/dist/run/paths.js +1 -1
- package/dist/run/pricing.d.ts +19 -9
- package/dist/run/pricing.js +30 -18
- package/dist/run/projection.d.ts +13 -13
- package/dist/run/projection.js +8 -8
- package/dist/run/reclaim.d.ts +6 -0
- package/dist/run/reclaim.js +13 -3
- package/dist/run/results.d.ts +1 -1
- package/dist/run/run-index.d.ts +1 -1
- package/dist/run/run-index.js +11 -11
- package/dist/run/run.d.ts +4 -2
- package/dist/run/run.js +9 -5
- package/dist/run/sandbox-receipts.d.ts +4 -4
- package/dist/run/sandbox-receipts.js +4 -4
- package/dist/run/shared-world-evidence.d.ts +47 -47
- package/dist/run/shared-world-shape.d.ts +3 -3
- package/dist/run/shared-world-shape.js +11 -11
- package/dist/run/stats.d.ts +5 -5
- package/dist/run/stats.js +8 -8
- package/dist/run/status.d.ts +16 -6
- package/dist/run/status.js +31 -8
- package/dist/run/streams.d.ts +26 -19
- package/dist/run/terminal-contract.d.ts +5 -5
- package/dist/run/terminal-contract.js +4 -4
- package/dist/run/transient-comms-secrets.d.ts +5 -0
- package/dist/run/transient-comms-secrets.js +12 -0
- package/dist/run-lab.d.ts +36 -34
- package/dist/run-lab.js +41 -37
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +1 -1
- package/dist/subject/local-tree-archive.d.ts +1 -1
- package/dist/subject/local-tree-archive.js +4 -4
- package/dist/subject/local-tree.d.ts +2 -2
- package/dist/subject/local-tree.js +1 -1
- package/dist/subject/node-bootstrap.d.ts +1 -1
- package/dist/subject/node-bootstrap.js +4 -4
- package/dist/subject/runtime.js +5 -5
- package/dist/subject/serve.js +1 -1
- package/dist/subject/steps.d.ts +4 -4
- package/dist/subject/steps.js +5 -5
- package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
- package/dist/substrates/e2b/cdp-probe.js +1 -1
- package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
- package/dist/substrates/e2b/desktop-browser.js +4 -4
- package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
- package/dist/substrates/e2b/desktop-cdp.js +4 -4
- package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
- package/dist/substrates/e2b/desktop-geometry.js +3 -3
- package/dist/substrates/e2b/desktop-media.js +2 -2
- package/dist/substrates/e2b/sandbox.js +1 -1
- package/dist/substrates/e2b/sdk.js +2 -2
- package/dist/substrates/local/runtime-host.d.ts +2 -0
- package/dist/substrates/local/runtime-host.js +6 -0
- package/dist/tui/actions.d.ts +7 -5
- package/dist/tui/actions.js +18 -9
- package/dist/tui-app.js +42 -42
- package/dist/verify/actor.d.ts +10 -10
- package/dist/verify/actor.js +15 -15
- package/dist/verify/artifacts.d.ts +1 -1
- package/dist/verify/artifacts.js +3 -3
- package/dist/verify/costs.d.ts +2 -2
- package/dist/verify/costs.js +2 -2
- package/dist/verify/liveness.d.ts +1 -1
- package/dist/verify/liveness.js +4 -1
- package/dist/verify/rerun.d.ts +1 -1
- package/dist/verify/rerun.js +1 -1
- package/dist/verify/shared-world.js +2 -2
- package/dist/verify/verify.js +6 -6
- package/docs/README.md +1 -1
- package/docs/architecture/actor-contract.md +60 -22
- package/docs/architecture/desktop-sessions.md +9 -9
- package/docs/architecture/external-public-shared-world.md +5 -0
- package/docs/architecture/observer.md +4 -4
- package/docs/architecture/restricted-codex-analysis.md +36 -2
- package/docs/architecture/state-driven-executor.md +4 -5
- package/docs/architecture/task-protocol-support.md +3 -5
- package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
- package/docs/contracts/run-bundle.md +10 -8
- package/docs/contracts/schemas.md +109 -53
- package/docs/contracts/study-analysis.md +24 -0
- package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
- package/docs/product/automatic-analysis.md +1 -0
- package/docs/ramp/README.md +2 -1
- package/package.json +4 -4
- package/skills/humanish/SKILL.md +3 -2
- package/skills/humanish/agents/openai.yaml +1 -1
- package/dist/deprecated.d.ts +0 -90
- package/dist/deprecated.js +0 -106
- package/dist/lab/bag-overrides.d.ts +0 -18
- package/dist/lab/bag-overrides.js +0 -121
- package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
- package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
- /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
- /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
- /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { normalizeLocalActorTranscript } from "../../run/terminal-contract.js";
|
|
2
|
+
import { MESSAGE_CHARS, PENDING_LINE_CHARS, TEXT_ITEMS_BYTES, TEXT_ITEMS_MAX } from "./types.js";
|
|
3
|
+
const itemEvents = new Set(["item.started", "item.updated", "item.completed"]);
|
|
4
|
+
const nonempty = (value) => typeof value === "string" && value.trim().length > 0;
|
|
5
|
+
const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
/** Each Codex item event in a run of complete JSON lines, in stream order. */
|
|
7
|
+
function* codexStreamItems(lines) {
|
|
8
|
+
for (const line of lines.split("\n")) {
|
|
9
|
+
let event;
|
|
10
|
+
try {
|
|
11
|
+
event = JSON.parse(line);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (!object(event) ||
|
|
17
|
+
typeof event.type !== "string" ||
|
|
18
|
+
!itemEvents.has(event.type) ||
|
|
19
|
+
!object(event.item) ||
|
|
20
|
+
!nonempty(event.item.id))
|
|
21
|
+
continue;
|
|
22
|
+
yield { event: event.type, id: event.item.id, item: event.item };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function isParticipantItem(item) {
|
|
26
|
+
return (((item.type === "agent_message" || item.type === "reasoning") && nonempty(item.text)) ||
|
|
27
|
+
(item.type === "command_execution" && nonempty(item.command)) ||
|
|
28
|
+
(item.type === "web_search" &&
|
|
29
|
+
(nonempty(item.query) || (object(item.action) && nonempty(item.action.type)))) ||
|
|
30
|
+
(item.type === "file_change" &&
|
|
31
|
+
Array.isArray(item.changes) &&
|
|
32
|
+
item.changes.some((change) => object(change) && nonempty(change.path) && nonempty(change.kind))));
|
|
33
|
+
}
|
|
34
|
+
// The verdict parser removes all whitespace before matching, so a line is a marker line when its
|
|
35
|
+
// whitespace-free form names either marker. The parser reads the stored stream, not these items.
|
|
36
|
+
const MARKER = /HUMANISH_ACTOR_(?:VERDICT|NONCE)=/i;
|
|
37
|
+
const withoutMarkerLines = (text) => text
|
|
38
|
+
.split("\n")
|
|
39
|
+
.filter((line) => !MARKER.test(line.replace(/\s+/g, "")))
|
|
40
|
+
.join("\n");
|
|
41
|
+
/**
|
|
42
|
+
* Read participant text from the raw stdout as the recorder receives it. Source redaction runs on
|
|
43
|
+
* the stored stream and can cut through JSON framing (a redacted URL takes the closing quote with
|
|
44
|
+
* it), so each line is parsed here, in memory, and only decoded text that has passed `sanitize`
|
|
45
|
+
* is kept. The raw bytes are never stored.
|
|
46
|
+
*/
|
|
47
|
+
export function createTerminalParticipantReader(sanitize) {
|
|
48
|
+
let pending = "";
|
|
49
|
+
// Set while the rest of an over-long line is skipped, up to its newline.
|
|
50
|
+
let skipping = false;
|
|
51
|
+
let droppedLines = 0;
|
|
52
|
+
const participantIds = new Set();
|
|
53
|
+
const messageIds = new Set();
|
|
54
|
+
const done = new Set();
|
|
55
|
+
// Completed or left-out items; later events for them are ignored.
|
|
56
|
+
const closed = new Set();
|
|
57
|
+
const texts = new Map();
|
|
58
|
+
const numbers = { message: 0, reasoning: 0 };
|
|
59
|
+
let left = 0;
|
|
60
|
+
let result;
|
|
61
|
+
const take = (lines) => {
|
|
62
|
+
for (const { event, id, item } of codexStreamItems(normalizeLocalActorTranscript(lines))) {
|
|
63
|
+
if (isParticipantItem(item))
|
|
64
|
+
participantIds.add(id);
|
|
65
|
+
const kind = item.type === "agent_message" ? "message" : item.type === "reasoning" ? "reasoning" : null;
|
|
66
|
+
if (kind === null || !nonempty(item.text) || closed.has(id))
|
|
67
|
+
continue;
|
|
68
|
+
if (kind === "message")
|
|
69
|
+
messageIds.add(id);
|
|
70
|
+
if (event === "item.completed") {
|
|
71
|
+
done.add(id);
|
|
72
|
+
closed.add(id);
|
|
73
|
+
}
|
|
74
|
+
// Redact the decoded text before cutting it, so a cut cannot split a value past the patterns.
|
|
75
|
+
const clean = [...sanitize(withoutMarkerLines(item.text))];
|
|
76
|
+
const text = (clean.length > MESSAGE_CHARS ? clean.slice(0, MESSAGE_CHARS) : clean).join("");
|
|
77
|
+
const previous = texts.get(id);
|
|
78
|
+
if (!text.trim()) {
|
|
79
|
+
texts.delete(id);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
texts.set(id, { kind, number: previous?.number ?? ++numbers[kind], text });
|
|
83
|
+
// The oldest item beyond the count limit is left out as the stream arrives, finished or not,
|
|
84
|
+
// so a long stream cannot hold every message in memory.
|
|
85
|
+
if (texts.size > TEXT_ITEMS_MAX) {
|
|
86
|
+
const oldest = texts.keys().next().value;
|
|
87
|
+
texts.delete(oldest);
|
|
88
|
+
closed.add(oldest);
|
|
89
|
+
left += 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
append(raw) {
|
|
95
|
+
if (result)
|
|
96
|
+
return;
|
|
97
|
+
if (skipping) {
|
|
98
|
+
const end = raw.indexOf("\n");
|
|
99
|
+
if (end < 0)
|
|
100
|
+
return;
|
|
101
|
+
skipping = false;
|
|
102
|
+
raw = raw.slice(end + 1);
|
|
103
|
+
}
|
|
104
|
+
pending += raw;
|
|
105
|
+
const end = pending.lastIndexOf("\n");
|
|
106
|
+
if (end >= 0) {
|
|
107
|
+
take(pending.slice(0, end));
|
|
108
|
+
pending = pending.slice(end + 1);
|
|
109
|
+
}
|
|
110
|
+
// A line with no newline in sight is dropped, so one runaway line cannot grow without bound.
|
|
111
|
+
if (pending.length > PENDING_LINE_CHARS) {
|
|
112
|
+
pending = "";
|
|
113
|
+
skipping = true;
|
|
114
|
+
droppedLines += 1;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
finish() {
|
|
118
|
+
if (result)
|
|
119
|
+
return result;
|
|
120
|
+
if (!skipping)
|
|
121
|
+
take(pending);
|
|
122
|
+
pending = "";
|
|
123
|
+
const entries = [...texts.entries()];
|
|
124
|
+
let start = entries.length;
|
|
125
|
+
let bytes = 0;
|
|
126
|
+
while (start > 0 && entries.length - start < TEXT_ITEMS_MAX) {
|
|
127
|
+
const size = Buffer.byteLength(entries[start - 1][1].text);
|
|
128
|
+
if (bytes + size > TEXT_ITEMS_BYTES)
|
|
129
|
+
break;
|
|
130
|
+
bytes += size;
|
|
131
|
+
start -= 1;
|
|
132
|
+
}
|
|
133
|
+
left += start;
|
|
134
|
+
const kept = entries.slice(start);
|
|
135
|
+
const items = kept.map(([source, { kind, number, text }]) => ({
|
|
136
|
+
id: `${kind}-${String(number).padStart(3, "0")}`,
|
|
137
|
+
kind,
|
|
138
|
+
lifecycle: done.has(source) ? "completed" : "started",
|
|
139
|
+
title: kind === "message" ? "agent message" : "agent reasoning",
|
|
140
|
+
text,
|
|
141
|
+
}));
|
|
142
|
+
const notices = [];
|
|
143
|
+
if (left > 0)
|
|
144
|
+
notices.push([
|
|
145
|
+
"agent text truncated",
|
|
146
|
+
`Kept the last ${kept.length} of ${kept.length + left} agent message and reasoning items, within ${TEXT_ITEMS_MAX} items and ${TEXT_ITEMS_BYTES / 1024} KiB. The terminal transcript keeps the captured stream.`,
|
|
147
|
+
]);
|
|
148
|
+
if (droppedLines > 0)
|
|
149
|
+
notices.push([
|
|
150
|
+
"agent output lines skipped",
|
|
151
|
+
`Skipped ${droppedLines} stdout line(s) that ran past ${PENDING_LINE_CHARS} characters without a newline. Items on those lines are not in this trace or its counts.`,
|
|
152
|
+
]);
|
|
153
|
+
notices.forEach(([title, text], index) => items.push({
|
|
154
|
+
id: `notice-${String(index + 1).padStart(3, "0")}`,
|
|
155
|
+
kind: "notice",
|
|
156
|
+
lifecycle: "completed",
|
|
157
|
+
status: "truncated",
|
|
158
|
+
title,
|
|
159
|
+
text,
|
|
160
|
+
}));
|
|
161
|
+
result = { items, messages: messageIds.size, participantItems: participantIds.size };
|
|
162
|
+
return result;
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { RoutePlanResult, RouteRefusal, TerminalPlan } from "../../lab/plan-types.js";
|
|
2
2
|
import type { LabConfig } from "../../lab/types.js";
|
|
3
|
-
import type { RunLabProvenance } from "../../run/status.js";
|
|
4
3
|
import { type TerminalProductLabResult } from "./types.js";
|
|
5
4
|
/** The error a terminal lab returns before a run starts. `actor` names the registered actor. */
|
|
6
5
|
export interface TerminalRefusal extends RouteRefusal<"terminal", NonNullable<TerminalProductLabResult["error"]>["code"]> {
|
|
@@ -13,9 +12,6 @@ export type TerminalPlanResult = RoutePlanResult<TerminalPlan, TerminalRefusal>;
|
|
|
13
12
|
*/
|
|
14
13
|
export declare function planTerminalLab(config: LabConfig, input: {
|
|
15
14
|
readonly dryRun: boolean;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
readonly hooks?: {
|
|
19
|
-
readonly costProbe?: unknown;
|
|
20
|
-
};
|
|
15
|
+
/** A test's costProbe can measure spend lines, so a positive maxUsd can trip. */
|
|
16
|
+
readonly hasCostProbe?: boolean;
|
|
21
17
|
}): TerminalPlanResult;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// The terminal route's plan: every configuration refusal the route makes before a run starts, in
|
|
2
2
|
// its order and with its codes, then the plan the run uses. The route checks nothing here again;
|
|
3
3
|
// what stays in the route reads external state (keys, the runtime env, the sandbox).
|
|
4
|
+
import { DEFAULT_OPENAI_CU_MODEL } from "../../actors/computer-use/openai-provider.js";
|
|
4
5
|
import { resolveAutomaticAnalysis } from "../../analysis/automatic-config.js";
|
|
5
6
|
import { isReasoningEffort } from "../../actors/reasoning-effort.js";
|
|
6
7
|
import { actorRegistry, isTerminalActorDescriptor } from "../../actors/registry.js";
|
|
@@ -48,7 +49,6 @@ export function planTerminalLab(config, input) {
|
|
|
48
49
|
return refuse("HUMANISH_TERMINAL_LAB_SUBJECT_INVALID", "terminal-product subjects require `subject.product` with a name and at least one public surface URL.", descriptor.id);
|
|
49
50
|
const base = planBase(config, {
|
|
50
51
|
dryRun: input.dryRun,
|
|
51
|
-
...(input.lab === undefined ? {} : { lab: input.lab }),
|
|
52
52
|
analysis,
|
|
53
53
|
});
|
|
54
54
|
const egressAllow = config.execution?.egressAllow;
|
|
@@ -62,7 +62,11 @@ export function planTerminalLab(config, input) {
|
|
|
62
62
|
...(actor?.mission === undefined ? {} : { mission: actor.mission }),
|
|
63
63
|
runtime: {
|
|
64
64
|
...(runtimeVersion === undefined ? {} : { version: runtimeVersion }),
|
|
65
|
-
|
|
65
|
+
// Codex's own default can change with any release and its JSON stream does not name it, so
|
|
66
|
+
// the route always passes a model: the declared one, else humanish's participant default.
|
|
67
|
+
...(actor?.model === undefined
|
|
68
|
+
? { model: DEFAULT_OPENAI_CU_MODEL, modelSource: "humanish_default" }
|
|
69
|
+
: { model: actor.model, modelSource: "declared" }),
|
|
66
70
|
...(actor?.reasoningEffort === undefined ? {} : { reasoningEffort: actor.reasoningEffort }),
|
|
67
71
|
...(config.execution?.runtimeAuth === undefined
|
|
68
72
|
? {}
|
|
@@ -74,7 +78,7 @@ export function planTerminalLab(config, input) {
|
|
|
74
78
|
const caps = config.scenario?.caps;
|
|
75
79
|
if (input.dryRun)
|
|
76
80
|
return { ok: true, plan: { ...shared, dryRun: true, ...(caps ? { caps } : {}) } };
|
|
77
|
-
// The live
|
|
81
|
+
// The live route injects the runtime key into one command only, and only a registered actor
|
|
78
82
|
// that declares that placement may run live.
|
|
79
83
|
const keyPlacement = descriptor.capabilities.keyPlacement;
|
|
80
84
|
if (keyPlacement !== "in-sandbox-command-scoped")
|
|
@@ -85,12 +89,12 @@ export function planTerminalLab(config, input) {
|
|
|
85
89
|
if (caps === undefined || maxUsd === undefined || maxMinutes === undefined || maxMinutes <= 0)
|
|
86
90
|
return refuse("HUMANISH_TERMINAL_LAB_CAPS_MISSING", "A live terminal-product run grants provider access to the in-sandbox agent and so REQUIRES a fail-closed cap: scenario.caps with maxUsd (0 = no-spend) and a positive maxMinutes (the codex command's wall-clock kill). The live key is never exercised without a cap in force.", descriptor.id);
|
|
87
91
|
// maxUsd is checked against the cost ledger after the session, and only known lines can trip it.
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
if (maxUsd > 0 && input.
|
|
93
|
-
return refuse("HUMANISH_TERMINAL_LAB_UNPRICED_CAP", `scenario.caps.maxUsd=${maxUsd} cannot be enforced:
|
|
92
|
+
// The ledger's provider line takes only provider-reported cost, which Codex does not report (the
|
|
93
|
+
// token estimate in run.json is not a measurement), and core has no product, media or payment
|
|
94
|
+
// signal, so without a costProbe every line is null and a positive maxUsd could never trip. That
|
|
95
|
+
// cap would promise a bound nothing enforces, so it is refused; maxMinutes bounds a live run.
|
|
96
|
+
if (maxUsd > 0 && input.hasCostProbe !== true)
|
|
97
|
+
return refuse("HUMANISH_TERMINAL_LAB_UNPRICED_CAP", `scenario.caps.maxUsd=${maxUsd} cannot be enforced: Codex reports no provider cost for the participant (its token cost is only estimated after the run) and no product, media or payment spend is measured, so a positive dollar cap can never trip. Set scenario.caps.maxUsd to 0 and bound the run with scenario.caps.maxMinutes, the codex command's wall-clock kill. No sandbox was created and the runtime key was not used.`, descriptor.id);
|
|
94
98
|
// The sandbox's timeout covers the steps before the codex command, maxMinutes and the teardown
|
|
95
99
|
// buffer, and E2B refuses a sandbox over an hour. Refuse here, with the arithmetic, rather than
|
|
96
100
|
// after the plan prints, from a provider 400 that names neither knob.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type CommandLogRecord, type InterventionRecord, type LifecycleRecord, type TerminalEventRecord } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* The terminal run's ledgers and capture buffers, mutated through the live lifecycle. Every chunk
|
|
4
|
-
* is scrubbed and redacted as it is stored
|
|
4
|
+
* is scrubbed and redacted as it is stored. Raw bytes leave the append functions only for the
|
|
5
|
+
* in-memory participant reader, which keeps sanitized decoded text.
|
|
5
6
|
*/
|
|
6
7
|
export declare function createTerminalRecorder(args: {
|
|
7
8
|
nowIso: () => string;
|
|
@@ -17,6 +18,10 @@ export declare function createTerminalRecorder(args: {
|
|
|
17
18
|
stderr: string;
|
|
18
19
|
combined: string;
|
|
19
20
|
};
|
|
21
|
+
participantText: {
|
|
22
|
+
append(raw: string): void;
|
|
23
|
+
finish(): import("./participant-text.js").TerminalParticipantText;
|
|
24
|
+
};
|
|
20
25
|
recordLifecycle: (event: string, message: string) => void;
|
|
21
26
|
recordStreamedTerminalChunk: (stream: "stdout" | "stderr", raw: string) => void;
|
|
22
27
|
appendReturnedTerminalOutput: (stream: "stdout" | "stderr", raw: string) => void;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { createTerminalParticipantReader } from "./participant-text.js";
|
|
2
3
|
import { MAX_TRANSCRIPT_BYTES, } from "./types.js";
|
|
3
4
|
/**
|
|
4
5
|
* The terminal run's ledgers and capture buffers, mutated through the live lifecycle. Every chunk
|
|
5
|
-
* is scrubbed and redacted as it is stored
|
|
6
|
+
* is scrubbed and redacted as it is stored. Raw bytes leave the append functions only for the
|
|
7
|
+
* in-memory participant reader, which keeps sanitized decoded text.
|
|
6
8
|
*/
|
|
7
9
|
export function createTerminalRecorder(args) {
|
|
8
10
|
const { nowIso, sanitize, knownSecretValues } = args;
|
|
@@ -13,7 +15,9 @@ export function createTerminalRecorder(args) {
|
|
|
13
15
|
// cross-chunk redaction below; this overlap is never added to terminal events/artifacts.
|
|
14
16
|
const discardedPrefixes = { stdout: "", stderr: "", combined: "" };
|
|
15
17
|
const maxDiscardedPrefixChars = Math.max(0, ...knownSecretValues.map((value) => value.length - 1));
|
|
16
|
-
const interventions = []; //
|
|
18
|
+
const interventions = []; // Always empty while no assisted-input path ships.
|
|
19
|
+
// Reads the agent's text from the raw stdout in memory; it keeps only sanitized decoded text.
|
|
20
|
+
const participantText = createTerminalParticipantReader(sanitize);
|
|
17
21
|
let transcriptBytes = 0;
|
|
18
22
|
const recordLifecycle = (event, message) => {
|
|
19
23
|
lifecycle.push({ at: nowIso(), event, message: sanitize(message) });
|
|
@@ -28,10 +32,13 @@ export function createTerminalRecorder(args) {
|
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
30
34
|
transcriptBytes += Buffer.byteLength(raw, "utf8");
|
|
31
|
-
// Scrub
|
|
35
|
+
// Scrub, then redact, at the source (safety contract item 5). Only the participant reader below
|
|
36
|
+
// sees the raw bytes, and it stores none of them.
|
|
32
37
|
terminalEvents.push({ at: nowIso(), stream, chunk: sanitize(raw) });
|
|
38
|
+
if (stream === "stdout")
|
|
39
|
+
participantText.append(raw);
|
|
33
40
|
};
|
|
34
|
-
// E2B can stream every byte through callbacks
|
|
41
|
+
// E2B can stream every byte through callbacks and return the same complete output (#667).
|
|
35
42
|
// Track transport delivery, independently per stream, rather than deduplicating participant
|
|
36
43
|
// lines or equal usage records. Hash raw callback bytes before redaction/truncation so the
|
|
37
44
|
// comparison cannot confuse two values that redact identically or lose capped-away delivery.
|
|
@@ -70,6 +77,7 @@ export function createTerminalRecorder(args) {
|
|
|
70
77
|
terminalEvents,
|
|
71
78
|
interventions,
|
|
72
79
|
discardedPrefixes,
|
|
80
|
+
participantText,
|
|
73
81
|
recordLifecycle,
|
|
74
82
|
recordStreamedTerminalChunk,
|
|
75
83
|
appendReturnedTerminalOutput,
|
|
@@ -46,14 +46,14 @@ export function terminalExecutionFailures(args) {
|
|
|
46
46
|
/** The terminal-product lab result for a live run, from its session, cleanup and cost ledger. */
|
|
47
47
|
export function terminalLabResult(args) {
|
|
48
48
|
const { cwd, labId, actorId, productName, runId, sessionStatus, completionReason, sessionReason, sessionError, sandboxId, cleanup, cost, noSpendProof, capFailure, declaredScorerFailure, judgment, execution, observer, warnings, } = args;
|
|
49
|
-
// The lab's exit code: verified evidence
|
|
50
|
-
// timed-out agent run is
|
|
51
|
-
// but the
|
|
49
|
+
// The lab's exit code: verified evidence, no harness error and proven cleanup. A blocked/
|
|
50
|
+
// timed-out agent run is still ok-as-evidence at the bundle level (the failure is the evidence),
|
|
51
|
+
// but the lab result surfaces ok:false on a harness error or unproven teardown (fail-closed).
|
|
52
52
|
// remaining===0 is the by-id-confirmed-reclaimed state; remaining===1 (still present) and
|
|
53
53
|
// remaining===-1 (kill(id) itself failed) are both unproven by design.
|
|
54
54
|
const cleanupProven = cleanup.killed && cleanup.remaining === 0;
|
|
55
55
|
// A CONFIG-DECLARED scorer that failed to render a pass (status:"fail" / malformed / throw) fails the
|
|
56
|
-
// run
|
|
56
|
+
// run result as well as the persisted verdict: the keystone route's declared rubric is a gate, so
|
|
57
57
|
// its fail must drive exit code. Library callers never set this (additive, back-compat).
|
|
58
58
|
const ok = resultOk({
|
|
59
59
|
judgment,
|
|
@@ -8,39 +8,39 @@
|
|
|
8
8
|
// live-sandbox.ts and live-finish.ts); a dry plan publishes its contract bundle (dry-run.ts);
|
|
9
9
|
// 4. automatic analysis of a run that published its final bundle.
|
|
10
10
|
//
|
|
11
|
-
//
|
|
12
|
-
// the files each item names, and
|
|
11
|
+
// The safety contract (`docs/goals/terminal-product-lane/goal.md`) is enforced by construction in
|
|
12
|
+
// the files each item names, and checked by the verifier (verify/actor.ts
|
|
13
13
|
// validateTerminalProductEvidence):
|
|
14
|
-
// 1.
|
|
15
|
-
//
|
|
14
|
+
// 1. Explicit key placement. openai-env (default) injects the raw runtime key command-scoped,
|
|
15
|
+
// never through Sandbox.create({envs}). Opt-in openai-egress sends it only in the host-side E2B
|
|
16
16
|
// header transform and passes an inert command placeholder. The proxy is spendable by every
|
|
17
17
|
// sandbox process from creation; this protects the raw key, not provider spending.
|
|
18
18
|
// Enforced in credentials.ts and runtime-auth.ts.
|
|
19
|
-
// 2.
|
|
19
|
+
// 2. Fail-closed cap. The live key is never exercised without scenario.caps in force: maxUsd
|
|
20
20
|
// (default/require 0 = no-spend) + maxMinutes (wall-clock kill of the codex command).
|
|
21
21
|
// Enforced in plan.ts (caps required), live-sandbox.ts and lifetime.ts (the wall clock).
|
|
22
|
-
// 3.
|
|
23
|
-
// author mission. No clone, no private-source access — nothing is git-cloned
|
|
22
|
+
// 3. Public surfaces only. The mission references only subject.product.publicSurfaces + the
|
|
23
|
+
// author mission. No clone, no private-source access — nothing is git-cloned on this route.
|
|
24
24
|
// Enforced in session.ts, which composes the prompt.
|
|
25
|
-
// 4.
|
|
25
|
+
// 4. Deny-by-default credentials. The command envs are built from an allowlist holding only the
|
|
26
26
|
// declared runtime key; GITHUB_TOKEN/GH_TOKEN/payment/deploy/db/media keys are excluded by
|
|
27
27
|
// construction (a banned-name guard also fails closed if one is ever requested).
|
|
28
28
|
// Enforced in credentials.ts.
|
|
29
|
-
// 5.
|
|
29
|
+
// 5. No secret values in evidence. Every captured byte (event stream, transcript, command logs,
|
|
30
30
|
// agent report, metadata) passes scrubKnownValues (literal scrub of the runtime key + any
|
|
31
|
-
// provisioned values, >=4 chars,
|
|
32
|
-
// persisting. The transport is labeled
|
|
31
|
+
// provisioned values, >=4 chars, before truncation), then redactText (shape patterns), before
|
|
32
|
+
// persisting. The transport is labeled exec-stream/snapshot; there is no interactive pty.
|
|
33
33
|
// Enforced in recorder.ts, with the scrubber session.ts builds.
|
|
34
|
-
// 6.
|
|
34
|
+
// 6. Metadata positive allowlist. buildSandboxMetadata(allowlist) is the only way metadata is
|
|
35
35
|
// set; it carries solely non-secret labels (mode/tool/labId/simId/provider/runId).
|
|
36
36
|
// Enforced in credentials.ts.
|
|
37
|
-
// 7.
|
|
38
|
-
// bundle
|
|
37
|
+
// 7. Stdin disabled + interventions ledger. stdin is never wired to the codex command; the
|
|
38
|
+
// bundle always carries an interventions ledger (empty array is valid + required-present).
|
|
39
39
|
// Enforced in live-sandbox.ts (stdin) and recorder.ts (the ledger).
|
|
40
|
-
// 8.
|
|
41
|
-
// proof is
|
|
40
|
+
// 8. Proven cleanup, by id, never account-wide. Sandbox.kill(id) in a finally; the cleanup
|
|
41
|
+
// proof is by exact id: kill(id)'s own found-and-killed boolean, confirmed further by
|
|
42
42
|
// Sandbox.getInfo(id) when the SDK exposes it (a thrown SandboxNotFoundError means gone).
|
|
43
|
-
// humanish
|
|
43
|
+
// humanish never calls Sandbox.list to prove cleanup, so a shared operator key never reaches a
|
|
44
44
|
// sandbox it did not create. A live run that cannot prove teardown fails closed.
|
|
45
45
|
// Enforced in sandbox.ts.
|
|
46
46
|
import { resolveAutomaticAnalysis } from "../../analysis/automatic-config.js";
|
|
@@ -50,18 +50,18 @@ import { runScope } from "../../run/run.js";
|
|
|
50
50
|
import { planTerminalLab } from "./plan.js";
|
|
51
51
|
import { runDryTerminalLab } from "./dry-run.js";
|
|
52
52
|
import { checkLiveTerminalMachine, runLiveTerminalSession } from "./session.js";
|
|
53
|
-
import {
|
|
53
|
+
import { terminalRouteScorer } from "../../lab/adapter-scorer-loader.js";
|
|
54
|
+
import { withLateScorer } from "../../lab/route-inputs.js";
|
|
54
55
|
import { TERMINAL_PRODUCT_LAB_SCHEMA, } from "./types.js";
|
|
55
56
|
/**
|
|
56
57
|
* The config-taking entry point. It plans, returns a refusal with the same envelope and analysis
|
|
57
58
|
* record the route has always returned, and otherwise runs the plan.
|
|
58
59
|
*/
|
|
59
60
|
export async function runTerminalProductLab(options) {
|
|
60
|
-
const { config, dryRun,
|
|
61
|
+
const { config, dryRun, ...input } = options;
|
|
61
62
|
const planned = planTerminalLab(config, {
|
|
62
63
|
dryRun,
|
|
63
|
-
|
|
64
|
-
...(input.hooks === undefined ? {} : { hooks: input.hooks }),
|
|
64
|
+
hasCostProbe: input.deps?.costProbe !== undefined,
|
|
65
65
|
});
|
|
66
66
|
if (planned.ok)
|
|
67
67
|
return runTerminalPlan(planned.plan, input);
|
|
@@ -84,7 +84,7 @@ export function terminalLabRefusal(options, refusal) {
|
|
|
84
84
|
};
|
|
85
85
|
// A refusal starts no run, so a declared or default analysis is recorded as skipped.
|
|
86
86
|
const analysis = resolveAutomaticAnalysis(config.review?.analysis);
|
|
87
|
-
return completeAutomaticAnalysis(refused, undefined, analysis.ok ? analysis.config : undefined, options
|
|
87
|
+
return completeAutomaticAnalysis(refused, undefined, analysis.ok ? analysis.config : undefined, options, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
90
|
* Run a terminal plan. The run scope gives a direct library caller the same run lifetime the CLI
|
|
@@ -106,11 +106,11 @@ export async function admitTerminalPlan(plan, input) {
|
|
|
106
106
|
return { ok: false, outcome: terminalOutcome(admission.result) };
|
|
107
107
|
return {
|
|
108
108
|
ok: true,
|
|
109
|
-
run: async (scorer) => terminalOutcome(await runAdmittedTerminalRun(admission.admitted,
|
|
109
|
+
run: async (scorer) => terminalOutcome(await runAdmittedTerminalRun(admission.admitted, withLateScorer(input, scorer, terminalRouteScorer))),
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
112
|
function terminalOutcome(result) {
|
|
113
|
-
return { route: "terminal",
|
|
113
|
+
return { route: "terminal", result };
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* A live plan's local checks, made outside any run scope. A refusal is the result runTerminalPlan
|
|
@@ -132,7 +132,7 @@ async function runAdmittedTerminalRun(admitted, input) {
|
|
|
132
132
|
return completeTerminalAnalysis(admitted.plan, input, result, finished);
|
|
133
133
|
}
|
|
134
134
|
function completeTerminalAnalysis(plan, input, result, finished) {
|
|
135
|
-
return completeAutomaticAnalysis(result, finished, plan.analysis?.config, input
|
|
135
|
+
return completeAutomaticAnalysis(result, finished, plan.analysis?.config, input, {
|
|
136
136
|
...(plan.analysis === undefined ? {} : { trigger: plan.analysis.trigger }),
|
|
137
137
|
preferLargerOutput: plan.analysis?.preferLargerOutput === true,
|
|
138
138
|
});
|
|
@@ -157,7 +157,7 @@ async function runTerminalPlanInScope(admitted, input, scope) {
|
|
|
157
157
|
const cwd = path.resolve(input.cwd);
|
|
158
158
|
const { warnings } = admitted;
|
|
159
159
|
const failed = terminalFailure(admitted.plan, input, warnings);
|
|
160
|
-
//
|
|
160
|
+
// Live path: the real in-sandbox agent session. A separate orchestrator owns the
|
|
161
161
|
// create -> inject (command-scoped) -> run -> capture -> teardown lifecycle so the dry-run path
|
|
162
162
|
// below stays a pure contract builder. It enforces the safety contract by construction (the
|
|
163
163
|
// keyPlacement-routed command-scoped key, the deny-by-default allowlist, the fail-closed cap,
|
|
@@ -6,9 +6,10 @@ export declare function isExactRuntimeVersion(value: unknown): value is string;
|
|
|
6
6
|
/** Captured Codex CLI output: `codex-cli 0.153.3\n`. Other shapes fail closed. */
|
|
7
7
|
export declare function parseTerminalRuntimeVersion(stdout: string): string | undefined;
|
|
8
8
|
export declare function buildRuntimeVersionCommand(requestedVersion?: string): string;
|
|
9
|
-
export declare function buildRuntimeExecPrefix(version: string, model
|
|
9
|
+
export declare function buildRuntimeExecPrefix(version: string, model: string, reasoningEffort?: ReasoningEffort): string;
|
|
10
10
|
export declare function declaredRuntimeProvenance(args: {
|
|
11
11
|
version?: string;
|
|
12
|
-
model
|
|
12
|
+
model: string;
|
|
13
|
+
modelSource: "declared" | "humanish_default";
|
|
13
14
|
reasoningEffort?: ReasoningEffort;
|
|
14
15
|
}): ActorRuntimeProvenance;
|
|
@@ -26,7 +26,7 @@ export function buildRuntimeExecPrefix(version, model, reasoningEffort) {
|
|
|
26
26
|
if (!isExactRuntimeVersion(version))
|
|
27
27
|
throw new Error("Codex execution requires a verified exact runtime version.");
|
|
28
28
|
return (`npm_config_update_notifier=false npx -y ${TERMINAL_RUNTIME_PACKAGE}@${version} exec` +
|
|
29
|
-
|
|
29
|
+
` --model ${shellQuote(model)}` +
|
|
30
30
|
(reasoningEffort === undefined
|
|
31
31
|
? ""
|
|
32
32
|
: ` -c ${shellQuote(`model_reasoning_effort=${JSON.stringify(reasoningEffort)}`)}`));
|
|
@@ -37,8 +37,8 @@ export function declaredRuntimeProvenance(args) {
|
|
|
37
37
|
package: TERMINAL_RUNTIME_PACKAGE,
|
|
38
38
|
requestedVersion: args.version ?? "latest",
|
|
39
39
|
versionStatus: "unobserved",
|
|
40
|
-
|
|
41
|
-
modelStatus: args.
|
|
40
|
+
requestedModel: args.model,
|
|
41
|
+
modelStatus: args.modelSource,
|
|
42
42
|
...(args.reasoningEffort === undefined
|
|
43
43
|
? {}
|
|
44
44
|
: { requestedReasoningEffort: args.reasoningEffort }),
|
|
@@ -2,13 +2,13 @@ import type { OwnedDesktopAllocation } from "../../substrates/desktop-session.js
|
|
|
2
2
|
import { E2BDesktopStartupError, type E2BDesktopModule } from "../../substrates/e2b/sdk.js";
|
|
3
3
|
import type { TerminalLedgers } from "./types.js";
|
|
4
4
|
/**
|
|
5
|
-
* Tear the sandbox down and
|
|
5
|
+
* Tear the sandbox down and prove it by exact id, never by Sandbox.list (humanish must never
|
|
6
6
|
* enumerate the operator's E2B account; see docs/principles/invariants-and-defaults.md). The
|
|
7
7
|
* allocation's release (src/substrates/e2b/sandbox.ts) kills the exact id and reads the answer the
|
|
8
8
|
* same way every route does: true is terminated, false or a not-found error is already gone. That
|
|
9
|
-
* is the
|
|
9
|
+
* is the primary proof. Where the SDK exposes Sandbox.getInfo(id), a thrown SandboxNotFoundError is
|
|
10
10
|
* a second by-id confirmation that the exact sandbox is gone; a returned SandboxInfo with a live
|
|
11
|
-
* state means teardown is
|
|
11
|
+
* state means teardown is unconfirmed. Never throws: teardown failure is recorded, and the caller
|
|
12
12
|
* fails closed on an unproven teardown.
|
|
13
13
|
*/
|
|
14
14
|
export declare function teardownSandbox(args: {
|
|
@@ -2,20 +2,20 @@ import { toErrorMessage } from "../../evidence/redaction.js";
|
|
|
2
2
|
import { E2BDesktopStartupError, isSandboxNotFoundError, } from "../../substrates/e2b/sdk.js";
|
|
3
3
|
import { releaseUnavailableDetail } from "../../substrates/e2b/sandbox.js";
|
|
4
4
|
/**
|
|
5
|
-
* Tear the sandbox down and
|
|
5
|
+
* Tear the sandbox down and prove it by exact id, never by Sandbox.list (humanish must never
|
|
6
6
|
* enumerate the operator's E2B account; see docs/principles/invariants-and-defaults.md). The
|
|
7
7
|
* allocation's release (src/substrates/e2b/sandbox.ts) kills the exact id and reads the answer the
|
|
8
8
|
* same way every route does: true is terminated, false or a not-found error is already gone. That
|
|
9
|
-
* is the
|
|
9
|
+
* is the primary proof. Where the SDK exposes Sandbox.getInfo(id), a thrown SandboxNotFoundError is
|
|
10
10
|
* a second by-id confirmation that the exact sandbox is gone; a returned SandboxInfo with a live
|
|
11
|
-
* state means teardown is
|
|
11
|
+
* state means teardown is unconfirmed. Never throws: teardown failure is recorded, and the caller
|
|
12
12
|
* fails closed on an unproven teardown.
|
|
13
13
|
*/
|
|
14
14
|
export async function teardownSandbox(args) {
|
|
15
15
|
const { allocation, sandboxModule, startupCleanup, startupCleanupDetail, requestTimeoutMs, sanitize, recordLifecycle, warnings, } = args;
|
|
16
16
|
if (allocation === undefined || !sandboxModule) {
|
|
17
|
-
// create() can reject
|
|
18
|
-
// that authority and reclaims it before rejecting; the
|
|
17
|
+
// create() can reject after its constructor acquired a handle. The default loader retains
|
|
18
|
+
// that authority and reclaims it before rejecting; the route itself never receives its ID.
|
|
19
19
|
if (startupCleanup === "killed" || startupCleanup === "already_gone") {
|
|
20
20
|
const reason = `desktop startup guard confirmed its acquired sandbox ${startupCleanup === "killed" ? "was killed" : "was already gone"}`;
|
|
21
21
|
recordLifecycle("terminal-lab.cleanup.killed", reason);
|
|
@@ -49,12 +49,12 @@ export async function teardownSandbox(args) {
|
|
|
49
49
|
recordLifecycle("terminal-lab.cleanup.unconfirmed", `Sandbox ${sandboxId} ${reason}.`);
|
|
50
50
|
return { killed: false, remaining: -1, reason };
|
|
51
51
|
}
|
|
52
|
-
//
|
|
52
|
+
// By-id verification only, from here down: never Sandbox.list. A released result is itself proof
|
|
53
53
|
// the exact sandbox is gone: terminated when kill(id) found and killed it, already gone when
|
|
54
54
|
// kill(id) answered false or threw not-found (a 404, e.g. the server-side kill-on-timeout raced
|
|
55
55
|
// ahead). Both mean "this id is no longer running." Sandbox.getInfo(id), when the SDK exposes
|
|
56
56
|
// it, adds a second by-id confirmation; the only thing that overturns the release proof is
|
|
57
|
-
// getInfo returning a
|
|
57
|
+
// getInfo returning a live sandbox for this exact id.
|
|
58
58
|
const killNote = released.reason === "terminated"
|
|
59
59
|
? "kill(id) returned true (found and killed)"
|
|
60
60
|
: "kill(id) found the exact sandbox already gone (404)";
|
|
@@ -85,8 +85,8 @@ export async function teardownSandbox(args) {
|
|
|
85
85
|
reason: `reclaimed by id; getInfo(id) confirms the exact sandbox no longer exists (SandboxNotFoundError)`,
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
-
// getInfo(id) failed for a reason
|
|
89
|
-
// no second by-id confirmation is available, so the
|
|
88
|
+
// getInfo(id) failed for a reason other than "not found" (e.g. a transient network error):
|
|
89
|
+
// no second by-id confirmation is available, so the resolved kill(id) call stands as the proof
|
|
90
90
|
// of absence. Never fall back to Sandbox.list.
|
|
91
91
|
const sanitizedError = sanitize(toErrorMessage(error));
|
|
92
92
|
recordLifecycle("terminal-lab.cleanup.killed", `Sandbox ${sandboxId} reclaimed: ${killNote}; getInfo(id) re-verification errored (${sanitizedError}), so kill(id)'s resolved result is the proof.`);
|