Skip to content

feat(telegram): support non-image document attachments (PDF/DOCX/etc.)#540

Open
Austin5925 wants to merge 1 commit intoop7418:mainfrom
Austin5925:feat/telegram-document-attachments
Open

feat(telegram): support non-image document attachments (PDF/DOCX/etc.)#540
Austin5925 wants to merge 1 commit intoop7418:mainfrom
Austin5925:feat/telegram-document-attachments

Conversation

@Austin5925
Copy link
Copy Markdown

Summary

Adds non-image document attachment support to the Telegram bridge. Previously
PDFs/DOCX/TXT/ZIP files sent to a CodePilot Telegram bot were either silently
dropped (single message) or caused inconsistent failures (mixed album with
images), making the Telegram bridge unable to handle anything but images.

Closes #539

What was broken

The inbound dispatch (telegram-adapter.ts:551-600) only recognized photos
and image-MIME documents:

const hasPhoto = m.photo && m.photo.length > 0;
const hasDocImage = m.document && this.isDocumentImage(m.document);
const hasMedia = hasPhoto || hasDocImage;

Non-image documents fell into the // Unhandled message type — skip branch
at line 597 with no enqueue, no error, no acknowledgment. The album path
(flushMediaGroup, line 791-805) similarly ignored non-image documents.

CodePilot's main chat UI input already supports file attachments (per #11
and PR #508), but the Telegram bridge adapter is a separate code path that
had not been updated.

What this PR does

  1. Single-document path: new processSingleDocumentMessage() mirrors
    processSingleImageMessage(), downloads the file, and enqueues with the
    original filename + Telegram-reported MIME.
  2. Mixed-media album path: flushMediaGroup now iterates documents in
    addition to photos/image-docs, with separate counts in the audit summary.
  3. Refactor: downloadFileById is parameterized (mimeOverride,
    nameOverride, mimeFallback, nameFallback, kind) so all three
    paths share a single implementation. Photo and image-doc paths preserve
    their existing behavior; non-image docs use doc.file_name and
    doc.mime_type directly so Claude can recognize the file format.
  4. Settings (mirror existing image_ pattern)*:
    • bridge_telegram_document_enabled (default true)
    • bridge_telegram_max_document_size (default 20 MB — Telegram Bot API limit)

The downstream attachment pipeline (claude-client.ts:1037-1048) already
handles non-image files end-to-end — they're written to .codepilot-uploads/
and Claude is prompted to read them via its Read tool. No changes needed
there.

Test plan

  • npm run typecheck — clean
  • npm run test — 1143/1143 passing
  • npx eslint src/lib/bridge/adapters/telegram-adapter.ts src/lib/bridge/adapters/telegram-media.ts — no new warnings (only pre-existing _chatId/_draftId unused-param warnings on line 325, unrelated to this change)
  • Manual reproduction (please verify):
    • DM bot a .pdf → bot should reply with content analysis
    • DM bot an album of [image, pdf] → bot should reply analyzing both
    • DM bot a 25 MB file → bot should reply "File too large (25.0 MB, limit 20 MB)."
    • DM bot a .png (regression) → still works as before
    • Set bridge_telegram_document_enabled=false → docs with caption fall through to text-only path; docs without caption silently skip (matches old behavior for unsupported types)

Notes

Previously, sending non-image documents (PDF, DOCX, TXT, ZIP, etc.) to a
Telegram bot fell through to the "unhandled message type" branch in the
inbound dispatch and was silently dropped. In mixed-media albums, the
album-flush loop ignored documents entirely. Both gaps left users unable
to send any non-image file via the Telegram bridge — the only working
attachment type was images.

This adds full document support, mirroring the existing image flow:

- New downloadDocument() in telegram-media.ts that preserves the
  user-supplied filename and Telegram-reported MIME, so Claude can
  recognize formats correctly via its Read tool.
- New processSingleDocumentMessage() in telegram-adapter.ts handling
  standalone document messages.
- flushMediaGroup() now downloads non-image documents in mixed albums
  with separate counts in the audit summary.
- Refactored downloadFileById to be parameterized (mime/name overrides,
  size cap, kind), so all three paths (photo / image-doc / non-image-doc)
  share a single implementation.
- Two new settings, mirroring the existing image_* pattern:
    - bridge_telegram_document_enabled (default true)
    - bridge_telegram_max_document_size (default 20 MB)

Document handling is wired into the same FileAttachment pipeline that
claude-client.ts:1037-1048 already uses for non-image files (writes to
.codepilot-uploads/ and prompts Claude to use Read tool).

Closes op7418#539
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 27, 2026

@Austin5925 is attempting to deploy a commit to the op7418's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(telegram): non-image document attachments are silently dropped or trigger "unexpected error"

1 participant