From 03a70fb9fe466e50276a32f7cec38263ec071ff2 Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Wed, 18 Feb 2026 22:58:27 +0100 Subject: [PATCH] warn agents when popup windows are detected during execution When window.open() creates a popup, agents have no visibility into it and can't control it via playwriter. This adds a [WARNING] line to the executor output telling agents the popup page index, URL, and to repeat the interaction without popups or navigate to the URL directly. Detection uses page.opener() on newly created pages (context 'page' event), not on existing pages during reconnection to avoid false positives. --- playwriter/src/executor.ts | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/playwriter/src/executor.ts b/playwriter/src/executor.ts index 00c3643..d2add02 100644 --- a/playwriter/src/executor.ts +++ b/playwriter/src/executor.ts @@ -219,6 +219,7 @@ export class PlaywrightExecutor { private browserLogs: Map = new Map() private lastSnapshots: WeakMap = new WeakMap() private lastRefToLocator: WeakMap> = new WeakMap() + private popupWarnings: string[] = [] private scopedFs: ScopedFS private sandboxedRequire: NodeRequire @@ -305,6 +306,28 @@ export class PlaywrightExecutor { } } + private setupPageListeners(page: Page) { + this.setupPageConsoleListener(page) + this.setupPopupDetection(page) + } + + private setupPopupDetection(page: Page) { + // Check if this page was opened by window.open() (has an opener) + const opener = page.opener() + if (!opener) { + return + } + const context = page.context() + const pages = context.pages() + const pageIndex = pages.indexOf(page) + const url = page.url() + this.popupWarnings.push( + `Popup window detected (page index ${pageIndex}, url: ${url}). ` + + `Popup windows cannot be controlled by playwriter. ` + + `Repeat the interaction in a way that does not open a popup, or navigate to the URL directly in a new tab.`, + ) + } + private setupPageConsoleListener(page: Page) { // Use targetId() if available, fallback to internal _guid for CDP connections const targetId = page.targetId() || (page as any)._guid as string | undefined @@ -410,7 +433,7 @@ export class PlaywrightExecutor { const context = contexts.length > 0 ? contexts[0] : await browser.newContext() context.on('page', (page) => { - this.setupPageConsoleListener(page) + this.setupPageListeners(page) }) context.pages().forEach((p) => this.setupPageConsoleListener(p)) @@ -485,7 +508,7 @@ export class PlaywrightExecutor { const context = contexts.length > 0 ? contexts[0] : await browser.newContext() context.on('page', (page) => { - this.setupPageConsoleListener(page) + this.setupPageListeners(page) }) context.pages().forEach((p) => this.setupPageConsoleListener(p)) @@ -861,6 +884,12 @@ export class PlaywrightExecutor { } } + // Drain any popup warnings that fired during execution + if (this.popupWarnings.length > 0) { + responseText += this.popupWarnings.map((w) => `[WARNING] ${w}`).join('\n') + '\n' + this.popupWarnings = [] + } + if (!responseText.trim()) { responseText = 'Code executed successfully (no output)' }