Skip to content

Voice messages bypass channel file auto-download (PR #2972 only handles File, not Voice) #3211

Description

@neo-wanderer

Summary

PR #2972 (commit cf308d6b) added auto-download for ChannelContent::File so agents receive a saved-on-disk path instead of a raw URL. The same treatment is missing for ChannelContent::Voice, which still flows through as [User sent a voice message ({Xs}): {url}] text — forcing the agent to download the audio itself before tools like media_transcribe can read it.

Repro

  1. Send a Telegram voice note to any agent on a channel-bridged hand.
  2. Observe the inbound prompt body contains the raw https://api.telegram.org/file/bot.../voice/file_N.oga URL.
  3. The agent must curl the URL, then juggle workspace-allowed paths (/data/workspaces vs /tmp) before invoking media_transcribe or mcp_filesystem_read_file. The web_fetch tool also rejects the host in some configs.

Expected

Voice messages should mirror the File path: stream-download to channels.file_download_dir (default <tempdir>/librefang_uploads), respect channels.file_download_max_bytes, and dispatch a [File: voice.ogg] saved to /tmp/librefang_uploads/<id>.ogg block (plus a Text block carrying the caption + duration if either is present). media_transcribe then works end-to-end against the saved path with no agent-side curl.

Code pointers

  • Voice text-only formatter: `crates/librefang-channels/src/bridge.rs` ~line 2682 (`ChannelContent::Voice` arm in `dispatch_message`).
  • File download arm to mirror: same file, ~line 2506.
  • Helper to reuse: `download_file_to_blocks` (~line 3492) — takes `url`, `filename`, `max_bytes`, `download_dir`. Filename can be derived from the URL path basename, falling back to `voice.ogg`.
  • Existing test fixture: `test_content_to_text_voice` (~line 5300) — add a parallel `test_voice_dispatch_downloads` exercising the new path.

Notes

  • WhatsApp already ships a `send_voice` companion (feat(whatsapp): add send_voice and dm/group message policies #3012) on the outbound side; this issue is purely the inbound dispatch gap.
  • Caption preservation matters: today's text formatter appends ` {caption}` after the URL line. The downloaded-block path should emit a separate `ContentBlock::Text { text: caption }` so it's not lost in the saved-path block.
  • Same gap likely applies to `ChannelContent::Video` / `ChannelContent::Audio` — worth scoping in the same PR if cheap, otherwise file as follow-ups.

Happy to send a PR — drafting now against `upstream/main`.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/channelsMessaging channel adaptershas-prA pull request has been linked to this issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions