Skip to content

fix(feishu): transcribe native voice notes - #29295

Closed
EloquentBrush0x wants to merge 2 commits into
NousResearch:mainfrom
EloquentBrush0x:fix/feishu-voice-note-stt
Closed

fix(feishu): transcribe native voice notes#29295
EloquentBrush0x wants to merge 2 commits into
NousResearch:mainfrom
EloquentBrush0x:fix/feishu-voice-note-stt

Conversation

@EloquentBrush0x

Copy link
Copy Markdown
Contributor

Problem

Feishu's audio message type is exclusively for voice notes recorded in
the Lark app — it is never used for generic audio file uploads (those
arrive as file or media message types instead).

_resolve_normalized_message_type routed preferred == "audio" through
_resolve_media_message_type, which returns MessageType.AUDIO for any
audio/* MIME type. gateway/run.py:7605 explicitly skips STT for
MessageType.AUDIO:

# MessageType.AUDIO = audio file attachment (e.g. .mp3, .m4a) — never STT
# MessageType.VOICE = voice message (Opus/OGG) — always STT
if event.message_type == MessageType.AUDIO:
    audio_file_paths.append(path)
elif event.message_type == MessageType.VOICE or ...:
    audio_paths.append(path)  # → STT

Result: every Feishu voice note was silently dropped from the
auto-transcription pipeline.

Fix

Return MessageType.VOICE directly in the preferred == "audio" branch
of _resolve_normalized_message_type. No other branch is affected:
file and media message types map to preferred == "document" and
continue to resolve via MIME type as before.

Sibling fixes

This is the same AUDIO-vs-VOICE misclassification that was fixed for:

Feishu's case is simpler: the audio message type at the API level is
already unambiguous — no secondary marker is needed.

Tests

  • test_extract_audio_message_classified_as_voice — renames the
    existing test and corrects its assertion from "audio" to "voice"
    (it was asserting the bug).
  • test_extract_audio_type_voice_invariant_regardless_of_mime — pins
    that the message-level type, not the downloaded MIME type, is
    authoritative (AMR, OGG, etc. all produce MessageType.VOICE).
  • test_extract_file_message_stays_document_not_voice — regression
    guard ensuring file type messages are unaffected.

All 156 tests/gateway/test_feishu.py tests pass (43 skipped — lark_oapi not installed). Ruff clean.

Checklist

  • Root cause identified and explained
  • Fix is minimal and scoped to the affected branch only
  • Existing test corrected (was asserting the bug)
  • Two new regression tests added
  • Full Feishu test suite: 156 passed, 0 failed
  • Ruff: no issues

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter comp/gateway Gateway runner, session dispatch, delivery duplicate This issue or pull request already exists labels May 20, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #29235 — both PRs make the identical change: return MessageType.VOICE directly in the preferred == "audio" branch of _resolve_normalized_message_type in gateway/platforms/feishu.py. Follow-up to merged #28993 (Discord + DingTalk fix).

Feishu's "audio" message type is exclusively for in-app voice
recordings, but _resolve_normalized_message_type was delegating to
_resolve_media_message_type which maps audio/* MIME types to
MessageType.AUDIO.  gateway/run.py:7605 skips STT for AUDIO, so every
voice note sent on Feishu was silently dropped instead of transcribed.

Generic audio file uploads in Feishu travel through message_type="file"
→ preferred_message_type="document", never through the "audio" branch,
so returning MessageType.VOICE here is unambiguous.

Sibling fix to PR NousResearch#28922 (DingTalk) and PR NousResearch#28918 (Discord) which
corrected the same AUDIO-vs-VOICE misclassification on those platforms.

Update the existing test to assert MessageType.VOICE and rename it to
reflect the invariant it actually guards.
@EloquentBrush0x
EloquentBrush0x force-pushed the fix/feishu-voice-note-stt branch from 94f07e9 to bf5c5c5 Compare May 21, 2026 07:19
- test_extract_audio_type_voice_invariant_regardless_of_mime: pins that
  message_type='audio' always yields MessageType.VOICE regardless of the
  downloaded MIME container (AMR, OGG, OPUS, MP4).
- test_extract_file_message_audio_mime_stays_audio_not_voice: regression
  guard confirming that message_type='file' with an audio/* MIME stays
  MessageType.AUDIO (not VOICE), so generic audio uploads are never
  silently routed through STT.
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused Feishu voice-note fix. Current main still has the reported behavior: raw Feishu audio selects the audio preference in plugins/platforms/feishu/adapter.py:870-881, then resolves to MessageType.AUDIO at plugins/platforms/feishu/adapter.py:3802-3824; gateway/run.py:10414-10458 excludes AUDIO from STT and transcribes VOICE.

Problems

  • The PR targets the removed gateway/platforms/feishu.py path. Commit 5600105478ffde29d7566b45421b100eaa29c4ef moved this adapter to plugins/platforms/feishu/adapter.py, and GitHub currently reports the PR as conflicting.

Suggested changes

  • Salvage the same one-branch resolver change and regression coverage at the current plugin path. The existing fixture at tests/gateway/test_feishu.py:1475-1494 still asserts the defective AUDIO classification for an audio message named voice.ogg.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing as stale target: this PR patches gateway/platforms/feishu.py, which was deleted when the platform adapters were rewritten as plugins — the live code now lives in plugins/platforms/*/adapter.py, so this diff can no longer apply.

Feishu native voice-note VOICE routing is being salvaged via #29235, which targets the live plugins/platforms/feishu/adapter.py (the upcoming Feishu salvage covers this PR's intent).

Thanks @EloquentBrush0x — if anything in your change isn't covered by the salvage noted above, please resubmit against the current plugin adapter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists platform/feishu Feishu / Lark adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants