#22113: feat: support non-image file attachments in webchat chat.send
app: web-ui
gateway
size: S
Cluster:
Attachment Processing Enhancements
## Problem
Non-image file attachments (PDFs, documents, etc.) sent via WebSocket `chat.send` are silently dropped by `parseMessageWithAttachments()`. This means webchat/WebUI clients cannot send documents for the agent to process, unlike Telegram/Signal channels which save files to disk and pass them through `MediaPath`/`MediaType` context.
## Solution
Instead of dropping non-image attachments, collect them as `ChatFileContent`, save to disk via `saveMediaBuffer()`, and populate `MediaPaths`/`MediaTypes` on `MsgContext` — mirroring the existing Telegram/Signal channel behavior.
The agent then sees `[media attached: /path/to/file]` in its prompt and can use the Read tool to process file contents.
## Changes
- **`chat-attachments.ts`**: New `ChatFileContent` type; `parseMessageWithAttachments` now returns a `files[]` array instead of dropping non-image payloads
- **`server-methods/chat.ts`**: Saves file attachments to disk via `saveMediaBuffer`, sets `MediaPaths`/`MediaTypes` on `MsgContext`
- **`chat-attachments.test.ts`**: Updated tests for new file collection behavior (all 12 tests pass)
## Backward Compatibility
- `ParsedMessageWithImages` type gains an optional-style `files` field; existing consumers that only destructure `images` are unaffected
- Image attachment handling is completely unchanged
- The `chat.send` schema already accepts `Type.Array(Type.Unknown())` for attachments, so no schema changes needed
- Other callers of `parseMessageWithAttachments` (e.g. `server-node-events.ts`) simply ignore the new `files` field
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Extended WebSocket `chat.send` to handle non-image file attachments (PDFs, documents, etc.) by saving them to disk via `saveMediaBuffer` and populating `MediaPaths`/`MediaTypes` on the message context, mirroring the existing Telegram/Signal channel behavior. The agent now sees `[media attached: /path/to/file]` in its prompt and can use the Read tool to process file contents.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with minimal risk.
- The implementation correctly extends file attachment handling and maintains backward compatibility. All tests pass, the code follows existing patterns from other channels (Telegram/Signal), and the changes are well-contained. The only concern is the potential for file path conflicts if multiple files have the same name, but this is a minor edge case that the existing `saveMediaBuffer` function already handles via UUIDs.
- No files require special attention.
<sub>Last reviewed commit: f852c58</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#22781: fix(webchat): persist chat attachments after guards and expose medi...
by Kansodata · 2026-02-21
85.4%
#10441: webchat: switch file uploads to HTTP /uploads
by supernewbilityxht1 · 2026-02-06
83.0%
#4327: Gateway Web Chat: add image/file upload (attach, drag-drop, paste)
by RogerHsu7 · 2026-01-30
78.7%
#8284: Fix: Webchat images now persist after sending
by vishaltandale00 · 2026-02-03
78.5%
#21230: Fix [Bug]: Discord attachments silently missing (Fixes #19956)
by vasujain00 · 2026-02-19
77.6%
#13961: fix(telegram): support media attachments in replied Telegram messages
by shan-mx · 2026-02-11
77.1%
#15879: Support for forwarded messages and file_shared messages in slack
by olyashok · 2026-02-14
77.1%
#17842: Fix Google Chat media upload failure by inferring content-type from...
by Clawborn · 2026-02-16
77.0%
#6663: Web UI: handle drag-drop image attachments
by mar0der · 2026-02-01
76.9%
#6591: fix(signal): process all inbound attachments in parallel
by ProofOfReach · 2026-02-01
76.6%