Summary
Issue 1: Feishu voice bubble — MP3/WAV files sent as file attachment instead of voice bubble
Description
When OpenClaw sends TTS-generated MP3 files to Feishu, they are delivered as file attachments instead of voice bubbles (audio messages). Feishu requires Opus format (audio msg_type) to render voice bubbles natively.
Current Behavior
- TTS provider (Microsoft Edge TTS) generates an MP3 file
sendMediaFeishu() in the Feishu extension detects the file extension
.mp3 is not in the Opus/OGG match list, so it falls through to fileType: "stream" → msgType: "file"
- Feishu displays it as a downloadable file, not a playable voice bubble
Expected Behavior
MP3 and WAV files sent through the Feishu channel should be automatically converted to Opus (using ffmpeg) and sent as msgType: "audio", so they render as native voice bubbles in the Feishu client.
Suggested Implementation
In extensions/feishu/src/media.ts (or the compiled equivalent), before resolveFeishuOutboundMediaKind() is called in sendMediaFeishu():
- Detect audio format from buffer magic bytes (MP3:
ID3 header or 0xFF 0xE0 frame sync; WAV: RIFF header)
- If the file is MP3 or WAV, convert to Opus via ffmpeg:
ffmpeg -y -i input.mp3 -ac 1 -b:a 32k -application voip output.opus
- Update the filename to
.opus and contentType to audio/opus
- Then
resolveFeishuOutboundMediaKind() will correctly route it as msgType: "audio"
Minimal code sketch
// In sendMediaFeishu(), after buffer is loaded, before routing:
const ext = path.extname(name).toLowerCase();
const audioFormat = detectAudioFormat(buffer); // check magic bytes
if (['.wav', '.mp3'].includes(ext) && audioFormat !== 'unknown') {
buffer = await convertToOpus(buffer, audioFormat); // ffmpeg conversion
name = path.basename(name, ext) + '.opus';
contentType = 'audio/opus';
}
Environment
- OpenClaw: v2026.3.24
- Channel: Feishu
- TTS Provider: Microsoft Edge TTS (outputs MP3)
- OS: Linux (Debian 13, ffmpeg 7.1.3 available)
Workaround
Currently patching the compiled send-*.js file manually to add ffmpeg conversion. This patch breaks on every OpenClaw update.
Issue 2: Per-agent TTS voice override for Microsoft Edge TTS
Description
In a multi-agent setup, different agents should be able to use different TTS voices to be distinguishable. Currently, [[tts:...]] directives only support OpenAI and ElevenLabs voice overrides — Microsoft Edge TTS voice cannot be overridden per-agent or per-message.
Current Behavior
- Global TTS config sets
messages.tts.microsoft.voice: "zh-TW-HsiaoChenNeural"
- Agent "fanqie" (番茄) tries to use a different voice via
[[tts:zh-CN-XiaoxiaoNeural]]
parseTtsDirectives() parses [[tts:key=value]] format only — bare voice names without = are skipped (if (eqIndex === -1) continue;)
- Even with correct
key=value format, only voice (OpenAI) and voiceId (ElevenLabs) keys are recognized — there is no microsoft_voice key
- Result: all agents use the same Microsoft TTS voice, making them indistinguishable
Expected Behavior
Option A: Per-agent TTS config (preferred)
Allow agents.list[] entries to include TTS overrides:
{
agents: {
list: [
{
id: "main",
tts: { microsoft: { voice: "zh-TW-HsiaoChenNeural" } }
},
{
id: "fanqie",
tts: { microsoft: { voice: "zh-CN-XiaoxiaoNeural" } }
}
]
}
}
Option B: [[tts:...]] directive support for Microsoft voice
Add a microsoft_voice (or just extend voice to be provider-aware) key to parseTtsDirectives():
[[tts:microsoft_voice=zh-CN-XiaoxiaoNeural]]
This would allow agents to override the Microsoft voice inline, same as OpenAI/ElevenLabs voices today.
Option C: Both
Per-agent config as the default, with [[tts:...]] as a per-message override.
Additional Context
Use Case
Multi-agent team where each agent has a distinct persona:
- 小师妹 (main):
zh-TW-HsiaoChenNeural — sweet Taiwanese accent
- 番茄 (fanqie):
zh-CN-XiaoxiaoNeural — warm news-anchor voice
Cron delivery TTS gap
Related issue: when a cron job uses --announce delivery to a Feishu group, [[tts:...]] tags in the agent's response are not parsed — they appear as literal text in the message. The TTS post-processing pipeline seems to be skipped for cron announce delivery.
This means even if [[tts:...]] supported Microsoft voices, cron-delivered messages to Feishu groups would still not get voice output. The per-agent config approach (Option A) would solve this more cleanly since it doesn't depend on inline tags.
Environment
- OpenClaw: v2026.3.24
- TTS Provider: Microsoft Edge TTS
- Multi-agent setup with Feishu channel
- Agents: main (Claude Opus 4.6) + fanqie (GLM-5-Turbo)
Summary
| Gap |
Impact |
Suggested Fix |
No microsoft_voice in parseTtsDirectives() |
Can't override Microsoft TTS voice per-message |
Add microsoft_voice key |
No per-agent TTS config in agents.list[] |
All agents sound the same |
Add tts field to agent config |
| Cron announce skips TTS tag parsing |
[[tts:...]] appears as literal text in group |
Process TTS tags in announce delivery pipeline |
Problem to solve
Issue 1: Feishu voice bubble — MP3/WAV sent as file instead of voice bubble
Issue 2: Per-agent TTS voice override for Microsoft Edge TTS
Proposed solution
Issue 1: Feishu voice bubble — MP3/WAV files sent as file attachment instead of voice bubble
Description
When OpenClaw sends TTS-generated MP3 files to Feishu, they are delivered as file attachments instead of voice bubbles (audio messages). Feishu requires Opus format (audio msg_type) to render voice bubbles natively.
Current Behavior
- TTS provider (Microsoft Edge TTS) generates an MP3 file
sendMediaFeishu() in the Feishu extension detects the file extension
.mp3 is not in the Opus/OGG match list, so it falls through to fileType: "stream" → msgType: "file"
- Feishu displays it as a downloadable file, not a playable voice bubble
Expected Behavior
MP3 and WAV files sent through the Feishu channel should be automatically converted to Opus (using ffmpeg) and sent as msgType: "audio", so they render as native voice bubbles in the Feishu client.
Suggested Implementation
In extensions/feishu/src/media.ts (or the compiled equivalent), before resolveFeishuOutboundMediaKind() is called in sendMediaFeishu():
- Detect audio format from buffer magic bytes (MP3:
ID3 header or 0xFF 0xE0 frame sync; WAV: RIFF header)
- If the file is MP3 or WAV, convert to Opus via ffmpeg:
ffmpeg -y -i input.mp3 -ac 1 -b:a 32k -application voip output.opus
- Update the filename to
.opus and contentType to audio/opus
- Then
resolveFeishuOutboundMediaKind() will correctly route it as msgType: "audio"
Minimal code sketch
// In sendMediaFeishu(), after buffer is loaded, before routing:
const ext = path.extname(name).toLowerCase();
const audioFormat = detectAudioFormat(buffer); // check magic bytes
if (['.wav', '.mp3'].includes(ext) && audioFormat !== 'unknown') {
buffer = await convertToOpus(buffer, audioFormat); // ffmpeg conversion
name = path.basename(name, ext) + '.opus';
contentType = 'audio/opus';
}
Environment
- OpenClaw: v2026.3.24
- Channel: Feishu
- TTS Provider: Microsoft Edge TTS (outputs MP3)
- OS: Linux (Debian 13, ffmpeg 7.1.3 available)
Workaround
Currently patching the compiled send-*.js file manually to add ffmpeg conversion. This patch breaks on every OpenClaw update.
Issue 2: Per-agent TTS voice override for Microsoft Edge TTS
Description
In a multi-agent setup, different agents should be able to use different TTS voices to be distinguishable. Currently, [[tts:...]] directives only support OpenAI and ElevenLabs voice overrides — Microsoft Edge TTS voice cannot be overridden per-agent or per-message.
Current Behavior
- Global TTS config sets
messages.tts.microsoft.voice: "zh-TW-HsiaoChenNeural"
- Agent "fanqie" (番茄) tries to use a different voice via
[[tts:zh-CN-XiaoxiaoNeural]]
parseTtsDirectives() parses [[tts:key=value]] format only — bare voice names without = are skipped (if (eqIndex === -1) continue;)
- Even with correct
key=value format, only voice (OpenAI) and voiceId (ElevenLabs) keys are recognized — there is no microsoft_voice key
- Result: all agents use the same Microsoft TTS voice, making them indistinguishable
Expected Behavior
Option A: Per-agent TTS config (preferred)
Allow agents.list[] entries to include TTS overrides:
{
agents: {
list: [
{
id: "main",
tts: { microsoft: { voice: "zh-TW-HsiaoChenNeural" } }
},
{
id: "fanqie",
tts: { microsoft: { voice: "zh-CN-XiaoxiaoNeural" } }
}
]
}
}
Option B: [[tts:...]] directive support for Microsoft voice
Add a microsoft_voice (or just extend voice to be provider-aware) key to parseTtsDirectives():
[[tts:microsoft_voice=zh-CN-XiaoxiaoNeural]]
This would allow agents to override the Microsoft voice inline, same as OpenAI/ElevenLabs voices today.
Option C: Both
Per-agent config as the default, with [[tts:...]] as a per-message override.
Additional Context
Use Case
Multi-agent team where each agent has a distinct persona:
- 小师妹 (main):
zh-TW-HsiaoChenNeural — sweet Taiwanese accent
- 番茄 (fanqie):
zh-CN-XiaoxiaoNeural — warm news-anchor voice
Cron delivery TTS gap
Related issue: when a cron job uses --announce delivery to a Feishu group, [[tts:...]] tags in the agent's response are not parsed — they appear as literal text in the message. The TTS post-processing pipeline seems to be skipped for cron announce delivery.
This means even if [[tts:...]] supported Microsoft voices, cron-delivered messages to Feishu groups would still not get voice output. The per-agent config approach (Option A) would solve this more cleanly since it doesn't depend on inline tags.
Environment
- OpenClaw: v2026.3.24
- TTS Provider: Microsoft Edge TTS
- Multi-agent setup with Feishu channel
- Agents: main (Claude Opus 4.6) + fanqie (GLM-5-Turbo)
Summary
| Gap |
Impact |
Suggested Fix |
No microsoft_voice in parseTtsDirectives() |
Can't override Microsoft TTS voice per-message |
Add microsoft_voice key |
No per-agent TTS config in agents.list[] |
All agents sound the same |
Add tts field to agent config |
| Cron announce skips TTS tag parsing |
[[tts:...]] appears as literal text in group |
Process TTS tags in announce delivery pipeline |
Alternatives considered
No response
Impact
Feishu voice bubble — MP3/WAV sent as file instead of voice bubble
Per-agent TTS voice override for Microsoft Edge TTS
Evidence/examples
No response
Additional information
No response
Summary
Issue 1: Feishu voice bubble — MP3/WAV files sent as file attachment instead of voice bubble
Description
When OpenClaw sends TTS-generated MP3 files to Feishu, they are delivered as file attachments instead of voice bubbles (audio messages). Feishu requires Opus format (
audiomsg_type) to render voice bubbles natively.Current Behavior
sendMediaFeishu()in the Feishu extension detects the file extension.mp3is not in the Opus/OGG match list, so it falls through tofileType: "stream"→msgType: "file"Expected Behavior
MP3 and WAV files sent through the Feishu channel should be automatically converted to Opus (using ffmpeg) and sent as
msgType: "audio", so they render as native voice bubbles in the Feishu client.Suggested Implementation
In
extensions/feishu/src/media.ts(or the compiled equivalent), beforeresolveFeishuOutboundMediaKind()is called insendMediaFeishu():ID3header or0xFF 0xE0frame sync; WAV:RIFFheader).opusand contentType toaudio/opusresolveFeishuOutboundMediaKind()will correctly route it asmsgType: "audio"Minimal code sketch
Environment
Workaround
Currently patching the compiled
send-*.jsfile manually to add ffmpeg conversion. This patch breaks on every OpenClaw update.Issue 2: Per-agent TTS voice override for Microsoft Edge TTS
Description
In a multi-agent setup, different agents should be able to use different TTS voices to be distinguishable. Currently,
[[tts:...]]directives only support OpenAI and ElevenLabs voice overrides — Microsoft Edge TTS voice cannot be overridden per-agent or per-message.Current Behavior
messages.tts.microsoft.voice: "zh-TW-HsiaoChenNeural"[[tts:zh-CN-XiaoxiaoNeural]]parseTtsDirectives()parses[[tts:key=value]]format only — bare voice names without=are skipped (if (eqIndex === -1) continue;)key=valueformat, onlyvoice(OpenAI) andvoiceId(ElevenLabs) keys are recognized — there is nomicrosoft_voicekeyExpected Behavior
Option A: Per-agent TTS config (preferred)
Allow
agents.list[]entries to include TTS overrides:Option B:
[[tts:...]]directive support for Microsoft voiceAdd a
microsoft_voice(or just extendvoiceto be provider-aware) key toparseTtsDirectives():This would allow agents to override the Microsoft voice inline, same as OpenAI/ElevenLabs voices today.
Option C: Both
Per-agent config as the default, with
[[tts:...]]as a per-message override.Additional Context
Use Case
Multi-agent team where each agent has a distinct persona:
zh-TW-HsiaoChenNeural— sweet Taiwanese accentzh-CN-XiaoxiaoNeural— warm news-anchor voiceCron delivery TTS gap
Related issue: when a cron job uses
--announcedelivery to a Feishu group,[[tts:...]]tags in the agent's response are not parsed — they appear as literal text in the message. The TTS post-processing pipeline seems to be skipped for cron announce delivery.This means even if
[[tts:...]]supported Microsoft voices, cron-delivered messages to Feishu groups would still not get voice output. The per-agent config approach (Option A) would solve this more cleanly since it doesn't depend on inline tags.Environment
Summary
microsoft_voiceinparseTtsDirectives()microsoft_voicekeyagents.list[]ttsfield to agent config[[tts:...]]appears as literal text in groupProblem to solve
Issue 1: Feishu voice bubble — MP3/WAV sent as file instead of voice bubble
Issue 2: Per-agent TTS voice override for Microsoft Edge TTS
Proposed solution
Issue 1: Feishu voice bubble — MP3/WAV files sent as file attachment instead of voice bubble
Description
When OpenClaw sends TTS-generated MP3 files to Feishu, they are delivered as file attachments instead of voice bubbles (audio messages). Feishu requires Opus format (
audiomsg_type) to render voice bubbles natively.Current Behavior
sendMediaFeishu()in the Feishu extension detects the file extension.mp3is not in the Opus/OGG match list, so it falls through tofileType: "stream"→msgType: "file"Expected Behavior
MP3 and WAV files sent through the Feishu channel should be automatically converted to Opus (using ffmpeg) and sent as
msgType: "audio", so they render as native voice bubbles in the Feishu client.Suggested Implementation
In
extensions/feishu/src/media.ts(or the compiled equivalent), beforeresolveFeishuOutboundMediaKind()is called insendMediaFeishu():ID3header or0xFF 0xE0frame sync; WAV:RIFFheader).opusand contentType toaudio/opusresolveFeishuOutboundMediaKind()will correctly route it asmsgType: "audio"Minimal code sketch
Environment
Workaround
Currently patching the compiled
send-*.jsfile manually to add ffmpeg conversion. This patch breaks on every OpenClaw update.Issue 2: Per-agent TTS voice override for Microsoft Edge TTS
Description
In a multi-agent setup, different agents should be able to use different TTS voices to be distinguishable. Currently,
[[tts:...]]directives only support OpenAI and ElevenLabs voice overrides — Microsoft Edge TTS voice cannot be overridden per-agent or per-message.Current Behavior
messages.tts.microsoft.voice: "zh-TW-HsiaoChenNeural"[[tts:zh-CN-XiaoxiaoNeural]]parseTtsDirectives()parses[[tts:key=value]]format only — bare voice names without=are skipped (if (eqIndex === -1) continue;)key=valueformat, onlyvoice(OpenAI) andvoiceId(ElevenLabs) keys are recognized — there is nomicrosoft_voicekeyExpected Behavior
Option A: Per-agent TTS config (preferred)
Allow
agents.list[]entries to include TTS overrides:Option B:
[[tts:...]]directive support for Microsoft voiceAdd a
microsoft_voice(or just extendvoiceto be provider-aware) key toparseTtsDirectives():This would allow agents to override the Microsoft voice inline, same as OpenAI/ElevenLabs voices today.
Option C: Both
Per-agent config as the default, with
[[tts:...]]as a per-message override.Additional Context
Use Case
Multi-agent team where each agent has a distinct persona:
zh-TW-HsiaoChenNeural— sweet Taiwanese accentzh-CN-XiaoxiaoNeural— warm news-anchor voiceCron delivery TTS gap
Related issue: when a cron job uses
--announcedelivery to a Feishu group,[[tts:...]]tags in the agent's response are not parsed — they appear as literal text in the message. The TTS post-processing pipeline seems to be skipped for cron announce delivery.This means even if
[[tts:...]]supported Microsoft voices, cron-delivered messages to Feishu groups would still not get voice output. The per-agent config approach (Option A) would solve this more cleanly since it doesn't depend on inline tags.Environment
Summary
microsoft_voiceinparseTtsDirectives()microsoft_voicekeyagents.list[]ttsfield to agent config[[tts:...]]appears as literal text in groupAlternatives considered
No response
Impact
Feishu voice bubble — MP3/WAV sent as file instead of voice bubble
Per-agent TTS voice override for Microsoft Edge TTS
Evidence/examples
No response
Additional information
No response