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
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { CuaProvider } from "../computer-use/loop.js";
|
|
2
2
|
import { type RestrictedCodexSessionOptions } from "./restricted-session.js";
|
|
3
|
+
import type { RestrictedCodexAnalysisErrorCode } from "./restricted-policy.js";
|
|
3
4
|
import type { ReasoningEffort } from "../reasoning-effort.js";
|
|
4
5
|
export type ParticipantProviderCloseResult = {
|
|
5
6
|
status: "confirmed" | "unconfirmed";
|
|
7
|
+
/** Run warnings from the native session, such as notification methods humanish does not know. */
|
|
8
|
+
warnings?: string[];
|
|
9
|
+
/** A refusal after the last request, such as a disallowed item outside a turn. It fails the run. */
|
|
10
|
+
refusal?: RestrictedCodexAnalysisErrorCode;
|
|
6
11
|
};
|
|
7
12
|
export interface RestrictedParticipantOptions {
|
|
8
13
|
session?: RestrictedCodexSessionOptions;
|
|
@@ -13,6 +18,31 @@ export interface RestrictedParticipantOptions {
|
|
|
13
18
|
/** Admit speech actions and heard-speaker evidence for a speech-capable desktop only. */
|
|
14
19
|
speechEnabled?: boolean;
|
|
15
20
|
}
|
|
21
|
+
/** What doctor's hosted-participant check found, before any turn. */
|
|
22
|
+
export interface ParticipantReadiness {
|
|
23
|
+
ready: boolean;
|
|
24
|
+
errorCode: RestrictedCodexAnalysisErrorCode | null;
|
|
25
|
+
/** The release the launch admitted. */
|
|
26
|
+
cliVersion?: string;
|
|
27
|
+
/** How the release's schema differs from the fields humanish reads, when that refused it. */
|
|
28
|
+
protocolIncompatibilities?: readonly string[];
|
|
29
|
+
/** Schema values beyond the baseline, recorded by a launch that passed. */
|
|
30
|
+
protocolAdditions?: readonly string[];
|
|
31
|
+
/** The model thread/start resolved from the operator's configuration or the declared model. */
|
|
32
|
+
resolvedModel?: string;
|
|
33
|
+
authentication?: "chatgpt-account" | "api-key";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* doctor's check for a hosted Codex participant: the operator-auth launch up to an ephemeral
|
|
37
|
+
* thread (the version check, initialize, config/read, account/read and thread/start). It sends no
|
|
38
|
+
* turn, so no model request is made, and its tool is never called.
|
|
39
|
+
*/
|
|
40
|
+
export declare function checkRestrictedCodexParticipantReadiness(options: {
|
|
41
|
+
session?: RestrictedCodexSessionOptions;
|
|
42
|
+
model?: string;
|
|
43
|
+
reasoningEffort?: ReasoningEffort;
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
}): Promise<ParticipantReadiness>;
|
|
16
46
|
/** One native tool-calling conversation; the existing CUA loop owns every input. */
|
|
17
47
|
export declare function createRestrictedCodexParticipant(options?: RestrictedParticipantOptions): {
|
|
18
48
|
provider: CuaProvider;
|
|
@@ -4,6 +4,8 @@ import { CuaProviderError, isCuaProviderError, } from "../computer-use/provider-
|
|
|
4
4
|
import { validateBrowserControlPng, validateHeardSpeech } from "../../browser-control/protocol.js";
|
|
5
5
|
import { createRestrictedCodexSession, } from "./restricted-session.js";
|
|
6
6
|
import { PARTICIPANT_PROFILE, PARTICIPANT_LIMITS as L, PARTICIPANT_FINAL_SCHEMA, participantToolSchema, parseParticipantTool, parseParticipantFinal, } from "./restricted-participant-policy.js";
|
|
7
|
+
import { truncatedFrameWarning, unknownNotificationsWarning } from "./restricted-notifications.js";
|
|
8
|
+
import { protocolAdditionsWarning, protocolIncompatibilityMessage } from "./protocol-compat.js";
|
|
7
9
|
const codeOf = (code) => {
|
|
8
10
|
if (code === "cancelled" || code === "timeout" || code === "refusal")
|
|
9
11
|
return code === "refusal" ? "refused" : code;
|
|
@@ -37,7 +39,7 @@ function deferred() {
|
|
|
37
39
|
return { promise, resolve, reject };
|
|
38
40
|
}
|
|
39
41
|
const toolDescription = (speechEnabled) => `Act on the participant's browser through humanish. Submit one to four UI actions${speechEnabled ? ", including speak when you need to reply aloud," : ""} and a short public comment; never private reasoning. humanish returns a JSON STRING with execution acknowledgments${speechEnabled ? ", speech heard from the actual participant speaker sink," : ""} and a fresh screenshot. In Code Mode use: const r = JSON.parse(await tools.humanish_ui({narration: "...", actions: [...]})); text({acknowledgments: r.acknowledgments${speechEnabled ? ", heardSpeech: r.heardSpeech" : ""}, contextHint: r.contextHint, closing: r.closing}); image(r.imageUrl). Call serially and inspect each returned screenshot${speechEnabled ? " and heardSpeech array" : ""} before deciding what to do next.${speechEnabled ? " Use speak only after the visible UI shows that you joined the call and your microphone is unmuted; it sends audio into that call." : ""} Acknowledged input does not prove an application outcome. If closing is true, stop calling tools and give your final account.`;
|
|
40
|
-
const participantInstructions = (
|
|
42
|
+
const participantInstructions = (prompt, speechEnabled) => `${prompt}\n\nYou are the study participant throughout this conversation, including its closing account. Use only the supplied screenshots and humanish_ui tool to interact. The tool returns a JSON string: parse it, inspect acknowledgments${speechEnabled ? " and heardSpeech captured from the actual participant speaker sink" : ""}, and display imageUrl with Code Mode image(). Do not print the image data URL as text. Keep your persona and earlier observations throughout the session.${speechEnabled ? " A speak action plays into the participant microphone; use it only after the visible UI shows that you joined the call and the microphone is unmuted." : ""} Speak publicly about your experience, never reveal private reasoning. Completed inputs do not prove application outcomes; verify on the next screenshot. When the task ends, return only the required final JSON with outcome, summary and frictionReports. Report observed confusion and recovered mistakes as well as blockers. Do not invent observations.`;
|
|
41
43
|
/** Turns and failures from the native run, handed in order to the next provider request. */
|
|
42
44
|
class ParticipantEvents {
|
|
43
45
|
queued = [];
|
|
@@ -194,6 +196,43 @@ function participantSession(options, speechEnabled, effort, call) {
|
|
|
194
196
|
},
|
|
195
197
|
});
|
|
196
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* doctor's check for a hosted Codex participant: the operator-auth launch up to an ephemeral
|
|
201
|
+
* thread (the version check, initialize, config/read, account/read and thread/start). It sends no
|
|
202
|
+
* turn, so no model request is made, and its tool is never called.
|
|
203
|
+
*/
|
|
204
|
+
export async function checkRestrictedCodexParticipantReadiness(options) {
|
|
205
|
+
const session = participantSession({
|
|
206
|
+
authMode: "operator",
|
|
207
|
+
...(options.session === undefined ? {} : { session: options.session }),
|
|
208
|
+
}, false, options.reasoningEffort ?? "low", async () => {
|
|
209
|
+
throw new Error("A readiness check makes no tool call");
|
|
210
|
+
});
|
|
211
|
+
const result = await session.run({
|
|
212
|
+
...(options.model === undefined ? {} : { model: options.model }),
|
|
213
|
+
instructions: participantInstructions("Readiness check only.", false),
|
|
214
|
+
evidence: "",
|
|
215
|
+
images: [],
|
|
216
|
+
schema: PARTICIPANT_FINAL_SCHEMA,
|
|
217
|
+
maxOutputTokens: null,
|
|
218
|
+
timeoutMs: options.timeoutMs ?? 15_000,
|
|
219
|
+
}, true);
|
|
220
|
+
const closed = await session.close();
|
|
221
|
+
const errorCode = closed ? result.errorCode : (result.errorCode ?? "codex_cleanup_failed");
|
|
222
|
+
return {
|
|
223
|
+
ready: errorCode === null && result.status === "completed",
|
|
224
|
+
errorCode,
|
|
225
|
+
...(session.cliVersion === undefined ? {} : { cliVersion: session.cliVersion }),
|
|
226
|
+
...(session.protocolIncompatibilities === undefined
|
|
227
|
+
? {}
|
|
228
|
+
: { protocolIncompatibilities: session.protocolIncompatibilities }),
|
|
229
|
+
...(session.protocolAdditions === undefined || session.protocolAdditions.length === 0
|
|
230
|
+
? {}
|
|
231
|
+
: { protocolAdditions: session.protocolAdditions }),
|
|
232
|
+
...(session.resolvedModel === undefined ? {} : { resolvedModel: session.resolvedModel }),
|
|
233
|
+
...(session.authentication === undefined ? {} : { authentication: session.authentication }),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
197
236
|
/**
|
|
198
237
|
* The profile a run records: the detected release, or the host default before the first launch.
|
|
199
238
|
* An operator-auth session has one only once it resolved a model on a ChatGPT account.
|
|
@@ -244,6 +283,22 @@ function closeParticipantSession(state) {
|
|
|
244
283
|
return confirmed;
|
|
245
284
|
}));
|
|
246
285
|
}
|
|
286
|
+
/** What the closed native session reports beside cleanup: its run warnings and a late refusal. */
|
|
287
|
+
function sessionReport(session) {
|
|
288
|
+
const warnings = [
|
|
289
|
+
session.protocolIncompatibilities === undefined
|
|
290
|
+
? undefined
|
|
291
|
+
: protocolIncompatibilityMessage(session.cliVersion, session.protocolIncompatibilities),
|
|
292
|
+
protocolAdditionsWarning(session.cliVersion, session.protocolAdditions),
|
|
293
|
+
unknownNotificationsWarning(session.unknownNotifications, session.cliVersion),
|
|
294
|
+
truncatedFrameWarning(session.truncatedFrameBytes),
|
|
295
|
+
].filter((warning) => warning !== undefined);
|
|
296
|
+
const refusal = session.policyRefusal;
|
|
297
|
+
return {
|
|
298
|
+
...(warnings.length === 0 ? {} : { warnings }),
|
|
299
|
+
...(refusal === undefined ? {} : { refusal }),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
247
302
|
/** Stops the conversation: abort the native run, reject a waiting tool call, close the session. */
|
|
248
303
|
function revokeParticipant(state) {
|
|
249
304
|
state.closed = true;
|
|
@@ -424,7 +479,10 @@ export function createRestrictedCodexParticipant(options = {}) {
|
|
|
424
479
|
const work = Promise.all([state.nativeTask, closeParticipantSession(state)]).then(([, ok]) => ok);
|
|
425
480
|
if (!(await withinCleanupBudget(work, state.abortAt)))
|
|
426
481
|
state.failedCleanup = true;
|
|
427
|
-
return {
|
|
482
|
+
return {
|
|
483
|
+
status: state.failedCleanup ? "unconfirmed" : "confirmed",
|
|
484
|
+
...sessionReport(state.session),
|
|
485
|
+
};
|
|
428
486
|
})();
|
|
429
487
|
return closing;
|
|
430
488
|
},
|
|
@@ -11,7 +11,7 @@ export declare const RESTRICTED_CODEX_ANALYSIS_IDENTITY: {
|
|
|
11
11
|
readonly reasoningEffort: "low";
|
|
12
12
|
};
|
|
13
13
|
export declare const RESTRICTED_CODEX_ANALYSIS_MODELS: readonly ["gpt-6-astra"];
|
|
14
|
-
export type RestrictedCodexAnalysisErrorCode = "invalid_request" | "cancelled" | "timeout" | "response_too_large" | "invalid_response" | "refusal" | "output_incomplete" | "codex_unavailable" | "codex_unsupported_version" | "codex_unsupported_platform" | "codex_login_required" | "codex_unsupported_auth" | "codex_unsafe_configuration" | "codex_model_unavailable" | "codex_protocol_error" | "codex_tool_call" | "codex_process_failed" | "codex_cleanup_failed" | "codex_busy";
|
|
14
|
+
export type RestrictedCodexAnalysisErrorCode = "invalid_request" | "cancelled" | "timeout" | "response_too_large" | "invalid_response" | "refusal" | "output_incomplete" | "codex_unavailable" | "codex_unsupported_version" | "codex_incompatible_release" | "codex_unsupported_platform" | "codex_login_required" | "codex_unsupported_auth" | "codex_unsafe_configuration" | "codex_model_unavailable" | "codex_protocol_error" | "codex_tool_call" | "codex_process_failed" | "codex_cleanup_failed" | "codex_busy";
|
|
15
15
|
export interface RestrictedCodexRequest {
|
|
16
16
|
model?: string | undefined;
|
|
17
17
|
instructions: string;
|
|
@@ -40,6 +40,14 @@ export interface RestrictedCodexResult {
|
|
|
40
40
|
usageComplete: boolean;
|
|
41
41
|
dispatched: boolean;
|
|
42
42
|
errorCode: RestrictedCodexAnalysisErrorCode | null;
|
|
43
|
+
/** Notification methods this humanish does not know that carried no item, by count. */
|
|
44
|
+
unknownNotifications?: Readonly<Record<string, number>>;
|
|
45
|
+
/** How the release's app-server schema differs from the fields humanish reads (protocol-compat). */
|
|
46
|
+
protocolIncompatibilities?: readonly string[];
|
|
47
|
+
/** Schema values beyond the baseline humanish knows; recorded, and the launch continued. */
|
|
48
|
+
protocolAdditions?: readonly string[];
|
|
49
|
+
/** Bytes of a last frame cut off when humanish stopped the app-server. */
|
|
50
|
+
truncatedFrameBytes?: number;
|
|
43
51
|
}
|
|
44
52
|
export declare const CODEX_MAX_REQUEST_BYTES: number;
|
|
45
53
|
export declare const CODEX_MAX_OUTPUT_BYTES: number;
|
|
@@ -14,7 +14,7 @@ export interface RestrictedCodexSessionOptions {
|
|
|
14
14
|
/**
|
|
15
15
|
* Bypasses qualification: replaces this host's admitted releases with any list. It exists only
|
|
16
16
|
* so scripts/codex-qualify.mjs can launch an unqualified candidate. No library export, lab
|
|
17
|
-
* manifest, CLI flag, RunLabOptions field or
|
|
17
|
+
* manifest, CLI flag, RunLabOptions field or LabDeps seam reaches it
|
|
18
18
|
* (tests/actors/codex/cli-versions-seam.test.ts).
|
|
19
19
|
*/
|
|
20
20
|
cliVersions?: readonly string[];
|
|
@@ -40,6 +40,19 @@ export interface RestrictedCodexSession {
|
|
|
40
40
|
readonly authentication?: "chatgpt-account" | "api-key" | undefined;
|
|
41
41
|
/** The admitted release this session launched, once its version check has passed. */
|
|
42
42
|
readonly cliVersion?: string | undefined;
|
|
43
|
+
/** Notification methods this humanish does not know that carried no item, by count. */
|
|
44
|
+
readonly unknownNotifications?: Readonly<Record<string, number>>;
|
|
45
|
+
/**
|
|
46
|
+
* The first policy refusal or unchecked output in the session, whether or not a request reported
|
|
47
|
+
* it. A participant's close fails the run with it.
|
|
48
|
+
*/
|
|
49
|
+
readonly policyRefusal?: RestrictedCodexAnalysisErrorCode | undefined;
|
|
50
|
+
/** Bytes of last frames cut off after humanish stopped the app-server; a run warning. */
|
|
51
|
+
readonly truncatedFrameBytes?: number | undefined;
|
|
52
|
+
/** How the release's schema differs from the fields humanish reads, when that refused it. */
|
|
53
|
+
readonly protocolIncompatibilities?: readonly string[] | undefined;
|
|
54
|
+
/** Schema values beyond the baseline humanish knows, recorded at launch. */
|
|
55
|
+
readonly protocolAdditions?: readonly string[] | undefined;
|
|
43
56
|
run(request: RestrictedCodexRequest, readinessOnly?: boolean): Promise<RestrictedCodexResult>;
|
|
44
57
|
close(): Promise<boolean>;
|
|
45
58
|
}
|
|
@@ -5,9 +5,10 @@ import path from "node:path";
|
|
|
5
5
|
import { admittedCodexCliVersions } from "./qualified-versions.js";
|
|
6
6
|
import { launchAdmittedAppServer, } from "./restricted-launch.js";
|
|
7
7
|
import { CODEX_IMAGE, CODEX_MAX_OUTPUT_BYTES, CODEX_MAX_REQUEST_BYTES, RESTRICTED_CODEX_ANALYSIS_MODELS, codexRecord, restrictedCodexFailure, restrictedCodexRequestError, } from "./restricted-policy.js";
|
|
8
|
-
import { RestrictedCodexDeadline, RestrictedCodexStop,
|
|
8
|
+
import { RestrictedCodexDeadline, RestrictedCodexStop, hasUnclosedChildren, retainUnclosedChild, } from "./restricted-transport.js";
|
|
9
9
|
import { checkVersion, childEnvironment, resolveExecutable, restrictedCodexNpmTarget, } from "./restricted-executable.js";
|
|
10
10
|
import { RestrictedCodexTurn } from "./restricted-turn.js";
|
|
11
|
+
import { countUnknownNotification, detachTurn, idleNotifications, installSessionHandlers, notificationPolicyOf, refuseSession, } from "./restricted-notifications.js";
|
|
11
12
|
function validParticipant(options) {
|
|
12
13
|
if (!options)
|
|
13
14
|
return true;
|
|
@@ -34,12 +35,29 @@ function validParticipant(options) {
|
|
|
34
35
|
export async function runRestrictedCodexSession(request, options = {}, readinessOnly = false) {
|
|
35
36
|
const session = createRestrictedCodexSession(options);
|
|
36
37
|
const result = await session.run(request, readinessOnly);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const closed = await session.close();
|
|
39
|
+
const unknownNotifications = session.unknownNotifications ?? {};
|
|
40
|
+
const truncatedFrameBytes = session.truncatedFrameBytes;
|
|
41
|
+
const { protocolIncompatibilities, protocolAdditions } = session;
|
|
42
|
+
const noted = {
|
|
43
|
+
...(Object.keys(unknownNotifications).length === 0 ? {} : { unknownNotifications }),
|
|
44
|
+
...(truncatedFrameBytes === undefined ? {} : { truncatedFrameBytes }),
|
|
45
|
+
...(protocolIncompatibilities === undefined ? {} : { protocolIncompatibilities }),
|
|
46
|
+
...(protocolAdditions === undefined || protocolAdditions.length === 0
|
|
47
|
+
? {}
|
|
48
|
+
: { protocolAdditions }),
|
|
49
|
+
};
|
|
50
|
+
if (!closed)
|
|
51
|
+
return {
|
|
40
52
|
...restrictedCodexFailure("codex_cleanup_failed", result.dispatched, result.usage),
|
|
41
53
|
failurePhase: "cleanup",
|
|
54
|
+
...noted,
|
|
42
55
|
};
|
|
56
|
+
// A disallowed item while the app-server shut down fails a request that had completed.
|
|
57
|
+
const refusal = session.policyRefusal;
|
|
58
|
+
return refusal !== undefined && result.errorCode === null
|
|
59
|
+
? { ...restrictedCodexFailure(refusal, result.dispatched, result.usage), ...noted }
|
|
60
|
+
: { ...result, ...noted };
|
|
43
61
|
}
|
|
44
62
|
async function writeRecoveryMarker(work, sourceEnv, reason) {
|
|
45
63
|
const cache = sourceEnv.XDG_CACHE_HOME ?? path.join(sourceEnv.HOME ?? homedir(), ".cache");
|
|
@@ -200,17 +218,12 @@ function newTurn(settings, state, deadline) {
|
|
|
200
218
|
turnStarted: (turnId) => {
|
|
201
219
|
state.interrupt = { threadId: state.threadId, turnId };
|
|
202
220
|
},
|
|
221
|
+
policy: notificationPolicyOf(participant),
|
|
222
|
+
idle: (method, params) => idleNotifications(participant, state)(method, params),
|
|
223
|
+
recordUnknown: (method) => countUnknownNotification(state.unknownNotifications, method),
|
|
224
|
+
refuse: (code) => refuseSession(state, code),
|
|
203
225
|
});
|
|
204
226
|
}
|
|
205
|
-
/** After a request: the turn's handlers come off the transport. */
|
|
206
|
-
function detachTurn(transport) {
|
|
207
|
-
if (transport)
|
|
208
|
-
transport.onNotification = () => undefined;
|
|
209
|
-
if (transport)
|
|
210
|
-
transport.onRequest = undefined;
|
|
211
|
-
if (transport)
|
|
212
|
-
transport.onRequestComplete = undefined;
|
|
213
|
-
}
|
|
214
227
|
/** Request dispatch: launch on the first request, then one turn; a failed request tears down. */
|
|
215
228
|
async function runTurn(settings, state, dispose, request, readinessOnly) {
|
|
216
229
|
const participant = settings.participant;
|
|
@@ -228,13 +241,13 @@ async function runTurn(settings, state, dispose, request, readinessOnly) {
|
|
|
228
241
|
if (!state.transport) {
|
|
229
242
|
state.transport = await launchAdmittedAppServer(settings, state, request, deadline, frameLimit, (next) => {
|
|
230
243
|
phase = next;
|
|
231
|
-
});
|
|
244
|
+
}, (transport) => installSessionHandlers(participant, state, transport));
|
|
232
245
|
selectedModel = state.identity.model;
|
|
233
246
|
}
|
|
234
247
|
else
|
|
235
248
|
state.transport.beginRequest(deadline, frameLimit);
|
|
236
|
-
//
|
|
237
|
-
// callback, so wiring both
|
|
249
|
+
// Before dispatch the turn passes notifications to the idle handler the launch installed,
|
|
250
|
+
// and onRequestComplete follows only a host callback, so wiring both here loses nothing.
|
|
238
251
|
state.transport.onNotification = turn.onNotification;
|
|
239
252
|
state.transport.onRequestComplete = turn.onRequestComplete;
|
|
240
253
|
if (readinessOnly)
|
|
@@ -269,7 +282,7 @@ async function runTurn(settings, state, dispose, request, readinessOnly) {
|
|
|
269
282
|
state.pendingInferenceUsage = undefined;
|
|
270
283
|
deadline.close();
|
|
271
284
|
state.activeDeadline = undefined;
|
|
272
|
-
detachTurn(state
|
|
285
|
+
detachTurn(participant, state);
|
|
273
286
|
if (result.errorCode !== null) {
|
|
274
287
|
if (result.errorCode === "codex_cleanup_failed")
|
|
275
288
|
state.cleanupTrusted = false;
|
|
@@ -335,10 +348,15 @@ export function createRestrictedCodexSession(options = {}) {
|
|
|
335
348
|
resolvedModel: undefined,
|
|
336
349
|
authentication: undefined,
|
|
337
350
|
cliVersion: undefined,
|
|
351
|
+
unknownNotifications: new Map(),
|
|
352
|
+
protocolIncompatibilities: undefined,
|
|
353
|
+
protocolAdditions: undefined,
|
|
338
354
|
activeDeadline: undefined,
|
|
339
355
|
interrupt: undefined,
|
|
340
356
|
closed: false,
|
|
341
357
|
cleanupTrusted: true,
|
|
358
|
+
policyRefusal: undefined,
|
|
359
|
+
truncatedFrameBytes: undefined,
|
|
342
360
|
};
|
|
343
361
|
let pending, closing, disposing;
|
|
344
362
|
const dispose = () => {
|
|
@@ -361,6 +379,21 @@ export function createRestrictedCodexSession(options = {}) {
|
|
|
361
379
|
get cliVersion() {
|
|
362
380
|
return state.cliVersion;
|
|
363
381
|
},
|
|
382
|
+
get unknownNotifications() {
|
|
383
|
+
return Object.fromEntries(state.unknownNotifications);
|
|
384
|
+
},
|
|
385
|
+
get policyRefusal() {
|
|
386
|
+
return state.policyRefusal;
|
|
387
|
+
},
|
|
388
|
+
get truncatedFrameBytes() {
|
|
389
|
+
return state.truncatedFrameBytes;
|
|
390
|
+
},
|
|
391
|
+
get protocolIncompatibilities() {
|
|
392
|
+
return state.protocolIncompatibilities;
|
|
393
|
+
},
|
|
394
|
+
get protocolAdditions() {
|
|
395
|
+
return state.protocolAdditions;
|
|
396
|
+
},
|
|
364
397
|
run(request, readinessOnly = false) {
|
|
365
398
|
const refusal = refusedRun(settings, state, request, () => pending !== undefined);
|
|
366
399
|
if (refusal)
|
|
@@ -34,11 +34,21 @@ export declare class RestrictedCodexDeadline {
|
|
|
34
34
|
}
|
|
35
35
|
export declare function retainUnclosedChild(closed: Promise<void>): void;
|
|
36
36
|
export declare const hasUnclosedChildren: () => boolean;
|
|
37
|
+
/** How the process exited: its exit code, or the signal that ended it. */
|
|
38
|
+
interface OwnedCodexExit {
|
|
39
|
+
code: number | null;
|
|
40
|
+
signal: NodeJS.Signals | null;
|
|
41
|
+
}
|
|
37
42
|
export interface OwnedCodexProcess {
|
|
38
43
|
child: ChildProcessWithoutNullStreams;
|
|
39
44
|
closed: Promise<void>;
|
|
40
45
|
isClosed(): boolean;
|
|
41
46
|
hasExited(): boolean;
|
|
47
|
+
/** Resolves with the 'exit' event's code and signal. */
|
|
48
|
+
readonly exit: Promise<OwnedCodexExit>;
|
|
49
|
+
/** The signals humanish delivered while the process was still running (signalOwnedChild). */
|
|
50
|
+
signalsSent(): readonly NodeJS.Signals[];
|
|
51
|
+
recordSignal(signal: NodeJS.Signals): void;
|
|
42
52
|
}
|
|
43
53
|
export declare function ownCodexProcess(child: ChildProcessWithoutNullStreams): OwnedCodexProcess;
|
|
44
54
|
export declare function closeOwnedCodexProcess(owned: OwnedCodexProcess): Promise<boolean>;
|
|
@@ -55,11 +65,29 @@ export declare class RestrictedCodexTransport {
|
|
|
55
65
|
private eventCount;
|
|
56
66
|
private closing;
|
|
57
67
|
onNotification: (method: string, params: Record<string, unknown>) => void;
|
|
68
|
+
/** Notifications after the deadline stopped or close began: no turn handles them, only the policy. */
|
|
69
|
+
onPolicyOnlyNotification: (method: string, params: Record<string, unknown>) => void;
|
|
70
|
+
/** A server request with no handler, or output that could not be checked (failUninspected). */
|
|
71
|
+
onPolicyFailure: (code: RestrictedCodexAnalysisErrorCode) => void;
|
|
72
|
+
/** The size of a last frame cut off after humanish stopped the process: a warning only. */
|
|
73
|
+
onTruncatedFrame: (bytes: number) => void;
|
|
58
74
|
onRequest: ((method: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>) | undefined;
|
|
59
75
|
onRequestComplete: (() => void) | undefined;
|
|
60
76
|
constructor(owned: OwnedCodexProcess, deadline: RestrictedCodexDeadline, frameLimit?: number);
|
|
61
77
|
/** A completed turn releases its deadline and wire budget, not its conversation. */
|
|
62
78
|
beginRequest(deadline: RestrictedCodexDeadline, frameLimit: number): void;
|
|
79
|
+
/** One line of output: a malformed line could not be checked. */
|
|
80
|
+
private frame;
|
|
81
|
+
/**
|
|
82
|
+
* Output that could not be checked: past a byte, frame or event limit, malformed, or cut off.
|
|
83
|
+
* The session records it through onPolicyFailure, whatever state the transport is in.
|
|
84
|
+
*/
|
|
85
|
+
private failUninspected;
|
|
86
|
+
/**
|
|
87
|
+
* Refuses the session with `code`: stops the current deadline and rejects pending requests.
|
|
88
|
+
* Between requests the stopped deadline makes the next beginRequest throw the code.
|
|
89
|
+
*/
|
|
90
|
+
refuse(code: RestrictedCodexAnalysisErrorCode): void;
|
|
63
91
|
private fail;
|
|
64
92
|
private message;
|
|
65
93
|
private write;
|
|
@@ -71,3 +99,4 @@ export declare class RestrictedCodexTransport {
|
|
|
71
99
|
turnId: string;
|
|
72
100
|
}): Promise<boolean>;
|
|
73
101
|
}
|
|
102
|
+
export {};
|
|
@@ -91,8 +91,12 @@ export function retainUnclosedChild(closed) {
|
|
|
91
91
|
export const hasUnclosedChildren = () => unclosedChildren.size > 0;
|
|
92
92
|
export function ownCodexProcess(child) {
|
|
93
93
|
let closed = false, exited = false;
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const sent = [];
|
|
95
|
+
const exit = new Promise((resolve) => {
|
|
96
|
+
child.once("exit", (code, signal) => {
|
|
97
|
+
exited = true;
|
|
98
|
+
resolve({ code, signal });
|
|
99
|
+
});
|
|
96
100
|
});
|
|
97
101
|
const completion = new Promise((resolve) => {
|
|
98
102
|
child.once("close", () => {
|
|
@@ -100,7 +104,17 @@ export function ownCodexProcess(child) {
|
|
|
100
104
|
resolve();
|
|
101
105
|
});
|
|
102
106
|
});
|
|
103
|
-
return {
|
|
107
|
+
return {
|
|
108
|
+
child,
|
|
109
|
+
closed: completion,
|
|
110
|
+
isClosed: () => closed,
|
|
111
|
+
hasExited: () => exited,
|
|
112
|
+
exit,
|
|
113
|
+
signalsSent: () => sent,
|
|
114
|
+
recordSignal: (signal) => {
|
|
115
|
+
sent.push(signal);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
104
118
|
}
|
|
105
119
|
async function settlesWithin(promise, ms) {
|
|
106
120
|
let timer;
|
|
@@ -122,7 +136,9 @@ function signalOwnedChild(owned, signal) {
|
|
|
122
136
|
if (owned.hasExited() || owned.isClosed())
|
|
123
137
|
return;
|
|
124
138
|
try {
|
|
125
|
-
|
|
139
|
+
// kill() is true when the signal was delivered.
|
|
140
|
+
if (owned.child.kill(signal))
|
|
141
|
+
owned.recordSignal(signal);
|
|
126
142
|
}
|
|
127
143
|
catch {
|
|
128
144
|
/* Closing is still checked below. */
|
|
@@ -142,6 +158,15 @@ export async function closeOwnedCodexProcess(owned) {
|
|
|
142
158
|
owned.child.stderr.destroy();
|
|
143
159
|
return closed;
|
|
144
160
|
}
|
|
161
|
+
function isJson(text) {
|
|
162
|
+
try {
|
|
163
|
+
JSON.parse(text);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
145
170
|
export class RestrictedCodexTransport {
|
|
146
171
|
owned;
|
|
147
172
|
deadline;
|
|
@@ -155,6 +180,12 @@ export class RestrictedCodexTransport {
|
|
|
155
180
|
eventCount = 0;
|
|
156
181
|
closing = false;
|
|
157
182
|
onNotification = () => undefined;
|
|
183
|
+
/** Notifications after the deadline stopped or close began: no turn handles them, only the policy. */
|
|
184
|
+
onPolicyOnlyNotification = () => undefined;
|
|
185
|
+
/** A server request with no handler, or output that could not be checked (failUninspected). */
|
|
186
|
+
onPolicyFailure = () => undefined;
|
|
187
|
+
/** The size of a last frame cut off after humanish stopped the process: a warning only. */
|
|
188
|
+
onTruncatedFrame = () => undefined;
|
|
158
189
|
onRequest;
|
|
159
190
|
onRequestComplete;
|
|
160
191
|
constructor(owned, deadline, frameLimit = CODEX_MAX_OUTPUT_BYTES) {
|
|
@@ -165,38 +196,59 @@ export class RestrictedCodexTransport {
|
|
|
165
196
|
child.on("error", () => this.fail("codex_process_failed"));
|
|
166
197
|
child.stdin.on("error", () => this.fail("codex_process_failed"));
|
|
167
198
|
child.on("close", () => this.fail("codex_process_failed"));
|
|
199
|
+
// Output is read until the process exits. Once the deadline stops or close begins, it is read
|
|
200
|
+
// for the item policy only (message); only the byte and frame limits stop reading, and they
|
|
201
|
+
// count as unchecked output.
|
|
168
202
|
child.stdout.on("data", (chunk) => {
|
|
169
|
-
if ((!this.closing && this.deadline.code !== null) ||
|
|
170
|
-
(this.closing && this.pending.size === 0))
|
|
171
|
-
return;
|
|
172
203
|
this.stdoutBytes += chunk.length;
|
|
173
204
|
if (this.stdoutBytes >
|
|
174
205
|
Math.max(CODEX_MAX_STDOUT_BYTES, this.frameLimit * 2 + CODEX_MAX_OUTPUT_BYTES * 2)) {
|
|
175
|
-
this.
|
|
206
|
+
this.failUninspected("response_too_large");
|
|
176
207
|
return;
|
|
177
208
|
}
|
|
178
209
|
this.line += this.decoder.write(chunk);
|
|
179
210
|
if (Buffer.byteLength(this.line) > this.frameLimit) {
|
|
180
|
-
this.
|
|
211
|
+
this.failUninspected("response_too_large");
|
|
181
212
|
return;
|
|
182
213
|
}
|
|
183
214
|
while (this.line.includes("\n")) {
|
|
184
|
-
const split = this.line.indexOf("\n")
|
|
215
|
+
const split = this.line.indexOf("\n");
|
|
216
|
+
const line = this.line.slice(0, split);
|
|
185
217
|
this.line = this.line.slice(split + 1);
|
|
186
|
-
|
|
187
|
-
this.fail("codex_protocol_error");
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
try {
|
|
191
|
-
this.message(JSON.parse(line));
|
|
192
|
-
}
|
|
193
|
-
catch {
|
|
194
|
-
this.fail("codex_protocol_error");
|
|
195
|
-
}
|
|
196
|
-
if (this.deadline.code !== null && !this.closing)
|
|
197
|
-
return;
|
|
218
|
+
this.frame(line);
|
|
198
219
|
}
|
|
199
220
|
});
|
|
221
|
+
// A last frame without its newline is parsed when it is whole JSON. A cut-off frame is a
|
|
222
|
+
// warning with its size only when humanish's own signal cut it: the signal reached the running
|
|
223
|
+
// process before its output ended, and the process then exited by that signal or with a code.
|
|
224
|
+
// Any other cut-off frame (an exit on its own, a crash, a signal humanish did not send) went
|
|
225
|
+
// unchecked.
|
|
226
|
+
child.stdout.on("end", () => {
|
|
227
|
+
const rest = this.line + this.decoder.end();
|
|
228
|
+
this.line = "";
|
|
229
|
+
const lines = rest.split("\n").filter((line) => line.length > 0);
|
|
230
|
+
const last = lines.pop();
|
|
231
|
+
for (const line of lines)
|
|
232
|
+
this.frame(line);
|
|
233
|
+
if (last === undefined)
|
|
234
|
+
return;
|
|
235
|
+
if (isJson(last)) {
|
|
236
|
+
this.frame(last);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (this.owned.signalsSent().length === 0) {
|
|
240
|
+
this.failUninspected("codex_protocol_error");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const bytes = Buffer.byteLength(last);
|
|
244
|
+
void this.owned.exit.then(({ code, signal }) => {
|
|
245
|
+
const ours = signal === null ? code !== null : this.owned.signalsSent().includes(signal);
|
|
246
|
+
if (ours)
|
|
247
|
+
this.onTruncatedFrame(bytes);
|
|
248
|
+
else
|
|
249
|
+
this.failUninspected("codex_protocol_error");
|
|
250
|
+
});
|
|
251
|
+
});
|
|
200
252
|
child.stderr.on("data", (chunk) => {
|
|
201
253
|
this.stderrBytes += chunk.length;
|
|
202
254
|
if (this.stderrBytes > CODEX_MAX_OUTPUT_BYTES)
|
|
@@ -215,6 +267,41 @@ export class RestrictedCodexTransport {
|
|
|
215
267
|
this.stderrBytes = 0;
|
|
216
268
|
this.eventCount = 0;
|
|
217
269
|
}
|
|
270
|
+
/** One line of output: a malformed line could not be checked. */
|
|
271
|
+
frame(line) {
|
|
272
|
+
let parsed;
|
|
273
|
+
try {
|
|
274
|
+
parsed = line.length === 0 ? undefined : JSON.parse(line);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
parsed = undefined;
|
|
278
|
+
}
|
|
279
|
+
if (parsed === undefined) {
|
|
280
|
+
this.failUninspected("codex_protocol_error");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
this.message(parsed);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
this.fail("codex_protocol_error");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Output that could not be checked: past a byte, frame or event limit, malformed, or cut off.
|
|
292
|
+
* The session records it through onPolicyFailure, whatever state the transport is in.
|
|
293
|
+
*/
|
|
294
|
+
failUninspected(code) {
|
|
295
|
+
this.onPolicyFailure(code);
|
|
296
|
+
this.fail(code);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Refuses the session with `code`: stops the current deadline and rejects pending requests.
|
|
300
|
+
* Between requests the stopped deadline makes the next beginRequest throw the code.
|
|
301
|
+
*/
|
|
302
|
+
refuse(code) {
|
|
303
|
+
this.fail(code);
|
|
304
|
+
}
|
|
218
305
|
fail(code) {
|
|
219
306
|
if (!this.closing)
|
|
220
307
|
this.deadline.stop(code);
|
|
@@ -225,13 +312,31 @@ export class RestrictedCodexTransport {
|
|
|
225
312
|
message(raw) {
|
|
226
313
|
const value = codexRecord(raw);
|
|
227
314
|
if (Object.keys(value).length === 0) {
|
|
228
|
-
this.
|
|
315
|
+
this.failUninspected("codex_protocol_error");
|
|
229
316
|
return;
|
|
230
317
|
}
|
|
318
|
+
// After the deadline stopped or close began, output is read for the item policy only.
|
|
319
|
+
const policyOnly = this.closing || this.deadline.code !== null;
|
|
231
320
|
if (value.id !== undefined && typeof value.method === "string") {
|
|
321
|
+
// A server request is then declined unhandled: its turn is over or being interrupted, so a
|
|
322
|
+
// tool call that crossed the stop runs nothing and is not a policy refusal.
|
|
323
|
+
if (policyOnly) {
|
|
324
|
+
try {
|
|
325
|
+
this.write({
|
|
326
|
+
id: value.id,
|
|
327
|
+
error: { code: -32601, message: "Host request is disabled" },
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
/* The process is already closing. */
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
232
335
|
if (!this.onRequest || ++this.eventCount > CODEX_MAX_EVENTS) {
|
|
336
|
+
const code = this.eventCount > CODEX_MAX_EVENTS ? "response_too_large" : "codex_tool_call";
|
|
337
|
+
this.onPolicyFailure(code);
|
|
233
338
|
this.write({ id: value.id, error: { code: -32601, message: "Host request is disabled" } });
|
|
234
|
-
this.fail(
|
|
339
|
+
this.fail(code);
|
|
235
340
|
return;
|
|
236
341
|
}
|
|
237
342
|
const id = value.id;
|
|
@@ -263,7 +368,9 @@ export class RestrictedCodexTransport {
|
|
|
263
368
|
if (typeof value.id === "number" && value.method === undefined) {
|
|
264
369
|
const pending = this.pending.get(value.id);
|
|
265
370
|
if (!pending) {
|
|
266
|
-
|
|
371
|
+
// A late reply, such as an interrupt's after its wait, carries no item.
|
|
372
|
+
if (!policyOnly)
|
|
373
|
+
this.fail("codex_protocol_error");
|
|
267
374
|
return;
|
|
268
375
|
}
|
|
269
376
|
this.pending.delete(value.id);
|
|
@@ -280,10 +387,12 @@ export class RestrictedCodexTransport {
|
|
|
280
387
|
if (typeof value.method !== "string" ||
|
|
281
388
|
value.id !== undefined ||
|
|
282
389
|
++this.eventCount > CODEX_MAX_EVENTS) {
|
|
283
|
-
this.
|
|
390
|
+
this.failUninspected(this.eventCount > CODEX_MAX_EVENTS ? "response_too_large" : "codex_protocol_error");
|
|
284
391
|
return;
|
|
285
392
|
}
|
|
286
|
-
if (
|
|
393
|
+
if (policyOnly)
|
|
394
|
+
this.onPolicyOnlyNotification(value.method, codexRecord(value.params));
|
|
395
|
+
else
|
|
287
396
|
this.onNotification(value.method, codexRecord(value.params));
|
|
288
397
|
}
|
|
289
398
|
write(value) {
|
|
@@ -324,6 +433,9 @@ export class RestrictedCodexTransport {
|
|
|
324
433
|
}
|
|
325
434
|
async close(interrupt) {
|
|
326
435
|
this.closing = true;
|
|
436
|
+
// Shutdown output gets its own byte and event budget.
|
|
437
|
+
this.stdoutBytes = 0;
|
|
438
|
+
this.eventCount = 0;
|
|
327
439
|
if (interrupt && !this.owned.isClosed()) {
|
|
328
440
|
const { id, result } = this.request("turn/interrupt", interrupt);
|
|
329
441
|
await settlesWithin(result, 1000);
|