Skip to content

fix(discord): upload local video replies instead of printing the file:// path - #3289

Merged
zhayujie merged 1 commit into
zhayujie:masterfrom
Lesereingrape:fix/discord-video-reply
Sep 29, 2026
Merged

zhayujie merged 1 commit into
zhayujie:masterfrom
Lesereingrape:fix/discord-video-reply

Conversation

@Lesereingrape

Copy link
Copy Markdown
Contributor

What

Add ReplyType.VIDEO to the local-file branch of DiscordChannel._async_send, so a video reply whose content is a file:// path is uploaded through discord.File instead of falling through to the plain-text fallback.

Fixes #3288

Why

channel/chat_channel.py:418 produces Reply(ReplyType.VIDEO, f"file://{url}") for locally generated videos. QQ, wechatcom, weixin and wecom_bot all match ReplyType.VIDEO in their send paths; the Discord dispatch table only lists (VOICE, FILE), so the reply reaches the final else and the user gets the literal server path — file:///opt/cow/tmp/clip.mp4 — as a text bubble, with no video attached.

ReplyType.VIDEO_URL is untouched on purpose: Discord unfurls a bare URL into a player, so posting it as text is already correct.

Tests

tests/test_discord_video_reply.py stubs the discord module (it is imported lazily inside _async_send) and records what the channel sends:

  • one test asserts a VIDEO reply uploads the path as a file and posts no text;
  • one test pins the existing VIDEO_URL behaviour so the fix cannot regress URL unfurling.

On master, the first test fails with the bug reproduced:

AssertionError: video sent as a text bubble: ('file:///srv/cow/tmp/clip.mp4',) {}
1 failed, 1 passed

With the patch:

$ python -m pytest tests/test_discord_video_reply.py -q
2 passed in 0.40s

$ python -m pytest tests/ -q
36 failed, 2180 passed, 35 skipped, 55 subtests passed in 106.13s

The 36 failures are pre-existing: plain master at the same commit (c872f6f0) gives 36 failed, 2178 passed, 35 skipped, 55 subtests passed in 110.69s, the same failing set (test_scheduler_timezone, test_search_files_tool, test_security_read_env_bypass, …), none of it in the Discord channel. This branch adds exactly the two passing tests above.

The two extra lines in the diff

ruff (F-class gate) lints the Python files a PR changes, and channel/discord/discord_channel.py already carries two findings on master:

  • F541 — a placeholder-free f-string at line 188;
  • F841 — receiver = str(message.channel.id) at line 280, never read afterwards (context["receiver"] is set independently at line 263, and agent_router.resolve() takes only explicit_agent_id).

I cleared both so the gate stays green. They are pre-existing debt in this file, unrelated to the video bug.

$ ruff check channel/discord/discord_channel.py tests/test_discord_video_reply.py --select F --ignore F403,F405
All checks passed!

…:// path

chat_channel.py builds Reply(ReplyType.VIDEO, "file://<path>") for locally
generated videos, but DiscordChannel._async_send only dispatches
(VOICE, FILE), so a VIDEO reply falls through to the plain-text fallback and
the user receives the raw server path while the video is never uploaded.

Add ReplyType.VIDEO to that branch and cover it with a test that stubs the
lazily imported discord module; VIDEO_URL keeps its existing text behaviour.

Also clear the two pre-existing ruff F-class findings in this file (F541 on a
placeholder-free f-string, F841 on a dead local), which the repo's changed-files
lint gate would otherwise report on this PR.
@zhayujie
zhayujie merged commit c7ae3ba into zhayujie:master Sep 29, 2026
3 checks passed
@zhayujie

Copy link
Copy Markdown
Owner

Merged, thanks! Slack and Telegram had the same gap, so we added ReplyType.VIDEO there as well on master.

zhayujie pushed a commit that referenced this pull request Sep 29, 2026
chat_channel.py hands an agent-produced video to channels as
Reply(ReplyType.VIDEO, "file://" + path). WechatKfChannel.send dispatches
ReplyType.VIDEO_URL but never ReplyType.VIDEO, so a locally generated video
fell through to the trailing else and was only logged as

    [wechat_kf] unsupported reply type: VIDEO

send() is the whole outbound contract for this channel and _send_reply() has
no per-type fallback, so the user received nothing at all -- not even the raw
file:// path the other channels used to leak before they were fixed.

The asymmetry is unique to wechat_kf: every sibling that dispatches VIDEO_URL
also dispatches VIDEO (weixin, wechatcom, wechatmp, wecom_bot, qq), and the
three channels that used to share this gap got the same one-line treatment
(#3289 discord, slack/telegram). _send_video() already exists and the video
branch already reads through _read_media(), which loads a file:// path from
disk and size-caps a genuine http(s) download, so no new plumbing is needed.

Tests: a file:// VIDEO reply is uploaded as "video" and handed to
_send_video(), and requests.get is never called for it; a remote VIDEO_URL
reply keeps its existing download-and-send behaviour.
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.

Discord drops local video replies: the raw file:// path is sent to the user as text

2 participants