diff --git a/gateway/platforms/weixin.py b/gateway/platforms/weixin.py index 8f4afd5f1b70..bd25319fc8b4 100644 --- a/gateway/platforms/weixin.py +++ b/gateway/platforms/weixin.py @@ -979,6 +979,18 @@ def _extract_text(item_list: List[Dict[str, Any]]) -> str: # gibberish). Return empty so the central STT pipeline in # ``gateway/run.py`` produces the body from the downloaded # audio instead. + voice_item = item.get("voice_item") or {} + if not (voice_item.get("media") or {}): + # No raw audio to download — Weixin supplied only its own + # speech-to-text result. Use it, but preserve the voice + # origin so the agent can distinguish this from text the + # user typed (#65022). + voice_text = str(voice_item.get("text") or "") + if voice_text: + return ( + "[Voice transcription provided by Weixin]\n" + f"{voice_text}" + ) continue return "" diff --git a/tests/gateway/test_weixin.py b/tests/gateway/test_weixin.py index 2d9a3609f3be..e5343d7e021d 100644 --- a/tests/gateway/test_weixin.py +++ b/tests/gateway/test_weixin.py @@ -27,6 +27,41 @@ def _make_adapter() -> WeixinAdapter: ) +class TestWeixinInboundVoiceTranscript: + def test_voice_transcript_keeps_voice_origin_marker(self): + item_list = [ + { + "type": weixin.ITEM_VOICE, + "voice_item": {"text": "帮我查一下今天天气"}, + } + ] + + assert weixin._extract_text(item_list) == ( + "[Voice transcription provided by Weixin]\n" + "帮我查一下今天天气" + ) + + def test_typed_text_remains_unmarked(self): + item_list = [ + { + "type": weixin.ITEM_TEXT, + "text_item": {"text": "帮我查一下今天天气"}, + } + ] + + assert weixin._extract_text(item_list) == "帮我查一下今天天气" + + def test_empty_voice_transcript_keeps_empty_fallback(self): + item_list = [ + { + "type": weixin.ITEM_VOICE, + "voice_item": {"text": ""}, + } + ] + + assert weixin._extract_text(item_list) == "" + + class TestWeixinFormatting: def test_format_message_preserves_markdown(self): adapter = _make_adapter()