Repository navigation
Show the images and PDFs an agent's tools return or write inline in the chat - #18401
Conversation
A reply's inline image opens a viewer over the pane: zoom about the pointer (pinch, Command-scroll, double click, + - 0), pan a zoomed image, arrows and the arrow keys through every image of the chat, copy as PNG, Escape or a click beside the image to close. The mock light-theme chat shows three screens to open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agent-pane.image-viewer: a reply with three screenshots, and images in two replies the viewer's arrows go through. The opened viewer needs a click, so its states wait for play steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red: the viewer's image list keeps an image on a fence's later line, loses images after a lone backtick, with parentheses in the target or inside bold; Tab leaves the viewer; an image the list misses opens without its name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The viewer's image list now comes from Markdown.tsx's own block parser and inline pattern (inlineImages), so it holds exactly the images a reply draws: none from code, and those after a lone backtick, with parentheses in the target or inside bold. An image the list still misses opens under its own name. WebKit's pinch (gesture events) zooms about the pointer; the stage's padding is symmetric so zoom stays about the pointer; Tab wraps inside the viewer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e data URLs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Notes draw under the reply by first reference, so the viewer lists their images there too; a reply whose only image has an upper-case data URL scheme is read, as Markdown.tsx draws it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The mock chat and the gallery entry show a chart, a gradient and a diagram instead of drawn app screens: previews are never mockups of cmux. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The viewer is a ui/Dialog (Base UI): it traps focus, makes the pane behind inert, closes on Escape and returns focus to the image, replacing the hand-rolled role, tab index and Tab handling the UI rules forbid. Only its own image keys (arrows, + - 0) stay a key handler, marked ui-allow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-image-viewer # Conflicts: # webviews/src/agent-session/acpmux/conversation/Markdown.tsx
…e reply budget Red: since base moved data URLs over 4 KB behind short refs and capped a reply at 8 MB, chatImages lists none of a reply's long images. Focused: bun test src/agent-session/acpmux/conversation/imageViewer.test.tsx -t budget (fail: 0 listed, 6 drawn) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he reply budget inlineImages mirrors renderInline again: it takes the URLs back from capDataUrls' short refs (passed down into bold, italic and link text), and chatImages drops the reply's images past dataUrlsOverBudget, which draw as their name. Focused: bun test src/agent-session/acpmux/conversation/imageViewer.test.tsx -t budget (pass) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red since the move to ui/Dialog: a press inside the viewer focuses the dialog popup, above the body that handled the image keys, and the wheel and gesture listeners ran before the portal mounted the stage. Focused: bun test src/agent-session/acpmux/conversation/imageViewer.test.tsx (fail: keys stay at scale(1); Control-scroll not prevented) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ui/Dialog passes onKeyDown to its popup, which takes focus after a press inside, so the viewer's arrows and + - 0 keys go there. The stage is a callback ref, so the pinch and wheel listeners attach once the portal mounts it. Focused: bun test src/agent-session/acpmux/conversation/imageViewer.test.tsx (11 pass) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-image-viewer # Conflicts: # webviews/src/agent-session/acpmux/App.tsx
The opened viewer as play steps on the reply with three images, and anchors that prove nothing under the viewer moves. Regenerated agent pane bundle for the base merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-image-viewer # Conflicts: # webviews/src/agent-session/acpmux/Localizable.xcstrings # webviews/src/agent-session/acpmux/conversation/Markdown.tsx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-image-viewer # Conflicts: # webviews/src/agent-session/acpmux/conversation/Markdown.tsx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red: direct.ts drops ACP image content blocks, and a tool that writes or prints an image path (a screenshot, a rendered chart) shows only text. Red (local): bun test src/agent-session/acpmux/conversation/toolImages.test.tsx fails: ../toolImages does not exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An agent's image outputs now show inline under the tool row, without opening it: - images a call returns (ACP image content blocks), kept as data URLs up to 8 MB each; - image files it wrote or printed (a saved screenshot, a rendered chart): its edited file, its locations and absolute image paths in its output, loaded through the host like a reply's local image. At most four per call, capped at 360x220 and lazily decoded. A click opens the image viewer, as does a local or web image in a reply now (ReplyImage's shown image is OpenableImage). Gallery: transcript variant tool-images with a returned screenshot and a saved chart. Focused (local): bun test src/agent-session/acpmux/conversation/toolImages.test.tsx 4 pass (red at 5c3dbb8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-image-viewer # Conflicts: # webviews/src/agent-session/acpmux/App.tsx
…r branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red: the host's image.load refuses a PDF (not a raster or SVG), and a tool's PDF output path shows no preview. Red (local): bun test src/agent-session/acpmux/conversation/toolImages.test.tsx fails on the report.pdf case; AgentPaneReplyImageTests .aPDFShowsItsFirstPageAsAPNG names thumbnailSide, which does not exist yet (runs in hosted cmux-next swift test). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The host draws page 1 of a local PDF (CoreGraphics, on white, longest side 1024) and hands the pane a PNG data URL, so the chip and the tool image strip show it like any image and a click opens the in-pane viewer. Only page 1 is decoded, so PDFs up to 100 MB qualify; a file that is not a PDF is refused. Tool output and edited paths ending in .pdf now count as image outputs. Gallery: the transcript tool-images variant adds a build-report PDF thumbnail. Focused: bun test toolImages.test.tsx (red 3/1 at 788b662, green 4/0); AgentPaneReplyImageTests.aPDFShowsItsFirstPageAsAPNG on the fleet suite runner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Blacksmith runners detected OOM events on the following jobs:
|
|
|
|
Unclear: CI failed on
Not re-run automatically: Written by |
Base no longer commits the web bundles: the agent-pane bundle files are dropped; only GENERATED.md stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops the committed agent-pane bundle files, as base did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops the committed agent-pane bundle files, as base did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picks up the bundle-removal CI fixes. The string catalog keeps base's text and adds only this branch's keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CGPDFPageGetDrawingTransform only scales a page down, so a page smaller than the thumbnail drew at its natural size in white margins. Build the transform by hand and clip to the crop box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merge kept this branch's generated strings and dropped base's composer.connectSSH and composer.connectCloud. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # webviews/src/agent-session/acpmux/conversation/Markdown.tsx
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/37689519735 at 3e0a1ad failed: cmux-next generated files. |
Summary
Image outputs from an agent's tool calls now show inline in the chat, and a PDF an agent writes or links shows as a thumbnail of its first page. Before this, the transcript dropped returned images and showed a PDF only as a file chip.
This PR now includes #18357 (closed into this one), so it lands both changes:
Returned images (from cmux-next agent pane: tool calls show the images they return or write #18357): a tool that returns an image, such as a browser screenshot, shows it. ACP
imagecontent blocks are kept as data URLs, png/jpeg/gif/webp only, up to 8 MB each.Written images (from cmux-next agent pane: tool calls show the images they return or write #18357): a tool that writes or prints an image file shows that file: the edited file, the call's locations, and absolute image paths in its output. They load through the host like a reply's local image (
image.load), so only files inside the session's folders show. At most four per call, each capped at 360x220 and decoded lazily. A click opens the image viewer (Agent pane: image viewer for chat images #18200), as do reply images, through the sharedOpenableImage.Host-drawn page: the host draws page 1 of the PDF with CoreGraphics, on white, with the longest side at 1024 px. It hands the pane a PNG data URL through the existing
image.loadpath. The page never receives the document and keeps itsimg-src data:CSP.Limits: only page 1 is decoded, so PDFs up to 100 MB qualify (other images stay at 10 MB). A file that CoreGraphics can't read as a PDF is refused, as is a locked one. As for any reply image, only files inside the session's folders load.
Tool outputs: a
.pdfa tool edits, lists in its locations or prints as an absolute path now joins the tool's image strip. A reply link to a local PDF shows the same thumbnail throughReplyImage.Click: opens the in-pane image viewer (Agent pane: image viewer for chat images #18200), never a browser tab.
Targets
feat-cmux-nextand carries #18357's commits. Part of bead cx-ncc.51. Video and artifact links follow in separate PRs.Testing
toolImages.test.tsxcovers returned and written images.bun test src/agent-session/acpmux/conversation/toolImages.test.tsx(local): 3 pass, 1 fail at the red commit; 4 pass after the fix.AgentPaneReplyImageTests.aPDFShowsItsFirstPageAsAPNGchecks a two-page portrait PDF. The result must be a PNG data URL whose longest side isthumbnailSideand which stays portrait, and a fake.pdfmust be refused. Fleet Swift suite (step 18909ba90b44,run-swift-testing-suites.shat c24deb9, which carries this PR's Swift unchanged): passes./Rotate 90page. Fleet suite at 6c94740:aPDFShowsItsFirstPageAsAPNGfails with 2 issues, one on each page. The fix 8eb5524 builds the transform by hand and clips to the crop box. At 8eb5524 the rotated page passes, but the Letter-page check still failed: that page stores its blue as sRGB, and its device-RGB value missed the exact-byte threshold. 476b12d matches blue by hue, and the test passes on the fleet at 476b12d.vp checkandvp fmtpass on the changed files.verify-local.py --only swift-syntaxpasses on the changed Swift file. The agent pane bundle is no longer committed (base dropped it); builds generate it.Changelog
Added: Images an agent's tools return or save (screenshots, charts) show inline in the agent chat, and a click zooms them
Added: A PDF an agent writes or links shows a first-page thumbnail in the agent chat, and a click zooms it
Proof
Before (feat-cmux-next): a tool call shows only text; returned and written images are dropped, and a PDF shows only as a file chip. The base gallery has no
tool-imagesvariant:/live/?entry=agent-pane.transcriptAfter: variant
tool-imagesshows a sign-in page screenshot a browser tool returned, a build-time chart a script saved, and a three-page build-report PDF a script wrote, shown as its real first page. Preview: /wt/feat-cmux-next-media-thumbnails/?entry=agent-pane.transcript#/agent-pane.transcript/tool-imagesThe gallery host's branch sync is stuck on a deleted branch, so the preview shows the newest build before the latest base merge. The variant's content is the same.
🤖 Generated with Claude Code
Note
Medium Risk
Adds host-side PDF decoding and new transcript UI for tool outputs; bounded by size caps and session-folder rules, but CoreGraphics PDF handling is a new attack surface for malicious files.
Overview
Tool calls in the agent transcript now show inline image thumbnails under each row (even when collapsed): ACP
imagecontent blocks are kept as capped data URLs, and absolute image/PDF paths from edits, locations, or output text load through the existing hostimage.loadpath viaReplyImage, at most four per call.On macOS, local PDFs (replies and tool outputs) no longer pass through the raster pipeline—the host renders page 1 with CoreGraphics to a PNG data URL (1024px longest side, up to 100 MB), including
/Rotate, so the webview still only seesdata:images under CSP.OpenableImagecentralizes click-to-zoom for shown images (markdown inline, reply images, and tool strips); gallery adds atool-imagestranscript variant and tests cover PDF thumbnails andtoolImagesmerging.Reviewed by Cursor Bugbot for commit 654801f. Bugbot is set up for automated code reviews on this repo. Configure here.