Skip to content

feat: add browser context support for isolated multi-identity workflows#1340

Open
pedro-saraiva88 wants to merge 4 commits into
vercel-labs:mainfrom
pedro-saraiva88:feat/browser-context
Open

feat: add browser context support for isolated multi-identity workflows#1340
pedro-saraiva88 wants to merge 4 commits into
vercel-labs:mainfrom
pedro-saraiva88:feat/browser-context

Conversation

@pedro-saraiva88
Copy link
Copy Markdown

Summary

Adds first-class support for Chrome's BrowserContext primitive (CDP Target.createBrowserContext), enabling isolated cookies, localStorage, and cache between groups of tabs within a single Chrome process. Mirrors the BrowserContext concept in Playwright and Puppeteer.

Why this fits agent-browser

The project's tagline is "Browser automation CLI for AI agents." As agents move from single-task scripts to longer-running workflows, several capabilities that previously required orchestrating multiple daemons become natural inside a single process:

  • Multi-identity workflows — operate with several authenticated sessions concurrently (e.g. multi-tenant customer support automation, parallel review of the same dashboard as different roles).
  • A/B state comparison — compare side-by-side how a logged-in vs anonymous session sees the same URL, in one process, with one snapshot loop.
  • Sandboxed exploration — visit untrusted URLs in a throwaway context that is disposed when done, so the agent's main session is never polluted.
  • Sub-agent task isolation — a parent agent dispatches N sub-agents, each operating inside its own clean context, sharing one Chrome.
  • Future synergy with auth save / auth login — saved auth profiles can be loaded into named contexts (out of scope for this PR but noted as natural follow-up).

The alternative today is launching multiple daemons. Each spawns its own Chrome (~200 MB). Two isolated contexts in one Chrome use ~250 MB total versus ~400 MB with two daemons — and a single CDP loop instead of N.

API

agent-browser context new [--label <name>]      # creates "c1", "c2", ...
agent-browser context list                       # lists active contexts
agent-browser context close <c1|label>           # closes its tabs first, then disposes
agent-browser tab new --context <c1|label> [url] # tab inside a specific context

Stable refs c1, c2, ... follow the same pattern as the existing t1, t2 tab refs introduced in v0.26.0. Labels are optional and interchangeable with refs everywhere a context ref is accepted.

Behaviour

  • Closing a context closes its tabs first (best-effort Target.closeTarget), then disposes the context. Active tab index falls back gracefully when the active tab is removed.
  • Idempotent — closing an already-closed ref returns a clear Unknown context: <ref> error, no panic.
  • State save/load is per-contextNetwork.getCookies is called with browserContextId; localStorage is collected via a temp target opened inside each context. On load, contexts are recreated (preserving labels) and cookies/storage are restored. State files written by older versions continue to load via #[serde(default)].
  • Validation upfronttab new --context c99 returns Unknown context: c99 before any CDP call.

Scope

In:

  • CDP plumbing (CreateBrowserContextParams/Result, DisposeBrowserContextParams, Network.getCookies / setCookies with browserContextId)
  • BrowserManager: ContextInfo, context_new, context_close, resolve_context, tab_new_in_context
  • Action handlers, CLI parsing, output formatting (pretty + --json)
  • State scoping with backward-compat
  • 9 e2e tests (isolation, cleanup, idempotency, save/load round-trip)
  • Docs in all five locations per AGENTS.md, CHANGELOG entry

Deliberately out:

  • auth load --context <ref> integration (future PR)
  • Cross-context tab move
  • Persistent context aliases across daemon restarts (refs are session-scoped today)

Testing

cd cli && cargo test                              # 724 unit tests pass
cd cli && cargo test e2e_context -- --ignored --test-threads=1   # 9 e2e tests pass
cd cli && cargo fmt --check && cargo clippy --tests -- -D warnings  # clean

Smoke verified manually: 2 contexts with same origin, cookie set in c1, c2 sees no cookie; context close <label> closes tabs and disposes; state save → close → load preserves context labels and cookies.

Documentation updates (per AGENTS.md)

  • cli/src/output.rsagent-browser context --help block
  • README.md — "Browser Contexts" section, --context in tab options
  • skill-data/core/SKILL.md — workflow section, plus new references/contexts.md reference guide
  • docs/src/app/commands/page.mdx — section with HTML <table> for flags
  • Inline Rustdoc on ContextInfo, context_new, context_close, resolve_context, tab_new_in_context, ContextSnapshot
  • CHANGELOG.md + docs/src/app/changelog/page.mdx (within existing 0.27.0 release markers)

Adds first-class support for Chrome's BrowserContext primitive (CDP
Target.createBrowserContext), enabling isolated cookies, localStorage, and
cache between groups of tabs within a single Chrome process.

New commands:
  agent-browser context new [--label <name>]
  agent-browser context list
  agent-browser context close <c1|label>
  agent-browser tab new --context <c1|label> [url]

Stable refs `c1`, `c2`, ... parallel to the existing `t1`, `t2` tab refs.
Closing a context closes its tabs first; state save/load preserves
per-context cookies and storage with backward-compat for old state files.

Includes 9 e2e tests (isolation, cleanup, idempotency, save/load round-trip)
and docs across all five locations per AGENTS.md.
The cookies and localStorage isolation tests were using `data:` URLs which
trigger SecurityError when accessing storage. Switched to about:blank tabs
followed by an explicit navigate to https://example.com so the storage APIs
are available with a real origin. The same origin in both contexts also
makes the test stronger — isolation must come from the BrowserContext, not
from a different origin.
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 9, 2026

@pedro-saraiva88 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown
Contributor

@vercel vercel Bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

The load_storage_state function uses state::load_state() which only restores global cookies and localStorage, silently dropping all saved BrowserContext snapshots when launching with --state <path>.

Fix on Vercel

load_storage_state was calling state::load_state(), which only restores
global cookies and localStorage. Saved BrowserContext snapshots were
silently dropped on launch with --state, even though state_save had
written them to disk and the runtime state_load action restored them
correctly.

Switch to state::load_state_into_manager() so the launch-time path
matches the runtime path, recreating each saved context with its label
and per-context cookies/localStorage.

Reported by Vercel VADE review on vercel-labs#1340.
@pedro-saraiva88
Copy link
Copy Markdown
Author

Thanks for catching this — fixed in 7fbcd14.

load_storage_state in actions.rs was calling state::load_state(), which only restores global cookies and localStorage. It now calls state::load_state_into_manager() so the launch-time --state <path> flow matches the runtime state_load action — saved BrowserContext snapshots are recreated with their labels and per-context cookies/localStorage. Signature changed from &DaemonState to &mut DaemonState; all four call sites updated.

Validated with cargo build, cargo clippy --tests -- -D warnings, cargo fmt --check, and the full unit + doctor test suites.

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.

1 participant