fix(wecom): use reply_stream for progress messages to avoid errcode=40008

The plain reply() uses cmd="reply" which does not support "text" msgtype
and causes WeCom API to return errcode=40008 (invalid message type).
Unify both progress and final text messages to use reply_stream()
(cmd="aibot_respond_msg"), differentiating via finish flag.

Fixes #2999
This commit is contained in:
chengyongru 2026-04-10 22:20:28 +08:00
parent 6af81bc4a3
commit df6f9dd171
2 changed files with 21 additions and 22 deletions

View File

@ -513,23 +513,21 @@ class WecomChannel(BaseChannel):
return
if frame:
if is_progress:
# Progress messages (thinking text): send as plain reply, no streaming
await self._client.reply(frame, {
"msgtype": "text",
"text": {"content": content},
})
logger.debug("WeCom progress sent to {}", msg.chat_id)
else:
# Final response: use streaming reply for better UX
stream_id = self._generate_req_id("stream")
await self._client.reply_stream(
frame,
stream_id,
content,
finish=True,
)
logger.debug("WeCom message sent to {}", msg.chat_id)
# Both progress and final messages must use reply_stream (cmd="aibot_respond_msg").
# The plain reply() uses cmd="reply" which does not support "text" msgtype
# and causes errcode=40008 from WeCom API.
stream_id = self._generate_req_id("stream")
await self._client.reply_stream(
frame,
stream_id,
content,
finish=not is_progress,
)
logger.debug(
"WeCom {} sent to {}",
"progress" if is_progress else "message",
msg.chat_id,
)
else:
# No frame (e.g. cron push): proactive send only supports markdown
await self._client.send_message(msg.chat_id, {

View File

@ -317,20 +317,21 @@ async def test_send_text_with_frame() -> None:
@pytest.mark.asyncio
async def test_send_progress_with_frame() -> None:
"""When metadata has _progress, send uses reply (not reply_stream)."""
"""When metadata has _progress, send uses reply_stream with finish=False."""
channel = WecomChannel(WecomConfig(bot_id="b", secret="s", allow_from=["*"]), MessageBus())
client = _FakeWeComClient()
channel._client = client
channel._generate_req_id = lambda x: f"req_{x}"
channel._chat_frames["chat1"] = _FakeFrame()
await channel.send(
OutboundMessage(channel="wecom", chat_id="chat1", content="thinking...", metadata={"_progress": True})
)
client.reply.assert_called_once()
client.reply_stream.assert_not_called()
call_args = client.reply.call_args
assert call_args[0][1]["text"]["content"] == "thinking..."
client.reply_stream.assert_called_once()
call_args = client.reply_stream.call_args
assert call_args[0][2] == "thinking..." # content arg
assert call_args[1]["finish"] is False
@pytest.mark.asyncio