humanish 0.107.0 → 0.108.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/ARCHITECTURE.md +22 -17
- package/CHANGELOG.md +14 -0
- package/CONTEXT.md +51 -44
- package/README.md +145 -172
- package/SECURITY.md +16 -26
- package/TELEMETRY.md +8 -6
- package/dist/actors/affordance.d.ts +4 -4
- package/dist/actors/affordance.js +12 -12
- package/dist/actors/agent-session.d.ts +2 -2
- package/dist/actors/agent-session.js +7 -7
- package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
- package/dist/actors/codex/app-server-actor-trace.js +1 -1
- package/dist/actors/codex/app-server-ui.js +1 -1
- package/dist/actors/codex/codex-admission.d.ts +91 -0
- package/dist/actors/codex/codex-admission.js +150 -0
- package/dist/actors/codex/restricted-executable.d.ts +4 -4
- package/dist/actors/codex/restricted-executable.js +8 -8
- package/dist/actors/codex/restricted-launch.d.ts +2 -1
- package/dist/actors/codex/restricted-launch.js +1 -1
- package/dist/actors/codex/restricted-participant.js +8 -6
- package/dist/actors/codex/restricted-policy.d.ts +2 -2
- package/dist/actors/codex/restricted-policy.js +2 -2
- package/dist/actors/codex/restricted-session.d.ts +2 -2
- package/dist/actors/codex/restricted-session.js +10 -5
- package/dist/actors/computer-use/actor.d.ts +16 -16
- package/dist/actors/computer-use/actor.js +2 -2
- package/dist/actors/computer-use/admission-limit.d.ts +1 -1
- package/dist/actors/computer-use/admission-limit.js +1 -1
- package/dist/actors/computer-use/loop/actions.d.ts +3 -3
- package/dist/actors/computer-use/loop/actions.js +10 -10
- package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
- package/dist/actors/computer-use/loop/backstop.js +14 -12
- package/dist/actors/computer-use/loop/ending.d.ts +5 -5
- package/dist/actors/computer-use/loop/ending.js +7 -7
- package/dist/actors/computer-use/loop/observation.d.ts +2 -2
- package/dist/actors/computer-use/loop/observation.js +9 -9
- package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
- package/dist/actors/computer-use/loop/provider-call.js +1 -1
- package/dist/actors/computer-use/loop/session.js +3 -3
- package/dist/actors/computer-use/loop/spend.d.ts +1 -1
- package/dist/actors/computer-use/loop/spend.js +1 -1
- package/dist/actors/computer-use/loop/trace.js +9 -8
- package/dist/actors/computer-use/loop/types.d.ts +25 -23
- package/dist/actors/computer-use/loop/usage.js +2 -2
- package/dist/actors/computer-use/openai-context.d.ts +37 -0
- package/dist/actors/computer-use/openai-context.js +214 -0
- package/dist/actors/computer-use/openai-provider.d.ts +11 -8
- package/dist/actors/computer-use/openai-provider.js +45 -34
- package/dist/actors/computer-use/openai-requests.d.ts +36 -10
- package/dist/actors/computer-use/openai-requests.js +82 -15
- package/dist/actors/computer-use/openai-wire.d.ts +19 -7
- package/dist/actors/computer-use/openai-wire.js +36 -34
- package/dist/actors/contract.d.ts +78 -43
- package/dist/actors/contract.js +29 -23
- package/dist/actors/local-agent/claude-session.d.ts +1 -1
- package/dist/actors/local-agent/claude-session.js +10 -9
- package/dist/actors/local-agent/cli.d.ts +8 -6
- package/dist/actors/local-agent/cli.js +24 -28
- package/dist/actors/local-agent/readiness.d.ts +2 -2
- package/dist/actors/local-agent/readiness.js +4 -4
- package/dist/actors/reasoning-effort.js +6 -6
- package/dist/actors/registry.d.ts +10 -10
- package/dist/actors/registry.js +18 -17
- package/dist/actors/scripted-browser/actor.d.ts +8 -8
- package/dist/actors/scripted-browser/actor.js +16 -16
- package/dist/actors/scripted-browser/browser-command.js +1 -1
- package/dist/actors/scripted-browser/steps.js +1 -1
- package/dist/actors/scripted-browser/types.d.ts +1 -1
- package/dist/actors/stop-conditions.d.ts +1 -1
- package/dist/analysis/codex-config.d.ts +6 -2
- package/dist/analysis/codex-config.js +22 -14
- package/dist/analysis/service.js +5 -5
- package/dist/cli/commands/analyze.js +19 -16
- package/dist/cli/commands/codex.js +9 -9
- package/dist/cli/commands/comms.js +54 -33
- package/dist/cli/commands/feedback.js +20 -21
- package/dist/cli/commands/lab-format.d.ts +5 -4
- package/dist/cli/commands/lab-format.js +35 -23
- package/dist/cli/commands/lab-route-computer-use.js +6 -7
- package/dist/cli/commands/lab-route-preview.js +4 -3
- package/dist/cli/commands/lab-route-shared-world.js +3 -3
- package/dist/cli/commands/lab-run.js +10 -11
- package/dist/cli/commands/lab-scorer.d.ts +2 -2
- package/dist/cli/commands/lab-scorer.js +1 -1
- package/dist/cli/commands/migrate.d.ts +4 -0
- package/dist/cli/commands/migrate.js +65 -0
- package/dist/cli/commands/observe.js +147 -108
- package/dist/cli/commands/run-command.d.ts +10 -0
- package/dist/cli/commands/run-command.js +85 -0
- package/dist/cli/commands/runs.js +137 -138
- package/dist/cli/commands/setup.d.ts +2 -2
- package/dist/cli/commands/setup.js +26 -21
- package/dist/cli/commands/study.d.ts +3 -0
- package/dist/cli/commands/study.js +182 -0
- package/dist/cli/commands/tui.d.ts +4 -4
- package/dist/cli/commands/tui.js +21 -21
- package/dist/cli/commands/watch.js +60 -75
- package/dist/cli/deprecations.d.ts +18 -0
- package/dist/cli/deprecations.js +48 -0
- package/dist/cli/doctor.d.ts +15 -5
- package/dist/cli/doctor.js +103 -48
- package/dist/cli/first-run-path.d.ts +12 -10
- package/dist/cli/first-run-path.js +30 -28
- package/dist/cli/io.d.ts +41 -6
- package/dist/cli/io.js +97 -22
- package/dist/cli/observer-follow.d.ts +2 -2
- package/dist/cli/observer-follow.js +5 -6
- package/dist/cli/orientation.d.ts +6 -3
- package/dist/cli/orientation.js +43 -39
- package/dist/cli/product-sentence.d.ts +6 -0
- package/dist/cli/product-sentence.js +6 -0
- package/dist/cli/program.d.ts +6 -1
- package/dist/cli/program.js +109 -40
- package/dist/cli/telemetry.d.ts +15 -15
- package/dist/cli/telemetry.js +48 -40
- package/dist/cli.js +1 -1
- package/dist/comms/capture-surface.d.ts +13 -12
- package/dist/comms/capture-surface.js +23 -22
- package/dist/comms/catch-host.d.ts +7 -7
- package/dist/comms/catch-host.js +14 -14
- package/dist/comms/email-catch.d.ts +3 -3
- package/dist/comms/email-catch.js +8 -8
- package/dist/comms/external-evidence.js +2 -2
- package/dist/comms/extract.js +2 -2
- package/dist/comms/fake-inbox.d.ts +2 -2
- package/dist/comms/fake-inbox.js +2 -2
- package/dist/comms/receiving-render.d.ts +1 -1
- package/dist/comms/receiving-render.js +2 -2
- package/dist/comms/sandbox-catch-script.d.ts +6 -6
- package/dist/comms/sandbox-catch-script.js +6 -6
- package/dist/comms/sandbox-catch.d.ts +36 -37
- package/dist/comms/sandbox-catch.js +34 -35
- package/dist/comms/setup.js +42 -8
- package/dist/comms/thread-evidence.d.ts +1 -1
- package/dist/comms/thread-evidence.js +6 -6
- package/dist/comms/types.d.ts +6 -6
- package/dist/comms/types.js +3 -3
- package/dist/evidence/frame-signature.d.ts +1 -1
- package/dist/evidence/frame-signature.js +4 -4
- package/dist/evidence/redaction.d.ts +3 -3
- package/dist/evidence/redaction.js +4 -4
- package/dist/feedback/draft.js +36 -78
- package/dist/feedback/export-bundle.js +1 -1
- package/dist/feedback/export.d.ts +5 -1
- package/dist/feedback/export.js +7 -8
- package/dist/feedback/feedback.d.ts +2 -2
- package/dist/feedback/feedback.js +21 -3
- package/dist/guest/chromium-text.js +2 -2
- package/dist/guest/desktop-native.d.ts +1 -1
- package/dist/guest/runtime.js +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +8 -6
- package/dist/keys/key-resolution.d.ts +5 -5
- package/dist/keys/key-resolution.js +23 -23
- package/dist/lab/adapter-extension.d.ts +7 -7
- package/dist/lab/adapter-extension.js +13 -36
- package/dist/lab/adapter-scorer-loader.d.ts +7 -7
- package/dist/lab/adapter-scorer-loader.js +32 -32
- package/dist/lab/composition-rules.js +42 -42
- package/dist/lab/config.js +65 -25
- package/dist/lab/deprecated-fields.d.ts +10 -0
- package/dist/lab/deprecated-fields.js +24 -0
- package/dist/lab/device-presets.d.ts +8 -8
- package/dist/lab/device-presets.js +11 -11
- package/dist/lab/discover.d.ts +13 -9
- package/dist/lab/discover.js +117 -57
- package/dist/lab/doctor.d.ts +10 -3
- package/dist/lab/doctor.js +47 -9
- package/dist/lab/init-templates.js +147 -147
- package/dist/lab/init.d.ts +1 -1
- package/dist/lab/init.js +41 -9
- package/dist/lab/keys.d.ts +2 -0
- package/dist/lab/keys.js +42 -8
- package/dist/lab/lab-deps.d.ts +7 -12
- package/dist/lab/parse/actors.js +9 -9
- package/dist/lab/parse/comms.js +5 -5
- package/dist/lab/parse/execution.js +13 -13
- package/dist/lab/parse/study-v3.d.ts +23 -0
- package/dist/lab/parse/study-v3.js +259 -0
- package/dist/lab/parse/subject-state.d.ts +7 -7
- package/dist/lab/parse/subject-state.js +16 -16
- package/dist/lab/parse/subject.js +28 -28
- package/dist/lab/parse/values.d.ts +1 -1
- package/dist/lab/parse/values.js +3 -3
- package/dist/lab/persona-resolve.d.ts +4 -4
- package/dist/lab/persona-resolve.js +4 -4
- package/dist/lab/plan-participants.d.ts +2 -2
- package/dist/lab/plan-types.d.ts +4 -4
- package/dist/lab/plan.d.ts +1 -7
- package/dist/lab/plan.js +10 -41
- package/dist/lab/preflight-probes.js +11 -11
- package/dist/lab/preflight-result.d.ts +2 -1
- package/dist/lab/preflight-result.js +5 -4
- package/dist/lab/preflight.d.ts +7 -5
- package/dist/lab/preflight.js +5 -5
- package/dist/lab/routing.d.ts +31 -25
- package/dist/lab/routing.js +60 -29
- package/dist/lab/run-lab-events.d.ts +0 -3
- package/dist/lab/run-lab-events.js +0 -6
- package/dist/lab/run-lab-homes.d.ts +22 -10
- package/dist/lab/run-lab-homes.js +5 -1
- package/dist/lab/run-lab-options.d.ts +1 -1
- package/dist/lab/run-lab-options.js +16 -13
- package/dist/lab/summary.d.ts +7 -6
- package/dist/lab/summary.js +10 -10
- package/dist/lab/tasks.d.ts +15 -15
- package/dist/lab/tasks.js +14 -14
- package/dist/lab/types.d.ts +101 -95
- package/dist/lab/types.js +2 -0
- package/dist/lab/validation.d.ts +13 -13
- package/dist/lab/validation.js +44 -42
- package/dist/lab/warnings.d.ts +10 -0
- package/dist/lab/warnings.js +61 -33
- package/dist/library-aliases.d.ts +56 -0
- package/dist/library-aliases.js +22 -0
- package/dist/observer/artifact.d.ts +1 -1
- package/dist/observer/artifact.js +6 -6
- package/dist/observer/data.d.ts +6 -6
- package/dist/observer/data.js +5 -4
- package/dist/observer/exposure.d.ts +1 -1
- package/dist/observer/exposure.js +11 -11
- package/dist/observer/http.js +1 -1
- package/dist/observer/library.d.ts +1 -1
- package/dist/observer/library.js +4 -2
- package/dist/observer/listen.js +5 -4
- package/dist/observer/render.d.ts +1 -1
- package/dist/observer/render.js +10 -5
- package/dist/observer/run-routes.d.ts +3 -3
- package/dist/observer/run-routes.js +1 -1
- package/dist/observer/serve.js +7 -3
- package/dist/observer/tunnel.js +1 -1
- package/dist/observer-app.html +4 -4
- package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
- package/dist/routes/computer-use/bundle-parts.js +15 -15
- package/dist/routes/computer-use/bundle.js +3 -3
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/comms.js +14 -14
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +4 -3
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
- package/dist/routes/computer-use/e2b-desktop/prepare.js +7 -7
- package/dist/routes/computer-use/e2b-desktop/start.js +9 -8
- package/dist/routes/computer-use/e2b-desktop/teardown.js +5 -4
- package/dist/routes/computer-use/external-comms.d.ts +1 -1
- package/dist/routes/computer-use/external-comms.js +1 -1
- package/dist/routes/computer-use/fanout-bundle.js +18 -18
- package/dist/routes/computer-use/fanout-records.js +10 -11
- package/dist/routes/computer-use/live-flush.d.ts +1 -1
- package/dist/routes/computer-use/live-flush.js +6 -6
- package/dist/routes/computer-use/live-phase.d.ts +4 -2
- package/dist/routes/computer-use/live-phase.js +6 -6
- package/dist/routes/computer-use/local-vm.js +1 -1
- package/dist/routes/computer-use/participant-desktop.d.ts +4 -4
- package/dist/routes/computer-use/participant-desktop.js +4 -4
- package/dist/routes/computer-use/participant-execution.d.ts +4 -4
- package/dist/routes/computer-use/participant-execution.js +9 -9
- package/dist/routes/computer-use/participant-model.d.ts +6 -0
- package/dist/routes/computer-use/participant-model.js +31 -13
- package/dist/routes/computer-use/participant-prompt.d.ts +11 -11
- package/dist/routes/computer-use/participant-prompt.js +6 -6
- package/dist/routes/computer-use/participant-runs.d.ts +7 -7
- package/dist/routes/computer-use/participant-runs.js +13 -13
- package/dist/routes/computer-use/plan.js +22 -22
- package/dist/routes/computer-use/preflight.js +21 -21
- package/dist/routes/computer-use/rerun-selection.js +1 -1
- package/dist/routes/computer-use/result.js +11 -11
- package/dist/routes/computer-use/route.d.ts +2 -1
- package/dist/routes/computer-use/route.js +15 -14
- package/dist/routes/computer-use/self-report.d.ts +7 -7
- package/dist/routes/computer-use/self-report.js +31 -31
- package/dist/routes/computer-use/setup.d.ts +1 -1
- package/dist/routes/computer-use/setup.js +17 -18
- package/dist/routes/computer-use/single-bundle.d.ts +7 -7
- package/dist/routes/computer-use/single-bundle.js +28 -30
- package/dist/routes/computer-use/subject-projection.d.ts +1 -1
- package/dist/routes/computer-use/subject-projection.js +6 -6
- package/dist/routes/computer-use/types.d.ts +40 -42
- package/dist/routes/computer-use/types.js +10 -10
- package/dist/routes/preview.d.ts +8 -2
- package/dist/routes/preview.js +8 -4
- package/dist/routes/scripted/bundle.d.ts +2 -2
- package/dist/routes/scripted/bundle.js +13 -12
- package/dist/routes/scripted/plan.d.ts +1 -1
- package/dist/routes/scripted/plan.js +9 -9
- package/dist/routes/scripted/result.js +5 -5
- package/dist/routes/scripted/route.js +5 -6
- package/dist/routes/scripted/scenario.js +2 -2
- package/dist/routes/scripted/setup.js +7 -7
- package/dist/routes/scripted/subject.js +1 -1
- package/dist/routes/scripted/surface-records.js +3 -3
- package/dist/routes/scripted/types.d.ts +3 -5
- package/dist/routes/scripted/types.js +1 -1
- package/dist/routes/shared-world/bundle-records.js +9 -8
- package/dist/routes/shared-world/bundle.d.ts +5 -5
- package/dist/routes/shared-world/bundle.js +40 -38
- package/dist/routes/shared-world/checkpoints.d.ts +1 -1
- package/dist/routes/shared-world/checkpoints.js +1 -1
- package/dist/routes/shared-world/comms.d.ts +5 -5
- package/dist/routes/shared-world/comms.js +14 -14
- package/dist/routes/shared-world/external-public.d.ts +4 -3
- package/dist/routes/shared-world/external-public.js +16 -12
- package/dist/routes/shared-world/handoff.d.ts +7 -6
- package/dist/routes/shared-world/handoff.js +65 -57
- package/dist/routes/shared-world/lobby-code.d.ts +2 -2
- package/dist/routes/shared-world/lobby-code.js +9 -9
- package/dist/routes/shared-world/participant-specs.d.ts +7 -6
- package/dist/routes/shared-world/participant-specs.js +31 -24
- package/dist/routes/shared-world/plan.js +7 -7
- package/dist/routes/shared-world/provenance.d.ts +2 -2
- package/dist/routes/shared-world/provenance.js +2 -2
- package/dist/routes/shared-world/provisioned.js +14 -13
- package/dist/routes/shared-world/result.js +20 -21
- package/dist/routes/shared-world/route.js +23 -22
- package/dist/routes/shared-world/setup.d.ts +3 -3
- package/dist/routes/shared-world/setup.js +4 -4
- package/dist/routes/shared-world/types.d.ts +30 -28
- package/dist/routes/shared-world/types.js +4 -4
- package/dist/routes/terminal/adapter.d.ts +3 -3
- package/dist/routes/terminal/adapter.js +5 -5
- package/dist/routes/terminal/bundle.d.ts +3 -3
- package/dist/routes/terminal/bundle.js +22 -21
- package/dist/routes/terminal/credentials.d.ts +4 -4
- package/dist/routes/terminal/credentials.js +7 -7
- package/dist/routes/terminal/dry-run.js +4 -4
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +3 -3
- package/dist/routes/terminal/ledger.js +14 -14
- package/dist/routes/terminal/live-finish.js +3 -3
- package/dist/routes/terminal/live-sandbox.js +12 -13
- package/dist/routes/terminal/persona.js +1 -1
- package/dist/routes/terminal/plan.js +11 -11
- package/dist/routes/terminal/recorder.js +2 -2
- package/dist/routes/terminal/result.js +8 -8
- package/dist/routes/terminal/route.js +6 -7
- package/dist/routes/terminal/sandbox.d.ts +1 -1
- package/dist/routes/terminal/sandbox.js +1 -1
- package/dist/routes/terminal/session.js +8 -7
- package/dist/routes/terminal/token-usage.d.ts +1 -1
- package/dist/routes/terminal/token-usage.js +7 -8
- package/dist/routes/terminal/trace.d.ts +2 -2
- package/dist/routes/terminal/trace.js +2 -2
- package/dist/routes/terminal/types.d.ts +26 -28
- package/dist/routes/terminal/types.js +3 -3
- package/dist/run/bundle-shape.js +3 -3
- package/dist/run/bundle.d.ts +46 -46
- package/dist/run/bundle.js +2 -1
- package/dist/run/cost-summary.js +3 -3
- package/dist/run/costs.js +7 -1
- package/dist/run/detail.d.ts +6 -6
- package/dist/run/detail.js +4 -4
- package/dist/run/dry-run-inputs.js +1 -1
- package/dist/run/dry-run.js +18 -18
- package/dist/run/judge.d.ts +19 -13
- package/dist/run/judge.js +18 -8
- package/dist/run/paths.d.ts +1 -1
- package/dist/run/paths.js +1 -1
- package/dist/run/pricing.d.ts +11 -6
- package/dist/run/pricing.js +20 -13
- package/dist/run/projection.d.ts +14 -14
- package/dist/run/projection.js +15 -15
- package/dist/run/reclaim.js +2 -2
- package/dist/run/results.d.ts +5 -5
- package/dist/run/run-index.d.ts +8 -6
- package/dist/run/run-index.js +15 -16
- package/dist/run/run-not-found.d.ts +5 -0
- package/dist/run/run-not-found.js +15 -0
- package/dist/run/run.d.ts +5 -4
- package/dist/run/run.js +1 -1
- package/dist/run/sandbox-receipts.d.ts +2 -2
- package/dist/run/sandbox-receipts.js +3 -3
- package/dist/run/shared-world-evidence.d.ts +36 -35
- package/dist/run/shared-world-evidence.js +4 -4
- package/dist/run/shared-world-shape.d.ts +1 -1
- package/dist/run/shared-world-shape.js +6 -6
- package/dist/run/stats.d.ts +12 -6
- package/dist/run/stats.js +116 -58
- package/dist/run/status.d.ts +8 -29
- package/dist/run/status.js +5 -27
- package/dist/run/stored-runs.js +2 -1
- package/dist/run/stream-shape.js +1 -1
- package/dist/run/streams.d.ts +6 -6
- package/dist/run/study-provenance.d.ts +47 -0
- package/dist/run/study-provenance.js +63 -0
- package/dist/run/study-result.d.ts +16 -0
- package/dist/run/study-result.js +9 -0
- package/dist/run/text.d.ts +2 -0
- package/dist/run/text.js +4 -0
- package/dist/run-lab.d.ts +7 -7
- package/dist/run-lab.js +1 -3
- package/dist/study/convert.d.ts +33 -0
- package/dist/study/convert.js +432 -0
- package/dist/study/field-paths.d.ts +12 -0
- package/dist/study/field-paths.js +126 -0
- package/dist/study/files.d.ts +26 -0
- package/dist/study/files.js +43 -0
- package/dist/study/migrate.d.ts +48 -0
- package/dist/study/migrate.js +408 -0
- package/dist/study/owned-files.d.ts +38 -0
- package/dist/study/owned-files.js +182 -0
- package/dist/subject/clone.d.ts +1 -1
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +2 -2
- package/dist/subject/local-tree-archive.js +1 -1
- package/dist/subject/local-tree.d.ts +1 -1
- package/dist/subject/node-bootstrap.js +1 -1
- package/dist/subject/runtime.js +8 -9
- package/dist/subject/serve.d.ts +1 -1
- package/dist/subject/serve.js +3 -3
- package/dist/subject/state.d.ts +1 -1
- package/dist/subject/steps.d.ts +5 -5
- package/dist/subject/steps.js +4 -4
- package/dist/substrates/command-failure.d.ts +3 -3
- package/dist/substrates/command-failure.js +3 -3
- package/dist/substrates/detached.d.ts +6 -6
- package/dist/substrates/detached.js +7 -7
- package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
- package/dist/substrates/e2b/cdp-probe.js +14 -17
- package/dist/substrates/e2b/desktop-browser.d.ts +2 -2
- package/dist/substrates/e2b/desktop-browser.js +8 -8
- package/dist/substrates/e2b/desktop-cdp.d.ts +9 -9
- package/dist/substrates/e2b/desktop-cdp.js +8 -8
- package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
- package/dist/substrates/e2b/desktop-executor.js +1 -1
- package/dist/substrates/e2b/desktop-geometry.d.ts +3 -3
- package/dist/substrates/e2b/desktop-geometry.js +7 -7
- package/dist/substrates/e2b/desktop-media.d.ts +1 -1
- package/dist/substrates/e2b/desktop-media.js +1 -1
- package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
- package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
- package/dist/substrates/e2b/sandbox.d.ts +1 -1
- package/dist/substrates/e2b/sandbox.js +1 -1
- package/dist/substrates/e2b/sdk.d.ts +11 -11
- package/dist/substrates/e2b/sdk.js +6 -6
- package/dist/tui/actions.d.ts +1 -1
- package/dist/tui/actions.js +13 -13
- package/dist/tui/contract.d.ts +16 -16
- package/dist/tui/contract.js +10 -10
- package/dist/tui/launch.d.ts +4 -4
- package/dist/tui/launch.js +18 -19
- package/dist/tui/project.js +5 -5
- package/dist/tui-app.js +82 -82
- package/dist/verify/actor.d.ts +8 -8
- package/dist/verify/actor.js +36 -36
- package/dist/verify/artifacts.d.ts +2 -2
- package/dist/verify/artifacts.js +3 -3
- package/dist/verify/context-growth.d.ts +9 -0
- package/dist/verify/context-growth.js +62 -0
- package/dist/verify/costs.d.ts +6 -6
- package/dist/verify/costs.js +8 -8
- package/dist/verify/shared-world-concurrent.d.ts +2 -2
- package/dist/verify/shared-world-concurrent.js +79 -76
- package/dist/verify/shared-world.d.ts +2 -2
- package/dist/verify/shared-world.js +16 -16
- package/dist/verify/subject.d.ts +4 -4
- package/dist/verify/subject.js +18 -18
- package/dist/verify/verify.js +92 -43
- package/docs/README.md +25 -32
- package/docs/architecture/actor-contract.md +56 -87
- package/docs/architecture/desktop-sessions.md +7 -7
- package/docs/architecture/external-public-shared-world.md +61 -59
- package/docs/architecture/github-feedback-loop.md +1 -4
- package/docs/architecture/guest-desktop.md +2 -2
- package/docs/architecture/observer.md +34 -34
- package/docs/architecture/restricted-codex-analysis.md +34 -28
- package/docs/architecture/serve.md +34 -37
- package/docs/architecture/state-driven-executor.md +55 -58
- package/docs/architecture/task-protocol-support.md +5 -5
- package/docs/architecture/terminal-product-route.md +67 -107
- package/docs/contracts/README.md +24 -0
- package/docs/contracts/adapter-admission.md +3 -3
- package/docs/contracts/adapter-fixtures.md +2 -5
- package/docs/contracts/core.md +1 -3
- package/docs/contracts/errors.md +62 -0
- package/docs/contracts/feedback.md +8 -9
- package/docs/contracts/policy.md +7 -12
- package/docs/contracts/run-bundle.md +45 -44
- package/docs/contracts/schemas.md +421 -362
- package/docs/contracts/study-analysis.md +3 -3
- package/docs/contracts/study-costs.md +11 -7
- package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
- package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
- package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
- package/docs/principles/actor-fidelity.md +4 -4
- package/docs/principles/engineering.md +3 -3
- package/docs/principles/invariants-and-defaults.md +38 -38
- package/docs/principles/self-driving-harness.md +1 -5
- package/docs/principles/three-roles.md +1 -1
- package/docs/product/automatic-analysis.md +7 -7
- package/examples/participant/README.md +5 -5
- package/examples/participant/run.mjs +11 -10
- package/examples/scorer/README.md +3 -3
- package/examples/scorer/run.mjs +11 -12
- package/package.json +16 -17
- package/skills/humanish/SKILL.md +60 -58
- package/skills/humanish/agents/openai.yaml +1 -1
- package/AGENTS.md +0 -99
- package/CONTRIBUTING.md +0 -148
- package/dist/actors/codex/qualified-versions.d.ts +0 -72
- package/dist/actors/codex/qualified-versions.js +0 -132
- package/dist/cli/commands/lab.d.ts +0 -3
- package/dist/cli/commands/lab.js +0 -199
- package/dist/cli/renamed-options.d.ts +0 -11
- package/dist/cli/renamed-options.js +0 -18
- package/dist/observer/static.d.ts +0 -39
- package/dist/observer/static.js +0 -369
- package/docs/architecture/comms-inbox.md +0 -122
- package/docs/architecture/desktop-recording.md +0 -80
- package/docs/architecture/local-browser-runtime.md +0 -178
- package/docs/architecture/observer-review.md +0 -144
- package/docs/architecture/participant-media.md +0 -90
- package/docs/architecture/project-layout.md +0 -62
- package/docs/architecture/real-email-receiving.md +0 -136
- package/docs/assets/humanish-drawdb-hero.png +0 -0
- package/docs/assets/humanish-observer-hero.png +0 -0
- package/docs/goals/current.md +0 -207
- package/docs/product/lobby-trivia-3player-external-public.md +0 -77
- package/docs/product/open-source-install-experience.md +0 -240
- package/docs/ramp/README.md +0 -295
- package/docs/release/open-source-readiness.md +0 -222
- package/docs/release/public-readiness-standard.md +0 -210
- package/docs/roadmap/world-class-open-source-v0.md +0 -311
|
@@ -5,16 +5,16 @@ import { type CuaSubjectProvenanceArg, type ParticipantRunOutcome } from "./type
|
|
|
5
5
|
/** The human-readable state story appended to the provenance event (and review.md via it). */
|
|
6
6
|
export declare function describeSubjectState(state: RunSubjectProvenance["state"], dryRun: boolean): string;
|
|
7
7
|
/**
|
|
8
|
-
* Feedback candidates derived from what
|
|
8
|
+
* Feedback candidates derived from what live participants actually reported.
|
|
9
9
|
*
|
|
10
|
-
* A live run's feedback draft
|
|
11
|
-
*
|
|
10
|
+
* A live run's feedback draft comes from these candidates, never from a dry-run template. The
|
|
11
|
+
* candidate worth filing is the one the study produced: a participant
|
|
12
12
|
* who reported friction on the way (the most valuable thing a run captures), or one who stopped
|
|
13
|
-
* trying. A clean pass files nothing here
|
|
14
|
-
* any falls back to
|
|
13
|
+
* trying. A clean pass files nothing here: feedback exists to carry findings, and a run without
|
|
14
|
+
* any falls back to a live summary in the draft layer instead of a template.
|
|
15
15
|
*
|
|
16
|
-
* Everything quoted is already scrub+redacted
|
|
17
|
-
* through redactNarration in the loop
|
|
16
|
+
* Everything quoted is already scrub+redacted (participant messages and `session.reason` pass
|
|
17
|
+
* through redactNarration in the loop) and passes redactText again here as defense-in-depth.
|
|
18
18
|
*/
|
|
19
19
|
export declare function participantFeedbackCandidates(args: {
|
|
20
20
|
runId: string;
|
|
@@ -34,8 +34,8 @@ export declare function participantFeedbackCandidates(args: {
|
|
|
34
34
|
commsArtifactPath?: string;
|
|
35
35
|
}>;
|
|
36
36
|
}): RunFeedbackCandidate[];
|
|
37
|
-
/** Human-readable provenance line for the single-participant subject.provenance event
|
|
38
|
-
* claims "cloned/packed and served"
|
|
37
|
+
/** Human-readable provenance line for the single-participant subject.provenance event:
|
|
38
|
+
* claims "cloned/packed and served" only when it actually happened. */
|
|
39
39
|
export declare function subjectProvenanceMessage(provenance: CuaSubjectProvenanceArg, publicAppUrl: string, dryRun: boolean, hasSession: boolean): string;
|
|
40
40
|
export declare function providerResourcesForOutcome(args: {
|
|
41
41
|
outcome: ParticipantRunOutcome | undefined;
|
|
@@ -14,9 +14,9 @@ export function describeSubjectState(state, dryRun) {
|
|
|
14
14
|
case "seeded":
|
|
15
15
|
return `seeded (${state.seed?.length ?? 0} step(s): ${(state.seed ?? []).map((record) => record.name).join(", ")})`;
|
|
16
16
|
case "unpinned":
|
|
17
|
-
return `
|
|
17
|
+
return `unpinned (external: ${(state.externalEnvNames ?? []).join(", ")})`;
|
|
18
18
|
case "declared-not-run":
|
|
19
|
-
return `declared, not run (${dryRun ? "dry
|
|
19
|
+
return `declared, not run (${dryRun ? "dry run" : "provisioning did not complete"})`;
|
|
20
20
|
case "undeclared":
|
|
21
21
|
return "undeclared";
|
|
22
22
|
case "external-public":
|
|
@@ -24,16 +24,16 @@ export function describeSubjectState(state, dryRun) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Feedback candidates derived from what
|
|
27
|
+
* Feedback candidates derived from what live participants actually reported.
|
|
28
28
|
*
|
|
29
|
-
* A live run's feedback draft
|
|
30
|
-
*
|
|
29
|
+
* A live run's feedback draft comes from these candidates, never from a dry-run template. The
|
|
30
|
+
* candidate worth filing is the one the study produced: a participant
|
|
31
31
|
* who reported friction on the way (the most valuable thing a run captures), or one who stopped
|
|
32
|
-
* trying. A clean pass files nothing here
|
|
33
|
-
* any falls back to
|
|
32
|
+
* trying. A clean pass files nothing here: feedback exists to carry findings, and a run without
|
|
33
|
+
* any falls back to a live summary in the draft layer instead of a template.
|
|
34
34
|
*
|
|
35
|
-
* Everything quoted is already scrub+redacted
|
|
36
|
-
* through redactNarration in the loop
|
|
35
|
+
* Everything quoted is already scrub+redacted (participant messages and `session.reason` pass
|
|
36
|
+
* through redactNarration in the loop) and passes redactText again here as defense-in-depth.
|
|
37
37
|
*/
|
|
38
38
|
export function participantFeedbackCandidates(args) {
|
|
39
39
|
const candidates = [];
|
|
@@ -59,8 +59,8 @@ export function participantFeedbackCandidates(args) {
|
|
|
59
59
|
persona_id: participant.personaId,
|
|
60
60
|
actor: "computer-use",
|
|
61
61
|
substrate: args.substrate,
|
|
62
|
-
// The participant is reporting on the
|
|
63
|
-
// findings by the three-roles rule. A harness failure never reaches this builder
|
|
62
|
+
// The participant is reporting on the product: friction and abandonment are target-app
|
|
63
|
+
// findings by the three-roles rule. A harness failure never reaches this builder; it is
|
|
64
64
|
// not a participant report.
|
|
65
65
|
failure_owner: "target-app",
|
|
66
66
|
summary,
|
|
@@ -109,12 +109,12 @@ export function participantFeedbackCandidates(args) {
|
|
|
109
109
|
}
|
|
110
110
|
return candidates;
|
|
111
111
|
}
|
|
112
|
-
/** Human-readable provenance line for the single-participant subject.provenance event
|
|
113
|
-
* claims "cloned/packed and served"
|
|
112
|
+
/** Human-readable provenance line for the single-participant subject.provenance event:
|
|
113
|
+
* claims "cloned/packed and served" only when it actually happened. */
|
|
114
114
|
export function subjectProvenanceMessage(provenance, publicAppUrl, dryRun, hasSession) {
|
|
115
115
|
if (provenance.source === "clone") {
|
|
116
116
|
if (dryRun) {
|
|
117
|
-
return `Subject declared: clone of ${provenance.repo}, to be served at ${publicAppUrl} in-sandbox (dry
|
|
117
|
+
return `Subject declared: clone of ${provenance.repo}, to be served at ${publicAppUrl} in-sandbox (dry run; nothing cloned)`;
|
|
118
118
|
}
|
|
119
119
|
if (provenance.commit) {
|
|
120
120
|
return hasSession
|
|
@@ -124,7 +124,7 @@ export function subjectProvenanceMessage(provenance, publicAppUrl, dryRun, hasSe
|
|
|
124
124
|
return `Subject clone attempted from ${provenance.repo}; commit unresolved (provisioning failed before resolution)`;
|
|
125
125
|
}
|
|
126
126
|
if (dryRun) {
|
|
127
|
-
return `Subject declared: local working tree, to be packed and served at ${publicAppUrl} in-sandbox (dry
|
|
127
|
+
return `Subject declared: local working tree, to be packed and served at ${publicAppUrl} in-sandbox (dry run; nothing packed)`;
|
|
128
128
|
}
|
|
129
129
|
if (provenance.archiveSha256) {
|
|
130
130
|
const dirtyLabel = provenance.dirty === true
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// and buildCuaRunBundle sends it to the single-participant or the fan-out builder with that
|
|
3
3
|
// shape's arguments. renderCuaReviewMarkdown writes review.md. shared-world/bundle.ts holds the
|
|
4
4
|
// same for that route.
|
|
5
|
-
import { judgeOneParticipant, judgeParticipants } from "../../run/judge.js";
|
|
5
|
+
import { judgeOneParticipant, judgeParticipants, verdictText, } from "../../run/judge.js";
|
|
6
6
|
import { desktopSpanToMinutes } from "../../run/cost-summary.js";
|
|
7
7
|
import { e2bDesktopTemplate } from "../../substrates/e2b/sandbox.js";
|
|
8
8
|
import { providerResourcesForOutcome } from "./bundle-parts.js";
|
|
@@ -157,13 +157,13 @@ export function renderCuaReviewMarkdown(bundle) {
|
|
|
157
157
|
"",
|
|
158
158
|
`- run: ${bundle.runId}`,
|
|
159
159
|
`- mode: ${bundle.mode}`,
|
|
160
|
-
`- run gate: ${bundle.review.verdict}`,
|
|
160
|
+
`- run gate: ${verdictText(bundle.review.verdict, bundle.mode)}`,
|
|
161
161
|
`- summary: ${bundle.review.summary}`,
|
|
162
162
|
...(provenance ? [`- subject: ${provenance.message}`] : []),
|
|
163
163
|
...(trace
|
|
164
164
|
? [
|
|
165
165
|
`- actor: ${trace.provider} (${trace.lane}/${trace.protocol})`,
|
|
166
|
-
//
|
|
166
|
+
// Name the trace's actual screenshot mode ("raw" | "blurred"); say
|
|
167
167
|
// nothing when no frames exist ("n/a") rather than claim a redaction that never ran.
|
|
168
168
|
`- evidence: ${trace.items.length} trace item(s), ${trace.counts.screenshots ?? 0} ${trace.redaction.screenshots === "raw" || trace.redaction.screenshots === "blurred"
|
|
169
169
|
? `${trace.redaction.screenshots} screenshot(s)`
|
|
@@ -19,7 +19,7 @@ export interface ParticipantComms {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* On an in-sandbox subject route, redirect the app's email-API sends into an in-sandbox catch
|
|
22
|
-
* (loopback) so its verification mail is
|
|
22
|
+
* (loopback) so its verification mail is captured instead of sent to the internet. Undefined when the
|
|
23
23
|
* lab declares no fake email, which leaves the participant unchanged.
|
|
24
24
|
*/
|
|
25
25
|
export declare function planParticipantComms(comms: LabConfig["comms"], serveUrl: string | undefined, targetUrl: string, inSandboxSubject: boolean): ParticipantComms | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Off-app email for one E2B desktop participant
|
|
1
|
+
// Off-app email for one E2B desktop participant: the in-sandbox catch the subject app sends to, the
|
|
2
2
|
// persona's inbox surface, the real-email receiving surface, and the evidence drained at teardown.
|
|
3
3
|
import { setTimeout as delay } from "node:timers/promises";
|
|
4
4
|
import { buildOriginMap } from "../../../comms/capture-surface.js";
|
|
@@ -15,7 +15,7 @@ import { addressedRecipients } from "../../../lab/parse/comms.js";
|
|
|
15
15
|
const INBOX_SURFACE_CADENCE_MS = 2500;
|
|
16
16
|
/**
|
|
17
17
|
* On an in-sandbox subject route, redirect the app's email-API sends into an in-sandbox catch
|
|
18
|
-
* (loopback) so its verification mail is
|
|
18
|
+
* (loopback) so its verification mail is captured instead of sent to the internet. Undefined when the
|
|
19
19
|
* lab declares no fake email, which leaves the participant unchanged.
|
|
20
20
|
*/
|
|
21
21
|
export function planParticipantComms(comms, serveUrl, targetUrl, inSandboxSubject) {
|
|
@@ -42,7 +42,7 @@ export function planParticipantComms(comms, serveUrl, targetUrl, inSandboxSubjec
|
|
|
42
42
|
export function participantCommsEnv(comms) {
|
|
43
43
|
if (comms === undefined)
|
|
44
44
|
return {};
|
|
45
|
-
// injectEnv is absent on an adopter-hosted plane
|
|
45
|
+
// injectEnv is absent on an adopter-hosted plane: there is no subject env to inject
|
|
46
46
|
// because the operator points their own app at their own catch.
|
|
47
47
|
const env = comms.email.injectEnv === undefined
|
|
48
48
|
? {}
|
|
@@ -75,23 +75,23 @@ export async function startCommsCatch(shell, comms, requestTimeoutMs) {
|
|
|
75
75
|
if (!deployed.ready) {
|
|
76
76
|
throw new Error(`comms email catch did not become ready on 127.0.0.1:${comms.port} in the subject sandbox`);
|
|
77
77
|
}
|
|
78
|
-
// Write the
|
|
79
|
-
// yet." page
|
|
78
|
+
// Write the empty inbox once up front so the persona's /inbox always resolves to the "No messages
|
|
79
|
+
// yet." page (never a bare 404) the instant it navigates there, even before any mail arrives or if
|
|
80
80
|
// the app sends to an address no declared recipient matches (the loop only re-renders on new mail).
|
|
81
81
|
await writeInboxSurface(shell, deployed.surfaceDir, [], {
|
|
82
82
|
originMap: comms.originMap,
|
|
83
83
|
requestTimeoutMs,
|
|
84
84
|
});
|
|
85
|
-
// The surface uses its
|
|
86
|
-
// readers of the append-only NDJSON
|
|
85
|
+
// The surface uses its own FakeInbox + cursor, independent of the teardown evidence drain (two
|
|
86
|
+
// readers of the append-only NDJSON, so no double-count).
|
|
87
87
|
const stop = new AbortController();
|
|
88
88
|
let renderedCount = 0;
|
|
89
89
|
const loop = (async () => {
|
|
90
90
|
// Render-first (so even a short session gets a populated inbox), then refresh on a cadence. The
|
|
91
|
-
// cadence uses a
|
|
91
|
+
// cadence uses a real timer instead of the injected instant clock: this loop is unbounded, so an instant
|
|
92
92
|
// sleep would busy-spin and starve the session's own timers. `stop` interrupts the wait
|
|
93
93
|
// (and clears the timer) so teardown never blocks for a full cadence. Each refresh
|
|
94
|
-
// is a full, idempotent rebuild; `renderedCount` only advances on a
|
|
94
|
+
// is a full, idempotent rebuild; `renderedCount` only advances on a successful render so a
|
|
95
95
|
// transient failure retries cleanly (no duplicate emails).
|
|
96
96
|
for (;;) {
|
|
97
97
|
try {
|
|
@@ -200,19 +200,19 @@ export async function drainCommsEvidence(args) {
|
|
|
200
200
|
return path;
|
|
201
201
|
}
|
|
202
202
|
if (collected.captured > 0) {
|
|
203
|
-
// Captured mail that matched no declared recipient must not vanish silently
|
|
204
|
-
//
|
|
203
|
+
// Captured mail that matched no declared recipient must not vanish silently: tell the
|
|
204
|
+
// operator to declare comms.email.recipients[].address to match
|
|
205
205
|
// the address the app actually sends to (e.g. the one the persona surface will sign up with).
|
|
206
|
-
warnings.push(`
|
|
206
|
+
warnings.push(`The email catch captured ${collected.captured} email send(s), but none matched a declared recipient inbox, so no email evidence was written. Set comms.email.recipients[].address to the address the app sends to.`);
|
|
207
207
|
}
|
|
208
208
|
else {
|
|
209
|
-
// Zero captures is the silent-broken shape
|
|
209
|
+
// Zero captures is the silent-broken shape: the app never posted to the catch at
|
|
210
210
|
// all, so the personas stared at an empty inbox. Most common cause: the app does not
|
|
211
211
|
// actually read the declared injectEnv var for its email API base URL.
|
|
212
212
|
const transportHint = comms.email.smtp
|
|
213
213
|
? `Verify the app reads ${comms.email.smtp.hostEnv}/${comms.email.smtp.portEnv} for its SMTP host and port`
|
|
214
214
|
: `Verify the app reads ${comms.email.injectEnv} for its email API base URL (an SDK that ignores it sends real mail or throws)`;
|
|
215
|
-
warnings.push(`
|
|
215
|
+
warnings.push(`The email catch captured no email sends: the app never delivered mail through it. ${transportHint} and that the flow reached an email step.`);
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
catch (error) {
|
|
@@ -15,7 +15,7 @@ export function createE2BParticipantDesktop(spec, deps, warnings) {
|
|
|
15
15
|
warnings,
|
|
16
16
|
targetUrl,
|
|
17
17
|
desktopCliRoute: deps.subject.kind === "desktop-cli",
|
|
18
|
-
// Off-app comms
|
|
18
|
+
// Off-app comms: gated entirely on config.comms; no comms declared, no change.
|
|
19
19
|
comms: planParticipantComms(deps.residual.comms, participantServeUrl(deps.subject), targetUrl, deps.subject.kind === "clone" || deps.subject.kind === "local-tree"),
|
|
20
20
|
// The default or injected sink sees every event, started and completed alike, so an operator
|
|
21
21
|
// watching stderr sees both halves of each phase; the state keeps only completed ones.
|
|
@@ -23,9 +23,9 @@ export function createE2BParticipantDesktop(spec, deps, warnings) {
|
|
|
23
23
|
if (event.ok !== undefined)
|
|
24
24
|
state.phaseRecords.push(event);
|
|
25
25
|
deps.reportSubjectPhase(event, {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
id: spec.planned.id,
|
|
27
|
+
index: spec.planned.index,
|
|
28
|
+
count: deps.participantCount,
|
|
29
29
|
});
|
|
30
30
|
},
|
|
31
31
|
};
|
|
@@ -19,7 +19,8 @@ export declare function mobileLaunchFlags(residual: Readonly<ResidualConfig>, sp
|
|
|
19
19
|
* observation. A request that cannot be applied fails the participant closed with the reason. Only
|
|
20
20
|
* participants on a mobile preset are emulated: a run-wide flag must not hand a desktop or tablet
|
|
21
21
|
* participant an iPhone user agent (the first live proof did exactly that to the desktop newcomer
|
|
22
|
-
* beside the phone participant). Those participants carry no fidelity block,
|
|
22
|
+
* beside the phone participant). Those participants carry no fidelity block, since nothing was
|
|
23
|
+
* emulated.
|
|
23
24
|
*/
|
|
24
25
|
export declare function applyParticipantMobileFidelity(args: {
|
|
25
26
|
desktop: E2BDesktopSandbox;
|
|
@@ -44,8 +45,8 @@ export declare function participantBrowserStateObserver(args: {
|
|
|
44
45
|
}): ReturnType<typeof makeChromeBrowserStateObserver>;
|
|
45
46
|
/**
|
|
46
47
|
* The participant's final browser geometry, measured while the sandbox is alive. A final capture that
|
|
47
|
-
* measured
|
|
48
|
-
* had
|
|
48
|
+
* measured either field wins whole, so a partial final capture omits fields the launch-time capture
|
|
49
|
+
* had; only a final capture that measured nothing falls back to the launch-time
|
|
49
50
|
* capture. Also reads the emulation holder's log into the fidelity block.
|
|
50
51
|
*/
|
|
51
52
|
export declare function finalParticipantGeometry(args: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Device fidelity for one E2B desktop participant: mobile emulation beyond viewport size
|
|
2
|
-
// browser-state observer that watches it for drift
|
|
1
|
+
// Device fidelity for one E2B desktop participant: mobile emulation beyond viewport size, the
|
|
2
|
+
// browser-state observer that watches it for drift, and the final browser geometry.
|
|
3
3
|
import { redactText, toErrorMessage } from "../../../evidence/redaction.js";
|
|
4
4
|
import { readDetachedLog } from "../../../substrates/detached.js";
|
|
5
5
|
import { applyMobileEmulation, DEFAULT_MOBILE_USER_AGENT, makeChromeBrowserStateObserver, } from "../../../substrates/e2b/desktop-cdp.js";
|
|
@@ -28,7 +28,8 @@ function cdpEndpoint(identity, targetUrl) {
|
|
|
28
28
|
* observation. A request that cannot be applied fails the participant closed with the reason. Only
|
|
29
29
|
* participants on a mobile preset are emulated: a run-wide flag must not hand a desktop or tablet
|
|
30
30
|
* participant an iPhone user agent (the first live proof did exactly that to the desktop newcomer
|
|
31
|
-
* beside the phone participant). Those participants carry no fidelity block,
|
|
31
|
+
* beside the phone participant). Those participants carry no fidelity block, since nothing was
|
|
32
|
+
* emulated.
|
|
32
33
|
*/
|
|
33
34
|
export async function applyParticipantMobileFidelity(args) {
|
|
34
35
|
const { spec, deps } = args;
|
|
@@ -63,10 +64,10 @@ export function participantBrowserStateObserver(args) {
|
|
|
63
64
|
return makeChromeBrowserStateObserver(args.desktop, deps.requestTimeoutMs, cdpEndpoint(args.launchIdentity, args.targetUrl), {
|
|
64
65
|
targetId: args.targetId,
|
|
65
66
|
// Once per participant: a dark observation channel is a gap in the instrument, and the
|
|
66
|
-
// funnel's
|
|
67
|
+
// funnel's "never measured" count needs this line to explain itself.
|
|
67
68
|
onUnavailable: (reason) => {
|
|
68
69
|
warnings.push(`Browser-state observer unavailable for participant ${spec.planned.id} (${redactText(deps.scrubKnownValues(reason))}); ` +
|
|
69
|
-
"urlIncludes
|
|
70
|
+
"urlIncludes, urlPathEquals and textIncludes stop conditions and task criteria are not measured in this session.");
|
|
70
71
|
},
|
|
71
72
|
drift: fidelity.emulatedTargetId === undefined
|
|
72
73
|
? undefined
|
|
@@ -75,11 +76,11 @@ export function participantBrowserStateObserver(args) {
|
|
|
75
76
|
expectedWidth: spec.planned.device.preset.width,
|
|
76
77
|
expectTouch: fidelity.applied?.requested.touch === true,
|
|
77
78
|
onDrift: (reason) => {
|
|
78
|
-
warnings.push(`Mobile emulation drift for participant ${spec.planned.id}: ${reason}
|
|
79
|
+
warnings.push(`Mobile emulation drift for participant ${spec.planned.id}: ${reason}.`);
|
|
79
80
|
},
|
|
80
81
|
onCovered: (coveredTargetId, read) => {
|
|
81
82
|
// A later tab the page itself reported at the phone width: evidence that
|
|
82
|
-
// the emulation followed the participant
|
|
83
|
+
// the emulation followed the participant, kept on the bundle.
|
|
83
84
|
if (fidelity.applied === undefined)
|
|
84
85
|
return;
|
|
85
86
|
fidelity.applied = {
|
|
@@ -95,8 +96,8 @@ export function participantBrowserStateObserver(args) {
|
|
|
95
96
|
}
|
|
96
97
|
/**
|
|
97
98
|
* The participant's final browser geometry, measured while the sandbox is alive. A final capture that
|
|
98
|
-
* measured
|
|
99
|
-
* had
|
|
99
|
+
* measured either field wins whole, so a partial final capture omits fields the launch-time capture
|
|
100
|
+
* had; only a final capture that measured nothing falls back to the launch-time
|
|
100
101
|
* capture. Also reads the emulation holder's log into the fidelity block.
|
|
101
102
|
*/
|
|
102
103
|
export async function finalParticipantGeometry(args) {
|
|
@@ -126,7 +127,7 @@ export async function finalParticipantGeometry(args) {
|
|
|
126
127
|
];
|
|
127
128
|
warnings.push(...geometryWarnings);
|
|
128
129
|
// The emulation holder's own log, after its announce line: which later targets it
|
|
129
|
-
// attached to, what it sent, and any reply that came back as an error
|
|
130
|
+
// attached to, what it sent, and any reply that came back as an error. Read while
|
|
130
131
|
// the sandbox is alive; the first live proof had no way to say what the holder did.
|
|
131
132
|
if (fidelity.applied !== undefined && fidelity.holderName !== undefined) {
|
|
132
133
|
const holderLog = await readDetachedLog(e2bShell(desktop), fidelity.holderName, deps.requestTimeoutMs).catch(() => "");
|
|
@@ -24,7 +24,7 @@ export async function acquireParticipantDesktop(ctx, state) {
|
|
|
24
24
|
const { residual, env } = deps;
|
|
25
25
|
const subjectEnvNames = participantSubjectEnv(deps.subject);
|
|
26
26
|
const subjectEnvValues = residual.subject.envValues ?? {};
|
|
27
|
-
// Off-app comms
|
|
27
|
+
// Off-app comms: the base-URL env is injected at sandbox create, so the app reads it at
|
|
28
28
|
// boot; the catch starts right after create.
|
|
29
29
|
const commsEnv = participantCommsEnv(ctx.comms);
|
|
30
30
|
const desktopModule = await (deps.desktopModule ?? loadE2BDesktopModule)();
|
|
@@ -39,10 +39,10 @@ export async function acquireParticipantDesktop(ctx, state) {
|
|
|
39
39
|
metadata: {
|
|
40
40
|
...CUA_ACTOR_LAB_PROVIDER_METADATA,
|
|
41
41
|
labId: deps.labId,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
recordId: spec.recordId,
|
|
43
|
+
participantId: spec.planned.id,
|
|
44
|
+
participantIndex: String(spec.planned.index),
|
|
45
|
+
participantCount: String(deps.participantCount),
|
|
46
46
|
},
|
|
47
47
|
// The participant's model key never enters the sandbox (the model drives from outside).
|
|
48
48
|
// The subject's declared env names are provisioned here on the clone route.
|
|
@@ -129,7 +129,7 @@ export async function verifyParticipantScreen(ctx, state, desktop) {
|
|
|
129
129
|
state.desktopGeometry = { ...state.desktopGeometry, warnings: [screenGeometry.warning] };
|
|
130
130
|
}
|
|
131
131
|
if (screenGeometry.error && deps.screenMismatchPolicy !== "record-evidence") {
|
|
132
|
-
state.failureCode = "
|
|
132
|
+
state.failureCode = "HUMANISH_COMPUTER_USE_DEVICE_GEOMETRY";
|
|
133
133
|
throw new Error(screenGeometry.error);
|
|
134
134
|
}
|
|
135
135
|
if (screenGeometry.error && screenGeometry.verified) {
|
|
@@ -149,7 +149,7 @@ export async function provisionParticipantSubject(ctx, state, desktop) {
|
|
|
149
149
|
const { residual, subject } = deps;
|
|
150
150
|
const shell = e2bShell(desktop);
|
|
151
151
|
if (subject.kind === "desktop-cli") {
|
|
152
|
-
// Prepare the runtime and any declared product install,
|
|
152
|
+
// Prepare the runtime and any declared product install, with no keys. With install omitted,
|
|
153
153
|
// the participant discovers and installs the product from its public surfaces.
|
|
154
154
|
await provisionDesktopCli(shell, {
|
|
155
155
|
product: subject.product.name,
|
|
@@ -7,6 +7,7 @@ import { captureDesktopBrowserGeometry } from "../../../substrates/e2b/desktop-g
|
|
|
7
7
|
import { prepareDesktopMedia, startE2BDesktopMedia, } from "../../../substrates/e2b/desktop-media.js";
|
|
8
8
|
import { startE2BDesktopRecording } from "../../../substrates/e2b/desktop-recording.js";
|
|
9
9
|
import { applyParticipantMobileFidelity, mobileLaunchFlags } from "./fidelity.js";
|
|
10
|
+
import { streamEvent } from "../../../lab/run-lab-homes.js";
|
|
10
11
|
/** Start the declared speech worker and screen recording. A recording that cannot start is a warning. */
|
|
11
12
|
export async function startParticipantMedia(ctx, state, desktop) {
|
|
12
13
|
const { spec, deps, warnings } = ctx;
|
|
@@ -47,13 +48,13 @@ export async function openParticipantSurface(ctx, state, desktop) {
|
|
|
47
48
|
if (subject.kind === "desktop-cli") {
|
|
48
49
|
// A terminal window, opened the way the browser is opened on every other route: the
|
|
49
50
|
// participant arrives at a desktop with the thing they were asked to use already in front
|
|
50
|
-
// of them. They can still open another from the dock
|
|
51
|
+
// of them. They can still open another from the dock; that is the point of a desktop.
|
|
51
52
|
await openDesktopTerminal(desktop, deps.requestTimeoutMs, subject.product.workdir);
|
|
52
53
|
await desktop.wait(DESKTOP_SETTLE_MS).catch(() => undefined);
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
const requestedMedia = residual.execution?.desktop?.media;
|
|
56
|
-
// A declared camera
|
|
57
|
+
// A declared camera is in place before the browser starts: the feed is generated or
|
|
57
58
|
// uploaded first, and a feed that cannot be produced fails the participant closed here.
|
|
58
59
|
const mediaEvidence = requestedMedia === undefined
|
|
59
60
|
? undefined
|
|
@@ -76,7 +77,7 @@ export async function openParticipantSurface(ctx, state, desktop) {
|
|
|
76
77
|
state.browserLaunched = true;
|
|
77
78
|
noteDevToolsReadiness(ctx, browserLaunch.devTools, emulationFlags.length > 0);
|
|
78
79
|
await desktop.wait(DESKTOP_SETTLE_MS).catch(() => undefined);
|
|
79
|
-
// Mobile fidelity
|
|
80
|
+
// Mobile fidelity is applied outside startParticipantStream's best-effort catch, so a request
|
|
80
81
|
// that cannot be applied fails the participant closed.
|
|
81
82
|
state.fidelity = await applyParticipantMobileFidelity({
|
|
82
83
|
desktop,
|
|
@@ -91,7 +92,7 @@ export async function openParticipantSurface(ctx, state, desktop) {
|
|
|
91
92
|
}
|
|
92
93
|
/**
|
|
93
94
|
* DevTools answering later than this after launch is recorded as a warning on the participant. Six live
|
|
94
|
-
* launches answered in 4.8-7.7 s;
|
|
95
|
+
* launches answered in 4.8-7.7 s; without this wait the reads it guards give up at about 11 s.
|
|
95
96
|
*/
|
|
96
97
|
const SLOW_DEVTOOLS_MS = 10_000;
|
|
97
98
|
/**
|
|
@@ -168,14 +169,14 @@ export async function startParticipantStream(ctx, state, desktop) {
|
|
|
168
169
|
});
|
|
169
170
|
if (typeof candidateStreamUrl === "string" && candidateStreamUrl.trim().length > 0) {
|
|
170
171
|
state.streamUrl = candidateStreamUrl;
|
|
171
|
-
await deps.onStream({
|
|
172
|
+
await deps.onStream(streamEvent({
|
|
172
173
|
type: "ready",
|
|
173
174
|
participantId: spec.planned.id,
|
|
174
175
|
sandboxId: desktop.sandboxId,
|
|
175
|
-
|
|
176
|
+
recordId: spec.recordId,
|
|
176
177
|
streamId: spec.streamId,
|
|
177
178
|
url: candidateStreamUrl,
|
|
178
|
-
});
|
|
179
|
+
}));
|
|
179
180
|
}
|
|
180
181
|
else {
|
|
181
182
|
warnings.push("Live desktop stream started but did not return a usable watch URL; Observer will fall back to screenshots.");
|
|
@@ -188,7 +189,7 @@ export async function startParticipantStream(ctx, state, desktop) {
|
|
|
188
189
|
// never a participant finding about missing controls. Both computer-use and shared-world participants
|
|
189
190
|
// use this route.
|
|
190
191
|
if (state.initialBrowserGeometry?.unusable !== undefined) {
|
|
191
|
-
state.failureCode = "
|
|
192
|
+
state.failureCode = "HUMANISH_COMPUTER_USE_DEVICE_GEOMETRY";
|
|
192
193
|
throw new Error(`${state.failureCode}: ${state.initialBrowserGeometry.unusable} Participant actions were not started.`);
|
|
193
194
|
}
|
|
194
195
|
}
|
|
@@ -7,6 +7,7 @@ import { readE2BRelease } from "../../../substrates/e2b/sandbox.js";
|
|
|
7
7
|
import { e2bShell } from "../../../substrates/e2b/shell.js";
|
|
8
8
|
import { drainCommsEvidence } from "./comms.js";
|
|
9
9
|
import { finalParticipantGeometry } from "./fidelity.js";
|
|
10
|
+
import { streamEvent } from "../../../lab/run-lab-homes.js";
|
|
10
11
|
/**
|
|
11
12
|
* Each route's own keep flag gates its own participants only: a clone.keep can never leak into a
|
|
12
13
|
* local-tree participant's teardown decision, and vice versa.
|
|
@@ -145,16 +146,16 @@ export async function finishE2BDesktop(ctx, state, failed) {
|
|
|
145
146
|
state.sandboxTornDownAtMs = deps.now();
|
|
146
147
|
// The participant's live stream is now a dead page whichever teardown path ran (released, kept, or
|
|
147
148
|
// release-failed-awaiting-TTL); tell the watch overlay so the tile falls back to recorded
|
|
148
|
-
// evidence instead of "sandbox not found"
|
|
149
|
+
// evidence instead of "sandbox not found". Guarded: a viewer callback must never
|
|
149
150
|
// break teardown.
|
|
150
151
|
if (state.streamUrl !== undefined) {
|
|
151
152
|
try {
|
|
152
|
-
await deps.onStream({
|
|
153
|
+
await deps.onStream(streamEvent({
|
|
153
154
|
type: "ended",
|
|
154
155
|
participantId: spec.planned.id,
|
|
155
|
-
|
|
156
|
+
recordId: spec.recordId,
|
|
156
157
|
streamId: spec.streamId,
|
|
157
|
-
});
|
|
158
|
+
}));
|
|
158
159
|
}
|
|
159
160
|
catch {
|
|
160
161
|
// viewer-side only; nothing to record
|
|
@@ -2,7 +2,7 @@ import type { LabCommsEmail, LabCommsExternal } from "../../lab/types.js";
|
|
|
2
2
|
import type { PreparedRunArtifactPaths } from "../../run/paths.js";
|
|
3
3
|
import type { DesktopParticipantRun, ParticipantRunOutcome } from "./types.js";
|
|
4
4
|
/**
|
|
5
|
-
* Adopter-hosted drain
|
|
5
|
+
* Adopter-hosted drain: once per run, after every participant finished, because the catch is one
|
|
6
6
|
* shared external endpoint, not a per-sandbox file. Same routing and digest-only artifact as
|
|
7
7
|
* the in-sandbox drain; the artifact is registered on every participant that declared a recipient
|
|
8
8
|
* address, since the thread carries each inbox's mail. A drain failure never fails the run.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { collectExternalCommsEvidence } from "../../comms/external-evidence.js";
|
|
2
2
|
import { participantHasInboxRecipient } from "./participant-desktop.js";
|
|
3
3
|
/**
|
|
4
|
-
* Adopter-hosted drain
|
|
4
|
+
* Adopter-hosted drain: once per run, after every participant finished, because the catch is one
|
|
5
5
|
* shared external endpoint, not a per-sandbox file. Same routing and digest-only artifact as
|
|
6
6
|
* the in-sandbox drain; the artifact is registered on every participant that declared a recipient
|
|
7
7
|
* address, since the thread carries each inbox's mail. A drain failure never fails the run.
|
|
@@ -35,26 +35,26 @@ function fanoutReview(args, streams) {
|
|
|
35
35
|
// The judge's verdict: live fan-out must prove every participant (judgeParticipants).
|
|
36
36
|
const verdict = args.verdict;
|
|
37
37
|
const passedParticipants = (outcomes ?? []).filter((outcome) => participantPassed(participantFactsOf(outcome))).length;
|
|
38
|
-
// What happened to the
|
|
38
|
+
// What happened to the participants, with the denominator attached. The verdict above has to
|
|
39
39
|
// collapse the run to one word; this does not (docs/principles/three-roles.md).
|
|
40
40
|
const terminalOutcomes = (outcomes ?? []).filter((outcome) => outcome?.session?.status !== undefined);
|
|
41
41
|
const participants = terminalOutcomes.length > 0
|
|
42
42
|
? tallyParticipantOutcomes(
|
|
43
|
-
// A
|
|
43
|
+
// A no-engagement participant is not one who reached the goal. It said "done" having
|
|
44
44
|
// taken zero actions and said nothing, and `passedParticipants` above already refuses to
|
|
45
|
-
// count it
|
|
46
|
-
// "not a passed participant"
|
|
45
|
+
// count it, but `reachedGoal` was reading the trace status directly, so one run could be both
|
|
46
|
+
// "not a passed participant" and "1/1 reached the goal". The headline number a researcher reads
|
|
47
47
|
// first was the dishonest one. Found by a provider bug that ended a study on turn one.
|
|
48
48
|
terminalOutcomes.map((outcome) => participantStatus(outcome.session.status, {
|
|
49
49
|
noEngagement: outcome.noEngagement === true,
|
|
50
50
|
selfReportedBlocker: outcome.selfReportedBlocker === true,
|
|
51
51
|
})),
|
|
52
|
-
// A participant who reached the goal
|
|
52
|
+
// A participant who reached the goal and told you the road there was broken is the most
|
|
53
53
|
// useful result a study produces; reporting only the outcome would bury it.
|
|
54
54
|
terminalOutcomes.map((outcome) => outcome.reportedFriction === true))
|
|
55
55
|
: undefined;
|
|
56
56
|
// The study funnel: per-task completion rates across every session that measured one. This is
|
|
57
|
-
// "where did people get stuck" as data, next to
|
|
57
|
+
// "where did people get stuck" as data, next to who got stuck (participants) above.
|
|
58
58
|
const participantFunnels = (outcomes ?? [])
|
|
59
59
|
.map((outcome) => outcome?.session?.trace.taskFunnel)
|
|
60
60
|
.filter((funnel) => funnel !== undefined);
|
|
@@ -74,12 +74,12 @@ function fanoutReview(args, streams) {
|
|
|
74
74
|
summary: args.inProgress === true
|
|
75
75
|
? `Live computer-use fan-out is running (${specs.length} participants, one world each); terminal participant evidence has not been written yet.`
|
|
76
76
|
: args.dryRun
|
|
77
|
-
? `${args.rerun ? `Rerun
|
|
77
|
+
? `${args.rerun ? `Rerun from ${args.rerun.sourceRunId}: ` : ""}Dry-run fan-out: ${specs.length} participants composed for ${args.descriptor.id} against ${args.appUrl}, one world each; no desktops launched, $0 spend.`
|
|
78
78
|
: `${args.rerun ? `Rerun from ${args.rerun.sourceRunId}: ` : ""}Computer-use fan-out (${specs.length} participants, one world each): ${passedParticipants}/${specs.length} participant(s) reached a terminal, engaged verdict${participants ? `: ${formatParticipantOutcomes(participants, participantEndings)}` : ""}${runTasks ? `; tasks: ${formatRunTaskFunnel(runTasks)}` : ""}.`,
|
|
79
79
|
gaps: args.inProgress === true
|
|
80
80
|
? ["Live fan-out session is still running."]
|
|
81
81
|
: args.dryRun
|
|
82
|
-
? ["Live fan-out session not yet run (dry
|
|
82
|
+
? ["Live fan-out session not yet run (dry run only)."]
|
|
83
83
|
: specs
|
|
84
84
|
.map((spec, index) => ({ spec, outcome: outcomes?.[index] }))
|
|
85
85
|
.filter(({ outcome }) => outcome === undefined ||
|
|
@@ -112,7 +112,7 @@ function fanoutDesktopBrowser(args) {
|
|
|
112
112
|
}
|
|
113
113
|
function fanoutCost(args) {
|
|
114
114
|
const { specs, outcomes } = args;
|
|
115
|
-
// Run-level cost
|
|
115
|
+
// Run-level cost estimate: one model-token line per participant that ran a session (from its persisted
|
|
116
116
|
// trace.estimatedCost) + a desktop line per owned allocation, priced at its observed resources.
|
|
117
117
|
// `per-lane-worlds` participants have no shared provisioning to double-count. Omitted on a pure dry-run.
|
|
118
118
|
const costTraces = specs
|
|
@@ -218,22 +218,22 @@ export function buildCuaFanoutBundle(args) {
|
|
|
218
218
|
persona: {
|
|
219
219
|
id: specs[0].persona.id,
|
|
220
220
|
name: `Computer-use fan-out (${specs.length} participants)`,
|
|
221
|
-
source: `
|
|
221
|
+
source: `study:${plan.labId}`,
|
|
222
222
|
sourceDigest: specs[0].persona.promptDigest,
|
|
223
223
|
},
|
|
224
224
|
scenario: {
|
|
225
225
|
id: `cua-${plan.labId}`,
|
|
226
226
|
title: plan.title ?? `Computer-use fan-out: ${plan.labId}`,
|
|
227
|
-
// Redacted at
|
|
228
|
-
// digest-only by design, but scenario.goal keeps one participant's composed instructions verbatim
|
|
227
|
+
// Redacted at write time, like every other raw-text surface in the bundle. Participant records are
|
|
228
|
+
// digest-only by design, but scenario.goal keeps one participant's composed instructions verbatim,
|
|
229
229
|
// and an adopter whose authored participant text must name a runtime world URL (an inbox on a route
|
|
230
230
|
// where the harness does not inject one) put an *.e2b.app address in it. That landed raw here
|
|
231
231
|
// and in observer-data.json, the sensitive-text scanner matched it, and verify failed a bundle
|
|
232
|
-
// this writer produced. The only adopter-side workaround was scanner evasion
|
|
232
|
+
// this writer produced. The only adopter-side workaround was scanner evasion.
|
|
233
233
|
//
|
|
234
234
|
// The instructions the model actually receives are untouched; only the persisted copy changes.
|
|
235
235
|
goal: redactText(specs[0].evidenceInstructions ?? specs[0].instructions),
|
|
236
|
-
source: `
|
|
236
|
+
source: `study:${plan.labId}`,
|
|
237
237
|
sourceDigest: specs[0].persona.promptDigest,
|
|
238
238
|
},
|
|
239
239
|
lifecycle: [
|
|
@@ -251,14 +251,14 @@ export function buildCuaFanoutBundle(args) {
|
|
|
251
251
|
status: "passed",
|
|
252
252
|
notes: ranLive
|
|
253
253
|
? anyRaw
|
|
254
|
-
? "Typed text recorded as length only and reasoning
|
|
254
|
+
? "Typed text is recorded as its length only, and reasoning and messages pass through text redaction. Some participants captured unblurred screenshots, kept for local use and not redacted for publishing. Set policies.redactScreenshots: true to blur screenshots in a bundle you plan to share."
|
|
255
255
|
: "Typed text recorded as length only and reasoning/messages pass through text redaction. Screenshots are blurred at capture (policies.redactScreenshots: true) for a share-as-is bundle."
|
|
256
|
-
: "Dry-run fan-out
|
|
256
|
+
: "Dry-run fan-out bundle: no desktops launched and no screenshots captured. Typed text is recorded as length only and reasoning/messages pass through text redaction whenever a session runs.",
|
|
257
257
|
},
|
|
258
258
|
artifacts: bundleArtifacts(),
|
|
259
259
|
review,
|
|
260
|
-
// What the participants reported, when any reported anything
|
|
261
|
-
// bundles carry none
|
|
260
|
+
// What the participants reported, when any reported anything. Dry-run and in-progress
|
|
261
|
+
// bundles carry none: there is no participant yet to quote.
|
|
262
262
|
feedbackCandidates: fanoutFeedbackCandidates(args),
|
|
263
263
|
// Selected hosted image, including the optional speech default; omitted on the stock desktop.
|
|
264
264
|
...(desktopTemplate === undefined ? {} : { desktopTemplate }),
|