Skip to content

feat(agents): add the named browser session core - #2292

Closed
ben-reitz wants to merge 1 commit into
mainfrom
feat/browser-named-sessions
Closed

ben-reitz wants to merge 1 commit into
mainfrom
feat/browser-named-sessions

Conversation

@ben-reitz

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

Copy link
Copy Markdown
Contributor

What this is

A session engine. The host names a browser (e.g. "checkout", "research") and one call does the right thing:

resolve("checkout")
  browser still alive?    → reattach to it        (restarted: false)
  dead / closed / swept   → create a replacement  (restarted: true —
                                                   "heads up: fresh browser,
                                                    your login may be gone")

Internal module (browser/session-core.ts), plus two small backward-compatible additions to already-public helpers - this is the only public behaviour change in this stack.

Why

A Browser Rendering session is a real Chrome browser: slow to start, and it forgets logins, cookies, and tabs when it dies. Today, keeping one alive across model turns means the model does the bookkeeping — deciding survival with cdp.startSession() and carrying raw protocol ids between turns — and evaluation showed it keeps fumbling that (stale-id failures, attach ceremony). This engine moves all of it host-side:

  • Names are the only identity that crosses a boundary. Models never see platform session ids, so they cannot lose them.
  • Death is loud, not cryptic. restarted: true replaces CDP error -32001; first-ever use is not a restart.
  • Settings stick to the name. keepAliveMs, recording, and guardrails are stored durably and reapplied to every replacement browser. Keep-alive defaults to the 600-second platform max.
  • Cleanup is bounded. close() tombstones then deletes (best-effort — the tombstone is the durable outcome, and the pinned keep_alive reclaims any browser whose delete failed); sweep() closes idle browsers and prunes aged tombstones (10-minute default; alarm scheduling lands in the next PR).
  • Active browsers are never reaped. CDP commands on a socket from connect() refresh the session's idle clock (throttled to 60s, capped at half the sweep window so a short custom sweepIdleMs cannot outrun the touch cadence), so a sweep only closes browsers that are genuinely idle.
  • Restart evidence survives recovery. Dead sessions are tombstoned — never deleted — while a replacement is created, so a resolver racing the recovery also reports restarted: true instead of mistaking it for first use.
  • The trivial case stays trivial. openOneShotBrowserSession() is store-less create-use-delete. Kitesurf will use this option.

Storage discipline mirrors the existing connector: locks wrap storage reads/writes only, never Browser Run network calls; concurrent create races resolve first-commit-wins with best-effort cleanup of the loser. The tests include a detector that fails if any network call happens while a lock is held.

Public API impact

Two additions to existing agents/browser exports, both backward compatible:

 createBrowserSession(browser, {
   keepAliveMs, includeTargets, recording,
+  guardrails: { allowedDomains: [...], allowedDomainSets: [...] }
 })

-connectBrowserSession(browser, sessionId, timeoutMs?)
+connectBrowserSession(browser, sessionId, { timeoutMs?, onClose?, onActivity? })

The bare-number timeoutMs form still works but is marked @deprecated (overload-level, so editors flag it) — the options object is the canonical form and internal callers are migrated to it.

  • guardrails are just an addition to the existing POST body to acquire a Browser Run session (recently added to their REST contract) and are fixed for the session's life, every connection included. The type names are exported (with the changeset) in the docs PR at the top of the stack.
  • allow passing in onClose, run exactly once when the session reaches a terminal state — explicit close, peer closure, or socket error
  • allow passing in onActivity, invoked on every CDP command sent — the activity signal the session core uses for idle tracking

The engine uses a new browser:session:<name> keyspace, disjoint from the connector's cdp:exec: / cdp:reuse: entries — the two coexist, and browser_execute behavior is untouched.

Reviewing

  • session-core.ts reads top to bottom: resolve → connect → close → sweep → one-shot.
  • 23 new tests in browser-session-core.test.ts: first-create, live reattach, dead/tombstoned recreate, a concurrent dead-recovery race (both resolvers report restarted: true, first-commit-wins, redundant browser reclaimed), option reapplication, per-name isolation, lock discipline, activity touches (refresh, throttle, derived interval under a short sweep window, no resurrection of closed sessions), sweep behavior, close with a failed platform delete, one-shot cleanup including the attach-failure and peer-closure paths plus the dispose-once guard, Kitesurf rejection.

@changeset-bot

changeset-bot Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 5b4dad0

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 #2295 September 16, 2026 22:31
@pkg-pr-new

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

Copy link
Copy Markdown

Open in StackBlitz

agents

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

@cloudflare/ai-chat

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

@cloudflare/codemode

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

hono-agents

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

@cloudflare/shell

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

@cloudflare/think

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

@cloudflare/voice

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

@cloudflare/worker-bundler

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

commit: 5b4dad0

@ben-reitz
ben-reitz force-pushed the feat/browser-named-sessions branch from 5a1519c to 671c189 Compare September 17, 2026 00:00
@ben-reitz
ben-reitz force-pushed the feat/browser-interaction-contract branch from 1cd5d17 to 440148c Compare September 17, 2026 00:00
@agent-think

agent-think Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

🟡 agents import sizes

Measured 343 runtime imports as minified bundles. The primary size is gzip; raw minified size is included for diagnosis. An existing import growing by more than 10% is marked red. This report is informational.

Red Yellow Green Unchanged New Removed
0 10 0 333 0 0

Compared 16b68560 with 5b4dad0f. Open workflow run.

Changed imports (10)
Status Import Base gzip Head gzip Delta
🟡 agents/browser#BrowserConnector 50.5 KiB 50.6 KiB +158 B (+0.31%)
🟡 agents/browser#connectBrowserSession 37.5 KiB 37.6 KiB +86 B (+0.22%)
🟡 agents/browser#connectBrowser 37.8 KiB 37.9 KiB +66 B (+0.17%)
🟡 agents/browser#createBrowserSession 36.3 KiB 36.4 KiB +61 B (+0.16%)
🟡 agents/browser#connectUrl 37.6 KiB 37.6 KiB +57 B (+0.15%)
🟡 agents/browser#CdpSession 37.2 KiB 37.3 KiB +54 B (+0.14%)
🟡 agents/browser/ai#createBrowserRuntime 147.0 KiB 147.1 KiB +144 B (+0.1%)
🟡 agents/browser/ai#createBrowserTools 147.0 KiB 147.2 KiB +144 B (+0.1%)
🟡 agents/browser/tanstack-ai#createBrowserTools 162.7 KiB 162.9 KiB +134 B (+0.08%)
🟡 agents/browser/ai#createQuickActionTools 122.5 KiB 122.5 KiB +1 B (+0%)
All 343 current runtime imports
Status Import Gzip Raw minified
⚪ agents#__DO_NOT_USE_WILL_BREAK__agentContext 261.1 KiB 1141.0 KiB
⚪ agents#__DO_NOT_USE_WILL_BREAK__withInvocationScope 261.1 KiB 1141.0 KiB
⚪ agents#Agent 261.1 KiB 1141.0 KiB
⚪ agents#AGENT_TOOL_MILESTONE_PART 261.1 KiB 1141.0 KiB
⚪ agents#AGENT_TOOL_PROGRESS_PART 261.1 KiB 1141.0 KiB
⚪ agents#buildAgentPath 261.7 KiB 1143.3 KiB
⚪ agents#buildAgentUrl 261.8 KiB 1143.7 KiB
⚪ agents#callable 261.1 KiB 1141.0 KiB
⚪ agents#camelCaseToKebabCase 261.1 KiB 1141.0 KiB
⚪ agents#createHeaderBasedEmailResolver 261.3 KiB 1141.4 KiB
⚪ agents#DEFAULT_AGENT_STATIC_OPTIONS 261.1 KiB 1141.0 KiB
⚪ agents#DurableObjectOAuthClientProvider 261.1 KiB 1141.0 KiB
⚪ agents#getAgentByName 261.1 KiB 1141.0 KiB
⚪ agents#getCurrentAgent 261.1 KiB 1141.0 KiB
⚪ agents#getSubAgentByName 261.4 KiB 1141.6 KiB
⚪ agents#isDurableObjectCodeUpdateReset 261.1 KiB 1141.0 KiB
⚪ agents#isDurableObjectMemoryLimitReset 261.1 KiB 1141.0 KiB
⚪ agents#isDurableObjectStorageReset 261.1 KiB 1141.0 KiB
⚪ agents#isPlatformTransientError 261.1 KiB 1141.0 KiB
⚪ agents#MCP_SERVER_ID_MAX_LENGTH 261.1 KiB 1141.0 KiB
⚪ agents#MessageType 261.2 KiB 1141.3 KiB
⚪ agents#normalizeServerId 261.1 KiB 1141.0 KiB
⚪ agents#parseSubAgentPath 261.1 KiB 1141.0 KiB
⚪ agents#routeAgentEmail 261.4 KiB 1141.7 KiB
⚪ agents#routeAgentRequest 261.7 KiB 1142.9 KiB
⚪ agents#routeSubAgentRequest 261.3 KiB 1141.5 KiB
⚪ agents#SqlError 261.1 KiB 1141.0 KiB
⚪ agents#StreamingResponse 261.1 KiB 1141.0 KiB
⚪ agents#SUB_PREFIX 261.1 KiB 1141.0 KiB
⚪ agents#unstable_callable 261.2 KiB 1141.2 KiB
⚪ agents/agent-tools#agentTool 112.5 KiB 538.2 KiB
🟡 agents/browser#BrowserConnector 50.6 KiB 177.0 KiB
⚪ agents/browser#browserContent 36.3 KiB 127.4 KiB
⚪ agents/browser#browserExtract 36.3 KiB 127.4 KiB
⚪ agents/browser#browserLinks 36.3 KiB 127.4 KiB
⚪ agents/browser#browserMarkdown 36.3 KiB 127.4 KiB
⚪ agents/browser#browserPdf 36.3 KiB 127.3 KiB
⚪ agents/browser#BrowserRenderingError 36.0 KiB 126.7 KiB
⚪ agents/browser#browserScrape 36.3 KiB 127.4 KiB
⚪ agents/browser#browserScreenshot 36.3 KiB 127.3 KiB
⚪ agents/browser#browserSnapshot 36.3 KiB 127.4 KiB
🟡 agents/browser#CdpSession 37.3 KiB 130.0 KiB
⚪ agents/browser#CodemodeRuntime 39.6 KiB 139.0 KiB
🟡 agents/browser#connectBrowser 37.9 KiB 131.6 KiB
🟡 agents/browser#connectBrowserSession 37.6 KiB 130.6 KiB
🟡 agents/browser#connectUrl 37.6 KiB 130.7 KiB
🟡 agents/browser#createBrowserSession 36.4 KiB 127.7 KiB
⚪ agents/browser#DEFAULT_EXEC_SWEEP_IDLE_MS 36.0 KiB 126.6 KiB
⚪ agents/browser#DEFAULT_SWEEP_IDLE_MS 36.0 KiB 126.6 KiB
⚪ agents/browser#deleteBrowserSession 36.1 KiB 126.9 KiB
⚪ agents/browser#DurableBrowserSessionStore 36.4 KiB 127.6 KiB
⚪ agents/browser#getBrowserRecording 36.2 KiB 127.1 KiB
⚪ agents/browser#listBrowserTargets 36.1 KiB 126.9 KiB
⚪ agents/browser#loadCdpSpec 36.6 KiB 128.3 KiB
⚪ agents/browser#runQuickAction 36.0 KiB 126.6 KiB
🟡 agents/browser/ai#createBrowserRuntime 147.1 KiB 633.3 KiB
🟡 agents/browser/ai#createBrowserTools 147.2 KiB 633.3 KiB
🟡 agents/browser/ai#createQuickActionTools 122.5 KiB 554.3 KiB
🟡 agents/browser/tanstack-ai#createBrowserTools 162.9 KiB 702.2 KiB
⚪ agents/channels#ChannelHost 3.3 KiB 9.1 KiB
⚪ agents/channels#consumeChunks 237 B 321 B
⚪ agents/channels#createUserIdentityStore 1.3 KiB 3.2 KiB
⚪ agents/channels#fallback 155 B 160 B
⚪ agents/channels#fallbackChannel 893 B 1.9 KiB
⚪ agents/channels#fanout 151 B 156 B
⚪ agents/channels#fanoutChannel 875 B 1.9 KiB
⚪ agents/channels#identityKey 178 B 223 B
⚪ agents/channels#isChannelMessageSurface 271 B 452 B
⚪ agents/channels#linkChannelIdentities 113 B 99 B
⚪ agents/channels#matchesPath 110 B 96 B
⚪ agents/channels#routes 307 B 507 B
⚪ agents/channels#UserIdentityConflictError 248 B 335 B
⚪ agents/channels/ai-sdk#createSendMessageTool 112.2 KiB 537.4 KiB
⚪ agents/channels/ai-sdk#toChannelChunks 112.5 KiB 538.4 KiB
⚪ agents/channels/email#email 23.5 KiB 75.4 KiB
⚪ agents/channels/email#inboundEmail 22.3 KiB 72.3 KiB
⚪ agents/channels/slack#slack 5.5 KiB 14.6 KiB
⚪ agents/channels/slack#slackWebhook 2.2 KiB 5.1 KiB
⚪ agents/channels/tanstack-ai#createSendMessageTool 16.2 KiB 68.4 KiB
⚪ agents/channels/telegram#telegram 3.8 KiB 10.3 KiB
⚪ agents/channels/telegram#telegramWebhook 1.6 KiB 3.6 KiB
⚪ agents/channels/voice#browserVoice 1010 B 2.2 KiB
⚪ agents/chat#AbortRegistry 2.5 KiB 8.9 KiB
⚪ agents/chat#AGENT_TOOL_STREAM_PROGRESS_BUMP_THROTTLE_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#AgentToolProgressEmitter 2.7 KiB 9.5 KiB
⚪ agents/chat#AgentToolStreamProgressThrottle 2.4 KiB 8.3 KiB
⚪ agents/chat#aiSdkRecoveryCodec 2.3 KiB 8.2 KiB
⚪ agents/chat#applyAgentToolEvent 3.2 KiB 11.0 KiB
⚪ agents/chat#applyChunkToParts 2.3 KiB 8.2 KiB
⚪ agents/chat#applyToolUpdate 2.4 KiB 8.4 KiB
⚪ agents/chat#AutoContinuationController 2.3 KiB 8.2 KiB
⚪ agents/chat#awaitWithDeadline 2.4 KiB 8.4 KiB
⚪ agents/chat#broadcastTransition 3.2 KiB 11.4 KiB
⚪ agents/chat#buildChatRecoveringFrame 2.4 KiB 8.4 KiB
⚪ agents/chat#buildInClauseStrings 2.4 KiB 8.4 KiB
⚪ agents/chat#bumpChatRecoveryProgress 2.4 KiB 8.3 KiB
⚪ agents/chat#byteLength 2.5 KiB 8.5 KiB
⚪ agents/chat#CHAT_LAST_TERMINAL_KEY 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_MESSAGE_TYPES 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERING_FLAG_TTL_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERING_KEY 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERY_ALARM_DEBOUNCE_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERY_INCIDENT_KEY_PREFIX 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERY_INCIDENT_TTL_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERY_PROGRESS_KEY 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERY_STABLE_RETRY_DELAY_SECONDS 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_RECOVERY_TASK_NAME 2.3 KiB 8.2 KiB
⚪ agents/chat#CHAT_STREAM_PROGRESS_CREDIT_THROTTLE_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#ChatRecoveryEngine 4.4 KiB 15.3 KiB
⚪ agents/chat#chatRecoveryTaskRunOptions 2.4 KiB 8.6 KiB
⚪ agents/chat#ChatStreamStalledError 2.4 KiB 8.3 KiB
⚪ agents/chat#classifyAgentToolChildRecovery 2.4 KiB 8.5 KiB
⚪ agents/chat#clearChatTerminal 2.3 KiB 8.3 KiB
⚪ agents/chat#clientResolvableToolNames 2.3 KiB 8.3 KiB
⚪ agents/chat#ContinuationState 2.7 KiB 9.8 KiB
⚪ agents/chat#createAgentToolEventState 2.3 KiB 8.3 KiB
⚪ agents/chat#createChatFiberSnapshot 2.5 KiB 8.6 KiB
⚪ agents/chat#createChatRecoveryTaskDefinition 2.6 KiB 9.0 KiB
⚪ agents/chat#createChatStreams 6.4 KiB 22.1 KiB
⚪ agents/chat#createChatTurnTaskDefinition 2.7 KiB 8.9 KiB
⚪ agents/chat#createToolsFromClientSchemas 114.3 KiB 545.4 KiB
⚪ agents/chat#crossMessageToolResultUpdate 2.4 KiB 8.6 KiB
⚪ agents/chat#DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS 2.3 KiB 8.2 KiB
⚪ agents/chat#DEFAULT_CHAT_RECOVERY_MAX_OOM_RETRIES 2.3 KiB 8.2 KiB
⚪ agents/chat#DEFAULT_CHAT_RECOVERY_MAX_WORK 2.3 KiB 8.2 KiB
⚪ agents/chat#DEFAULT_CHAT_RECOVERY_NO_PROGRESS_TIMEOUT_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS 2.3 KiB 8.2 KiB
⚪ agents/chat#DEFAULT_CHAT_RECOVERY_TERMINAL_MESSAGE 2.4 KiB 8.3 KiB
⚪ agents/chat#dispatchChatRecoveryToHandoff 3.0 KiB 9.9 KiB
⚪ agents/chat#drainInteractionApplies 2.3 KiB 8.3 KiB
⚪ agents/chat#enforceRowSizeLimit 3.5 KiB 11.2 KiB
⚪ agents/chat#hasIncompleteToolBatch 2.4 KiB 8.6 KiB
⚪ agents/chat#interceptAgentToolBroadcast 2.5 KiB 8.7 KiB
⚪ agents/chat#isPlatformFailure 2.6 KiB 8.9 KiB
⚪ agents/chat#isReplayChunk 2.4 KiB 8.7 KiB
⚪ agents/chat#iterateWithStallWatchdog 2.6 KiB 8.8 KiB
⚪ agents/chat#KV_DELETE_MAX_KEYS 2.3 KiB 8.2 KiB
⚪ agents/chat#listActiveChatRecoveryIncidents 2.4 KiB 8.4 KiB
⚪ agents/chat#MAX_BOUND_PARAMS 2.3 KiB 8.2 KiB
⚪ agents/chat#MessageType 2.4 KiB 9.0 KiB
⚪ agents/chat#normalizeToolInput 2.3 KiB 8.2 KiB
⚪ agents/chat#parseProtocolMessage 2.5 KiB 9.0 KiB
⚪ agents/chat#partAwaitsClientInteraction 2.4 KiB 8.6 KiB
⚪ agents/chat#pausedExecutionUpdate 2.4 KiB 8.4 KiB
⚪ agents/chat#pendingChatTerminal 2.3 KiB 8.3 KiB
⚪ agents/chat#persistReconstructedOrphan 3.1 KiB 11.0 KiB
⚪ agents/chat#PreStreamTurns 2.6 KiB 9.3 KiB
⚪ agents/chat#readChatRecoveryProgress 2.3 KiB 8.3 KiB
⚪ agents/chat#reconcileMessages 2.8 KiB 9.6 KiB
⚪ agents/chat#reconcileOrphanPartial 2.4 KiB 8.5 KiB
⚪ agents/chat#recordChatTerminal 2.4 KiB 8.3 KiB
⚪ agents/chat#repairInterruptedToolParts 2.6 KiB 9.1 KiB
⚪ agents/chat#resolveChatRecoveryConfig 2.6 KiB 8.9 KiB
⚪ agents/chat#resolveToolMergeId 2.4 KiB 8.5 KiB
⚪ agents/chat#ResumableStream 5.1 KiB 16.8 KiB
⚪ agents/chat#ResumeHandshake 3.0 KiB 10.4 KiB
⚪ agents/chat#ROW_MAX_BYTES 2.3 KiB 8.2 KiB
⚪ agents/chat#runChatRecoveryExhaustion 2.6 KiB 8.9 KiB
⚪ agents/chat#sanitizeMessage 2.5 KiB 8.8 KiB
⚪ agents/chat#sendIfOpen 2.4 KiB 8.4 KiB
⚪ agents/chat#setChatRecovering 2.5 KiB 8.5 KiB
⚪ agents/chat#shouldCreditStreamProgress 2.4 KiB 8.3 KiB
⚪ agents/chat#STREAM_RESUME_NONE_REASONS 2.3 KiB 8.2 KiB
⚪ agents/chat#StreamAccumulator 2.9 KiB 10.7 KiB
⚪ agents/chat#StreamProgressCreditThrottle 2.4 KiB 8.3 KiB
⚪ agents/chat#SubmitConcurrencyController 2.9 KiB 10.3 KiB
⚪ agents/chat#sweepStaleChatRecoveryIncidents 2.4 KiB 8.5 KiB
⚪ agents/chat#TextSegmentJoiner 2.7 KiB 9.2 KiB
⚪ agents/chat#TIMED_OUT 2.3 KiB 8.2 KiB
⚪ agents/chat#toolApprovalUpdate 2.4 KiB 8.5 KiB
⚪ agents/chat#toolPartHasSettledResult 2.3 KiB 8.4 KiB
⚪ agents/chat#toolResultUpdate 2.4 KiB 8.5 KiB
⚪ agents/chat#truncateOlderMessages 3.2 KiB 10.4 KiB
⚪ agents/chat#TurnQueue 2.6 KiB 9.2 KiB
⚪ agents/chat#unwrapChatFiberSnapshot 2.4 KiB 8.5 KiB
⚪ agents/chat#wrapChatFiberSnapshot 2.3 KiB 8.2 KiB
⚪ agents/chat-sdk#ChatSdkStateAdapter 263.5 KiB 1152.6 KiB
⚪ agents/chat-sdk#ChatSdkStateAgent 262.8 KiB 1150.0 KiB
⚪ agents/chat-sdk#createChatSdkState 263.5 KiB 1152.6 KiB
⚪ agents/chat-sdk#defaultKeyShard 261.2 KiB 1141.2 KiB
⚪ agents/chat-sdk#defaultThreadShard 261.1 KiB 1141.0 KiB
⚪ agents/chat/react#detectToolsRequiringConfirmation 3.3 KiB 8.3 KiB
⚪ agents/chat/react#extractClientToolSchemas 3.2 KiB 8.3 KiB
⚪ agents/chat/react#getAgentMessages 3.4 KiB 8.6 KiB
⚪ agents/chat/react#getToolApproval 3.1 KiB 8.0 KiB
⚪ agents/chat/react#getToolCallId 3.1 KiB 8.0 KiB
⚪ agents/chat/react#getToolInput 3.1 KiB 8.0 KiB
⚪ agents/chat/react#getToolOutput 3.1 KiB 8.0 KiB
⚪ agents/chat/react#getToolPartState 3.2 KiB 8.2 KiB
⚪ agents/chat/react#useAgentChat 132.9 KiB 609.7 KiB
⚪ agents/chat/react#WebSocketChatTransport 5.7 KiB 17.1 KiB
⚪ agents/chat/transport#WebSocketChatTransport 2.8 KiB 9.2 KiB
⚪ agents/client#AgentClient 21.8 KiB 75.2 KiB
⚪ agents/client#AgentConnectionError 16.3 KiB 57.8 KiB
⚪ agents/client#agentFetch 19.7 KiB 69.0 KiB
⚪ agents/client#createStubProxy 16.4 KiB 57.8 KiB
⚪ agents/client#DEFAULT_CALL_TIMEOUT_MS 16.2 KiB 57.6 KiB
⚪ agents/client#isTerminalCloseEvent 16.3 KiB 57.6 KiB
⚪ agents/client#nativeCall 16.5 KiB 58.3 KiB
⚪ agents/client#NativeCallQueue 16.7 KiB 58.9 KiB
⚪ agents/client#splitCallOptions 16.3 KiB 57.7 KiB
⚪ agents/context#AgentContextProvider 412 B 792 B
⚪ agents/context#AgentSearchProvider 640 B 1.3 KiB
⚪ agents/context#ContextBlocks 87.4 KiB 429.7 KiB
⚪ agents/email#createAddressBasedEmailResolver 193 B 227 B
⚪ agents/email#createCatchAllEmailResolver 110 B 97 B
⚪ agents/email#createHeaderBasedEmailResolver 334 B 492 B
⚪ agents/email#createSecureReplyEmailResolver 718 B 1.3 KiB
⚪ agents/email#DEFAULT_MAX_AGE_SECONDS 56 B 39 B
⚪ agents/email#isAutoReplyEmail 201 B 249 B
⚪ agents/email#signAgentHeaders 424 B 812 B
⚪ agents/experimental/webmcp#registerWebMcp 85.2 KiB 295.8 KiB
⚪ agents/lifecycle#getCurrentAgent 376 B 798 B
⚪ agents/lifecycle#Lifecycle 8.4 KiB 26.1 KiB
⚪ agents/lifecycle#LifecycleCapability 497 B 999 B
⚪ agents/mcp#createLegacyMcpHandler 378.6 KiB 1583.3 KiB
⚪ agents/mcp#createMcpHandler 390.9 KiB 1628.5 KiB
⚪ agents/mcp#DurableObjectEventStore 345.1 KiB 1441.8 KiB
⚪ agents/mcp#ElicitRequestSchema 345.1 KiB 1441.8 KiB
⚪ agents/mcp#experimental_createMcpHandler 378.7 KiB 1583.6 KiB
⚪ agents/mcp#getMcpAuthContext 345.1 KiB 1441.9 KiB
⚪ agents/mcp#MCP_SERVER_ID_MAX_LENGTH 345.1 KiB 1441.9 KiB
⚪ agents/mcp#McpAgent 345.1 KiB 1441.8 KiB
⚪ agents/mcp#normalizeServerId 345.1 KiB 1441.8 KiB
⚪ agents/mcp#RPC_DO_PREFIX 345.1 KiB 1441.8 KiB
⚪ agents/mcp#RPCClientTransport 345.1 KiB 1441.8 KiB
⚪ agents/mcp#RPCServerTransport 345.1 KiB 1441.8 KiB
⚪ agents/mcp#SSEEdgeClientTransport 345.2 KiB 1442.1 KiB
⚪ agents/mcp#StreamableHTTPEdgeClientTransport 345.2 KiB 1442.1 KiB
⚪ agents/mcp#WorkerTransport 348.5 KiB 1458.7 KiB
⚪ agents/mcp/client#getNamespacedData 62.9 KiB 240.0 KiB
⚪ agents/mcp/client#MCP_SERVER_ID_MAX_LENGTH 62.9 KiB 239.9 KiB
⚪ agents/mcp/client#MCPClientManager 158.6 KiB 702.6 KiB
⚪ agents/mcp/client#normalizeServerId 63.0 KiB 240.2 KiB
⚪ agents/mcp/do-oauth-client-provider#DurableObjectOAuthClientProvider 2.1 KiB 6.6 KiB
⚪ agents/mcp/server#createMcpHandler 80.5 KiB 307.2 KiB
⚪ agents/mcp/server#getMcpAuthContext 64.0 KiB 245.5 KiB
⚪ agents/observability#channels 259 B 549 B
⚪ agents/observability#genericObservability 470 B 1.2 KiB
⚪ agents/observability#subscribe 324 B 668 B
⚪ agents/observability/ai#wrapAISDK 8.8 KiB 30.5 KiB
⚪ agents/queue#Queue 3.1 KiB 9.6 KiB
⚪ agents/react#_testUtils 19.3 KiB 66.4 KiB
⚪ agents/react#useAgent 27.1 KiB 89.9 KiB
⚪ agents/react#useAgentToolEvents 21.1 KiB 73.7 KiB
⚪ agents/routing#getAgentByName 795 B 1.7 KiB
⚪ agents/routing#routeAgentRequest 1.6 KiB 3.6 KiB
⚪ agents/routing#RoutedAgents 2.4 KiB 6.2 KiB
⚪ agents/schedule#getSchedulePrompt 85.8 KiB 424.7 KiB
⚪ agents/schedule#scheduleSchema 85.3 KiB 423.6 KiB
⚪ agents/schedule#unstable_getSchedulePrompt 85.9 KiB 424.9 KiB
⚪ agents/schedule#unstable_scheduleSchema 85.3 KiB 423.6 KiB
⚪ agents/schedules#Scheduler 6.8 KiB 22.0 KiB
⚪ agents/schedules/parser#getSchedulePrompt 85.8 KiB 424.7 KiB
⚪ agents/schedules/parser#scheduleSchema 85.3 KiB 423.6 KiB
⚪ agents/sessions#COMPACTION_PREFIX 147 B 160 B
⚪ agents/sessions#createCompactFunction 1.7 KiB 4.0 KiB
⚪ agents/sessions#isCompactionMessage 177 B 200 B
⚪ agents/sessions#Session 2.0 KiB 6.3 KiB
⚪ agents/sessions#Sessions 9.6 KiB 34.3 KiB
⚪ agents/skills#fromManifest 309.8 KiB 1084.0 KiB
⚪ agents/skills#parseSkillFrontmatter 328.4 KiB 1146.2 KiB
⚪ agents/skills#parseSkillMarkdown 328.6 KiB 1146.5 KiB
⚪ agents/skills#r2 330.2 KiB 1150.4 KiB
⚪ agents/skills#runner 369.0 KiB 1297.8 KiB
⚪ agents/skills#SkillRegistry 416.4 KiB 1581.7 KiB
⚪ agents/skills/compile#compileSkillScript 15.4 KiB 43.4 KiB
⚪ agents/skills/compile#isCompilableSkillScript 15.4 KiB 43.3 KiB
⚪ agents/state#State 1.1 KiB 2.4 KiB
⚪ agents/streams#DEFAULT_MAX_CHUNK_BYTES 94 B 96 B
⚪ agents/streams#sseResponse 857 B 1.6 KiB
⚪ agents/streams#StreamClosedError 175 B 212 B
⚪ agents/streams#StreamNotFoundError 215 B 276 B
⚪ agents/streams#Streams 4.3 KiB 13.9 KiB
⚪ agents/streams#StreamSerializationError 171 B 201 B
⚪ agents/tasks#DuplicateTaskStepError 328 B 463 B
⚪ agents/tasks#MAX_SERIALIZED_BYTES 190 B 232 B
⚪ agents/tasks#MissingTaskDefinitionError 358 B 536 B
⚪ agents/tasks#NonRetryableError 238 B 308 B
⚪ agents/tasks#TaskReplayDivergedError 341 B 483 B
⚪ agents/tasks#Tasks 8.9 KiB 31.8 KiB
⚪ agents/tasks#TaskSerializationError 258 B 339 B
⚪ agents/types#MessageType 211 B 365 B
⚪ agents/vite#default 353.8 KiB 1356.1 KiB
⚪ agents/voice#addSFUTracks 324 B 424 B
⚪ agents/voice#createSFUSession 255 B 306 B
⚪ agents/voice#createSFUWebSocketAdapter 331 B 429 B
⚪ agents/voice#decodeVarint 157 B 160 B
⚪ agents/voice#downsample48kStereoTo16kMono 238 B 324 B
⚪ agents/voice#encodePayloadToProtobuf 189 B 279 B
⚪ agents/voice#encodeVarint 129 B 122 B
⚪ agents/voice#extractPayloadFromProtobuf 271 B 425 B
⚪ agents/voice#iterateText 1.6 KiB 3.8 KiB
⚪ agents/voice#renegotiateSFUSession 329 B 428 B
⚪ agents/voice#SentenceChunker 550 B 1.1 KiB
⚪ agents/voice#sfuFetch 294 B 358 B
⚪ agents/voice#upsample16kMonoTo48kStereo 211 B 272 B
⚪ agents/voice#VOICE_PROTOCOL_VERSION 51 B 31 B
⚪ agents/voice#withVoice 9.5 KiB 32.7 KiB
⚪ agents/voice#withVoiceInput 4.8 KiB 16.0 KiB
⚪ agents/voice#WorkersAIFluxSTT 1.5 KiB 4.3 KiB
⚪ agents/voice#WorkersAINova3STT 1.6 KiB 4.3 KiB
⚪ agents/voice#WorkersAITTS 682 B 1.4 KiB
⚪ agents/voice/client#VOICE_PROTOCOL_VERSION 473 B 768 B
⚪ agents/voice/client#VoiceClient 10.1 KiB 31.6 KiB
⚪ agents/voice/client#WebSocketVoiceTransport 4.6 KiB 13.3 KiB
⚪ agents/voice/errors#logVoiceError 132 B 173 B
⚪ agents/voice/errors#toVoiceError 94 B 80 B
⚪ agents/voice/errors#voiceErrorMessage 125 B 111 B
⚪ agents/voice/errors#VoiceProviderError 190 B 345 B
⚪ agents/voice/react#useVoiceAgent 13.6 KiB 42.5 KiB
⚪ agents/voice/react#useVoiceInput 13.3 KiB 41.4 KiB
⚪ agents/voice/react#WebSocketVoiceTransport 7.4 KiB 21.3 KiB
⚪ agents/voice/sfu#addSFUTracks 323 B 424 B
⚪ agents/voice/sfu#createSFUSession 254 B 306 B
⚪ agents/voice/sfu#createSFUWebSocketAdapter 329 B 429 B
⚪ agents/voice/sfu#decodeVarint 155 B 160 B
⚪ agents/voice/sfu#downsample48kStereoTo16kMono 236 B 324 B
⚪ agents/voice/sfu#encodePayloadToProtobuf 188 B 279 B
⚪ agents/voice/sfu#encodeVarint 129 B 122 B
⚪ agents/voice/sfu#extractPayloadFromProtobuf 270 B 425 B
⚪ agents/voice/sfu#renegotiateSFUSession 329 B 428 B
⚪ agents/voice/sfu#sfuFetch 292 B 358 B
⚪ agents/voice/sfu#upsample16kMonoTo48kStereo 209 B 272 B
⚪ agents/voice/text#iterateText 1.6 KiB 3.8 KiB
⚪ agents/voice/text#SentenceChunker 549 B 1.1 KiB
⚪ agents/voice/types#VOICE_PROTOCOL_VERSION 51 B 31 B
⚪ agents/voice/workers-ai#WorkersAIFluxSTT 1.5 KiB 4.3 KiB
⚪ agents/voice/workers-ai#WorkersAINova3STT 1.6 KiB 4.3 KiB
⚪ agents/voice/workers-ai#WorkersAITTS 682 B 1.4 KiB
⚪ agents/websockets#CAPNWEB_TRANSPORT_QUERY 12.4 KiB 43.3 KiB
⚪ agents/websockets#CAPNWEB_TRANSPORT_VALUE 12.4 KiB 43.3 KiB
⚪ agents/websockets#capnWebTransportUrl 12.5 KiB 43.5 KiB
⚪ agents/websockets#CF_NO_PROTOCOL_KEY 12.4 KiB 43.3 KiB
⚪ agents/websockets#CF_READONLY_KEY 12.4 KiB 43.3 KiB
⚪ agents/websockets#isCapnWebTransportUpgrade 12.5 KiB 43.4 KiB
⚪ agents/websockets#registerInternalConnectionKeys 12.4 KiB 43.4 KiB
⚪ agents/websockets#WebSockets 20.0 KiB 69.3 KiB
⚪ agents/workflows#AgentWorkflow 262.4 KiB 1145.7 KiB
⚪ agents/workflows#WorkflowRejectedError 261.2 KiB 1141.2 KiB
⚪ agents/x402#normalizeNetwork 14.7 KiB 61.1 KiB
⚪ agents/x402#withX402 23.0 KiB 89.2 KiB
⚪ agents/x402#withX402Client 104.1 KiB 346.5 KiB

Reported by agent-think[bot].

Base automatically changed from feat/browser-interaction-contract to main September 17, 2026 00:16
@ben-reitz
ben-reitz force-pushed the feat/browser-named-sessions branch from 671c189 to 41c4b81 Compare September 17, 2026 00:16
@ben-reitz
ben-reitz marked this pull request as ready for review September 17, 2026 08:28

@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.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 7 potential issues.

Devin Review

Comment thread packages/agents/src/browser/session-core.ts
Comment thread packages/agents/src/browser/session-core.ts Outdated
Comment thread packages/agents/src/browser/session-core.ts Outdated
Comment on lines +227 to +231
await this.#store.set(key, { ...current, closedAt: Date.now() });
} finally {
await lock.release();
}
await deleteBrowserSession(this.#browser, stored.sessionId);

@devin-ai-integration devin-ai-integration Bot Sep 17, 2026 •

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.

🟡 Deletion failures become unretryable

When deletion fails after close() tombstones a session, later closes return false without retrying. sweep() treats the tombstone as deleted, leaving the browser alive until platform expiry.

Learn more

A tombstone currently represents both “closure requested” and “platform deletion completed.” close() writes that state before making the delete request. If the request fails, the tombstone branch only ages and prunes the record; it never retries deletion. The sweep failure path has the same state transition before its best-effort delete.

Example: close("checkout") tombstones session-7, then Browser Run returns 500 to the delete. Retrying close("checkout") returns false, and future sweeps eventually remove the tombstone without another delete request.

Recommended fix: Persist a deletion-pending state and retry deletion from close() and sweep() until a successful or 404 response. Only transition to a completed tombstone after deletion succeeds, while retaining the restart evidence required by resolve().

Devin Review


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

Comment thread packages/agents/src/browser/browser-run.ts
Comment thread packages/agents/src/browser/browser-run.ts
Comment thread packages/agents/src/tests/browser-session-core.test.ts
@ben-reitz
ben-reitz force-pushed the feat/browser-named-sessions branch 3 times, most recently from c670fa0 to 2e30e9f Compare September 17, 2026 13:52

@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 2 new potential issues.

Devin Review

Comment thread packages/agents/src/browser/cdp-session.ts
Comment on lines +405 to +414
if (winner) {
try {
await deleteBrowserSession(this.#browser, stored.sessionId);
} catch (error) {
console.warn(
`[agents/browser] Failed to delete redundant Browser Run session ${stored.sessionId}`,
error
);
}
return { winner };

@devin-ai-integration devin-ai-integration Bot Sep 17, 2026 •

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.

🟡 Concurrent closure returns a dead session

If close() or sweep() tombstones the winner during redundant-session cleanup, resolve() returns its stale live snapshot. The returned session was already deleted, so attachment fails.

Learn more

A create race stores current in winner, releases the lock, and awaits deletion of the redundant platform session. The stored entry can change while that network request runs. The caller only checks winner.closedAt on the old object at resolve, so a concurrent tombstone is invisible.

Example: Two resolvers replace the same tombstone. Resolver A commits session A. Resolver B records session A as the winner and starts deleting session B. A concurrent close() tombstones and deletes session A before B's cleanup finishes. Resolver B still returns session A as live.

Recommended fix: Re-read and validate the key after redundant-session cleanup before returning a winner. Retry resolution when the current entry differs, is absent, or is tombstoned.

Devin Review


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

Provider-independent named sessions over the existing store contract:

- NamedBrowserSessions.resolve() is reattach-or-create keyed by
  browser:session:<name> — hosts wire names, models never see session
  identity. restarted: true signals loudly whenever a prior browser was
  lost (died upstream, closed, or swept); first-ever use is not a
  restart.
- Durable creation options (keepAliveMs, recording,
  guardrails.allowedDomains/allowedDomainSets) are reapplied on every
  create so they survive the restart path. keep_alive pins to the
  600-second platform max by default.
- createBrowserSession() gains guardrails support — they ride the
  acquire POST body per the Browser Run REST contract; Kitesurf rejects
  them.
- close() tombstones and deletes; sweep() closes idle sessions, leaves
  tombstones, and prunes aged ones (creator-overridable 10-minute TTL,
  alarm scheduling lands with the Lifecycle capability slice).
- openOneShotBrowserSession() is the trivial create-and-close branch:
  no store, platform session deleted when the CDP socket closes.
  connectBrowserSession() gains an optional onClose to support it.

Lock discipline mirrors BrowserConnector: locks wrap storage only,
probes and Browser Run calls run outside, commits re-check for
concurrent swaps (covered by tests, including a lock-across-network
violation detector). Internal module — no public export changes until
the starter-pack slice. Existing browser_execute behavior untouched.
@ben-reitz
ben-reitz force-pushed the feat/browser-named-sessions branch from 2e30e9f to 5b4dad0 Compare September 17, 2026 14:46
@ben-reitz

Copy link
Copy Markdown
Contributor Author

/devin review

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Starting Devin Review.

Devin Review

@ben-reitz
ben-reitz removed this pull request from stack #2295 September 18, 2026 09:51
@ben-reitz

Copy link
Copy Markdown
Contributor Author

Superseded by #2302 (identical commit, recreated so the review bot can pick it up). The stacked PRs above it (#2293, #2294) have been retargeted onto the new branch.

@ben-reitz ben-reitz closed this Sep 18, 2026
@ben-reitz
ben-reitz deleted the feat/browser-named-sessions branch September 18, 2026 10:05
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