openclaw - ✅(Solved) Fix [Bug] Feishu TTS auto:inbound not triggering - missing inboundAudio check in dispatch [1 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#72034Fetched 2026-04-27 05:35:51
View on GitHub
Comments
2
Participants
2
Timeline
5
Reactions
0
Author
Timeline (top)
commented ×2cross-referenced ×2closed ×1

When messages.tts.auto is set to "inbound" on Feishu channel, the system should respond with voice when receiving audio messages, but it responds with text instead. No TTS synthesis attempt is made.

Root Cause

After extensive debugging, I found the issue in dispatch-Dw_9PM8V.js:

The function maybeApplyTtsToReplyPayload only checks shouldAttemptTtsPayload (which checks ttsAuto config), but does NOT check inboundAudio for "inbound" auto mode:

async function maybeApplyTtsToReplyPayload(params) {
    if (!shouldAttemptTtsPayload({
        cfg: params.cfg,
        ttsAuto: params.ttsAuto
    })) return params.payload;
    // ❌ Missing: inboundAudio check for "inbound" mode
    const { maybeApplyTtsToPayload } = await loadTtsRuntime();
    return maybeApplyTtsToPayload(params);
}

However, in dispatch-acp-CEqX6KWn.js (ACP dispatch), there IS a correct check:

async function maybeApplyAcpTts(params) {
    const ttsStatus = resolveStatusTtsSnapshot({...});
    if (!ttsStatus) return params.payload;
    // ✅ Correct check:
    if (ttsStatus.autoMode === "inbound" && !params.inboundAudio) return params.payload;
    ...
}

The inconsistency: ACP dispatch has the inboundAudio gate, but the regular dispatch (dispatch-Dw_9PM8V.js) does not.

Fix Action

Fix / Workaround

After extensive debugging, I found the issue in dispatch-Dw_9PM8V.js:

However, in dispatch-acp-CEqX6KWn.js (ACP dispatch), there IS a correct check:

The inconsistency: ACP dispatch has the inboundAudio gate, but the regular dispatch (dispatch-Dw_9PM8V.js) does not.

PR fix notes

PR #72191: fix(auto-reply): add inboundAudio check for inbound TTS auto mode [AI-assisted]

Description (problem / solution / changelog)

Summary

Fixes #72034

The maybeApplyTtsToReplyPayload function in dispatch-from-config.ts was missing the inboundAudio gate that exists in the ACP dispatch path (dispatch-acp.ts line 215-216). This caused channels like Feishu to respond with text instead of TTS when messages.tts.auto is set to "inbound" and the user sends a voice message.

Changes

  • Added normalizeTtsAutoMode + inboundAudio check in maybeApplyTtsToReplyPayload before calling TTS runtime
  • Mirrors the existing logic in dispatch-acp.ts (!(ttsStatus.autoMode === "inbound" && !params.inboundAudio))

Testing

  • pnpm build passes
  • pnpm check:changed passes
  • pnpm test src/auto-reply/reply/dispatch-from-config.test.ts passes (83 tests)
  • pnpm test:contracts passes (30 tests)
  • Manual verification with Feishu voice message (needs real Feishu bot)

Related

  • Fixes #72034
  • Relates to #65951 (same root cause for Telegram)

AI-assisted: Code fix identified from issue report and verified against ACP dispatch reference implementation. Testing status: Fully tested locally (build + check + unit tests + contracts).

Changed files

  • src/auto-reply/reply/dispatch-from-config.ts (modified, +5/-0)

Code Example

async function maybeApplyTtsToReplyPayload(params) {
    if (!shouldAttemptTtsPayload({
        cfg: params.cfg,
        ttsAuto: params.ttsAuto
    })) return params.payload;
    // ❌ Missing: inboundAudio check for "inbound" mode
    const { maybeApplyTtsToPayload } = await loadTtsRuntime();
    return maybeApplyTtsToPayload(params);
}

---

async function maybeApplyAcpTts(params) {
    const ttsStatus = resolveStatusTtsSnapshot({...});
    if (!ttsStatus) return params.payload;
    // ✅ Correct check:
    if (ttsStatus.autoMode === "inbound" && !params.inboundAudio) return params.payload;
    ...
}

---

async function maybeApplyTtsToReplyPayload(params) {
    if (!shouldAttemptTtsPayload({
        cfg: params.cfg,
        ttsAuto: params.ttsAuto
    })) return params.payload;
    // Add inboundAudio check for "inbound" auto mode
    const ttsAuto = normalizeTtsAutoMode(params.ttsAuto);
    if (ttsAuto === "inbound" && !params.inboundAudio) return params.payload;
    const { maybeApplyTtsToPayload } = await loadTtsRuntime();
    return maybeApplyTtsToPayload(params);
}
RAW_BUFFERClick to expand / collapse

Summary

When messages.tts.auto is set to "inbound" on Feishu channel, the system should respond with voice when receiving audio messages, but it responds with text instead. No TTS synthesis attempt is made.

Environment

  • OpenClaw: 2026.4.24
  • Channel: Feishu (Lark)
  • TTS config: messages.tts.auto = "inbound", provider = "microsoft"
  • OS: Linux x64

What works

  • Feishu inbound voice messages reach the bot
  • Audio files are downloaded successfully to ~/.openclaw/media/inbound/
  • message_type is correctly identified as audio
  • MediaType is correctly set to audio/ogg; codecs=opus
  • MediaPaths contains the correct .ogg file path
  • isInboundAudioContext(ctx) returns true (verified by debugging)

What fails

  • Voice in → voice out does not happen
  • Replies arrive as plain text
  • Gateway logs show no TTS synthesis attempt for those replies
  • maybeApplyTtsToReplyPayload does not proceed to TTS synthesis

Root Cause Analysis

After extensive debugging, I found the issue in dispatch-Dw_9PM8V.js:

The function maybeApplyTtsToReplyPayload only checks shouldAttemptTtsPayload (which checks ttsAuto config), but does NOT check inboundAudio for "inbound" auto mode:

async function maybeApplyTtsToReplyPayload(params) {
    if (!shouldAttemptTtsPayload({
        cfg: params.cfg,
        ttsAuto: params.ttsAuto
    })) return params.payload;
    // ❌ Missing: inboundAudio check for "inbound" mode
    const { maybeApplyTtsToPayload } = await loadTtsRuntime();
    return maybeApplyTtsToPayload(params);
}

However, in dispatch-acp-CEqX6KWn.js (ACP dispatch), there IS a correct check:

async function maybeApplyAcpTts(params) {
    const ttsStatus = resolveStatusTtsSnapshot({...});
    if (!ttsStatus) return params.payload;
    // ✅ Correct check:
    if (ttsStatus.autoMode === "inbound" && !params.inboundAudio) return params.payload;
    ...
}

The inconsistency: ACP dispatch has the inboundAudio gate, but the regular dispatch (dispatch-Dw_9PM8V.js) does not.

Data Flow Verified

I added diagnostic logging and confirmed the complete data flow:

  1. parseMessageEventconvertMessageContent returns {content, resources} where resources contains the audio ResourceDescriptor ✅
  2. resolveMedia → downloads audio file, returns mediaList
  3. buildFeishuMediaPayload → sets MediaType, MediaPaths, MediaTypes
  4. buildInboundPayload → spreads mediaPayload into context ✅
  5. isInboundAudioContext(ctx) → correctly returns true (detects MediaType: audio/ogg and .ogg extension in MediaPaths) ✅
  6. inboundAudio is passed to maybeApplyTtsToReplyPayload
  7. maybeApplyTtsToReplyPayloaddoes not check inboundAudio, proceeds to loadTtsRuntime() but the condition fails somewhere else, no TTS synthesis ❌

Suggested Fix

Add inboundAudio check to maybeApplyTtsToReplyPayload in dispatch-Dw_9PM8V.js:

async function maybeApplyTtsToReplyPayload(params) {
    if (!shouldAttemptTtsPayload({
        cfg: params.cfg,
        ttsAuto: params.ttsAuto
    })) return params.payload;
    // Add inboundAudio check for "inbound" auto mode
    const ttsAuto = normalizeTtsAutoMode(params.ttsAuto);
    if (ttsAuto === "inbound" && !params.inboundAudio) return params.payload;
    const { maybeApplyTtsToPayload } = await loadTtsRuntime();
    return maybeApplyTtsToPayload(params);
}

Related Issues

  • #65951 - Similar issue for Telegram channel (same root cause)
  • #9722 - TTS MEDIA: directive not processed when model differs from default

Why this matters

The documented / expected behaviour for messages.tts.auto = "inbound" is voice in → voice out.

Currently, Feishu voice messages become:

  • voice in
  • transcript in agent context
  • text out only

with no TTS attempt.

extent analysis

TL;DR

Add an inboundAudio check to the maybeApplyTtsToReplyPayload function in dispatch-Dw_9PM8V.js to fix the issue with voice messages not being synthesized to voice replies.

Guidance

  • Verify that the inboundAudio parameter is being passed correctly to the maybeApplyTtsToReplyPayload function.
  • Check the ttsAuto configuration to ensure it is set to "inbound" for the Feishu channel.
  • Review the maybeApplyTtsToReplyPayload function to ensure the inboundAudio check is correctly implemented.
  • Test the fix by sending a voice message to the Feishu channel and verifying that a voice reply is received.

Example

The suggested fix involves adding the following code to the maybeApplyTtsToReplyPayload function:

const ttsAuto = normalizeTtsAutoMode(params.ttsAuto);
if (ttsAuto === "inbound" && !params.inboundAudio) return params.payload;

This code checks if the ttsAuto mode is set to "inbound" and if the inboundAudio parameter is false, in which case it returns the original payload without attempting TTS synthesis.

Notes

This fix assumes that the inboundAudio parameter is being passed correctly to the maybeApplyTtsToReplyPayload function. If this is not the case, additional debugging may be required to identify the issue.

Recommendation

Apply the suggested fix by adding the inboundAudio check to the maybeApplyTtsToReplyPayload function. This should resolve the issue with voice messages not being synthesized to voice replies on the Feishu channel.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug] Feishu TTS auto:inbound not triggering - missing inboundAudio check in dispatch [1 pull requests, 2 comments, 2 participants]