Skip to content

feat(vscode): render read-tool images inline in chat view - #12010

Merged
marius-kilocode merged 1 commit into
mainfrom
research-inline-image-rendering
Jul 7, 2026
Merged

feat(vscode): render read-tool images inline in chat view#12010
marius-kilocode merged 1 commit into
mainfrom
research-inline-image-rendering

Conversation

@marius-kilocode

@marius-kilocode marius-kilocode commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Problem

When the agent reads an image file via the read tool, the image bytes never appear in the chat view. The user only sees a text line (Read <filename>) with no visual confirmation of what was read, even though the agent itself receives the image as vision input. CLI is out of scope and much more difficult.

file-500d919f0c1f692608bb963c55b873b7 file-ea144fb7fb3f09725092ec8308e86568 file-3f26cb8ac890083c36f9160d9c6b7cf9

Why this happens

The data pipeline already exists end-to-end but stops short of rendering:

  • The read tool (packages/opencode/src/tool/read.ts:327-333) base64-encodes image files and returns them as FilePart attachments with a data: URL.
  • The processor persists them onto ToolStateCompleted.attachments, they flow over SSE (message.part.updated), land in the webview part store (context/session.tsx:1635), and survive session reload (they are not touched by compaction or stripPartMetadata).
  • The PART_MAPPING["tool"] renderer passes input/metadata/output/status into each tool component but not part.state.attachments, so the read renderer never sees the image data. The webview CSP already allows img-src ... data: https:, and user-attached images already render with <img src={file.url}> at message-part.tsx:836.

So the only missing piece is a renderer.

What this change does

Three additions to packages/kilo-ui/src/components/message-part.tsx (Kilo-owned, no upstream markers):

  1. Add attachments?: FilePart[] to ToolProps.
  2. Pass part.state.attachments through the Dynamic component in PART_MAPPING["tool"].
  3. In the read tool renderer, filter image attachments (mime.startsWith("image/") with a url) and render them inline as <img> thumbnails with loading="lazy" and decoding="async", clickable to open the existing ImagePreview dialog (the same pattern already shipping for user-attached images and image diffs).

Plus matching CSS in message-part.css for the tool-read-images slots (200px max thumbnail, rounded border, hover highlight, object-fit: contain).

No backend, schema, SDK, or extension-host changes. The FilePart schema (mime + base64 url) is already a first-class Part type and already carries images for both user-attached and tool-read paths.

Scope and limits

  • Applies to the read tool only. webfetch also emits image attachments but is left for a follow-up if desired.
  • Images render for the current and reloaded session. Compaction strips images from the model context window (existing behavior) but leaves them in the persisted PartTable.data, so the webview still shows them after compaction.
  • SVG is correctly excluded: SUPPORTED_IMAGE_MIMES in the read tool is jpeg/png/gif/webp only, so no SVG data URL ever reaches the renderer. Even if one did, <img>-loaded SVGs are sandboxed by the browser (scripts do not execute).
  • The backend already bounds payload size via image.normalize() (Photon WASM, 2000x2000 / ~5MB cap) before the data URL reaches the client, so each inline image is a bounded decode identical to the existing user-attachment and image-diff rendering paths.
  • Cross-platform: pure webview HTML/CSS/JSX, no native APIs. Works on Windows, Mac, and Linux.

The read tool already produces base64 data URL attachments for image
files and threads them through SSE into the webview part store, but the
tool renderer never received them. Thread part.state.attachments into
ToolProps and render image attachments inline below the read tool card,
reusing the existing user-attachment image pattern with click-to-open
preview. No backend, schema, or SDK changes needed.
@kilo-code-bot

kilo-code-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Small, well-scoped change confined to packages/kilo-ui/ (Kilo-owned, no upstream fork-hygiene concerns). It threads part.state.attachments through ToolProps using the same @ts-expect-error pattern already used for output/status, and reuses the existing user-attachment image-preview pattern (ImagePreview dialog, data: URL <img>, i18n alt fallback) rather than inventing a new one. Verified that read.ts also attaches PDFs, and the new images memo correctly filters those out via mime.startsWith("image/"). FilePart.url/mime are non-optional strings, so no null-safety issues. Changeset is present and written in user-facing language.

Files Reviewed (3 files)
  • .changeset/inline-read-images.md
  • packages/kilo-ui/src/components/message-part.css
  • packages/kilo-ui/src/components/message-part.tsx

Reviewed by claude-sonnet-5 · Input: 34 · Output: 9.2K · Cached: 700.5K

Review guidance: REVIEW.md from base branch main

@marius-kilocode
marius-kilocode enabled auto-merge July 7, 2026 12:50
@marius-kilocode
marius-kilocode merged commit 71a3530 into main Jul 7, 2026
26 checks passed
@marius-kilocode
marius-kilocode deleted the research-inline-image-rendering branch July 7, 2026 13:01
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
…-rendering

feat(vscode): render read-tool images inline in chat view
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants