Uh oh!
There was an error while loading. Please reload this page.
Add file management: upload, download, and send_file tool - #38
Merged
Conversation
…-produced files
Backend:
- New uploaded_files table (v022 migration) + FileStore DB mixin
- POST /api/files/upload: multipart upload, stores on disk + DB index
- GET /api/files/uploads/{id}: serve uploaded files for chat history
- GET /api/files/download: serve workspace files with path traversal protection
- WebSocket message handler extended to accept file_ids, loads files
and passes them to engine.run(images=...) reusing the Telegram pipeline
- engine.py stores image refs in user message blocks column for persistence
- Session deletion cleans up uploaded files from disk and DB
Frontend:
- New ImageBlockData and FileBlockData types in MessageBlock union
- ChatInput: paperclip file picker, drag-and-drop, clipboard paste (Ctrl+V)
with preview strip showing upload progress
- UserMessage: renders attached images as thumbnails, files as download cards
- BlockRenderer: handles image and file block types in assistant messages
- chatStore.sendMessage extended with fileIds and imageBlocks params
- hydrateMessage: restores image/file blocks from DB for chat history
- api/client.ts: uploadFiles method with multipart FormData
- api/websocket.ts: sendMessage accepts optional fileIdsBrowser <img src> and <a download> can't set Authorization headers, so file/image URLs need ?token= query parameter. Added query param support to get_token_from_request() and appended token to all image and file URLs in the frontend.
New session-scoped `send_file` tool that broadcasts a `file_attachment` WS event. The frontend handler injects a downloadable file block into the streaming assistant message, rendering it as a clickable card with filename and download link. Reverted the auto-inject approach (file_changed → file block) in favor of this explicit tool — agent decides when to send files.
- Added SendFileBlock renderer in ToolCallBlock router — send_file tool calls render as a clean download card instead of generic tool UI - Removed file_attachment WS event approach — the tool_call block itself is persisted in DB, so downloads survive page reload - Cleaned up unused handleFileAttachment handler and WS type
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 freeto 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
GET /api/files/downloadendpoint with path traversal protectionsend_filetool: agent can send files as inline download cards in chat — persists across page reload<img src>and<a download>that can't set headersBackend
uploaded_filestable +FileStoremixinPOST /api/files/upload: multipart upload → disk + DB indexGET /api/files/uploads/{id}: serve uploaded files for chat historyGET /api/files/download: serve workspace files with path traversal protectionmessagehandler acceptsfile_ids, loads files and passes toengine.run(images=...)reusing the Telegram pipelineengine.pystores image refs in user messageblockscolumn for persistencesend_filesession-scoped tool intools.pyFrontend
ImageBlockDataandFileBlockDatatypes added toMessageBlockunionChatInput: paperclip file picker, drag-and-drop overlay, clipboard paste (onPastehandler)UserMessage: renders attached images as thumbnails, files as download cardsBlockRenderer: handlesimageandfileblock typesToolCallBlock:SendFileBlockrenderssend_filetool calls as clean download cards (no generic tool chrome)chatStore.sendMessageextended withfileIdsandimageBlockshydrateMessage: restores image/file blocks from DB for chat historyTest plan
send_filetool → download card appears inline → download works