Skip to content

Conversation

@liorshk
Copy link

@liorshk liorshk commented Dec 29, 2025

Problem

When reloading an ACP session, file attachments were not being replayed correctly:

  • file type parts in stored messages were not being sent to ACP clients at all
  • Images lost their original filenames (always showed as "image")
  • Binary files (PDFs, etc.) were not replayed
  • Text files appeared as inline text instead of as file attachments
  • Synthetic text parts (injected for LLM context) were incorrectly sent to ACP clients

Solution

Updated processMessage() in agent.ts to properly handle file parts during session replay:

  • file:// URLs → Replayed as resource_link blocks
  • Images → Replayed as image blocks with preserved original filename
  • Text files (text/*, application/json) → Replayed as resource blocks with decoded text
  • Binary files → Replayed as resource blocks with blob data

Also updated the prompt() method to:

  • Preserve original filenames from resource_link.name and image.uri
  • Handle binary resource blocks (PDFs, etc.) by storing them as file parts with data URLs
  • Check for truthy resource.text instead of just property existence

Changes

  • Add file part handling in processMessage() for session replay
  • Filter synthetic text parts from ACP output (!part.synthetic)
  • Preserve filename from resource_link.name when converting to internal parts
  • Handle binary resource.blob blocks in prompt()

@liorshk liorshk marked this pull request as draft December 29, 2025 08:58
@liorshk liorshk marked this pull request as ready for review December 29, 2025 10:48
@liorshk liorshk marked this pull request as draft December 29, 2025 10:52
@liorshk liorshk force-pushed the fix/acp-file-attachments-clean branch from 9b3ebbb to cd8fde1 Compare December 29, 2025 10:52
@liorshk liorshk marked this pull request as ready for review December 29, 2025 10:58
@liorshk liorshk force-pushed the fix/acp-file-attachments-clean branch from f8f3077 to 0a9c595 Compare December 29, 2025 11:37
mediaType: part.mime,
filename: part.filename,
})
if (part.type === "file") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

im skeptical of the updates here, what are the reasons here?

This file shouldnt really need updates to fix acp stuff

Copy link
Author

Choose a reason for hiding this comment

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

You're right - the message-v2.ts changes were unnecessary for this fix.
The initial approach tried to handle binary content detection at the LLM message conversion layer, but that was the wrong place to solve this problem. The actual issue is purely in the ACP layer: when replaying a session, OpenCode's file parts weren't being converted back to proper ACP content blocks (image, resource, resource_link).
The current fix keeps all changes in agent.ts.

I updated the PR and the PR description.

@liorshk liorshk force-pushed the fix/acp-file-attachments-clean branch from 0a9c595 to ecaf273 Compare December 30, 2025 08:02
This PR fixes the issue where file attachments were not being correctly replayed during ACP session reload.

Changes to processMessage():
- Add handling for 'file' parts to correctly replay attachments
- file:// URLs -> resource_link blocks
- Images -> image blocks with preserved filename
- Text files -> resource blocks with decoded text
- Binary files -> resource blocks with blob data
- Filter synthetic text parts from ACP output

Changes to prompt():
- Preserve filenames from resource_link.name and image.uri
- Handle binary resource blocks (PDFs, etc.) as file parts
- Check for truthy resource.text instead of just property existence
@liorshk liorshk force-pushed the fix/acp-file-attachments-clean branch from ecaf273 to 44fccaf Compare December 30, 2025 08:22
@rekram1-node
Copy link
Collaborator

/review

// - data: URLs with text/* or application/json → resource with text
// - data: URLs with other types → resource with blob
const url = part.url
const filename = part.filename ?? "file"
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor style note: This uses a let statement which the style guide recommends avoiding. One alternative would be to calculate the effective MIME type inline:

const effectiveMime = (() => {
  const base64Match = url.match(/^data:([^;]+);base64,(.*)$/)
  return base64Match?.[1] || part.mime || "application/octet-stream"
})()

However, the current approach is readable and the reassignment is simple enough. Feel free to keep as-is if you prefer the clarity.

@github-actions
Copy link
Contributor

lgtm

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