Skip to content

evals: merge-readiness fixes for the external-harness stack - #2649

Merged
miguelg719 merged 6 commits into
external-agent-suitesfrom
agent-suites-merge-fixes
Aug 9, 2026
Merged

evals: merge-readiness fixes for the external-harness stack#2649
miguelg719 merged 6 commits into
external-agent-suitesfrom
agent-suites-merge-fixes

Conversation

@miguelg719

@miguelg719 miguelg719 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

The remaining merge blockers for the #2591#2611 stack, implemented per the review conclusions (verifier fallback accepted on empirical evidence; GAIA removal decided; Odysseys rubric item dropped as irrelevant).

  • Gate insurance for the verifier fallback: verifier-failed rows (verifierError set, _success self-reported) now count as ungraded runs on their arm. The per-arm verifiability line reports them, and when EVAL_MAX_UNVERIFIABLE_CRITERIA is configured, any ungraded run fails the batch. This changes no grading behavior — it converts "the fallback hasn't fired in hundreds of runs" into "if it ever fires, the batch fails loudly instead of publishing self-graded rows."
  • GAIA fully removed (dataset, suite builder, index.eval.ts fan-out, category overrides, legacy-only sets, help text, README). b:gaia → "Unknown benchmark", instead of a half-present suite pointing at a broken --legacy path.
  • Planner: a stagehand-harness selection that reduces to nothing runnable (suite name, agent category, dataset shorthand) errors with harness guidance instead of planning zero cases; broad targets still omit suites and plan the rest.
  • Codex step budget: tool steps (command executions + MCP tool calls) capped via stream abort — EVAL_CODEX_MAX_STEPS, falling back to the pre-migration AGENT_EVAL_MAX_STEPS, default 50. Runs get a citable, reproducible action budget.
  • Per-dataset prompt constraints restored from the retired suite modules: OnlineMind2Web's stay-on-site rule (validity: tasks were passable by googling the answer) and the navigate guidance for WebTailBench/Odysseys.
  • Tag hygiene: dom/hybrid/cua stripped from external-harness testcases so Braintrust tag filters don't pool them with historical Stagehand agent rows.
  • stagehand_code screenshot fix (ported from the facade worktree): v4 SDK returns Uint8Array; Buffer.isBuffer consumers silently dropped screenshots. Now normalized to Buffer.

Deliberately not here

  • Pre-navigation to startUrl: pending an explicit protocol decision (self-navigation as the documented norm vs. pre-goto for cross-era comparability).
  • The facade's >= relaxation of the codex observation guard: kept strict === — the relaxation reintroduces positional misattribution; the underlying trailing-capture undercount needs an attempted-run count in the recorder (follow-up with the facade work).
  • MCP tool surfaces and the Playwright facade: follow-up stack.

Verification

typecheck clean · 416/416 unit tests (3 GAIA-era tests updated to the new behavior, 1 new gate test) · oxfmt clean


Summary by cubic

Hardens external-harness evals for merge: enforces strict verifier gating, removes GAIA and the legacy runner/flag, adds a Codex step budget, restores dataset prompt guidance, fixes screenshot handling, and bounds setup-failure cleanup timeouts. Also cleans up docs/payloads, fixes a Codex abort-listener leak in long batches, tightens a dry-run test assertion, and removes the --provider flag (provider now derived from the model id).

  • New Features

    • Verifier gate: verifier-failed rows now count as ungraded; any ungraded run fails a gated batch. Per-arm report shows ungraded counts. Respects EVAL_MAX_UNVERIFIABLE_CRITERIA.
    • Codex step budget: cap tool steps via EVAL_CODEX_MAX_STEPS (fallback AGENT_EVAL_MAX_STEPS, default 50) with stream abort and clear stop reason.
    • Restored dataset guidance in prompts: OnlineMind2Web stay-on-site rule; navigation hints for WebTailBench and Odysseys.
    • Planner: selecting stagehand harness that leaves nothing runnable now errors with guidance instead of planning zero cases.
  • Refactors

    • GAIA fully removed; b:gaia now reports “Unknown benchmark.” b:osworld also reports “Unknown benchmark.”
    • Removed legacy runner and --legacy flag; deleted legacy files and commands. Dry-run payload drops skippedTasks; preview/help text, ARCHITECTURE.mmd, and README updated.
    • Removed --provider and provider-based model filtering; provider metadata is inferred from provider/model. Dropped EVAL_PROVIDER env, config/help surfaces, and related tests.
    • Tag hygiene: strip dom, hybrid, cua from external-harness testcases to keep Braintrust filters separated from legacy Stagehand runs.
    • stagehand_code screenshot bytes normalized to Buffer to fix dropped screenshots with the v4 SDK.
    • Codex runner: detach the abort forwarder after each run to avoid accumulating listeners in long batches.
    • External-harness adapters: apply the normal teardown timeout (EVAL_AGENT_MOUNT_CLEANUP_TIMEOUT_MS) to setup-failure cleanup to prevent wedging rows.
    • Docs: dry-run diagram lists the actual payload fields (target, normalizedTarget, tasks, envOverrides, runOptions, matrix, error?).
    • Tests: broad dry-run now asserts the unique planned task set to avoid model-multiplicity noise.

Written for commit 66bc69d. Summary will update on new commits.

Review in cubic


Update (second commit): the legacy runner is removed outright. --legacy could no longer run anything on this branch (a/e/o need the v4 harness context it never builds; the agent modules and suite targets it resolves are gone), so the escape hatch was routing users to a guaranteed failure. Deleted: cli-legacy.ts, index.eval.ts, args.ts, tui/commands/legacy.ts, the evals:old script, the --legacy flag, LEGACY_ONLY_BENCHMARKS (b:osworld now reports "Unknown benchmark"), and the legacy-skip plumbing in the run command, dry-run payload, and preview. Net −1,885 lines. Gates re-run green (typecheck, 416/416, oxfmt).

- Verifiability gate: verifier-failed rows now count as ungraded
  (self-reported) runs on their arm; a configured gate fails when any
  appear, and the per-arm report line shows them. A gated batch can no
  longer publish self-reported rows silently.
- GAIA: complete the removal — dataset, suite builder, fan-out,
  category overrides, legacy-only sets, help text. b:gaia now says
  'Unknown benchmark' instead of pointing at a broken --legacy path.
- Planner: a stagehand-harness selection that reduces to nothing
  runnable errors with harness guidance instead of planning zero cases;
  broad targets still omit suites and plan the rest.
- Codex: cap tool steps (EVAL_CODEX_MAX_STEPS, falling back to
  AGENT_EVAL_MAX_STEPS, default 50) by aborting the stream at budget —
  runs get a citable action budget instead of an unbounded one.
- Prompts: restore the per-dataset constraints from the retired suite
  modules (OnlineMind2Web's stay-on-site rule; navigate guidance for
  WebTailBench/Odysseys) in both harness prompt builders.
- Tags: strip stagehand agent-mode tags (dom/hybrid/cua) from external-
  harness testcases so Braintrust tag filters don't pool them with
  historical Stagehand agent runs.
- stagehand_code: normalize screenshot bytes to Buffer (v4 SDK returns
  Uint8Array; Buffer.isBuffer consumers silently dropped screenshots) —
  ported from the facade worktree.
@changeset-bot

changeset-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 66bc69d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 19 files

Architecture diagram
sequenceDiagram
    participant TUI as TUI / CLI (run)
    participant Plan as Bench Planner
    participant Suite as Suite Builders
    participant Prom as Prompt Builder
    participant Codex as Codex Runner
    participant SDK as Codex SDK / Thread
    participant Shot as stagehand_code
    participant Verif as Verifier Adapter
    participant Gate as Verifier Gate (run.ts)

    Note over TUI,Gate: External-harness eval run (webvoyager / onlineMind2Web / webtailbench / odysseys)
    Note over TUI: GAIA removed - b:gaia shorthand now reports "Unknown benchmark"

    TUI->>Plan: generateBenchTestcases(harness=stagehand)
    alt Selection reduces to nothing runnable (suite-only)
        Plan-->>TUI: CHANGED: EvalsError - re-run with --harness claude_code or codex
    else Broad target
        Plan->>Plan: omit agent suites from stagehand plan, keep rest
    end

    TUI->>Suite: build<Dataset>Testcases(models)
    Suite->>Suite: CHANGED: strip dom/hybrid/cua tags from testcases
    Suite-->>TUI: rows tagged harness/<harness>

    TUI->>Codex: runCodexAgent(plan)
    Codex->>Codex: NEW: read EVAL_CODEX_MAX_STEPS fallback AGENT_EVAL_MAX_STEPS, default 50
    Codex->>SDK: runStreamed(prompt, signal: budgetController)
    loop Agent tool loop
        SDK-->>Codex: event item.completed
        alt command_execution or mcp_tool_call
            Codex->>Codex: toolStepCount += 1
            opt toolStepCount >= maxToolSteps
                Codex->>SDK: abort stream (stop reason: tool step budget exhausted)
            end
        end
    end

    Note over Prom,Codex: NEW: dataset guidance added to prompt (codex + claude_code runners)
    Codex->>Prom: datasetPromptGuidance(dataset)
    Prom-->>Codex: stay-on-site (onlineMind2Web) / navigation hint (webtailbench, odysseys)

    Note over Shot,Verif: CHANGED: v4 SDK screenshot bytes normalized to Buffer
    Codex->>Shot: page.screenshot() / captureStagehandEvidence()
    Shot-->>Codex: Buffer.from(bytes)

    Codex->>Verif: gradeExternalTrajectory(trajectory)
    alt Verifier fails (verifierError set)
        Verif-->>Codex: self-reported _success only (ungraded)
    else Verifier grades
        Verif-->>Codex: criterionCount + evidenceInsufficient
    end
    Codex-->>TUI: TaskResult

    TUI->>Gate: summarizeArmVerifiability(results)
    Gate-->>TUI: per-arm gradedRuns + ungradedRuns
    Note over TUI,Gate: Verifiability line reports ungraded (self-reported) count
    alt EVAL_MAX_UNVERIFIABLE_CRITERIA set and any arm has ungraded runs
        TUI->>TUI: NEW: fail batch (exit 1) - self-reported rows never published
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/evals/framework/codexRunner.ts Outdated
Comment thread packages/evals/framework/externalHarnessPlan.ts
Comment thread packages/evals/tests/tui/run.test.ts Outdated
Comment thread packages/evals/framework/benchPlanner.ts Outdated
Comment thread packages/evals/framework/codexRunner.ts
Comment thread packages/evals/tui/commands/parse.ts Outdated
Comment thread packages/evals/tui/commands/run.ts Outdated
The --legacy escape hatch could no longer run anything on this branch:
bench a/e/o tasks need the v4 harness context the legacy runner never
builds, the individual agent modules are gone, and the suite fan-outs
resolve task modules that no longer exist. Dead escape hatches are
worse than none — they route users to a path that exits.

- Delete cli-legacy.ts, index.eval.ts, args.ts, and tui/commands/legacy.ts
  (and the evals:old script).
- Drop the --legacy flag, LEGACY_ONLY_BENCHMARKS (osworld now reports
  'Unknown benchmark'), the legacy-only target/split machinery in the
  run command, and the skipped-tasks plumbing in the dry-run payload
  and preview that existed only to report legacy-skipped suites.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 11 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/evals/tui/commands/run.ts
Comment thread packages/evals/tui/commands/run.ts
Comment thread packages/evals/tui/commands/parse.ts
Comment thread packages/evals/tui/commands/parse.ts
- ARCHITECTURE.mmd: drop the legacy CLI nodes and skippedTasks from the
  dry-run payload shape; README: drop the removed --agent-mode(s) row
- run.test: assert the exact planned matrix instead of a vacuous every()
- codexRunner: detach the abort forwarder after each run so long batches
  don't accumulate listeners on the shared signal
The matrix carries one row per default model; the exact-array assertion
tripped on multiplicity. The unique set still fails on an empty matrix
and on a suite leaking into the plan.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/evals/ARCHITECTURE.mmd Outdated
--provider filtered the default model list down to bare model ids
(gpt-4o-mini, claude-...), which the v4 initStagehand cannot key-resolve
— provider-filtered runs died before browser startup. The flag is
redundant: --model overrides a single run, and per-harness model lists
(EVAL_CLAUDE_CODE_MODELS / EVAL_CODEX_MODELS) cover multi-model
selection with fully-qualified ids.

