feat: accept document uploads via unified FileHandler branch#193
Open
timurvafin wants to merge 1 commit intoRichardAtCT:mainfrom
Open
feat: accept document uploads via unified FileHandler branch#193timurvafin wants to merge 1 commit intoRichardAtCT:mainfrom
timurvafin wants to merge 1 commit intoRichardAtCT:mainfrom
Conversation
4 tasks
Add a new `"document"` type to FileHandler for binary document formats. Matching files are persisted to `<current_dir>/.uploads/<timestamp>-<name>` and Claude receives a generic prompt with the absolute path, letting the agent pick whichever tool fits the format (Read for PDF/text; Bash with pandoc, python-docx, openpyxl, unzip, etc. for Office/OpenDocument). Covered formats (added to ALLOWED_EXTENSIONS): - Binary (document branch): .pdf, .docx, .xlsx, .pptx, .odt, .ods, .odp, .rtf - UTF-8 text-compatible (existing text branch): .csv, .tsv, .log, .ics, .eml Both agentic (`agentic_document`) and classic (`handle_document`) handlers pass `current_dir` into `FileHandler.handle_document_upload`, so classic mode gains document support for free. The `.uploads/` directory sits inside APPROVED_DIRECTORY, so Claude's tools can reach it without tool_monitor boundary issues. The file survives the upload call so follow-up turns can still read or reference it. Supersedes RichardAtCT#192 (narrow PDF-only patch that branched directly in `agentic_document`). This PR routes the same capability through the proper abstraction and extends it to the whole Office family in one step. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
220496e to
3f32a51
Compare
5 tasks
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
Accept a family of document uploads (PDF, Office, OpenDocument, and common text-table formats) by adding a new
"document"type toFileHandler. Binary documents are persisted to<current_dir>/.uploads/<timestamp>-<name>and Claude receives a generic prompt with the absolute path — the agent picks whichever tool fits the format. Both agentic (agentic_document) and classic (handle_document) paths go through the same FileHandler method.Design
Single document branch, one prompt
The
_process_document_filemethod is format-agnostic. The prompt just tells Claude where the file is:Claude infers the format from the extension and chooses Read (for PDF/text/notebooks) or Bash with an appropriate converter (pandoc, python-docx, openpyxl, unzip, etc.) for Office/OpenDocument. This means adding a new format is one line in
document_extensions.Storage
.uploads/sits insideAPPROVED_DIRECTORY, so Claude's tools reach it without trippingToolMonitorpath boundaries. The file is not deleted after the call — follow-up turns can still read or reference it without re-uploading. Timestamp prefix (YYYYMMDD-HHMMSS-fff) prevents collisions from rapid uploads.The existing archive/code/text branches are untouched.
Formats supported
Binary (persisted, document branch):
.pdf— Read tool (native parser).docx,.xlsx,.pptx— Bash with pandoc / python-docx / openpyxl.odt,.ods,.odp— Bash with pandoc / LibreOffice.rtf— Bash with pandocUTF-8 text-compatible (existing text branch, inline in prompt):
.csv,.tsv,.log,.ics,.emlChanges
src/security/validators.py— extendALLOWED_EXTENSIONSwith the two groups abovesrc/bot/features/file_handler.py— newdocument_extensionsset,_detect_file_typereturns"document"for them, new_process_document_filepersists and builds the generic prompt,handle_document_uploadaccepts optionalcurrent_dir(defaults toapproved_directory)src/bot/orchestrator.py(agentic) — resolvecurrent_dirbefore callinghandle_document_upload, pass it throughsrc/bot/handlers/message.py(classic) — same plumbing;.pdfadded to supported-formats help text.gitignore— ignore.uploads/tests/unit/test_bot/test_file_handler.py(6 tests: parametrized detection for all binary formats, CSV → text branch, unknown binary stays binary, persist + prompt shape, end-to-end PDF, fallback-to-approved-directory); validator whitelist extended +.pdf.exeregressionKnown limitations
pip installif pandoc/python-docx/openpyxl aren't found. Supports are graceful: Claude will report back if it can't convert a given format..uploads/has no automatic cleanup. Manual housekeeping for now — a follow-up PR could add a/newhook or cron-based LRU..doc(legacy MS Word binary) and.ppt(legacy PowerPoint) intentionally excluded — they're harder to convert reliably and less common today.Relationship to #192
This PR supersedes #192, which was a narrow patch that branched on
.pdfdirectly inagentic_document. #192 has been closed. This PR:FileHandlerwhere other document types already liveTest plan
make test— 542 passed (10 new tests)black/isort/flake8cleanSMOKE-TOKEN-42uploaded, saved, Claude read via Read and answered correctlySMOKE-DOCX-99uploaded as.docx, saved to.uploads/20260424-145608-997-contract.docx, Claude converted via Bash and answered correctly.exestill blocked,.pdf.exetrap still blocked, files > 10 MB still rejected🤖 Generated with Claude Code