Repository navigation
feat(task-step): browser_connect_cdp hands an agent a CDP address to an env's website browser - #493
Merged
Merged
Conversation
…website browser
A new task step asks the env's website browser for the agent's address
(browser/v1 cdp, the user its agent_name), rewrites it to what the
agent's sandbox reaches as deploy_agent does for MCP URLs, and adds it to
the agent's cdp-config/v1 as chromium, or the name given, with metadata
{browser}. Unless keep_tools, it hides every tool the env serves from the
agent's role, default when it has none, with tool access's wildcard. It
refuses an agent whose card has no cdp-config/v1, and an env whose
browser it can't tell. The connection is recorded, and reset_env makes it
again after a reset, since a reset ends the address and the tool rules.
The echo agent takes cdp-config/v1, and a "cdp <name> <url>" line has it
open the URL over raw CDP and report the title and its address's digest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… name, and fail closed when a reset can't reconnect A browser computer's driver takes its app's name, so asking the env for its child "chromium" got the driver's own card, which has no browser/v1: the step now calls the card it found among the env's children. Connecting an agent under a name it already has replaces that record, so a reset of the env it was connected to before no longer switches it back. A connection reset_env can't make again is removed from its agent's cdp-config, so its next turn fails closed as an infra_error instead of driving an address the reset ended, and the step fails naming it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and two agents on one browser On one browser computer the echo agent opens a page over its address after the app server and then the driver are killed and come back, and after the browser relaunches. A reconnect after a reset that fails, by an injected fault, leaves its next turn failing closed with cdp.no_endpoint, and connecting again restores it. Two agents connected at once open the page concurrently, each through an address of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its own reply Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st for now The driver keeps tool access rules in memory, so a restarted driver shows every tool again until the next reset. Making the rules survive a restart is backlogged; the chaos test keeps checking the CDP path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…which its CDP line needs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… agent's CDP line needs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…connects them again reset_env goes back to what it is on main, knowing nothing of CDP. A reset still ends an agent's address and its hidden-tool rules, so a task runs browser_connect_cdp again after reset_env, or gives the turn a retry_config that reruns it. The step keeps its record, one per agent and name, for the role its tools were hidden from. The integration test shows the contract: after a reset, a turn on the old address fails, and once the task connects the agent again its next turn opens the site through a fresh one. The chaos test keeps the app server and driver restarts and the relaunch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A tab made by Target.createTarget is about:blank, already complete, until it commits its URL, so the first evaluate could take that document's empty title for the page's. CI's chaos run got an empty title within a second of a relaunch. The open now waits for a complete document that isn't about:blank. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
A new task step,
browser_connect_cdp, hands a deployed agent a CDP address to an env's website browser. Browser Use (M8.18) and the CDP benchmark arms need agentenv to do this. M8.1 gave agentscdp-config/v1, M8.6 the browser'scdpoperation, and M8.7 the relay's guard, but no step connected them. This is FD-4964 (M8.17). Its four decisions are recorded there.What the step does (
task_steps/browser_connect_cdp.py), placed afterdeploy_agent(decision 1):browser/v1 cdp {user}, through the env with its control token, on the card of the browser app it finds among the env's children. A browser computer's driver takes its app's name, so the step never asks for the child by name.browsernames the app; unnamed, it's the env's only website browser.reachable_urlandhost_url_forthatdeploy_agentuses for MCP URLs. A browser deployed on its own then needs no gateway. An address anywhere else, at a gateway's public address for instance, is kept as it is (M8.11).cdp-config/v1aschromium, or thenamegiven, withmetadata {browser}. M8.15 and M8.16 addcontext(decision 4).keep_tools. It uses tool access's wildcard (tools: "*") on the env'sdisable-tool/v1. On a browser computer every tool drives the browser, so a CDP agent has one way in (decision 3).defaultwhen itsdeploy_agentstep has none (decision 2). So every other caller of that env without a role loses those tools too, includingenv_outcome_verifier, whoseverify(mcp_url)calls the env with no role. A task with both should give the agent a role or setkeep_tools. That cost was accepted on review for now; the step could later hide them only when the env is in the agent'senv_ids.context.metadata["browser_connections"]: its env, agent, browser, name, role and what was hidden. The address isn't recorded. A connection under a name the agent already has replaces that record.It refuses:
cdp-config/v1. The card is only known once the agent is deployed, so this is at execution.A reset ends the address, and the task connects the agent again.
reset_envis unchanged and knows nothing of CDP.browser_connect_cdpagain afterreset_env, or gives the turn aretry_configwhoseretry_from_step_idreruns it.reset_envreconnect recorded connections. Keepingreset_envfree of CDP was preferred to it, and putting this on the task author is for now.Two departures from FD-4964's text:
useris the agent'sagent_name, not itsdeploy_agentstep id. Every step names a deployed agent byagent_name, and the step id isn't in the context._needs_the_agent), since it calls the agent's own extension.The echo agent (
tst/data/a2a_agent) is the fixture:cdp-config/v1.cdp <name> <url>line in its prompt has it open the URL in a new tab over raw CDP, throughrequest.cdp_endpoint(name). It then addscdp <name> <digest>: <title>, with<digest>the first 12 hex digits of its address's SHA-256, so a test can tell one address from another without the token.websockets.Docs:
agents/AGENTS.mdnow says the step sends the endpoint, and that after a reset a task runs it again or reruns it with aretry_config.Not in this PR:
Size: 453 lines added, 266 of them tests and the fixture agent.
How it was tested
ruff check: clean.Unit tests: 11,938 passed. The new
test_browser_connect_cdp.pymocks only the HTTP boundary:cdpcall with the control token; the agent'saddwith the address rewritten fromlocalhosttohost.docker.internal, as an agent on the local provider reaches it; and the disable call with{"role": "default", "tools": "*"}.keep_tools, a name, and a gateway address left as it is.to_dictandfrom_dict.The episode spec test now covers the new type. Four tests fail on this Mac and on main alike: the two disk-recipe launcher tests, and the two optional-extras tests, because this venv's protocol metadata predates
websocketsin thecomputerextra. The new step imports withwebsocketsrefused.The fixture's CDP open, locally: run against Chrome 156 through the relay and guard, it opened the site twice and reported its title.
Integration, on agent-environments-admin VMs (amd64 c6i.2xlarge, arm64 c7g.2xlarge), a new browser computer test. It deploys the echo agent on the local provider beside a browser computer and runs
browser_connect_cdpon them:the agent's turn opens the site over CDP;
the computer's MCP lists no tools to a caller with no role;
after
reset_env, with the site served again, a turn on the old address fails. Once the task runsbrowser_connect_cdpagain, the next turn opens the site through a fresh address, and the tools are hidden again;the connection's record is checked.
At 9dea75f:
child env 'chromium' does not offer 'cdp': the step asked for the child by name and got the driver's own card. Fixed in 5df21be, and the unit test's computer now takes its app's name, as a real one does.exec format error).tst/util/image_cache.build_or_reusebuilds test images forlinux/amd64, so that's true on main too, and CI is amd64 only. The arm64 VM got Ubuntu'sqemu-user-staticso the amd64 agent runs there emulated.At 5df21be:
browser_computer_test.pyand the echo agent'stest_agent_on_local_sandbox.pypassed 7 of 7 on each arch.Chaos, two more browser computer tests, on both VMs and in CI's slow tier:
data:text/html,<title>Home</title>over its address needs no server, so a driver kill can't take the page down with it. The echo agent opens it through the same address:reset_env). A reset whose reconnect failed raised, and the agent's next turn failed closed withcdp.no_endpoint.computer_*tools were visible to the agent's role again, because the driver keeps those rules only in memory. That's also true ofmodify_env_tool_accesstoday. It's accepted for now and backlogged as FD-5246 (M8.55, persisting the rules). 6b9bc45 drops that one assertion.test_agent_on_local_sandbox.py.Review fixes (Greptile, 3/5 on 9dea75f), at 5df21be, each with a test that fails without it:
reset_envno longer reconnects.Greptile at dc03433 (5/5) found the two-agent test gave both turns of an agent one prompt id. Fixed in 270ab37, and Greptile's review of that commit is 5/5 with no findings.
CI on 6b9bc45:
integration-local-slow (2/12)failed inrun_bundle_installed_agent_test.py. Its bundle copies the echo agent'sagent.pyunder a Dockerfile of its own that installs onlyagentenv-protocol[agent], so the agent's newwebsocketsimport stopped it from starting.websocketsthere too. That test andtest_prompt_agent_file_parts_local.py, which loadsagent.pyin process, passed on the amd64 VM.CI on fba2fe2:
integration-local-slow (6/12)failed the same way inrun_bundle_built_agents_test.py, whose four agent images also install only the agent extra. 919ca3b installswebsocketsthere too. Those are the only two Dockerfiles in the tests that install the agent extra.run_bundle_built_agents_test.pypassed 3 of 3.run_bundle_installed_agent_test.pyran and passed its task, but missed its "building with docker" line there, because the VM already had the image from the previous run.CI on 919ca3b: every check passed (32), with the installer matrix's placeholder skipped as always. Greptile gives it 5/5 with no findings.
At c361ca3 (
reset_envdecoupled): 9 of 9 passed on each arch, the whole browser computer suite with the e2e and chaos tests, plustest_agent_on_local_sandbox.py.about:blank. That document is alreadycompletebefore the tab commits its URL.about:blank.At b98566c: 9 of 9 passed on each arch. In CI every check passed (32), with the installer matrix's placeholder skipped as always, and Greptile gives it 5/5 with no findings.
🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge with the documented reset and tool-visibility limits.Summary
Adds
browser_connect_cdpto give an agent a browser address and optionally hide the env’s tools from its role. The latest change waits until the new tab leavesabout:blankbefore reading its title.Diagram
sequenceDiagram participant Task participant Browser participant Agent Task->>Browser: Request CDP address for agent Browser-->>Task: HTTP and WebSocket addresses Task->>Task: Rewrite addresses for agent sandbox Task->>Agent: Add named CDP endpoint opt Tools not kept Task->>Browser: Hide env tools from agent role end Task->>Task: Replace saved connection recordReviews (9) · Last reviewed commit: "test: the echo agent's CDP open waits pa..." · Reviewed by Greptile