Skip to content

feat(agents): record the active tab on named browser sessions - #2370

Open
ben-reitz wants to merge 2 commits into
refactor/browser-connector-shared-helpersfrom
feat/browser-session-active-tab
Open

ben-reitz wants to merge 2 commits into
refactor/browser-connector-shared-helpersfrom
feat/browser-session-active-tab

Conversation

@ben-reitz

@ben-reitz ben-reitz commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Named sessions now remember the agent's current tab, so when the model references sessionId: "active" with the new connector we add in #2371, it will point at the same tab from one execution to the next. The record stores the tab's targetId because targets survive reconnects and CDP session ids don't.

 StoredBrowserSession { sessionId, createdAt, updatedAt, closedAt?,
+  activeTargetId? }

 connect(name) → { name, sessionId, restarted, cdp,
+  activeTargetId?,
+  setActiveTarget(targetId | undefined): Promise<boolean>,
+  spec(): Promise<SearchableCdpSpec> }
  • Stale connections can't write. setActiveTarget and the activity touch share one #update helper. It writes under the per-name lock only while the record still holds the same browser, and returns false otherwise. A closed or replaced session is never brought back.
  • A replacement browser starts with no active tab.
  • spec() reads the CDP protocol from this connection's own browser (the path added in refactor(agents): share connector validation and load the CDP spec from a live session #2369). The connector uses it without ever seeing the Browser Run binding.

Everything here is internal. BrowserSessions gets exported in #2372.

Architecture diff

Each outlined box is a component this PR changes, with one green box per change. Grey boxes are unchanged, and dashed boxes arrive later in the stack.

flowchart TB
  classDef ctx fill:none,stroke:#8c959f,color:#8c959f
  classDef changes fill:#dafbe1,stroke:#1a7f37,color:#1f2328
  classDef later fill:none,stroke:#8c959f,stroke-dasharray:4 3,color:#57606a

  Agent["Agent (host Durable Object)"]:::ctx

  BS["BrowserSessions · capability.ts"]:::ctx

  subgraph NBS["NamedBrowserSessions · session-core.ts"]
    direction TB
    N1["+ connect() returns activeTargetId, setActiveTarget()"]:::changes
    N2["+ connected session gets spec()"]:::changes
    N3["+ stale connections can't write the record"]:::changes
    N1 ~~~ N2 ~~~ N3
  end

  subgraph Store["StoredBrowserSession · session-manager.ts"]
    Sc["+ activeTargetId?"]:::changes
  end

  BR["Browser Run"]:::ctx
  Spec["loadCdpSpec · spec.ts"]:::ctx
  Next["BrowserSessionConnector (next PR)<br/>reads and saves the active tab"]:::later

  Agent -->|lifecycle.use| BS
  BS --> NBS
  NBS -->|"one record per name"| Store
  NBS -->|"create · probe · CDP socket"| BR
  NBS -->|"spec() for this sessionId"| Spec
  Next -.-> BS

  style NBS stroke:#1a7f37,stroke-width:2px
  style Store stroke:#1a7f37,stroke-width:2px
Loading

@changeset-bot

changeset-bot Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8d1bca3

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

@ben-reitz
ben-reitz added this pull request to stack #2373 September 25, 2026 08:21
@agent-think

agent-think Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🟡 agents import sizes: 1 entry point grew

Entry point Exports Largest gzip change Size now
🟡 agents/chat 1 resized, 2 new +156 B (+2.92%) 5.4 KiB
Changed exports (3)
Import Gzip change Size now
🟡 agents/chat#ResumableStream +156 B (+2.92%) 5.4 KiB
🆕 agents/chat#originMessageIds — 2.4 KiB
🆕 agents/chat#withOriginMessageIds — 2.3 KiB
How this works

Each runtime export is bundled on its own, minified, and gzipped. Changes smaller than 100 B, or smaller than 1% and 1 KiB, are ignored. Growth over 10% or 5 KiB is marked 🔴. This report is informational and does not fail CI. The workflow artifact contains every measurement.

Compared 9e5c0b8c → 8d1bca30 · workflow run · reported by agent-think[bot]

@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2370

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2370

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2370

hono-agents

npm i https://pkg.pr.new/hono-agents@2370

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2370

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2370

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2370

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2370

commit: 8d1bca3

@ben-reitz
ben-reitz force-pushed the feat/browser-session-active-tab branch 2 times, most recently from 9277c20 to 5eee444 Compare September 25, 2026 11:27
@ben-reitz
ben-reitz force-pushed the feat/browser-session-active-tab branch 2 times, most recently from 5eee444 to 88de7c7 Compare September 25, 2026 11:32
@ben-reitz
ben-reitz marked this pull request as ready for review September 25, 2026 13:12
devin-ai-integration[bot]

This comment was marked as resolved.

@ben-reitz
ben-reitz force-pushed the feat/browser-session-active-tab branch from 88de7c7 to 5306161 Compare September 25, 2026 13:48
@ben-reitz
ben-reitz force-pushed the feat/browser-session-active-tab branch from 5306161 to 98e8640 Compare September 25, 2026 13:57
Named session records gain an optional activeTargetId, and connect()
returns setActiveTarget(), which writes it only while the record still
holds the same browser, so a stale connection never resurrects a closed
or replaced session. A replacement browser starts with no active tab.
NamedBrowserSessions and BrowserSessions also expose their binding
through a browser getter. Internal; used by the persistent browser
connector.
@ben-reitz
ben-reitz force-pushed the feat/browser-session-active-tab branch from 98e8640 to dd053df Compare September 25, 2026 14:54

@devin-ai-integration devin-ai-integration 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.

Devin Review found 1 new potential issue.

Devin Review

Comment on lines +316 to +317
spec: () =>
loadCdpSpec({ browser: this.#browser, sessionId: resolved.sessionId })

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.

🔍 Connector handoff differs from PR description

The PR description promises browser getters, but the final code exposes spec() on connected sessions instead. Confirm the planned connector consumes spec() and needs no direct binding access.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

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