Session Caching Mechanism in browser-runtime.ts: How ego-lite Manages CDP Sessions with 2-Second TTL

The browser-runtime.ts module implements a lightweight session cache that retains Chrome DevTools Protocol (CDP) sessions for exactly 2 seconds, preventing redundant Target.attachToTarget calls while automatically recovering from lost connections.

The browser-runtime.ts file in the citrolabs/ego-lite repository serves as the core transport layer for browser automation, managing CDP session lifecycle through a time-based caching strategy. This session caching mechanism reduces communication overhead by reusing existing sessions within a strict 2000-millisecond window, ensuring efficient target interaction without requiring re-attachment on every operation.

Cache State Architecture

The session caching layer maintains mutable state through the centralized state object defined in package/ego-browser/src/state.ts.

State Properties for Session Management

Three critical properties track the cache condition:

  • sessionId: Stores the active CDP session identifier returned by Target.attachToTarget
  • sessionAt: Records the Date.now() timestamp of the last successful session acquisition
  • sessionInflight: Holds a promise that resolves to a new session while establishment is pending, preventing duplicate attachment requests

TTL Constants and Validation Logic

The 2-second cache window is enforced by the SESSION_TTL_MS constant defined at lines 5-6 of browser-runtime.ts:

const SESSION_TTL_MS = 2000;

When ensureSession() executes, it validates cache freshness through a timestamp comparison at lines 12-14:

if (state.sessionId && Date.now() - state.sessionAt < SESSION_TTL_MS) {
  return state.sessionId;               // ✅ Cached session still valid
}

This check determines whether to return the existing sessionId or proceed with new session establishment.

Session Acquisition Flow

The ensureSession() function (lines 7-44) orchestrates the cache logic and CDP attachment protocol.

Cache Hit Behavior

When the timestamp delta falls within the 2000ms threshold, the function immediately returns the cached identifier without network overhead. This optimization eliminates redundant Target.attachToTarget commands for rapid successive calls.

Cache Miss and Session Creation

If the cache is stale or empty, ensureSession() executes the following sequence:

  1. Enumerate targets via browserEgo().listTabs() (lines 16-18)
  2. Select a target using priority logic: preferred target, active tab, or last available tab (lines 19-23)
  3. Attach to target by sending the Target.attachToTarget CDP command when the target differs from the previous session (lines 28-33)
  4. Enable page events through Page.enable to activate domain notifications
  5. Update cache metadata by storing the new sessionId and recording the current timestamp in state.sessionAt (line 37)

Session Recovery and Invalidation

The caching mechanism includes automatic failure recovery to handle dropped CDP connections.

Detecting Session Loss

The browserCdp() function monitors request failures using the SESSION_LOST regex pattern defined at line 9. When a request returns a session-not-found error, the system recognizes the cached session as invalid.

Invalidation Strategy

Upon detecting connection loss, browserCdp() invokes invalidateSession() (lines 99-103), which:

  • Clears state.sessionId and state.sessionAt
  • Removes associated event listeners
  • Forces the next ensureSession() call to establish a fresh attachment

This recovery pattern ensures that transient network issues or target crashes do not permanently break automation workflows.

Implementation Examples

Basic Helper Usage

Helper functions automatically leverage the cache without explicit session management:

import { browserCdp } from "./browser-runtime.js";

async function clickSelector(selector: string) {
  // Automatically uses cached session if <2s old
  await browserCdp("Runtime.evaluate", { 
    expression: `document.querySelector('${selector}').click()` 
  });
}

Manual Cache Inspection

For debugging or advanced control, interact with the cache state directly:

import { state } from "./state.js";
import { ensureSession } from "./browser-runtime.js";

async function demoCache() {
  const first = await ensureSession();           // Creates new session
  console.log("First session:", first);

  // Wait 1s – still within TTL
  await new Promise(r => setTimeout(r, 1000));
  const second = await ensureSession();          // Returns cached session
  console.log("Second (cached) session:", second);

  // Wait 2s – TTL expired
  await new Promise(r => setTimeout(r, 2000));
  const third = await ensureSession();           // Creates fresh session
  console.log("Third (new) session:", third);
}

Forcing Session Refresh

Manually invalidate the cache to recover from specific error conditions:

import { invalidateSession, ensureSession } from "./browser-runtime.js";

async function recoverFromLoss() {
  invalidateSession();          // Clears cache and event maps
  const fresh = await ensureSession(); // Guarantees fresh attachment
  console.log("Recovered session:", fresh);
}

Summary

  • browser-runtime.ts implements a time-based session cache with a hardcoded 2000ms TTL via SESSION_TTL_MS
  • Cache state is centralized in state.ts through sessionId, sessionAt, and sessionInflight properties
  • ensureSession() returns cached identifiers when Date.now() - state.sessionAt < 2000, avoiding redundant Target.attachToTarget calls
  • Automatic recovery occurs through invalidateSession() when the SESSION_LOST regex detects disconnected sessions
  • Concurrent safety is maintained via sessionInflight promises that prevent duplicate attachment attempts during cache misses

Frequently Asked Questions

What triggers a session cache miss in browser-runtime.ts?

A cache miss occurs when state.sessionId is undefined, state.sessionAt is undefined, or when Date.now() - state.sessionAt equals or exceeds SESSION_TTL_MS (2000ms). Additionally, explicit calls to invalidateSession() or detection of a lost session through the SESSION_LOST error pattern immediately clear the cache and force a new attachment.

How does the 2-second TTL impact browser automation performance?

The 2-second window balances connection reuse against stale session detection. According to the citrolabs/ego-lite source code, this TTL reduces CDP attachment overhead for rapid successive operations—such as multi-step form interactions—while ensuring that automation recovers quickly from target crashes or navigation events that invalidate existing sessions.

Can the session TTL be configured or disabled?

No, SESSION_TTL_MS is defined as a constant at lines 5-6 of browser-runtime.ts with a fixed value of 2000ms. The repository does not expose configuration options for this parameter, as the 2-second duration is optimized for the typical lifecycle of browser automation tasks while preventing resource leaks from abandoned CDP sessions.

How does session recovery work after a Target.detachFromTarget event?

When browserCdp() encounters a "session lost" error matching the SESSION_LOST regex, it automatically invokes invalidateSession() (lines 99-103). This function clears state.sessionId and state.sessionAt, then forces the next CDP request to trigger ensureSession() and establish a fresh Target.attachToTarget connection. This recovery mechanism operates transparently without requiring manual intervention in helper functions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →