feat: attach files to chat messages as downloadable cards - #404
Open
wuxiangru915 wants to merge 2 commits into
Open
feat: attach files to chat messages as downloadable cards#404wuxiangru915 wants to merge 2 commits into
wuxiangru915 wants to merge 2 commits into
Conversation
Author
wuxiangru915
force-pushed
the
feat/file-attachments
branch
from
August 7, 2026 02:56
9944faf to
880431c
Compare
Adds a file attachment flow alongside the existing image attachments: - New paperclip button next to the image button opens a file picker; any non-image file is uploaded to a persistent local directory (~/.local/share/pi-web/attachments/<uuid>/<original-name>) and shown as a card with the original file name and size. - Dragging a file onto the chat window now attaches it as a card too (instead of inserting a path), so the behavior is uniform. - On send, each attached file is appended to the message as an "[附件] <path>" line; the agent (running locally) reads the file via that path. User messages render these lines as clickable download cards, never showing the raw path. - New POST /api/drop-files writes uploads (25MB/file, 100MB total, name sanitized, one uuid subdirectory per file so original names are always preserved — no -1 suffix renaming). New GET /api/attachments serves downloads, restricted to the attachments directory. - File attachments are saved in the same in-memory draft as images/text and restored when switching sessions.
wuxiangru915
force-pushed
the
feat/file-attachments
branch
from
August 8, 2026 02:40
880431c to
ba1b27b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
The chat input currently supports image attachments only. This PR adds a file attachment flow (paperclip button next to the image button, plus unified drag-and-drop), so you can attach any file to a message and the agent can read it.
Behavior
[附件] <path>line. The locally-running agent reads the file via that absolute path. In the UI, those lines render as clickable download cards — the raw path is never shown (it's only in the hover title).GET /api/attachments.Why this works everywhere
No browser-path magic: the file content is uploaded through the app (the browser always provides the bytes), so it works identically in Chrome, Firefox, Safari, any OS. Paths come from the server, never from
text/uri-list.Implementation
app/api/drop-files/route.ts: multipart upload → persistent~/.local/share/pi-web/attachments/<uuid>/<original-name>(one uuid subdir per file, so original names are always preserved — uploadinga.pdftwice yields twoa.pdffiles, and a file literally nameda-1.pdfnever collides). Name sanitized (no traversal), 25MB/file, 100MB total.app/api/attachments/route.ts: serves downloads, path restricted to the attachments directory (?path=absolute, must be inside;?name=kept for legacy root files).lib/file-attachments.ts:[附件] <path>line parsing/serialization + size formatting. Unit-tested.lib/upload-dropped-files.ts: client upload helper. Unit-tested (stubbed fetch).components/ChatInput.tsx:attachedFilesstate (draft-integrated like images/text), upload-on-select, card UI, send plumbing.hooks/useAgentSession.ts:handleSend(message, images, files)appends attachment paths to the message sent to the agent.components/MessageView.tsx: renders[附件]lines as download cards (coexists with the v0.8.7 slash-command collapsing).Verification
file-attachments,upload-dropped-files,drop-filesroute,attachmentsroute,MessageViewSSR incl. coexisting with slash-collapse tests);tsc --noEmit,eslint, productionnext buildclean.a.pdf; drag txt → card; message rendering shows cards with hidden raw paths; download works incl. CJK file names; upload persists across server restarts.