Repository navigation
fix(dingtalk): deliver ERROR and INFO replies instead of dropping them - #3282
Merged
zhayujie merged 1 commit intoSep 29, 2026
Merged
Conversation
ChatChannel._send_reply hands every reply that is not TEXT, IMAGE_URL or VOICE straight to send(), and this channel's dispatch only covered IMAGE_URL, FILE, VOICE and TEXT. An ERROR from a failed agent turn or an INFO from godcmd and the role plugins therefore returned without making a single API call, so the user saw the bot go quiet. Reply through the session webhook the way QQ and WecomBot already do, and log the reply types this channel genuinely cannot render instead of leaving no trace in the log.
Owner
|
Merged, thanks for the fix! |
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.
What does this PR do?
DingTalkChanel.send()dispatched onIMAGE_URL,FILE,VOICEandTEXTand had no branch for anything else, so anERRORorINFOreply returned fromsend()without making a single API call. It now delivers those two types through the session webhook — the same helper the text path already uses when cards are off or the card failed — and logs the reply types this channel genuinely cannot render instead of returning in silence.Type of change
Why it is a real defect
ChatChannel._send_reply(channel/chat_channel.py:318-356) ends withelse: self._send(reply, context), and_decorate_replykeepsERROR/INFOas their own types (it only prefixes the text). So every reply of those types arrives atsend()and is dropped. The producers are not rare paths:bridge/agent_bridge.py:935,:1590and:1842—Reply(ReplyType.ERROR, f"Agent error: {str(e)}"). When a turn raises, the user gets silence instead of the error.Reply(ReplyType.ERROR, ...)(models/chatgpt/chat_gpt_bot.py:185,:202,:284and the equivalent lines in the other providers), and the voice providers report a failed synthesis the same way.INFO(plugins/godcmd/godcmd.py:452,plugins/role/role.py:145,:177,:203,:208), so#help,#clearand role presets acknowledge nothing on DingTalk.models/chatgpt/chat_gpt_bot.py:131-137does the same for "记忆已清除" / "配置已更新".Every other channel already treats these three types as one text class —
channel/telegram/telegram_channel.py:656,channel/wechatcom/wechatcomapp_channel.py:107,channel/discord/discord_channel.py:458,channel/slack/slack_channel.py:461, andfeishureaches the same result by leavingmsg_type = "text"as the default (channel/feishu/feishu_channel.py:899) — and the ones that cannot render a type fall back with an explicit log:channel/qq/qq_channel.py:590,channel/wecom_bot/wecom_bot_channel.py:1003. DingTalk was the outlier.What changed
Two branches appended to the dispatch, no existing branch edited:
elif reply.type in (ReplyType.ERROR, ReplyType.INFO): stringify, skip an empty payload, and send through_reply_markdown_or_text, which already falls back to plain text when the webhook rejects markdown. Group chats are covered because that helper takes the sameincoming_messagethe text path uses.elsethat logsUnsupported reply type: <type>, not sent. An in-memoryIMAGE, aVIDEO_URLextracted out of an answer and the WeChat-only card types need an upload or payload this channel does not implement; today they disappear without a trace.How I checked
New
tests/test_dingtalk_reply_type_fallback.py(6 cases) drives the realsend()with a stubbed webhook: an agent error and a pluginINFOreach the chat as text, a group chat is covered with cards enabled, a webhook that rejects markdown still delivers the error as plain text, an empty reply sends nothing, and an unsendable media type is logged.Before the change, on pristine
4c00ca6d:After:
python -m pytest tests/ -q -k "dingtalk or telegram or weixin or wechat or reply"→132 passed.python -m pytest tests/ -qon this branch →36 failed, 2070 passed, 34 skipped, 55 subtests passed; on a pristine4c00ca6dworktree on the same machine and venv →36 failed, 2064 passed, 34 skipped, 55 subtests passed. The 36 node IDs are byte-identical on both sides (symlink-, zoneinfo- and POSIX-path-dependent tests that need this Linux CI image); the only difference is the six new passing tests.ruff check channel/dingtalk/dingtalk_channel.py tests/test_dingtalk_reply_type_fallback.py --select F --ignore F403,F405→All checks passed!Checklist