Skip to content

Take-the-wheel cannot reach a popup window: agent-computer pins one Page at launch, so popup OAuth sign-ins are never shown or clickable #270

Description

@jerelvelarde

agent-computer binds a Bot to one Playwright Page, captured once when Chromium launches, and never follows a second one. Any page the site opens in a new window or tab is invisible to the live screen and unreachable by input, including while a person holds the wheel.

This lands hardest on take-the-wheel, which exists so a person can complete the sign-ins a Bot cannot. Popup-based OAuth is how a large share of "Sign in with Google / Twitter / LinkedIn" buttons work, so the flows most likely to need a human are the ones the human cannot see.

What is wrong

The page is captured at launch and stored:

// agent-computer/src/profiles.ts:311
// Persistent contexts open with a page already; reuse it rather than leaving an extra blank tab.
const page = context.pages()[0] ?? (await context.newPage());
live.set(botId, { context, page, startedAt: ..., usedAt: ... });

live.set is the only write of that record, context.pages() is called on that one line and nowhere else, and there is **no context.on("page") or page.on("popup") handler anywhere in agent-computer/src.

Everything downstream funnels through one accessor, so they all inherit the pinned page:

// agent-computer/src/index.ts:212
async function currentPage(botId: string): Promise<Page> {
  return profiles.page(botId);
}

currentPage is what /stream, the control input path, /navigate, /screenshot, /read and /snapshot each resolve (index.ts:384, 593, 656, 724, 756, 879, 900, 916). The screencast then pins a CDP session to that same page:

// agent-computer/src/screencast.ts:110
const client: CDPSession = await page.context().newCDPSession(page);

So when a site calls window.open, Chromium creates a second Page in the context and gives it focus. That page loads and is perfectly real. But the cast keeps streaming page 0, and clicks and keystrokes keep going to page 0. The person sees a stale screen and their input lands on the wrong document.

How it shows up

A Bot working in Typefully handed the wheel over with "You have control — click and type on the page. Sign in to your Typefully account so I can continue in the same browser session." The login modal offers Google, X/Twitter, LinkedIn and Email. Clicking Google opens the Google consent window as a popup: the live screen does not change, and nothing the person clicks or types reaches it. Sign-in cannot be completed at all. Three of the four buttons in that modal take a popup route; only Email stays on the same document and works.

Suggested direction

Follow the context's active page rather than pinning one. Subscribe to context.on("page"), and when a new page becomes the active one, update the live record and re-attach the screencast's CDP session to it, moving back when it closes.

The awkward part is that page identity is currently assumed stable across the acting path as well as the viewing path — element refs and snapshots are resolved against "the" page — so switching pages mid-session needs a decision about what happens to refs taken against the page that just lost focus. Closing over that is more of the work than the listener is.

Possibly related but distinct: #190 concerns viewer/socket lifecycle rather than which page is being cast.

How to check it is fixed

Give a Bot a page with a button that calls window.open on a document that is visibly different from the opener, take the wheel, and click it. The live screen should show the opened document, and typing should reach it. Closing it should return the screen to the opener. The real-world check is completing a popup-based Google sign-in end to end while holding the wheel.

Scope of verification

The code path above was read at 7fda66a and the absence of any page or popup listener confirmed by grep across agent-computer/src. The failure was observed in a real deployment as described. I have not instrumented a reduced reproduction, and the suggested fix is untested.

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