Skip to content

fix(browser): auto-connect provisioned sessions - #119

Open
MagMueller wants to merge 1 commit into
mainfrom
cloud-auto-connect
Open

fix(browser): auto-connect provisioned sessions#119
MagMueller wants to merge 1 commit into
mainfrom
cloud-auto-connect

Conversation

@MagMueller

@MagMueller MagMueller commented Jul 28, 2026

Copy link
Copy Markdown

Summary

  • auto-connect a disconnected process-scoped Session before browser_execute runs a snippet when BU_CDP_WS or BU_CDP_URL is configured
  • deduplicate concurrent first calls with one per-Session in-flight connection promise
  • preserve explicit-connect behavior when neither provisioned endpoint variable is present
  • propagate the original connection failure instead of wrapping it as a snippet exception

Why

V4 provisions the browser and sets BU_CDP_WS, but a fresh worker still begins with a disconnected in-process Session. In a recent ordered production cohort, all 28 exact Not connected. Call session.connect(...) first. snippets reached CDP before executing a connection; 26/28 later recovered with successful browser calls. Initialization should be deterministic instead of model-dependent.

Semantics and tradeoffs

  • auto-connect runs only at the tool-call boundary; a snippet that closes its socket mid-execution still controls and must perform any same-snippet reconnect itself
  • an already-connected explicit replacement endpoint is left untouched
  • after an explicit close, a later tool call reconnects the fixed provisioned endpoint unless the snippet explicitly reconnects first within the same call
  • an expired or rejected provisioned endpoint is not retried or replaced here; its real WebSocket/endpoint error is returned
  • without BU_CDP_WS/BU_CDP_URL, local BrowserCode behavior is unchanged

Tests

  • first raw CDP snippet auto-connects and subsequent snippets reuse one socket
  • both BU_CDP_WS and BU_CDP_URL trigger the behavior
  • parallel first calls share one connection attempt
  • explicit close plus explicit reconnect remains under snippet control
  • non-cloud sessions still fail raw CDP until explicitly connected
  • failed auto-connect surfaces the original connection error and never runs the snippet

Validation:

  • cd packages/bcode-browser && bun typecheck
  • cd packages/bcode-browser && bun test — 23 passed, 8 live/smoke tests skipped, 0 failed
  • root filtered bun run typecheck — 16 packages passed
  • targeted oxlint — 0 errors; 5 pre-existing warnings in browser-execute.ts

Summary by cubic

Auto-connects provisioned cloud sessions in browser_execute when BU_CDP_WS or BU_CDP_URL is set, eliminating "Not connected" errors. Deduplicates concurrent first connections, keeps local sessions explicit-connect, and returns the original connect error on failure.

  • Bug Fixes
    • Connect the process-scoped Session before a snippet runs when a provisioned endpoint is present; reuse one socket across calls.
    • Share one in-flight connect per Session to avoid race conditions.
    • Leave already-connected or local sessions unchanged; do not retry or mask endpoint errors.

Written for commit f28d0aa. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/bcode-browser/src/browser-execute.ts">

<violation number="1" location="packages/bcode-browser/src/browser-execute.ts:176">
P1: Cloud snippets following the required `browser-execute` skill now connect twice: the tool boundary auto-connects, then the skill's first-call `session.connect()` opens and replaces the WebSocket because `Session.connect()` is not idempotent. Updating the skill to skip `connect()` when the boundary has already connected (for example, `if (!session.isConnected()) await session.connect()`) would keep the documented flow to one socket.</violation>

<violation number="2" location="packages/bcode-browser/src/browser-execute.ts:255">
P2: Auto-connect via `BU_CDP_URL` fails when deployment supplies `BU_CDP_WS=""`. Select the non-empty endpoint explicitly so an empty alias falls back to `BU_CDP_URL`, matching this gate's behavior.</violation>

<violation number="3" location="packages/bcode-browser/src/browser-execute.ts:255">
P2: A tool call that reconnects after `session.close()` can have its new CDP requests rejected as `CDP socket closed` if the prior socket's delayed close event arrives afterward. Scope the close handler's pending-request cleanup to the socket it created (or otherwise wait for the old socket to close) before automatic reconnects.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

})

yield* Effect.tryPromise({
try: () => ensureCloudConnected(session),

@cubic-dev-ai cubic-dev-ai Bot Jul 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Cloud snippets following the required browser-execute skill now connect twice: the tool boundary auto-connects, then the skill's first-call session.connect() opens and replaces the WebSocket because Session.connect() is not idempotent. Updating the skill to skip connect() when the boundary has already connected (for example, if (!session.isConnected()) await session.connect()) would keep the documented flow to one socket.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/bcode-browser/src/browser-execute.ts, line 176:

<comment>Cloud snippets following the required `browser-execute` skill now connect twice: the tool boundary auto-connects, then the skill's first-call `session.connect()` opens and replaces the WebSocket because `Session.connect()` is not idempotent. Updating the skill to skip `connect()` when the boundary has already connected (for example, `if (!session.isConnected()) await session.connect()`) would keep the documented flow to one socket.</comment>

<file context>
@@ -167,6 +172,11 @@ export const make = Effect.fn("BrowserExecute.make")(function* (dataDir: string)
       })
 
+      yield* Effect.tryPromise({
+        try: () => ensureCloudConnected(session),
+        catch: (err) => (err instanceof Error ? err : new Error(String(err))),
+      })
</file context>
Fix with cubic

const existing = cloudConnections.get(session)
if (existing) return existing

const connecting = session.connect()

@cubic-dev-ai cubic-dev-ai Bot Jul 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Auto-connect via BU_CDP_URL fails when deployment supplies BU_CDP_WS="". Select the non-empty endpoint explicitly so an empty alias falls back to BU_CDP_URL, matching this gate's behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/bcode-browser/src/browser-execute.ts, line 255:

<comment>Auto-connect via `BU_CDP_URL` fails when deployment supplies `BU_CDP_WS=""`. Select the non-empty endpoint explicitly so an empty alias falls back to `BU_CDP_URL`, matching this gate's behavior.</comment>

<file context>
@@ -235,4 +245,20 @@ export const make = Effect.fn("BrowserExecute.make")(function* (dataDir: string)
+  const existing = cloudConnections.get(session)
+  if (existing) return existing
+
+  const connecting = session.connect()
+  cloudConnections.set(session, connecting)
+  try {
</file context>
Suggested change
const connecting = session.connect()
const connecting = session.connect({ wsUrl: process.env.BU_CDP_WS || process.env.BU_CDP_URL })
Fix with cubic

const existing = cloudConnections.get(session)
if (existing) return existing

const connecting = session.connect()

@cubic-dev-ai cubic-dev-ai Bot Jul 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: A tool call that reconnects after session.close() can have its new CDP requests rejected as CDP socket closed if the prior socket's delayed close event arrives afterward. Scope the close handler's pending-request cleanup to the socket it created (or otherwise wait for the old socket to close) before automatic reconnects.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/bcode-browser/src/browser-execute.ts, line 255:

<comment>A tool call that reconnects after `session.close()` can have its new CDP requests rejected as `CDP socket closed` if the prior socket's delayed close event arrives afterward. Scope the close handler's pending-request cleanup to the socket it created (or otherwise wait for the old socket to close) before automatic reconnects.</comment>

<file context>
@@ -235,4 +245,20 @@ export const make = Effect.fn("BrowserExecute.make")(function* (dataDir: string)
+  const existing = cloudConnections.get(session)
+  if (existing) return existing
+
+  const connecting = session.connect()
+  cloudConnections.set(session, connecting)
+  try {
</file context>
Fix with cubic

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