Skip to content

fix(attachments): preserve original image filenames - #463

Merged
lucas77778 merged 1 commit into
masterfrom
chenyu/code-599
Aug 21, 2026
Merged

fix(attachments): preserve original image filenames#463
lucas77778 merged 1 commit into
masterfrom
chenyu/code-599

Conversation

@lucas77778

Copy link
Copy Markdown
Member

Summary

  • Preserve each image attachment's original filename from browser/native selection through the additive wire schema.
  • Forward the filename to OpenCode file parts and expose it on rendered image previews while keeping historical unnamed image blocks compatible.
  • Bump WIRE_PROTOCOL_VERSION to 78 while leaving the compatibility floor at 76.

Linear: CODE-599

Verification

  • pnpm check:ci
  • pnpm test — 346 files passed, 2977 tests passed, 1 skipped
  • Browser mock acceptance: uploaded icon-dock.png and icon.png, observed distinct filename tooltips, sent both through the OpenCode transport, and verified the sent images retained their names with no page errors
  • Acceptance recording

Checklist

  • pnpm check:ci and pnpm test both pass (plus cargo fmt / clippy / test for Rust changes)
  • I ran the affected surface and observed the change working
  • If a wire message changed: WIRE_PROTOCOL_VERSION is bumped
  • New code and assets are my own work, or their origin and license compatibility are noted above
  • Docs and comments are updated where behavior changed (no documentation change required)

Copilot AI lite review requested due to automatic review settings August 21, 2026 04:48
@linear-code

linear-code Bot commented Aug 21, 2026

Copy link
Copy Markdown

CODE-599

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@lucas77778
lucas77778 requested review from PeronGH and xiaoland August 21, 2026 04:50

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes — the full diff at 320a9a60: an optional name on the image content block, threaded from attachment capture through the wire to the opencode file part and the image preview.

  • Schema + wire versionname: z.string().optional() on the image variant; WIRE_PROTOCOL_VERSION 77→78 with MIN_COMPATIBLE_WIRE_VERSION left at 76.
  • Both producers updatedcomposer-attachments.ts:94 takes file.name on the browser paste/drop path, :163 takes fileNameFromPath(file.path) on the native "Attach" picker.
  • imageBlocksFrom widened — a field-copying reduce became a type-guard filter, so adapters now receive whole image blocks.
  • opencode forwardingfilename: image.name on the FilePartInput.
  • Previewalt={block.name ?? ''} plus a title tooltip, with historical unnamed blocks still rendering.
  • Tests — new coverage on the wire schema, the opencode prompt dispatch, the native-read attachment (Windows path basename), and the image preview; the command-menu send assertion was updated.

Four things I checked that hold up:

  • The imageBlocksFrom widening leaks nothing into vendor payloads. All three callers build fresh objects rather than spreading the block, so the newly-exposed uri/annotations go nowhere: claude-code.ts:765, opencode/adapter.ts:491, pi/adapter.ts:396. codex does not use the helper at all.
  • The version bump is the right half of Invariant 1. The change is purely additive and an older peer's zod strips the unknown key, so the compatibility floor correctly stays at 76. Nothing outside wire/message.ts hardcodes the version.
  • filename is metadata-only on the opencode side. Verified against upstream packages/opencode/src/session/prompt.ts: resolvePart dispatches on url.protocol and then mime, never on filename, so adding it cannot re-route a data:image/* part, and the value is never path-joined or read from disk. The file: branch that does resolve paths is unreachable for a data: URL. Worth stating explicitly because the adapter test mocks promptAsync and so proves argument shape only.
  • Every new test can actually fail. zod strips unknown keys, so the wire test's toMatchObject genuinely depends on the schema field; the other three use exact deep equality or an accessible-name lookup.

ℹ️ The filename reaches the model on opencode only

Nothing here is wrong, but it is worth being deliberate about where this stops. The name is captured, crosses the wire, and shows in the UI for every agent — yet only opencode passes it to the model. The other three image-capable adapters have no filename slot in their input shapes, so a claude/codex/pi session still cannot tell two attached screenshots apart. If the goal of CODE-599 is the tooltip, this is complete; if it is the model disambiguating attachments, it lands for one of four agents.

Technical details
# Filename delivery is opencode-only

## Affected sites
- `packages/host/agent-adapter/src/native/opencode/adapter.ts:495` — the only adapter that
  forwards the name.
- `packages/host/agent-adapter/src/native/claude-code.ts:770` — builds `ClaudeImageBlock`. The
  SDK has no slot: `ImageBlockParam` is `{source, type, cache_control?}` and `Base64ImageSource`
  is `{data, media_type, type}` (`node_modules/@anthropic-ai/sdk/resources/messages/messages.d.ts`).
- `packages/host/agent-adapter/src/native/pi/adapter.ts:396``ImageContent` is exactly
  `{type, data, mimeType}` (`node_modules/@earendil-works/pi-ai/dist/types.d.ts:236`).
- `packages/host/agent-adapter/src/native/codex/adapter.ts:652` — pushes a bare
  `{type: 'image', url: 'data:<mime>;base64,<data>'}`; the live-verified `turn/start` image item
  shape has no filename field.
- `packages/integrations/im-render/src/blocks.ts:12` — the one other surface that renders image
  blocks, still printing `🖼️ *image (image/png)*` with the mime but not the name.

## Required outcome
- A conscious decision, recorded on the PR or the Linear issue: either opencode-only is the
  intended landing for CODE-599, or the remaining adapters need the name carried by some other
  means.

## Suggested approach (optional)
- For the three adapters with no filename slot, the only channel is the text part — e.g. naming
  the attachments in the prompt text the way a file mention already does. That is a visible
  prompt-content change, so it belongs in its own change rather than bolted on here.

## Open questions for the human
- Is opencode-only sufficient for CODE-599, or is a follow-up expected?
- Should the IM renderer use the name when one is present?

Pullfrog  | View workflow run | Using Claude Opus𝕏

@xiaoland xiaoland left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Code Review

LGTM

Manual Test

Image Image

Comment thread packages/foundation/schema/tests/contract/wire/agent.test.ts
@lucas77778
lucas77778 merged commit c5e864b into master Aug 21, 2026
12 checks passed
@lucas77778
lucas77778 deleted the chenyu/code-599 branch August 21, 2026 07:13
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.

3 participants