Skip to content

feat(browser): browser/v1 contexts, leased beside the default one (M8.15) - #642

Draft
earakely-scale wants to merge 3 commits into
mainfrom
edgararakelyan/fd-4962-m815-browserv1-contexts-leases-grants
Draft

earakely-scale wants to merge 3 commits into
mainfrom
edgararakelyan/fd-4962-m815-browserv1-contexts-leases-grants

Conversation

@earakely-scale

Copy link
Copy Markdown
Collaborator

What and why

M8.15 (FD-4962): a website browser leases browser contexts beside its default one.

Until now a website browser had one set of cookies, local storage, tabs and downloads, so a task couldn't sign two users in at once, and contexts an agent made over CDP were invisible to agentenv. Now a task leases a context by a label, and each lease has its own cookies, local storage, tabs and downloads folder in the same Chromium.

Design note: M8.15: browser/v1 contexts, decisions 1a, 2a, 3a, 4b and 5a.

What changes

  • New ops:
    • contexts/lease {label} returns {context, id}. Leasing the same label again returns the same lease, so a retried step is harmless.
    • contexts/grant {context, user} records an agent a lease is for. Nothing enforces grants yet; M8.16 will (decision 1a).
    • contexts/release {context} closes the lease's tabs, disposes the context and deletes its folder. Releasing a label that isn't leased does nothing.
    • contexts/list lists every lease with who made it and its grants.
    • Labels are lowercase letters, digits and -, at most 40 characters. A task's label can't start with agent- (decision 2a).
  • context on the existing ops: tabs/*, cookies/*, local_storage/*, downloads/list and downloads/get take an optional context, a lease's label. Without one they act on the default context exactly as before, error messages included.
  • Downloads: a lease's downloads go to ~/Contexts/<label>/Downloads/, and ~/Downloads stays the default context's (decision 4b). Uploads stay shared. Each download and tab in record names its context.
  • Contexts agents make over CDP:
    • A context an agent creates through the relay is leased to it as agent-<user>-<n> and granted to it. One made where the relay didn't see is listed as agent-unknown-<n>, granted to nobody.
    • The relay refuses an agent disposing the task's lease or another agent's context. An agent may dispose its own.
    • An agent's setDownloadBehavior for a lease is pinned to that lease's folder.
  • Lifetime: a reset, or any relaunch of the browser, ends every lease (decision 3a). The lease table lives in memory, since a server restart relaunches the browser anyway.
  • Data plane:
    • data/get gains contexts: each lease's cookies, local storage, tabs, downloads, grants and who made it. Each lease's finished downloads are among the files.
    • data/add leases any context it names that isn't leased, then loads its cookies, local storage and tabs. A snapshot therefore round-trips (decision 5a). Files under Contexts/<label>/Downloads/ load into that lease.
  • Task steps:
    • browser_lease_context {label, grants?} and browser_release_context {label} are new.
    • The cookie, local storage, tab and sign-in steps take a context.
    • A step's to_dict only gains context when it's set, so tasks saved before this don't get new versions.
    • A step naming a context on a browser that leases none fails before any call.

Decided while building, for your review

  1. Dispose rules in the relay: only the agent that made a context may dispose it. The task's leases end only by release.
  2. disposeOnDetach: an agent context made with it (Playwright's default) ends its lease when that agent's connection closes, as Chromium disposes it.
  3. Downloads re-pinned: after an agent connection that set download behaviour closes, every lease's downloads are sent to its folder again, in case Chromium reset them when that session ended.
  4. Leftover folders: ~/Contexts is cleared before each launch, since a killed app server can't clean up after itself.
  5. data/get top level: closed_tabs stays the browser's whole history, each tab naming its context. cookies, local_storage, tabs and downloads are the default context's.
  6. An unknown label answers 404 target_unavailable. The note said not_found; this uses the computer error that already exists.
  7. Step fields: the lease and release steps take label, and the other steps name a lease as context.

How it was tested

  • Unit:
    • test_browser_contexts.py, new, 24 tests:
      • leases, labels and grants;
      • contexts agents make, their labels and the dispose rules;
      • each context's tabs, cookies, origins and downloads;
      • release and the end of the browser;
      • a release and a lease of the same label at once;
      • what a load may name;
      • the ops.
    • The relay: an agent's context is leased to it, its downloads are pinned, and dispose is refused for another agent's context or the task's lease. A disposeOnDetach context ends on disconnect.
    • Steps: the lease and release steps, context on cookies and tabs, a browser that leases none, config problems, round trips, and sign-in into a lease.
    • After merging main: agentenv-protocol's tests and tst/unit/task_step + tst/unit/task, 4,523 passed.
  • Integration, local Docker on agent-environments-admin VMs (amd64 and arm64), a new test in browser_computer_test.py:
    • Two leases made by steps each sign in to a loopback site as their own user, in tabs the default context doesn't list.
    • Five leases of one label at once are one lease.
    • A download lands in the lease's folder and is listed there only.
    • An agent's CDP context is agent-ada-1; bob can't dispose it, and ada can't dispose the task's lease but can dispose her own.
    • data/get carries the leases and their downloads, and a load leases a released one back with its cookies and tabs.
    • A reset leaves no lease and no folder.
  • Chaos, on the same VMs, not committed:
    • 60 leases and releases at once;
    • 8 agent connections churning;
    • a download released mid-flight;
    • the app server killed with leases open;
    • chromium killed.
  • Results: VM runs in progress; this section will be updated with them.

🤖 Generated with Claude Code

earakely-scale and others added 3 commits November 12, 2026 10:47
A website browser now leases browser contexts by a label: each has its own
cookies, local storage, tabs and a downloads folder in
~/Contexts/<label>/Downloads. contexts/lease is idempotent, contexts/grant
records the agents a lease is for (not enforced yet), contexts/release ends
it and contexts/list lists them. The tabs, cookies, local_storage and
downloads ops take a context, else act on the default context as before.

A context an agent makes over its CDP address is leased to it as
agent-<user>-<n>; only that agent may dispose it, and a lease's downloads
stay pinned to its folder. A reset or relaunch of the browser ends every
lease. data/get carries each lease under contexts, with its downloads, and
data/add leases any it names that are missing, so a snapshot round-trips.

Task steps: browser_lease_context and browser_release_context, and a
context on the cookie, local storage, tab and sign-in steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd clear leftover folders before each launch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2-m815-browserv1-contexts-leases-grants

# Conflicts:
#	packages/agentenv-protocol/src/agentenv_protocol/website_browser/environment.py
#	src/agent_env/task/episode/rules.py

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant