Skip to content

🤖 feat: auto-enable browser session streaming on bootstrap#3073

Merged
ThomasK33 merged 7 commits intomainfrom
stream-panel-erc4
Mar 25, 2026
Merged

🤖 feat: auto-enable browser session streaming on bootstrap#3073
ThomasK33 merged 7 commits intomainfrom
stream-panel-erc4

Conversation

@ThomasK33
Copy link
Member

Summary

Auto-enable runtime agent-browser streaming for missing_stream sessions in the Browser tab, eliminating the dead-end AGENT_BROWSER_STREAM_PORT env-var message.

Background

When an agent-browser session is started without AGENT_BROWSER_STREAM_PORT, the Browser tab discovers it but shows a dead-end message telling the user to restart with the env var set. The agent-browser CLI now supports runtime streaming commands (stream status, stream enable, stream disable), so Mux can enable streaming on demand instead of requiring a restart.

Implementation

Backend (AgentBrowserSessionDiscoveryService.ts, router.ts):

  • Added ensureSessionAttachable() method that auto-enables streaming for missing_stream sessions at bootstrap time
  • Added CLI helpers for agent-browser --json --session <name> stream status|enable with defensive JSON parsing
  • Fast-paths already-attachable sessions (no CLI overhead)
  • Updated getBootstrap handler to use ensureSessionAttachable instead of getSessionConnection
  • All CLI helpers are injectable for testing

Frontend (BrowserTab.tsx):

  • Removed getMissingStreamMessage() and the missing_stream disconnect guard
  • missing_stream sessions now proceed to getBootstrap which triggers runtime enablement
  • Shows "Starting live preview…" transient state instead of the env-var dead-end
  • Discovery badge changed from "Needs streaming" (warning) → "Activating" (accent)

Validation

  • make typecheck
  • make lint
  • make static-check ✅ (only hadolint missing, unrelated)
  • Backend tests (6 new cases): fast path, enable path, already-enabled-via-CLI, enable failure, session-not-found, unverifiable-post-enable
  • Frontend test: verifies missing_stream sessions trigger connect and show activating copy

Dogfood evidence

Tested with a sandboxed dev server + real agent-browser session started without AGENT_BROWSER_STREAM_PORT:

Test Result
Auto-enable for missing_stream session ✅ Live preview of example.com rendered
No env-var dead-end message ✅ Never appeared
Already-streaming session reconnects ✅ Immediate reconnection via fast path
Killed session → graceful failure ✅ Shows "Waiting for browser preview"
📸 Dogfood screenshots

Browser tab with live preview after auto-enable:
The Browser tab shows "Live" badge with mux-stream-smoke session rendering example.com. Session was started without AGENT_BROWSER_STREAM_PORT.

Reconnection fast path:
After switching tabs and back, the bridge reconnected immediately showing "Live" badge.

Negative path — session killed:
After killing the session, the Browser tab shows "Waiting for browser preview" with a neutral message about auto-attaching when available.

Risks

  • Low regression risk for existing attachable sessions: The fast path (status === "attachable") returns immediately without calling any CLI stream commands.
  • CLI contract dependency: The stream status and stream enable JSON output parsing is isolated behind narrow helpers, so upstream CLI changes are easy to adapt to.
  • No stream disable exposed: Intentionally omitted — no UX need identified.

📋 Implementation Plan

Plan: integrate runtime agent-browser streaming into the right-hand Browser panel

Goal

Make the RHS Browser tab auto-attach to a running agent-browser session even when that session was launched without AGENT_BROWSER_STREAM_PORT.

Target behavior:

  • keep discovering sessions by workspace/cwd as today,
  • when the selected session already has streaming enabled, reuse its active port,
  • when streaming is off, enable it at runtime with no explicit port and then connect,
  • remove the dead-end env-var-specific message from the Browser tab.

Verified context

  • src/browser/features/RightSidebar/BrowserTab/BrowserTab.tsx currently renders the env-var error via getMissingStreamMessage(...).
  • src/browser/features/RightSidebar/BrowserTab/useBrowserBridgeConnection.ts currently short-circuits and disconnects when the selected discovered session status is "missing_stream".
  • src/node/services/browser/AgentBrowserSessionDiscoveryService.ts currently marks a workspace-matching session as missing_stream when <session>.stream is absent, and reads the stream port from that file when present.
  • src/node/orpc/router.ts and src/common/orpc/schemas/api.ts currently expose browser.listSessions and browser.getBootstrap for the Browser tab flow.
  • The latest agent-browser CLI now advertises runtime streaming commands (stream enable [--port], stream disable, stream status), while the public README/docs still mostly describe the startup env-var path. Plan against the CLI/runtime behavior rather than the older docs.

Recommended approaches

A. Auto-enable on bootstrap — recommended (product code net LoC: +80 to +130)

Use the existing discovery flow to list sessions, but change backend bootstrap so the selected session is made attachable on demand:

  1. check stream status,
  2. reuse the port if already enabled,
  3. otherwise run stream enable with no --port,
  4. connect Mux to the resulting port.

Why this is the plan of record:

  • matches the requested “if it is off, enable it and connect” behavior,
  • removes the current dead-end UX without adding a new manual step,
  • keeps side effects out of the 2s polling loop,
  • minimizes frontend/API churn.

B. Explicit “Enable preview” action in the Browser tab (product code net LoC: +120 to +190)

Keep missing_stream as a blocked UI state and add a button that calls a new backend action to enable streaming before reconnecting.

Why this is the fallback only:

  • more UI state, more IPC surface, more tests,
  • does not match the user’s desired automatic fallback as closely,
  • still leaves a temporary dead-end state in the picker.

Plan of record

Implement Approach A.

Expected touch points

  • src/node/services/browser/AgentBrowserSessionDiscoveryService.ts
  • src/node/orpc/router.ts
  • src/browser/features/RightSidebar/BrowserTab/useBrowserBridgeConnection.ts
  • src/browser/features/RightSidebar/BrowserTab/BrowserTab.tsx
  • src/node/services/browser/AgentBrowserSessionDiscoveryService.test.ts
  • src/browser/features/RightSidebar/BrowserTab/BrowserTab.test.tsx
  • src/browser/features/RightSidebar/BrowserTab/useBrowserBridgeConnection.test.tsx (if present; otherwise extend the closest Browser tab test coverage)

Implementation phases

Phase 1 — backend: ensure runtime streaming before bridge bootstrap

Files: src/node/services/browser/AgentBrowserSessionDiscoveryService.ts, src/node/orpc/router.ts

  1. Extend the browser session discovery/backend helper layer with a narrow “ensure attachable session” path for a selected session name.
  2. Keep listSessions() read-only and cheap. It should continue to discover sessions and classify missing_stream without side effects.
  3. In the selected-session bootstrap path:
    • verify the session still belongs to the requested workspaceId,
    • call agent-browser --session <name> stream status --json,
    • if status reports streaming enabled with a positive port, use it,
    • otherwise call agent-browser --session <name> stream enable --json without --port,
    • confirm the resulting port via returned JSON and/or a follow-up status check before building the bridge.
  4. Update browser.getBootstrap to use that “ensure attachable” path instead of assuming missing_stream is terminal.
  5. Keep the public ORPC contract unchanged unless implementation proves a dedicated status/enable method is necessary.

Defensive-programming requirements

  • Assert/validate non-empty session names and positive port values.
  • Parse CLI output through a narrow schema/helper instead of trusting ad-hoc JSON.
  • Treat impossible states (enabled: true with no port, malformed JSON, vanished session) as explicit failures with clear error messages.
  • Prefer re-checking status after stream enable rather than assuming the returned data is sufficient.

Phase 1 quality gate

  • Add/extend targeted tests for:
    • already-enabled session path,
    • disabled → enabled path,
    • malformed stream status / stream enable payloads,
    • CLI failure / unsupported-command failure,
    • session disappears between discovery and bootstrap.

Phase 2 — frontend: stop treating missing_stream as terminal

Files: src/browser/features/RightSidebar/BrowserTab/useBrowserBridgeConnection.ts, src/browser/features/RightSidebar/BrowserTab/BrowserTab.tsx

  1. Remove the early missing_stream disconnect gate from useBrowserBridgeConnection.ts so selecting a discovered session still attempts browser.getBootstrap.
  2. Replace the env-var-specific dead-end copy in BrowserTab.tsx with a neutral state machine:
    • while bootstrap/auto-enable is in flight: show a transient “Starting live preview…” state,
    • on success: render the existing browser viewport,
    • on failure: show the actual enable/status/connect error instead of blaming startup env vars.
  3. After a successful attach, trigger an immediate session refresh so the UI can flip that session from missing_stream to attachable on the next render.
  4. Revisit the session picker badge text ("Needs streaming") if it becomes misleading once streaming can be started lazily; either rename it to something neutral or remove it once the refresh settles.

Phase 2 quality gate

  • Add/extend UI tests proving that:
    • selecting a missing_stream session no longer dead-ends,
    • the Browser tab shows a transient/loading state while runtime enablement happens,
    • failures surface actionable copy,
    • existing attachable sessions still connect normally.

Phase 3 — hardening and repo-level validation

  1. Confirm attachable sessions still use the fast path.
  2. Confirm a session started without AGENT_BROWSER_STREAM_PORT now attaches on first selection.
  3. Confirm graceful handling when:
    • the session exits after discovery,
    • stream status reports an unexpected shape,
    • the local bridge cannot connect even after enable succeeds.
  4. Run validation on touched areas:
    • targeted backend/browser-tab tests,
    • make typecheck,
    • make lint (or the repo’s preferred targeted lint equivalent for touched files).

Acceptance criteria

  • Selecting a discovered Browser-tab session that was launched without AGENT_BROWSER_STREAM_PORT no longer lands on the dead-end env-var message.
  • If runtime streaming is already enabled, Mux reuses the active port.
  • If runtime streaming is disabled, Mux enables it with no explicit port, discovers the resulting port, and connects.
  • Existing attachable sessions still connect without regression.
  • Failures are precise and session-specific (status failure, enable failure, vanished session, bridge failure), not misleading env-var copy.
  • Tests cover both the already-enabled path and the disabled→enable path.

Dogfooding / reviewer evidence

Setup

  1. Start the app with make dev.
  2. In a second terminal, from a cwd that matches the target workspace, start an agent-browser session without AGENT_BROWSER_STREAM_PORT, for example:
    • agent-browser --session mux-stream-smoke open https://example.com
  3. Open the workspace in Mux and switch to the right-hand Browser tab.

Dogfood flow

  1. Select the discovered agent-browser session.
  2. Verify Mux auto-enables streaming and renders the live preview without requiring a restart.
  3. Verify the old env-var-specific message never appears.
  4. Repeat with a session that already has streaming enabled and verify the preview still connects immediately.

Reviewer artifacts

Capture and attach all of the following:

  • a screenshot of the Browser tab before the connection settles (if the transient loading state is visible),
  • a screenshot of the live preview after attach succeeds,
  • a short screen recording showing: session selection → runtime enablement/connection → preview render.

Negative-path dogfood

  • Close/kill the session after discovery but before selecting it, then verify the Browser tab shows a precise failure.
  • Prefer to cover command-shape/CLI failures with automated tests; manual dogfooding should stay focused on the real UX path plus the vanished-session case.
Tradeoffs and rationale
  • Do not auto-enable during session polling. The polling loop runs every ~2 seconds, and turning discovery into a side-effecting loop would be noisy, surprising, and harder to debug.
  • Keep the first implementation minimal by extending the existing browser-session backend helper rather than introducing a brand-new service unless the parsing/error-handling code becomes unwieldy.
  • The CLI help appears to be ahead of the public README/docs. During implementation, treat the actual command behavior and tests as the source of truth, and isolate parsing behind tiny helpers so it is easy to adjust if upstream refines the JSON contract.
  • stream disable is not required for this user request; do not expose it in Mux unless a concrete UX need appears.

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $7.27

@ThomasK33
Copy link
Member Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1dfaa85c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Added streaming enablement failure patterns (failed to enable streaming, failed to verify streaming) to isRetryableBrowserError() so transient CLI failures during runtime enablement trigger automatic retry. Session-not-found remains non-retryable. New tests cover both paths.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 468cb368e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

@codex review

Fixed: ensureSessionAttachable() now distinguishes between empty discovery (CLI failure → retryable "is unavailable" error) vs. session genuinely not found (non-retryable). New tests cover both paths.

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Bravo.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33
Copy link
Member Author

CI Status Update

The only failing CI check is Test / Unit with 2 pre-existing BrowserViewport test failures:

  • BrowserViewport > forwards mapped click and wheel input for interactive sessions
  • BrowserViewport > continues to emit char events for printable typing

Evidence this is pre-existing and unrelated:

  • ❌ Failed 5x in a row across fresh CI runs (not a transient flake)
  • ✅ These tests pass locally (Bun 1.3.6 vs CI's 1.3.5)
  • BrowserViewport.test.tsx and BrowserViewport.tsx are NOT in our diff
  • ✅ Error: Unable to find role="region" with name "Browser viewport" — an accessibility tree difference in CI's happy-dom environment
  • ✅ Codex approved, all review threads resolved
  • ✅ All other CI checks pass (Static Checks, Integration, E2E, Storybook, Build, etc.)

This appears to be a CI environment issue that should be tracked separately.

@ThomasK33 ThomasK33 added this pull request to the merge queue Mar 25, 2026
Merged via the queue into main with commit e7efeab Mar 25, 2026
24 checks passed
@ThomasK33 ThomasK33 deleted the stream-panel-erc4 branch March 25, 2026 22:32
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