@@ -777,19 +777,42 @@ export class Agent extends LoopDetector {
777777 }
778778 }
779779
780+ async _captureFullPageWithBlankRetry(tabId, capturePolicy) {
781+ const probe = await this._captureViewportProbe(tabId);
782+ const captureOnce = async () => {
783+ const capture = await this._withIndicatorsHidden(tabId, () =>
784+ cdpClient.captureFullPageScreenshot(tabId, capturePolicy)
785+ );
786+ const imageData = typeof capture === 'string' ? capture : capture?.data;
787+ if (!imageData) return null;
788+ return {
789+ dataUrl: `data:image/png;base64,${imageData}`,
790+ capture,
791+ };
792+ };
793+ return this._retryBlankScreenshotCapture(
794+ await captureOnce(),
795+ captureOnce,
796+ { probe },
797+ );
798+ }
799+
780800 async captureFullPageScreenshotForUser(tabId) {
781801 if (!tabId) return { ok: false, error: 'No tab ID' };
782802 try {
783803 const capturePolicy = await this._getFullPageCapturePolicy(tabId);
784804 await cdpClient.attach(tabId);
785805 await this._preparePageForCapture(tabId);
786- const capture = await this._withIndicatorsHidden(tabId, () =>
787- cdpClient.captureFullPageScreenshot(tabId, capturePolicy)
788- );
789- const imageData = typeof capture === 'string' ? capture : capture?.data;
806+ const captured = await this._captureFullPageWithBlankRetry(tabId, capturePolicy);
807+ const capture = captured?.capture;
790808 const warning = typeof capture === 'object' ? capture?.warning || null : null;
791- if (!imageData) return { ok: false, error: 'Full-page screenshot returned no image data' };
792- return { ok: true, dataUrl: `data:image/png;base64,${imageData}`, warning };
809+ if (!captured?.dataUrl) {
810+ return { ok: false, error: 'Full-page screenshot returned no image data' };
811+ }
812+ if (captured?.blankFrameRetry?.finalBlank) {
813+ return { ok: false, error: 'Background full-page screenshot remained blank after retries' };
814+ }
815+ return { ok: true, dataUrl: captured.dataUrl, warning };
793816 } catch (e) {
794817 return { ok: false, error: e?.message || String(e) };
795818 }
@@ -15051,14 +15074,15 @@ Rules: no prose intro, no conclusion, no "this screenshot shows...", no layout d
1505115074 const capturePolicy = await this._getFullPageCapturePolicy(tabId);
1505215075 await cdpClient.attach(tabId);
1505315076 await this._preparePageForCapture(tabId);
15054- const capture = await this._withIndicatorsHidden(tabId, () =>
15055- cdpClient.captureFullPageScreenshot(tabId, capturePolicy)
15056- );
15057- const imageData = typeof capture === 'string' ? capture : capture?.data;
15077+ const captured = await this._captureFullPageWithBlankRetry(tabId, capturePolicy);
15078+ const capture = captured?.capture;
1505815079 const captureWarning = typeof capture === 'object' ? capture?.warning || null : null;
1505915080 const captureBounds = typeof capture === 'object' ? capture?.captureBounds || null : null;
15060- if (!imageData) throw new Error('Full-page screenshot returned no image data');
15061- const rawUrl = `data:image/png;base64,${imageData}`;
15081+ if (!captured?.dataUrl) throw new Error('Full-page screenshot returned no image data');
15082+ if (captured?.blankFrameRetry?.finalBlank) {
15083+ throw new Error('Background full-page screenshot remained blank after retries');
15084+ }
15085+ const rawUrl = captured.dataUrl;
1506215086 const warningNote = captureWarning ? `\nWarning: ${captureWarning}` : '';
1506315087
1506415088 // If the caller asked to save, do it with the RAW (uncompressed,
0 commit comments