Skip to content

feat: save file attachments to disk before model processing#30153

Open
ivanfernadezm99 wants to merge 1 commit into
anomalyco:devfrom
ivanfernadezm99:feat-attachment-save
Open

feat: save file attachments to disk before model processing#30153
ivanfernadezm99 wants to merge 1 commit into
anomalyco:devfrom
ivanfernadezm99:feat-attachment-save

Conversation

@ivanfernadezm99
Copy link
Copy Markdown

@ivanfernadezm99 ivanfernadezm99 commented Jun 1, 2026

Issue for this PR

No linked issue — this addresses the unrecoverable file attachment problem when using text-only models.

Type of change

  • New feature

What does this PR do?

When a user uploads an image or PDF to OpenCode and the model doesn't support that modality (e.g., deepseek-v4-pro with images), the file data is irreversibly lost. The model rejects it with a generic error, and the base64 data URL in the message part is discarded.

This PR saves the file to disk before it reaches the model layer, so tools like tesseract (OCR) can still access it.

How it works:

  1. New config: save_to_disk (bool, default true) + save_to_disk_path (optional string)
  2. New utility attachment-save.ts: decodes base64 data URLs and writes the raw buffer to {tmpdir}/opencode/attachments/{sessionID}/{timestamp}-{filename}
  3. Hook in prompt.ts resolvePart() case "data:" — saves every file part before it enters the session
  4. metadata.savedPath is threaded through message-v2.ts so the path survives the pipeline
  5. unsupportedParts() in transform.ts now appends " (saved to /path/to/file)" to the rejection message

Config behavior:

  • save_to_disk: true (default) — all data URL files are written to disk
  • save_to_disk: false — behavior is identical to current (no disk IO)
  • save_to_disk_path: "/custom/path" — overrides the default temp dir

Files changed: 11 files, +392 / -3 lines:

  • New: util/attachment-save.ts, test/util/attachment-save.test.ts, test/config/attachment-save.test.ts
  • Modified: config/attachment.ts (+core mirror), session/legacy.ts (metadata field), prompt.ts, message-v2.ts, transform.ts, transform.test.ts, prompt.test.ts

How did you verify your code works?

  • ✅ All 254 existing tests pass (0 regressions)
  • ✅ 13 new tests (7 config + 6 unit + integration + non-regression)
  • ✅ Manual verification: ran saveDataUrlToFile() with a real PNG base64, confirmed the file was written to /tmp/opencode/attachments/ with the correct PNG header
  • ✅ Vision models are unaffected — when the model supports image, unsupportedParts() never fires and no error text is injected

Screenshots / recordings

N/A — no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Add config option save_to_disk that writes attached files (images, PDFs, etc.) to a temp directory so they remain accessible to filesystem tools even when the model does not support the file modality.

- New util/attachment-save.ts: decode data URLs and write to disk
- Prompt pipeline hook in resolvePart() case 'data:'
- savedPath threaded through message metadata
- unsupportedParts() error now includes saved file path
- Config: save_to_disk (default true) + save_to_disk_path (optional)
- Tests: unit + integration + non-regression

All 254 tests pass.
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Jun 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

The following comment was made by an LLM, it may be inaccurate:

Found 2 potentially related PRs:

  1. PR fix(tui): save clipboard-pasted images to temp files for MCP tool access #21633 - fix(tui): save clipboard-pasted images to temp files for MCP tool access

    • Related because it also saves images to temp files for tool access, but specifically for clipboard-pasted content in the TUI
  2. PR fix(provider): emit file metadata instead of error when model lacks image/file support #29279 - fix(provider): emit file metadata instead of error when model lacks image/file support

    • Related because it addresses the same issue of handling attachments when models don't support certain file types

These PRs tackle similar problems (making attachments accessible to tools when models don't support them), but the current PR (#30153) appears to be a more comprehensive solution with the new save_to_disk config option and broader file attachment handling during model processing.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Jun 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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.

1 participant