Problem
When a user sends an image attachment via a chat channel (Slack, Discord, Mattermost, etc.), the session.media_dir context provided to the agent contains a path that does not match the actual filename stored in the media/ directory. The agent must discover the real filename by listing the directory, which wastes turns and creates confusion.
What the agent sees
The attachment metadata contains an inbox/ path:
inbox/screenshot_hist_3b27758edaa7f4fa.png
What actually exists in media/
The file was copied to media/ with a completely different GUID-based filename:
media/c0bbe128bd374eaf81e0c582ab390712.png
The agent has no way to derive the media/ filename from the metadata. It must ls the media/ directory to find it.
Root Cause
Three independent naming schemes operate simultaneously across the attachment pipeline:
- Inbox live download — preserves the original channel filename (
image.png)
- Inbox historical backfill — generates a hash-based stable name (
image_hist_<sha256_prefix>.png)
- Media/ inline copy — generates a GUID-based name (
<guid_no_dashes>.png)
When inlined=true, SessionMediaStore.CopyFile calls Guid.NewGuid().ToString("N") to generate the media/ filename, completely discarding the source filename from step 2. The attachment metadata reports the inbox path, but the actual file the agent accesses lives at a different path with a different name. The pipeline runs with zero warnings or errors.
Reproduction
- Send an image attachment (e.g.,
screenshot.png) through any chat channel to the agent
- Check the
session.media_dir context the agent receives — it contains an inbox/ path like inbox/screenshot_hist_3b27758edaa7f4fa.png
- The agent attempts to access the file at that path relative to
media/ — the file does not exist there
- The agent must list the
media/ directory to discover the actual GUID-based filename
Scope
This is not channel-specific. The shared components affected are:
| File |
Role |
src/Netclaw.Channels/AttachmentIngressFormatting.cs |
BuildAcceptedProjectionAsync constructs the attachment metadata with the inbox path |
src/Netclaw.Channels/HistoricalAttachmentInbox.cs |
PromoteOrReuse generates hash-based inbox filenames for historical backfill |
src/Netclaw.Actors/Protocol/SessionMediaStore.cs |
CreateMediaFileName / CopyFile generates GUID-based media filenames |
src/Netclaw.Actors/SessionToolExecutionPipeline.cs |
MaterializeModelInputFiles performs the inbox-to-media copy |
All chat channels (Slack, Discord, Mattermost) use these shared components equally. The naming mismatch affects every channel that sends attachments.
Impact
- Agent cannot trust the path reported in attachment metadata
- Forces the agent to perform directory listings to find the actual file — wasting turns and context window
- Creates confusing behavior where the agent references a path that doesn't match reality
- No log warnings or errors — the entire pipeline succeeds silently despite the mismatch
- Degrades the agent's ability to work reliably with user attachments
Suggested Fix
The cleanest fix would be for SessionMediaStore.CopyFile to preserve the source filename (without the directory path) instead of generating a new GUID. This would make the media/ filename match what's reported in the attachment metadata.
Alternative: after the inline copy completes, update the attachment metadata to report the actual media/ path and filename. This keeps the GUID scheme but ensures the agent receives accurate paths.
Either approach would eliminate the need for the agent to discover filenames through directory listings.
Problem
When a user sends an image attachment via a chat channel (Slack, Discord, Mattermost, etc.), the
session.media_dircontext provided to the agent contains a path that does not match the actual filename stored in themedia/directory. The agent must discover the real filename by listing the directory, which wastes turns and creates confusion.What the agent sees
The attachment metadata contains an
inbox/path:What actually exists in
media/The file was copied to
media/with a completely different GUID-based filename:The agent has no way to derive the
media/filename from the metadata. It mustlsthemedia/directory to find it.Root Cause
Three independent naming schemes operate simultaneously across the attachment pipeline:
image.png)image_hist_<sha256_prefix>.png)<guid_no_dashes>.png)When
inlined=true,SessionMediaStore.CopyFilecallsGuid.NewGuid().ToString("N")to generate themedia/filename, completely discarding the source filename from step 2. The attachment metadata reports the inbox path, but the actual file the agent accesses lives at a different path with a different name. The pipeline runs with zero warnings or errors.Reproduction
screenshot.png) through any chat channel to the agentsession.media_dircontext the agent receives — it contains aninbox/path likeinbox/screenshot_hist_3b27758edaa7f4fa.pngmedia/— the file does not exist theremedia/directory to discover the actual GUID-based filenameScope
This is not channel-specific. The shared components affected are:
src/Netclaw.Channels/AttachmentIngressFormatting.csBuildAcceptedProjectionAsyncconstructs the attachment metadata with the inbox pathsrc/Netclaw.Channels/HistoricalAttachmentInbox.csPromoteOrReusegenerates hash-based inbox filenames for historical backfillsrc/Netclaw.Actors/Protocol/SessionMediaStore.csCreateMediaFileName/CopyFilegenerates GUID-based media filenamessrc/Netclaw.Actors/SessionToolExecutionPipeline.csMaterializeModelInputFilesperforms the inbox-to-media copyAll chat channels (Slack, Discord, Mattermost) use these shared components equally. The naming mismatch affects every channel that sends attachments.
Impact
Suggested Fix
The cleanest fix would be for
SessionMediaStore.CopyFileto preserve the source filename (without the directory path) instead of generating a new GUID. This would make themedia/filename match what's reported in the attachment metadata.Alternative: after the inline copy completes, update the attachment metadata to report the actual
media/path and filename. This keeps the GUID scheme but ensures the agent receives accurate paths.Either approach would eliminate the need for the agent to discover filenames through directory listings.