Skip to content

fix(vscode): open sent-message images in an editor tab - #13683

Merged
johnnyeric merged 2 commits into
Kilo-Org:mainfrom
sylwester-liljegren:fix/user-message-image-preview-tab
Sep 3, 2026
Merged

fix(vscode): open sent-message images in an editor tab#13683
johnnyeric merged 2 commits into
Kilo-Org:mainfrom
sylwester-liljegren:fix/user-message-image-preview-tab

Conversation

@sylwester-liljegren

@sylwester-liljegren sylwester-liljegren commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Issue

No linked issue — small behavior inconsistency found while using the sidebar chat.

Context

Clicking an image attached in the prompt input opens it in a VS Code image preview editor tab, but clicking the same image after the message is sent opens it in a webview modal instead. The modal is small, cannot be zoomed or resized like the editor preview, and blocks the chat while it is open. This change makes both click targets behave the same way.

Implementation

UserMessageDisplay in @kilocode/kilo-ui opened image attachments through dialog.show(<ImagePreview />) unconditionally. That component is shared with non-VS Code clients (TUI/session UI) where an editor tab does not exist, so the modal cannot simply be removed.

Instead the component now accepts an optional onImageClick(url, filename) handler. Returning true means the host handled the click; returning false (or not passing the prop at all) keeps the existing modal, so every other consumer is unchanged.

VscodeUserMessage passes that handler and posts the already-existing previewImage webview message — the same message the prompt input's attachment thumbnails send. The extension host path (handleEditorActionpreviewImage in src/kilo-provider/editor-actions.ts) is reused as-is; no new message type, host handler, or extension command was added.

The handler only claims data: URLs, matching what the host-side parseImage can decode; anything else falls back to the modal rather than silently doing nothing.

Screenshots / Video

before after
image Clicking an image in a sent message opened the kilo-ui modal overlay image Clicking it opens the VS Code image preview editor tab

How to Test

Manual/local verification

Performed by the agent:

  • bun run typecheck in packages/kilo-vscode/ — passed (both check-types and check-types:webview)
  • bun run lint in packages/kilo-vscode/ — passed
  • bun run format in packages/kilo-vscode/ — no reformatting of the touched files
  • bun test tests/unit/image-preview.test.ts in packages/kilo-vscode/ — 9 pass, covering the host-side previewImage path this change now reuses

Reviewer test steps

  1. Open the Kilo sidebar chat and attach an image to the prompt input (paste or drag-and-drop)
  2. Click the attachment thumbnail below the input and confirm it opens in a VS Code image preview editor tab (unchanged baseline)
  3. Send the message
  4. Click the image thumbnail shown on the sent user message
  5. Confirm it now opens in an image preview editor tab instead of a modal overlay

Blocked checks and substitute verification

  • The pre-push hook's full bun turbo typecheck could not complete locally: @kilocode/kilo-jetbrains#typecheck fails because Gradle cannot find a JDK 21 toolchain on this machine (only Java 24 is installed). All 29 JS/TS typecheck tasks in that same run passed, including kilo-code, and this change does not touch the JetBrains plugin. Substitute verification was the package-level typecheck, lint, and unit test run listed above.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

Get in Touch

@kilo-code-bot

kilo-code-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • packages/kilo-vscode/src/image-preview.ts
  • packages/kilo-vscode/src/shared/image-data-url.ts
  • packages/kilo-vscode/tests/unit/image-preview.test.ts
  • packages/kilo-vscode/webview-ui/src/components/chat/VscodeUserMessage.tsx
Previous Review Summary (commit d5cdf64)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit d5cdf64)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • .changeset/user-message-image-preview-tab.md
  • packages/kilo-ui/src/components/message-part.tsx
  • packages/kilo-vscode/webview-ui/src/components/chat/VscodeUserMessage.tsx

Reviewed by grok-4.6 · Input: 104.6K · Output: 8.6K · Cached: 244K

Review guidance: REVIEW.md from base branch main

Comment on lines +65 to +68
onImageClick={(dataUrl, filename) => {
if (!dataUrl.startsWith("data:")) return false
vscode.postMessage({ type: "previewImage", dataUrl, filename: filename ?? "image" })
return true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may cause a regression with certain data: URLs: we suppress the modal, but the host can't decode the image, so neither preview opens. Here we should keep the modal fallback for URLs the host doesn't support.

@sylwester-liljegren sylwester-liljegren Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 7aff213. The guard was too broad: startsWith("data:") claimed URLs that the host's parseImage rejects (non-base64 data URLs, non-image mime types), so the modal was suppressed and nothing opened at all.

I pulled the host's accept rule into src/shared/image-data-url.ts and now use it on both sides: parseImage matches against it, and the webview only claims the click when imageMime(dataUrl) is truthy. Everything else falls through to the modal as before.

Sharing one matcher instead of duplicating the check keeps the two sides from drifting apart later. tests/unit/image-preview.test.ts now asserts that imageMime accepts exactly the URLs parseImage can decode, so a future change to one without the other fails the test.

onRevert={props.onRevert}
onImageClick={(dataUrl, filename) => {
if (!dataUrl.startsWith("data:")) return false
vscode.postMessage({ type: "previewImage", dataUrl, filename: filename ?? "image" })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty filename isn't handled by filename ?? "image". The host will reject the empty string, and the modal fallback has already been skipped at this point. I'd suggest using filename || "image".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7aff213 — switched to filename || "image".

You're right that ?? left a real gap: the host's previewImage handler guards with if (message.dataUrl && message.filename), so an empty string was dropped there while the webview had already returned true and skipped the modal.

@sylwester-liljegren

Copy link
Copy Markdown
Contributor Author

@johnnyeric I have updated the PR as per your feedback. Feel free to go through this again whenever you have time :)

@johnnyeric
johnnyeric merged commit e0dd6c8 into Kilo-Org:main Sep 3, 2026
33 checks passed
@johnnyeric

Copy link
Copy Markdown
Contributor

Thanks @sylwester-liljegren for the contribution! I was able to reproduce the fix. Merged.

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