Skip to content

Make target routing session-scoped for concurrent agents #10

Open

Description

@ZJHSteven

Hi! I ran into a routing race when multiple agents use the same persistent browser-harness-js REPL / WebSocket concurrently.

Problem

Session.use(targetId) attaches with flatten:true, then stores the returned CDP session in the single mutable activeSessionId. Every later non-browser-level command implicitly uses that value.

That is convenient for one agent, but unsafe for concurrent callers sharing the REPL. For example:

  1. Agent A calls use(tabA) -> active session = A
  2. Agent B calls use(tabB) -> active session = B
  3. Agent A sends Runtime.evaluate, DOM.*, Input.*, etc.
  4. A's command is now routed to tab B

This can also happen inside one long /eval request if it awaits between operations and another request changes activeSessionId meanwhile.

The underlying CDP flat-session model already supports multiple attached sessions over one WebSocket: each command can carry its own sessionId. Keeping long-lived sessions is important too (Network/Console/DOM event monitoring, etc.), so simply attach/detach on every CLI invocation would lose one of the useful properties of the persistent REPL.

There is a related event-side issue: onEvent exposes the event sessionId, but waitFor(method, predicate, timeout) currently does not filter by session. With multiple long-lived target sessions on one WebSocket, a same-named event from another tab could satisfy the wait.

Desired behavior

It would be useful to keep:

  • one persistent browser WebSocket
  • multiple long-lived CDP target sessions on that WebSocket
  • full/raw typed CDP surface (no high-level browser abstraction)
  • use(targetId) as a backwards-compatible single-agent convenience API if desired

while adding a session-scoped routing primitive so concurrent agents never depend on one global active-session pointer.

Conceptually, something like attach(targetId) / forSession(sessionId) could return a scoped view of the same generated CDP domains, permanently bound to that sessionId. Events / waits on that scoped view could likewise filter by sessionId. The exact API naming is flexible; the important property is that routing is carried by the scoped handle / call, not mutable global REPL state.

This would also let an agent explicitly keep and reuse a long-lived CDP session for monitoring, while another agent independently uses another target over the same WebSocket.

Would you be open to this direction? I'm happy to prepare a focused PR with tests for two concurrent target sessions if it fits the project's intended model.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions