Skip to content

[V2 Desktop] Pasted images show no thumbnail when the active model is text-only #54991

Closed

Description

@wc4440222

Describe the problem

On OpenCode Desktop 2.0.27 (Windows 11), when I paste an image into the prompt:

  • With a multimodal model (e.g. deepseek-v4.1-flash with modalities.input: ["text", "image"]), the image shows a thumbnail preview. Good.
  • With a text-only model (e.g. glm-5.2 with modalities.input: ["text"]), the image shows no thumbnail at all — it is silently stored as a file-path attachment (metadata.attachments: [{name, mime, path}]) with zero visual feedback.

The user has no way to tell whether the image was actually attached.

Why this matters

Text-only models are common in custom OpenAI-compatible providers. The attachment exists in the
message data but the chat UI renders nothing, so the paste looks like it did nothing.
A plugin can still process the file in the background, but the UI gives no indication of that.

What I would like

  • Show at least a thumbnail/file placeholder for image attachments even when the active model
    does not declare image input support, or
  • Show a small warning that the image will not be sent to the model natively.

Related

Related to #47480 (images silently replaced by text placeholder).
Similar area as #21227 (tool-result image attachments not rendered).

Environment

  • OpenCode Desktop version: 2.0.27
  • OS: Windows 11

Activity

  1. opencode-agent commented on Oct 13, 2026

    @opencode-agent
    Contributor

    Thanks for the clear write-up! You're asking for a visible preview, and ideally a short warning, when you paste an image while the active model is text-only (modalities.input: ["text"]), so it's obvious the image was attached and how the model will get it.

    Some background: since #49467, when the selected model doesn't accept image input, Desktop attaches the image as a file path that the model can open with its tools, not as inline image data. In 2.0.27 these path attachments should still show up as a generic file card (filename plus a "PNG"/"JPG" label) in the composer and on the sent message. They just don't get an image thumbnail, and nothing explains that the model won't see the image itself. If you see no card at all, please reply and say so (a screenshot helps), because that would be a bug rather than a missing feature.

    Maintainers will consider showing thumbnails for image path attachments and/or a hint about the model's image support. Related issues:

  2. wc4440222 commented on Oct 13, 2026

    @wc4440222
    Author

    Yes — I do see the generic file card (image.png + PNG label) in both the composer and the sent message. So per your classification this is the missing-feature case, not the no-card bug.

    Three specific pain points:

    1. Multiple images are indistinguishable. Pasting several images shows identical cards (clipboard pastes are often all named image.png). No way to tell which is which.
    2. No click-to-preview. The card can't be clicked to view the image, unlike thumbnails on vision-capable models. After sending, I can't verify what was actually attached.
    3. Regression from V1. V1 desktop showed thumbnails regardless of the active model. V2 only shows them when the model declares image input, which makes text-only models (common with custom OpenAI-compatible providers, e.g. glm-5.2) feel broken.

    Env: Windows 11, Desktop 2.0.27, glm-5.2 (modalities.input: [text]) via custom OpenAI-compatible provider.

    A thumbnail for image path attachments (the file is local, so even a small preview would work) plus a one-line hint that the model receives it as a file path rather than inline image data would fully resolve this. Thanks for considering it.

  3. wc4440222 commented on Oct 13, 2026

    @wc4440222
    Author

    One more thing worth mentioning: on my setup, pasted images do NOT break text-only sessions. I run a local plugin (vision-paste) that detects image attachments when the active model is text-only, transcribes them via a vision-capable model, and injects the description as text before the request is sent. So the image content still reaches the model — the only thing missing is UI feedback.

    This confirms the gap is purely in the UI layer (thumbnail/preview + hint), not a capability problem. The data path works; only the visual confirmation is absent. If thumbnails were shown for path attachments, the whole flow would feel complete with no backend changes needed.

  4. wc4440222 commented on Oct 13, 2026

    @wc4440222
    Author

    Update: tested on Desktop 2.0.28 — the issue persists. Text-only models still show only the generic file card with no thumbnail.

    Note: changelog for 2.0.28 mentions Loaded

  5. wc4440222 commented on Oct 17, 2026

    @wc4440222
    Author

    Update: still not fixed on Desktop 2.0.32 (Windows 11, installed 2026-10-17).

    Retested in a fresh session with a text-only model (glm-5.2, modalities.input: ["text"]):

    • Pasted a screenshot → both the composer and the sent message show only the generic file card (image.png + PNG label). No thumbnail.

    The 2.0.29 changelog item "render inline attachments before their server echo arrives" (#55251, #54650) does not cover this path — that one appears to apply only to models that accept image input. Re-verified as still broken on 2.0.32, so the regression window is now 2.0.27 → 2.0.28 → 2.0.29 → 2.0.32.

    Concrete asks, in the order that would help most:

    1. Thumbnail preview for path attachments — same rendering as the multimodal case. Cheapest possible fix since the image renderer already exists.
    2. Distinguish multiple pasted images — clipboard pastes are all named image.png, so N attachments render as N identical cards with no way to tell them apart.
    3. Click-to-preview — the card is not clickable, while thumbnails on vision-capable models are.
    4. A one-line hint that the image was attached as a file path rather than silently dropped.

    Worth repeating from my earlier comment, because it narrows the scope: the image content does reach the model on this setup. A local plugin transcribes image attachments for text-only models and injects the description as text before the request is sent. So the missing piece is purely UI feedback, not transport or capability.

  6. wc4440222 commented on Oct 22, 2026

    @wc4440222
    Author

    I dug through the current dev tree to see how much work a thumbnail would actually be, because I'd rather hand you something actionable than another "please fix".

    The two rendering paths are different

    In packages/session-ui/src/message/message-content.tsx:

    • Lines 349-363 — inline attachments (message.files): mime.startsWith("image/") renders <img src="data:<mime>;base64,...">. Thumbnails work here. This is the multimodal path.
    • Lines 333-338 — path attachments (references, shape { name, mime, path } from SessionUserAttachmentReference): always <AttachmentCard> (title + typeLabel subtitle), with no image branch at all. This is the text-only path, and it's exactly what I see.

    Why I don't think it's a small fix

    For the path case the renderer only has a path, not bytes. The desktop protocol handler (packages/desktop/src/main/windows/protocol.ts) deliberately serves only the app bundle — it rejects any host other than rendererHost and resolves paths inside rendererRoot (lines 82-92). Attachments can only be handed to the OS via openAttachment. So a thumbnail needs a new controlled read channel (a dedicated protocol handler, or an IPC returning a data URL), which touches the renderer's file-access boundary. That's presumably why this has stayed in the backlog, and it's a reasonable call — no complaints from me.

    What could ship without touching that boundary

    All of these are pure UI, confined to attachment-card.tsx plus its one call site, so they carry no security-review burden:

    1. A one-line hint on the card — e.g. Attached · the model reads this as a file path. This is the actual pain: after pasting, nothing confirms the image was attached at all.
    2. Distinguish multiple pastes — clipboard pastes are all image.png, so N attachments render as N identical cards. An index, dimensions, or file size would make them tellable apart.
    3. Show the size — image.png · 2.4 MB fits the existing subtitle slot, which already renders typeLabel.

    If a thumbnail is out of scope for now, (1) alone would close the "did my paste actually work?" ambiguity that made me open this in the first place.

    FWIW the data path is fine on my side: a local plugin transcribes path attachments for text-only models and injects the description as text before the request is sent, so the model does receive the image. Only the confirmation is missing.

  7. wc4440222 commented on Oct 29, 2026

    @wc4440222
    Author

    Confirmed fixed on Desktop 2.2.1 (Windows 11).

    • Version: 2.2.1 (installed 2026-10-29, update from 2.2.0)
    • Model: glm-5.2 with modalities.input: ["text"] — a text-only model, i.e. exactly the case in the original report
    • Action: pasted a screenshot into the composer, then sent it
    • Result: the thumbnail now renders both in the composer and in the sent message. Previously both places showed only the generic file card (image.png + PNG label).

    From the 2.2.1 bundle, AttachmentCard now carries readMedia / resolvedUrl / ImagePreview plus a placeholder style, so the path-attachment case gets real preview bytes instead of a static card. Combined with #59947 (request inline image bytes by default) this looks like the media-uri work (#59104, #59947) covered this scenario.

    Feel free to close this if you consider it resolved — thanks for shipping it.

  8. Tarquinen commented on Nov 2, 2026

    @Tarquinen
    Member

    Thanks for confirming it's fixed on 2.2.1! Closing this issue.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions