Open saved browser screenshots in image viewer

Route persisted browser screenshot thumbnails to the shared image viewer modal while keeping live Browser previews as Canvas entry points.\n\nAdd regression coverage so static screenshot artifacts do not regress back to opening the Browser surface.

Alessandro committed May 22, 2026 at 05:03 UTC 26b3ae00d52979ba18d74b71aacf5d333151defa
2 files changed +19 -1
plugins/_browser/extensions/webui/get_tool_message_handler/browser-tool-handler.js
+14 -1
@@ -2,6 +2,7 @@ import {
2 createActionButton,
3 copyToClipboard,
4 } from "/components/messages/action-buttons/simple-action-buttons.js";
5 +import { store as imageViewerStore } from "/components/modals/image-viewer/image-viewer-store.js";
6 import { store as stepDetailStore } from "/components/modals/process-step-detail/step-detail-store.js";
7 import { ttsService } from "/js/tts-service.js";
8 import { store as browserStore } from "/plugins/_browser/webui/browser-store.js";
@@ -206,6 +207,12 @@ function staticScreenshotSrc(uri = "") {
207 return uri ? uri.replace("img://", "/api/image_get?path=") : "";
208 }
209
210 +function openStaticScreenshot(uri = "") {
211 + const src = staticScreenshotSrc(uri);
212 + if (!src) return;
213 + imageViewerStore.open(src, { name: "Browser screenshot" });
214 +}
215 +
216 function releaseLiveScreenshotFrame(viewerId) {
217 const release = liveScreenshotFrames.get(viewerId);
218 if (!release) return;
@@ -348,6 +355,10 @@ function renderBrowserScreenshotKvp(kvpsTable, resolveBrowserPayload, label, sta
355 button.addEventListener("click", async (event) => {
356 event.preventDefault();
357 event.stopPropagation();
358 + if (staticUri) {
359 + openStaticScreenshot(staticUri);
360 + return;
361 + }
362 const canvasPayload = resolveBrowserPayload();
363 if (!canvasPayload) return;
364 await openBrowserSurface(canvasPayload);
@@ -477,7 +488,9 @@ function drawBrowserTool({
488 const screenshotUri = staticScreenshotUri(kvps);
489 const browserId = browserIdFromResult(browserResult, kvps);
490 const browserCanvasPayload = buildBrowserCanvasPayload(browserResult, kvps);
480 - const browserPreviewLabel = browserId
491 + const browserPreviewLabel = screenshotUri
492 + ? "Open Browser screenshot"
493 + : browserId
494 ? `Open Browser surface for Browser ${browserId}`
495 : "Open Browser surface from screenshot";
496 if (shouldRenderBrowserScreenshotKvp(browserResult, kvps)) {
tests/test_browser_agent_regressions.py
+5
@@ -1122,6 +1122,11 @@ def test_browser_viewer_uses_cdp_screencast_transport():
1122 assert '"snapshot": snapshot' in ws_browser
1123 assert 'const BROWSER_SNAPSHOT_META_KEY = "browser_snapshot";' in browser_tool_handler
1124 assert "staticScreenshotUri(kvps)" in browser_tool_handler
1125 + assert "/components/modals/image-viewer/image-viewer-store.js" in browser_tool_handler
1126 + assert "function openStaticScreenshot(uri = \"\")" in browser_tool_handler
1127 + assert "imageViewerStore.open(src, { name: \"Browser screenshot\" });" in browser_tool_handler
1128 + assert "if (staticUri) {" in browser_tool_handler
1129 + assert "openStaticScreenshot(staticUri);" in browser_tool_handler
1130 assert "delete displayKvps[BROWSER_SNAPSHOT_META_KEY];" in browser_tool_handler
1131 assert "startBrowserScreenshotPreview(button, image, resolveBrowserPayload)" in browser_tool_handler
1132 assert "FRAME_FALLBACK_SCREENSHOT_SECONDS" not in ws_browser