fix(dingtalk): don't let richText re-derivation clobber VOICE classification

The msg_type_str == "richText" branch reset msg_type to PHOTO/TEXT after
the rich-text item scan had already promoted it (e.g. a native voice item
→ VOICE), dropping voice notes from the auto-STT path. Only re-derive when
the scan left the type at TEXT.

Ports the root-cause analysis from PR #38276 (stale, targeted the deleted
gateway/platforms/dingtalk.py) onto the live plugin adapter, with
regression tests.

Refs #38211 #38219 #38276
This commit is contained in:
Teknium 2026-07-28 09:25:06 -07:00
parent c762314561
commit 7ee111ff9b
2 changed files with 43 additions and 5 deletions

View file

@ -920,11 +920,15 @@ class DingTalkAdapter(BasePlatformAdapter):
if msg_type_str == "picture" and not media_urls:
msg_type = MessageType.PHOTO
elif msg_type_str == "richText":
msg_type = (
MessageType.PHOTO
if any("image" in t for t in media_types)
else MessageType.TEXT
)
# Only re-derive the type when the rich-text scan above left it
# at TEXT. The scan may already have promoted it to VOICE/AUDIO/
# VIDEO/DOCUMENT for embedded media items — resetting those here
# dropped native voice notes back to TEXT and skipped STT
# (#38211, #38219; analysis from #38276).
if msg_type == MessageType.TEXT and any(
"image" in t for t in media_types
):
msg_type = MessageType.PHOTO
elif msg_type_str == "audio":
# Voice message — DingTalk already provides recognition text.
# Do NOT add media_urls here: if audio_paths is non-empty,

View file

@ -735,6 +735,40 @@ class TestExtractMedia:
assert urls == ["dl_voice_abc"]
assert mtypes == ["audio"]
def test_richtext_reset_does_not_clobber_voice(self):
"""A richText envelope containing a native voice item must stay
VOICE the ``msg_type_str == "richText"`` re-derivation used to
reset it to TEXT, dropping the voice note from the STT path
(#38211, #38219)."""
from plugins.platforms.dingtalk.adapter import DingTalkAdapter
from gateway.platforms.base import MessageType
msg = self._msg_with_rich_text(
[{"type": "voice", "downloadCode": "dl_voice_rt"}]
)
msg.message_type = "richText"
msg_type, urls, mtypes = DingTalkAdapter._extract_media(
DingTalkAdapter, msg
)
assert msg_type == MessageType.VOICE
assert urls == ["dl_voice_rt"]
assert mtypes == ["audio"]
def test_richtext_with_image_still_photo(self):
"""richText with only an embedded image keeps the PHOTO promotion."""
from plugins.platforms.dingtalk.adapter import DingTalkAdapter
from gateway.platforms.base import MessageType
msg = self._msg_with_rich_text(
[{"type": "picture", "downloadCode": "dl_img_rt"}]
)
msg.message_type = "richText"
msg_type, urls, mtypes = DingTalkAdapter._extract_media(
DingTalkAdapter, msg
)
assert msg_type == MessageType.PHOTO
assert urls == ["dl_img_rt"]
def test_audio_rich_text_item_stays_audio(self):
"""Generic audio uploads (e.g. an mp3 the user attached) must NOT
be auto-transcribed they stay MessageType.AUDIO."""