Braintrust metadata keeps its provider field — now derived from the
model id's provider/ prefix instead of a separate selector.
- Both external-harness adapters now apply the normal-teardown timeout
  (EVAL_AGENT_MOUNT_CLEANUP_TIMEOUT_MS) on the setup-failure cleanup
  path too — a hung cleanup can no longer wedge the row.
- ARCHITECTURE.mmd's dry-run node lists the actual payload fields.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 14 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/evals/framework/codexToolAdapter.ts
Comment thread packages/evals/tui/commands/run.ts
Comment thread packages/evals/framework/claudeCodeToolAdapter.ts
Comment thread packages/evals/framework/codexToolAdapter.ts
Comment thread packages/evals/framework/benchPlanner.ts
@miguelg719
miguelg719 merged commit df872fd into v4-spike Aug 9, 2026
22 checks passed
miguelg719 added a commit that referenced this pull request Aug 9, 2026
The agent-facing half of the stagehand_code code-mode surface:
prepareLLMExposure initializes a v4 Stagehand client via initStagehand
and declares a code_handles agent mount — stagehand/page/z in the
snippet scope, surface-owned prompt instructions and run-tool copy,
final-state evidence capture (screenshot + URL + aria tree), and cleanup
that closes the browser as well as the client (stagehand.close() alone
leaves the browser running). Nothing consumes the mount here; the
claude_code adapter does in #2596 and codex in #2609.

Bottom of the nondeterministic-evals stack (#2591#2611, with the
merge-readiness fixes in #2649 and the MCP tool surfaces in #2650
stacked on top).

⚠️ **Base housekeeping before merge**: this PR still targets
`evals-v4-root`, which has since merged (via #2570#2494) into
`v4-spike`. Rebase onto current `v4-spike` and retarget. One known
reconciliation: v4-spike removed the `EVAL_VERIFIER_MODEL` override
from `verifierAdapter` (2af557b) as redundant with V3Evaluator's own
constructor options; this stack's later PRs still carry it — drop it
during the rebase rather than reintroducing it.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds the `stagehand_code` code-mode tool and registers it in the core
tool registry, wiring a v4 `@browserbasehq/stagehand` client with scoped
handles, run-tool execution, artifact capture, and full teardown.
Enables the v4 code-mode surface for STG-2671 with a fixed SDK model and
local/Browserbase startup profiles.

- New Features
- New `StagehandCodeTool` (`id: stagehand_code`) with session,
navigation, evaluation, screenshot, viewport, wait, click, hover,
scroll, type, press, tabs, and representation.
  - Targets: `selector`, `coords`, `focused`.
- Agent mount via handles: `stagehand`, `page`, and `z`; scoped prompt
instructions; run-tool description, code param description, and deny
message. Snippets also get `startUrl`, `task`, and `console` in scope.
- Captures screenshot, URL, and ARIA tree; cleanup closes both the
Stagehand client and the browser.
- Profiles: `tool_launch_local` and `tool_create_browserbase`;
connection mode derived; model fixed to `openai/gpt-4.1-mini`.
- Registered in `listCoreTools`/`getCoreTool`; tests assert
`stagehand_code` is retrievable and that prompt guidance includes
awaited locator actions.

<sup>Written for commit e579140.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2591?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
miguelg719 added a commit that referenced this pull request Aug 9, 2026
## Summary

Codex joins claude_code as an external harness across all three code
tool surfaces (`stagehand_code`, `playwright_code`, `cdp_code`) —
recreating #2397 on the LLMExposure architecture.

codex-sdk has no in-process MCP mounting (unlike claude-agent-sdk), and
an external MCP process could not share this process's live surface
handles. So the codex mount for a `code_handles` exposure is a loopback
HTTP bridge: this process executes snippets against the in-memory
handles; the codex workspace gets a tiny `browser_run.mjs` client that
posts a snippet file to the bridge and prints the result. Scope
semantics are identical to the claude_code run tool.

- `codexCodeBridge.ts` (new): the bridge server + generated workspace
client
- `codexToolAdapter.ts`: code-surface mounting (exposure selection,
bridge lifecycle, tmpdir cwd, prompt rewrite from run-tool to
`browser_run.mjs` invocation)
- `codexRunner.ts` / `harnesses/codexAdapter.ts`: harness-observed
terminal artifact anchors the verifier's final observation, mirroring
the claude_code runner
- Tests: bridge round-trip + widened surface resolution

Part of the nondeterministic-evals stack; stacks on the exposure-adapter
PR.

Follow-up on top of the stack: #2650 adds the MCP tool surfaces
(playwright_mcp / chrome_devtools_mcp) to both external harnesses; MCP
tool calls there count against the codex tool-step budget introduced in
#2649.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Enable Codex on `stagehand_code`, `playwright_code`, and `cdp_code` via
a loopback HTTP bridge that runs snippets against in-memory handles,
with terminal artifact capture in the runner for grounded grading.
`browse_cli` remains supported with sane startup defaults, and code
surfaces now have clear `browser_run.mjs` guidance.

- **New Features**
- Bridge server/client in `codexCodeBridge.ts`: `browser_run.mjs` posts
snippet code to `/run`; executes with `handles`, `startUrl`, `task`, and
`console`; timeout via `EVAL_CODEX_RUN_TOOL_TIMEOUT_MS`; non-zero exit
on failure.
- Tool adapter and runner: `codexToolAdapter.ts` mounts `browse_cli`,
`stagehand_code`, `playwright_code`, `cdp_code`; defaults to tool-owned
browsers for `browse_cli`/`stagehand_code` and runner-provided CDP for
`playwright_code`/`cdp_code`; writes `browser_run.mjs` and rewrites
`AGENT_RUN_TOOL_NAME`; captures evidence via `captureEvidence` and
passes it to `codexAdapter.ts`; robust cleanup.

- **Bug Fixes**
- Final observation is only anchored when a screenshot is present;
URL-only artifacts no longer qualify.
- Redacts credential fragments (e.g., `signingKey`, `sk-*`) from snippet
error messages before crossing the bridge or hitting logs.

<sup>Written for commit a710ed6.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2609?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: miguel <miguelg71921@gmail.com>
miguelg719 added a commit that referenced this pull request Aug 9, 2026
…ection (#2610)

## Summary

STG-2752: external-harness runs now carry per-step observations and a
final observation grounded in harness-captured evidence, and
unverifiable-criteria counts are reported per arm and can gate the
batch.

- `ToolStartResult.captureEvidence` (optional hook): each code surface
captures current page state (url + screenshot + aria tree) through its
own handles — one shared capture per surface, resolved through
`session.activePage()` at capture time
- `observationRecorder.ts` (new): run-indexed probe buffer; a failed
capture leaves a gap instead of shifting later observations onto the
wrong step; `EVAL_HARNESS_OBSERVATIONS=none` excludes a run from
evidence collection
- Probes record after each run-tool execution in `claude_code` and each
bridge run in `codex`; the trajectory adapters attach them to code steps
only, and refuse attachment when counts mismatch (misattribution is
worse than a gap)
- `tui run` prints per-arm verifiability and enforces the
`EVAL_MAX_UNVERIFIABLE_CRITERIA` gate

Verified live: in webvoyager runs the verifier now rejects agent claims
that the collected step evidence does not support (e.g. asserted
ingredients absent from the extracted list).

Stacked follow-ups: #2649 extends the gate to count verifier-failed
(ungraded, self-reported) rows per arm and fail gated batches containing
any; #2650 extends per-step observation to the MCP tool surfaces via the
runner event streams.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Wires verifier-backed evidence capture into `claude_code` and `codex` so
runs include per-step URL/screenshot probes and a harness-observed final
artifact. Adds per-arm verifiability reporting and an optional gate for
STG-2752.

- **New Features**
- Added `ObservationRecorder` for per-step probes; opt out with
`EVAL_HARNESS_OBSERVATIONS=none`, timeout via
`EVAL_OBSERVATION_TIMEOUT_MS`.
- Probes record after each `run_tool` in `claude_code` and each bridge
run in `codex`; adapters attach only to code steps (`LLM_RUN_TOOL_NAME`,
`browser_run.mjs`) as `probeEvidence`. Final observation prefers the
harness-captured artifact, else the last agent screenshot.
- `tui run` prints per-arm verifiability and enforces the
`EVAL_MAX_UNVERIFIABLE_CRITERIA` gate.

- **Bug Fixes**
- Bridge probe callbacks are non-blocking; failed captures leave indexed
gaps instead of shifting evidence.
- `codex` only attaches observations when recorded bridge runs match
filtered steps; `claude_code` captures a terminal artifact before
cleanup; final observation requires a screenshot.
- Strict integer parsing for `EVAL_MAX_UNVERIFIABLE_CRITERIA`; the gate
fails loudly when set but no arms were graded.

<sup>Written for commit 88d32fd.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2610?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
miguelg719 added a commit that referenced this pull request Aug 9, 2026
…2611)

## Summary

Agent suites (webvoyager, onlineMind2Web, webtailbench, odysseysbench)
run exclusively through the external harnesses (claude_code / codex);
the v3 agent path is removed from the bench framework. Net −5,028 lines.

## Why now

The agent tier's history on this lineage:

| Date | Change | Event |
|---|---|---|
| 2026-05-01 | #2011 Evals v2 | agent bench tasks created |
| 2026-07-23 | v4-spike v3 purge | deleted |
| 2026-07-27 | #2401 Restore v3 evals | restored against the published
stagehand-v3 npm package |

#2401 restored the v3 agent tier as a stopgap because v4 had no agent
story. The nondeterministic-evals stack under this PR — the LLMExposure
contract, the external harnesses, per-step evidence collection — is that
story, so the stopgap retires. Suites are now planner-level constructs
(virtual registry entries over the dataset builders in `suites/`), not
task files.

## What changes

- stagehand bench harness is act/extract/observe-only on the Stagehand
SDK; both `initV3` branches, the `--api` path, and the v3 context fields
are gone
- An explicit suite target on the stagehand harness errors with harness
guidance; broad targets omit suites; dry-runs surface planner errors in
the payload instead of crashing
- Deleted as dead once the path is gone: the 47 v3-context agent tasks,
`runWithVerifier`, `TrajectoryRecorder` (its external-harness successors
— `gradeExternalTrajectory`, `observationRecorder` — live on the stack
below), the agent-mode/CUA matrix machinery, and the
`--agent-mode`/`--agent-modes` flags
- Plus three run fixes found during live benchmarking: extract-schema
steering in the stagehand_code prompt, `@browserbasehq/sdk`/`ws`
resolved from the evals package (the old resolver pointed at
`packages/core`, which does not exist on this lineage), and a CLI stderr
filter for the stale-frame CDP log flood

## Scope boundaries

- Deterministic evals untouched: zero changes to `defineTask.ts` /
`types.ts` / `context.ts` / framework barrel (the #2494 / #2587 stack);
a/e/o task-file v4 typing remains that stack's deliverable
- ~~The legacy runner (`--legacy`) keeps its own v3 wiring and is
scheduled for a separate removal~~ — done: #2649 (stacked on this PR)
removes the legacy runner outright, along with GAIA
- Zero changes under `packages/server` / `packages/extension`

## Stacked on top

- #2649 — merge-readiness fixes: gate counts verifier-failed rows as
ungraded and fails gated batches; GAIA removed entirely; legacy runner
removed; codex tool-step budget; per-dataset prompt constraints restored
(Mind2Web stay-on-site); agent-mode tag hygiene; stagehand_code
screenshot Buffer fix
- #2650 — playwright_mcp / chrome_devtools_mcp enabled on both external
harnesses

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Routes all agent benchmark suites (`webvoyager`, `onlineMind2Web`,
`webtailbench`, `odysseysbench`) through external harnesses
(`claude_code`, `codex`) and removes the v3 agent path. The `stagehand`
harness is now act/extract/observe-only; suites are discovered as
virtual entries; and the `stagehand_code` prompt now requires
single-word, all-required extract schema keys.

- **Bug Fixes**
- Filtered Stagehand stale-frame CDP ERROR lines from CLI stderr; other
errors still print.
- Fixed Browserbase target prep by resolving `@browserbasehq/sdk` and
`ws` from `packages/evals` dependencies.

- **Migration**
- Run suites with `--harness claude_code` or `--harness codex`; the
`stagehand` harness no longer runs agent suites and will error on
explicit suite targets (dry-run payloads include planner errors).
- Remove usage of `--agent-mode`, `--agent-modes`, and the `agentModes`
config key. The legacy runner (`--legacy`) keeps its own v3 wiring.

<sup>Written for commit 600adf1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2611?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
miguelg719 added a commit that referenced this pull request Aug 9, 2026
…esses (#2650)

## Summary

Stacked on #2649. `--tool playwright_mcp` and `--tool
chrome_devtools_mcp` now execute on `--harness claude_code` and
`--harness codex` — the first wiring of the MCP surfaces into the agent
harnesses (previously core-tier only).

**Design**: the generic `agentMount { via: "mcp", mcpServers }` contract
variant, produced by the tools and delivered by the adapters — no
surface-specific adapter code. The agent spawns its own MCP server
instance against the runner-provided CDP browser; the harness keeps its
own session on the same browser for evidence capture.

- **Tools**: export the mount (via new `buildPlaywrightMcpLaunchSpec` /
`buildChromeDevtoolsMcpLaunchSpec` helpers — named for the facade branch
to rebase onto) + `captureEvidence`. Mount requires a
`providedEndpoint`, so a tool-launched isolated browser can never split
agent and observer.
- **claude_code**: `mcpServers` passthrough to the SDK, `mcp__<server>`
tool allowlisting, per-step observation triggered from the runner's
`tool_result` stream keyed by `tool_use` id.
- **codex**: `mcp_servers` via SDK config overrides; observation on
`mcp_tool_call` completion events; MCP calls count against the #2649
tool-step budget.
- **Trajectory adapters**: `observedToolName` matcher generalizes
observation attachment to MCP steps; the strict `===` count guard is
kept (the facade's `>=` relaxation is deliberately not adopted — it
reintroduces positional misattribution; the trailing-capture undercount
wants an attempted-run count instead, follow-up).

Deliberately out (punted with the facade): `stagehand_playwright_code`,
callback batching, the facade's codex-only
`prepareCodexPlaywrightMcpAdapter` (superseded by the generic path).

## Verification

- typecheck / oxfmt clean, **420/420** unit tests (4 new: surface
resolution both harnesses, MCP observation attachment both adapters)
- Live smoke (claude_code × playwright_mcp, WebVoyager, LOCAL): agent
drove `mcp__playwright__*` tools for 50 steps, per-step url/aria probe
evidence attached to MCP steps only, verifier graded a 5-criterion
rubric (0 unverifiable)
- codex × chrome_devtools_mcp: config injection + server spawn validated
on Browserbase (run failed on an unrelated model-pairing error;
`mcp_servers` reached Codex and servers started)

Known rough edge: probe screenshots through the harness-side
`playwright_mcp` session are flaky under the 10s observation timeout
(url/aria reliable; ~1/40 screenshots in the smoke). Follow-up: bump
timeout for MCP surfaces or capture via raw CDP.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Enable MCP browser tool surfaces on the `claude_code` and `codex`
harnesses. `--tool playwright_mcp` and `--tool chrome_devtools_mcp` now
run end-to-end with per-step evidence attached to MCP steps; plus
reliability fixes for capture and tab syncing.

- **New Features**
- Tools export an MCP agent mount (`via: "mcp"`) with
`buildPlaywrightMcpLaunchSpec` / `buildChromeDevtoolsMcpLaunchSpec`,
plus `captureEvidence`.
- Claude Code: passes `mcpServers` to the SDK, allows `mcp__<server>`
tools, and attaches observations from the `tool_result` stream (tracks
`tool_use` id → name).
- Codex: injects `mcp_servers` via SDK config overrides; records
observations on `mcp_tool_call` completion; MCP calls count toward the
tool-step budget.
- Trajectory adapters: add an `observedToolName` matcher so observations
attach to MCP steps; strict count guard remains to avoid misattribution.
- Startup: MCP surfaces use runner-provided CDP endpoints (local or
Browserbase) so agent and harness share the same browser.

- **Bug Fixes**
- Evidence capture re-points the harness session to the browser’s
visible tab via CDP before probing (best-effort fallback if
unavailable).
- Observation recorder settles in-flight captures before drain;
`drainStepObservations` is async on both harnesses to avoid missing
last-step evidence.
- Codex `captureEvidence` is bounded by
`EVAL_CAPTURE_EVIDENCE_TIMEOUT_MS` (default 15s) to prevent stalls.

<sup>Written for commit 544b54a.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2650?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants