Skip to content

Restore hydrated image attachment previews in the Agents window#327381

Open
ulugbekna wants to merge 1 commit into
mainfrom
ulugbekna/investigate-missing-images
Open

Restore hydrated image attachment previews in the Agents window#327381
ulugbekna wants to merge 1 commit into
mainfrom
ulugbekna/investigate-missing-images

Conversation

@ulugbekna

@ulugbekna ulugbekna commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #327329

Builds on #327300.

Problem

In the Agents window, image attachments on user messages lose their thumbnail preview after a window reload / session resume, falling back to a generic file‑media icon — even though the file still exists on disk.

Background

Hydrated (reload/resume/reconnect) image attachments arrive as uri‑only variable entries whose value is a URI (the real file reference is in references[0], with no inline bytes). #327300 fixed the shared coerceImageBuffer helper so it returns undefined for such values instead of mis‑coercing the URI's enumerable keys into a bogus all‑zeros Uint8Array.

That stopped the corrupt buffer (and, on the edit‑and‑resend path, corrupt bytes being sent to the model), but the visible preview is still not restored: ImageAttachmentWidget receives undefined bytes and never loads the real image, so it renders the generic icon.

Fix

ImageAttachmentWidget now lazily reads the bytes via the injected IFileService when inline bytes are absent but a resource is available (and the image isn't fully omitted / over the image limit), then re‑renders the preview with the actual image. The icon fallback is kept if the read fails (e.g. the file no longer exists). Works for file: and remote vscode-agent-host: (filesystem provider registered) resources.

Tests

  • chatAttachmentsContentPart.test.ts — a hydrated uri‑only image triggers a resource read and re‑render; an inline‑bytes image does not.

Validation

  • npm run typecheck-client
  • Widget browser suite (14 tests, incl. 2 new hydrated‑image tests) ✔
  • Rebased on latest main (which now includes Fix hydrated image attachment previews #327300); this branch's earlier coerceImageBuffer URI guard and its duplicate extraction test were dropped as redundant.

Copilot AI review requested due to automatic review settings July 24, 2026 20:27

Copilot AI left a comment

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.

Pull request overview

Fixes hydrated image previews by rejecting URI values as image bytes and lazily reading referenced image files.

Changes:

  • Prevent URI objects from being coerced into corrupt buffers.
  • Load missing image bytes through IFileService.
  • Add regression tests for URI-only and inline-byte attachments.
Show a summary per file
File Description
chatImageExtraction.ts Excludes URIs from byte coercion.
chatAttachmentWidgets.ts Lazily loads and rerenders image previews.
chatImageExtraction.test.ts Tests URI-valued image extraction.
chatAttachmentsContentPart.test.ts Tests resource-read behavior.

Review details

Comments suppressed due to low confidence (1)

src/vs/workbench/contrib/chat/browser/attachments/chatAttachmentWidgets.ts:754

  • This inline comment exceeds the repository's one-line limit. Condense it to the lifecycle constraint that is not evident from the cleanup code.
	// Remove the pill and label from the DOM when disposed so the widget can safely re-render
	// (e.g. after lazily loading the image bytes for a hydrated attachment).
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment on lines +543 to +545
const renderImageElements = (buffer: Uint8Array) => {
imageElements.value = createImageElements(resource, attachment.name, fullName, this.element, buffer, attachment.id, this.hoverService, ariaLabel, currentLanguageModelName, clickHandler, this.currentLanguageModel, omittedState);
};
Comment on lines +192 to +194
// A URI references image bytes rather than being the bytes themselves. Its own
// enumerable properties (scheme, path, ...) would otherwise be misread as a
// serialized byte record by the object branch below, yielding a bogus buffer.
Comment on lines +548 to +550
// Hydrated image attachments (e.g. after a window reload or session resume) arrive as a
// resource reference without inline bytes. Load the bytes from disk so the preview renders
// the actual image instead of falling back to a generic file icon.
@ulugbekna
ulugbekna force-pushed the ulugbekna/investigate-missing-images branch from 905a622 to 81cf65d Compare July 24, 2026 20:36
@ulugbekna ulugbekna changed the title Fix hydrated image attachment previews in the Agents window Restore hydrated image attachment previews in the Agents window Jul 24, 2026
Hydrated (reload/resume/reconnect) image attachments arrive as uri-only
variable entries whose `value` is a URI, with the real file reference in
`references[0]` and no inline bytes. Since #327300, `coerceImageBuffer`
correctly returns undefined for such values instead of a bogus buffer, so
`ImageAttachmentWidget` no longer renders garbage - but it still falls back
to a generic file-media icon because nothing loads the real bytes.

Make `ImageAttachmentWidget` lazily read the bytes via `IFileService` when
inline bytes are absent but a resource is available (and the image is not
fully omitted / over the image limit), then re-render the preview with the
actual image. The icon fallback is kept if the read fails (e.g. the file no
longer exists). Works for `file:` and remote `vscode-agent-host:` resources.

Adds regression tests for the widget lazy byte-load (a hydrated uri-only
image triggers a resource read; an inline-bytes image does not).

Fixes #327329

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e04660de-4e7b-4432-99dd-24e0ffc35d1a
@ulugbekna
ulugbekna force-pushed the ulugbekna/investigate-missing-images branch from 81cf65d to d60cae0 Compare July 24, 2026 20:38
ulugbekna added a commit that referenced this pull request Jul 25, 2026
A uri-only image in a chat draft is not model-facing, so the draft path
keeps it as a lightweight MessageAttachmentKind.Resource reference and must
not read file bytes on every debounced draft sync (hydrateImageBytes defaults
to false). Locks in that behavior, which was previously untested.

Follow-up to #327381 for #327329.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c77566c8-d94f-4245-b965-75ea069af547
ulugbekna added a commit that referenced this pull request Jul 25, 2026
Uri-only image attachments (e.g. hydrated edit-and-resend images) reached the model as a Resource path reference instead of pixels, so the Agents window agent could not actually see them. In _toImageAttachment's no-inline-bytes branch, read the referenced file via IFileService and emit an EmbeddedResource (base64) for model-facing conversions (turn + pending), falling back to the existing Resource path reference on any read failure. Draft input-state sync stays a lightweight path reference.

The attachment-conversion caller chain (_convertVariableToAttachment, _variableEntriesToAttachments, _appendActiveEditorAttachments, _convertVariablesToAttachments, _syncPendingMessages, _inputStateToDraft) is now async. Per-session pending-message syncs are serialized and coalesced through a ThrottlerByKey so the added hydration I/O cannot interleave concurrent runs and dispatch a stale same-id message.

Helps Copilot and Codex; Claude still drops EmbeddedResource today (pre-existing, out of scope).

Follow-up to #327381 for #327329.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c77566c8-d94f-4245-b965-75ea069af547
ulugbekna added a commit that referenced this pull request Jul 25, 2026
A uri-only image in a chat draft is not model-facing, so the draft path
keeps it as a lightweight MessageAttachmentKind.Resource reference and must
not read file bytes on every debounced draft sync (hydrateImageBytes defaults
to false). Locks in that behavior, which was previously untested.

Follow-up to #327381 for #327329.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c77566c8-d94f-4245-b965-75ea069af547
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.

Agents window: hydrated image attachments lose their preview after window reload / session resume

3 participants