Repository navigation
[FEATURE]:Support drag-and-drop for Microsoft Office files (.docx, .xlsx) #27689
Description
Activity
github-actions commented
on May 15, 2026 on May 15, 2026 – with GitHub ActionsContributorMore actionsThis issue might be a duplicate of existing issues. Please check:
- [FEATURE]: Desktop should accept more dropped file types in prompt input #18143: Feature request for Desktop to accept more dropped file types in prompt input (same core request — expand supported drag-and-drop file types)
- [FEATURE]:It's recommended to drag and drop files in, and it should support more formats, such as .kt, .java, .xml, etc. #15177: Feature request to support more drag-and-drop file formats (e.g. .kt, .java, .xml)
Please review those issues and consider whether your request is already covered. If it is, adding a comment there with your specific use case (.docx/.xlsx + backend parsing) would help consolidate the discussion.
Hi! I would love to work on this feature. Could you assign it to me?
Here is my proposed implementation plan:
- Frontend: Update \ACCEPTED_FILE_TYPES\ in \packages/app/src/constants/file-picker.ts\ to include .docx, .xlsx, and their MIME types.
- Backend: Add \mammoth\ (for docx) and \xlsx\ (for Excel) to the dependencies in \packages/opencode/package.json.
- Modify \packages/opencode/src/tool/read.ts\ to intercept .docx\ and .xlsx\ before they hit the binary file check. We will parse their contents into text/CSV and return it within <content>\ tags for the LLM to ingest natively.
Let me know if this approach sounds good or if you have any feedback before I submit a PR!
Reacted by Alper Ünlü and Alex C.We use Opencode as a general harness for all our agent runs. I think an even simpler first change would start with:
- Frontnend. Same as @GP-commits
- Enable file passing to the LLM API endpoints. Anthropic and OpenAI already handle attachments natively.
A separate follow on PR would be great for support opensource models.
Adding our case for consolidation (as the dedupe bot suggested) — we hit this in a corporate rollout of opencode Desktop on a central config.
The angle that's slightly different from drag-and-drop: the “+” button / Cmd+U file picker filters selectable files by the model's
modalities.input(text, image, audio, video, pdf) — so .docx/.xlsx and other office formats are simply greyed out and can't be attached at all.Meanwhile the capability already exists elsewhere: the Read tool parses those same files fine once they're inside the project folder, and plugins (e.g. opencode-markitdown) convert them to Markdown. Only the picker blocks the path.
Two options from our users' perspective:
- add a
documentmodality for office formats, or - when attachments are handled tool-side, don't filter the picker — accept any file and route it through Read/conversion.
Observed on Desktop v1.17.18, macOS. Essentially the same request as #18143.
- add a
Adding our case: we run opencode against an internal gateway (LiteLLM proxy) that already handles Excel. The backend is fine with
.xlsx— only the client drops it.One correction to @bitfinop's note above — the picker doesn't filter on the model's
modalities.input; I couldn't find that in the attachment path at all. The actual blockers are three hardcoded lists:ACCEPTED_FILE_TYPESinpackages/app/src/constants/file-picker.ts— the picker allowlistattachmentMime()inprompt-input/files.ts— returnsundefinedfor.xlsx(it's a ZIP, so it fails the text sniff), so the file is dropped after selection even if the picker lets it through. This logic is duplicated insession-ui/src/v2/components/prompt-input/attachments.ts.local-attachment.tsin the TUI —if (!mime.startsWith("image/") && mime !== "application/pdf") return
The server already passes arbitrary mime through as a base64 file part (
session/prompt.ts), so this looks client-side only.Would you take a config option extending the allowed types, reusing the existing
attachmentnamespace?{ "attachment": { "types": [".xlsx"] } }Same token syntax that array already mixes (MIME,
text/*, or.ext), appended to the defaults. No parsing and no new dependencies — deliberately not what #32104 attempted.One design question before I start: when an accepted file's type is beyond what the model claims to support, should it be sent anyway and let the provider decide, or gated on capability? The former is what our proxy needs, and matches what the server does today.
Also affected on the desktop app (Windows). The attach button / file picker filters out .xlsx (and the attachment MIME sniffing rejects both .xls and .xlsx as binary), so spreadsheet files cannot be attached at all. Being able to drag-and-drop .xlsx and have it converted to Markdown tables (like the office-converter approach in the pending PRs) would be very useful. Looking forward to seeing this merged.
We hit this on OpenCode Desktop 1.18.25 (Windows) and spent some time instrumenting the shipped
bundle before building a working local patch. Sharing what we found, because there is a detail in
this thread that will cost the next person a day.The change proposed above is not sufficient on its own
Adding
.docx/.xlsxtoACCEPTED_FILE_TYPESinpackages/app/src/constants/file-picker.ts
does not make Office files attachable. We tried exactly that first, and nothing changed.There are two independent attachment pipelines in the renderer, each with its own accept list
and its own MIME resolver:list resolver add function legacy ACCEPTED_FILE_TYPES(packages/app/src/constants/file-picker.ts:3)attachmentMimecreatePromptAttachmentsCorev2 (the one actually rendered) accepted(packages/session-ui/src/v2/components/prompt-input/attachments.ts:5)its own attachmentMimeaddatattachments.ts:99The prompt input in the desktop app is
data-component=prompt-input-v2, so only the second row is
live. Patching the first list has no observable effect.Three places need to change
attachments.ts:5— add the extensions toaccepted(this drives both the<input accept>
attribute and the native picker'sextensions).attachments.ts:101—attachmentMime()samples the first 4096 bytes and rejects anything with
NUL bytes. A.xlsxis a zip, so it is rejected as binary even once the picker lets it through.
The file has to be converted to text before this call.file-picker.ts:3— for consistency with the legacy path.
A subtle bug worth flagging
If you convert the file by replacing the
Fileobject,attachments.ts:107const sourcePath = input.getPathForFile?.(file) || undefined
silently returns
undefined.getPathForFilelooks the file up in aWeakMappopulated by the
picker, and the convertedFileis a different object. The original reference has to be kept for
thesourcePathlookup, otherwise picker-attached documents lose their path.What we prototyped
Conversion in the desktop main process behind an IPC handler (
convert-office), exposed on the
preload bridge, called fromadd()beforeattachmentMime..xlsx/.xlsmbecome TSV per sheet,
.docxbecomes plain text.Deliberately no new dependencies: the zip central directory is read directly and inflated with
node:zlib, thenxl/worksheets/sheet*.xml+xl/sharedStrings.xml(orword/document.xml) are
parsed with regexes. Noxlsx, nomammoth, no native modules, nothing added to the bundle size
beyond ~180 lines. It has been running against real spreadsheets and Word documents on Windows.We are happy to open a PR with this cleaned up and tested.
Question for the maintainers
Per CONTRIBUTING this touches UI/product behaviour, so before writing anything we would like a
steer on scope:- Desktop-only, as we prototyped it (main-process IPC)? Simple, but the CLI and web clients
keep rejecting Office files. - Server-side, so every client benefits? Larger change, and it moves parsing into the server.
- Is a dependency-free parser acceptable, or would you rather pull in a real library and accept the
bundle cost?
Happy to go whichever way you prefer — or to just contribute the findings above if this is already
on someone's roadmap.We needed .docx/.xlsx drag-and-drop on a self-hosted
opencode web(1.18.25 → 1.18.29, Linux arm64) and ended up instrumenting the same code paths as @revaza88. A few findings not in this thread yet, in case they save someone time:-
attachmentMime()has two rejections, not one. After the NUL-byte check there is a control-character ratio check (> 0.3of the first 4096 bytes). OOXML zips are ~0.13 so they only hit the NUL check, but legacy OLE2 files (.doc/.xls/.ppt, ~0.49) are rejected by the ratio check as well. Extending the accept list alone won't let those through. -
Once a binary passes the client gate it is labeled
text/plainand sent as adata:URL. On the server,resolvePartturnstext/plaindata parts into syntheticCalled the Read tool …+ raw-content text parts beforechat.messageplugin hooks run. So a client-only fix leaks the raw bytes into the prompt as text — we saw the zip bytes land in context even though our hook had already replaced the file part. -
What worked for us end-to-end (web drop, paste, and
run --file): disable the two client checks (we patched the embedded bundle; upstream this could be theattachment.types-style allowlist suggested above) plus a server-sidechat.messageplugin that ignores the declared mime, sniffs magic bytes (PK\x03\x04withword/|xl/|ppt/entries, the OLE2 header,%PDF-), converts documents to text (pandoc / LibreOffice / pandas in our setup), and replaces non-document binaries with a visible notice so they never reach the model as text. Verified with a headless-Chromium drop test against the real bundle for docx/xlsx/pptx/doc, mixed drops, and a random-binary guard. The remaining wart is the duplicated synthetic part from (2), which a plugin cannot prevent. -
Trap: over a remote plain-HTTP origin nothing attaches at all, regardless of this fix — that is Web UI: pasting images fails with
Cannot read properties of undefined (reading 'digest')when accessing via HTTP on non-localhost #41706 / web: file attachments silently dropped on HTTP remote host — crypto.subtle undefined #47645 (crypto.subtleunavailable in insecure contexts). Test over HTTPS orlocalhost.
If maintainers prefer the server-side direction, the smallest upstream change that makes this cleanly pluggable is running the
text/plainsynthetic-part injection after plugin hooks (or letting hooks see the raw file part first), plus the allowlist. Happy to share the hook if useful.-
Feature hasn't been suggested before.
Describe the enhancement you want to request
Description: Currently, the opencode chat interface does not support dragging and dropping Microsoft Office files (such as .docx and .xlsx). Users are forced to manually provide file paths or convert files to text/PDF before uploading.
Proposed Solution:
Expand the allowed file types in the frontend's drag-and-drop handler to include .docx and .xlsx.
Integrate a backend parsing mechanism (e.g., using python-docx and openpyxl) to convert these documents into a text-based format (like Markdown) that the LLM can process.
Use Case: Many software engineering and administrative tasks involve reading requirements or data stored in Office documents. Direct support would significantly improve the user experience and workflow efficiency.