Bug Description
When messages.tts.auto is set to "inbound", the model's tts tool call generates audio successfully, but the MEDIA: directive in the reply is not processed as an audio attachment. This creates a conflict where:
- Auto-TTS is skipped because it detects the
MEDIA: directive in the reply
- The
MEDIA: directive itself is not processed into an audio attachment
Result: No audio is sent to the user. The MEDIA: path appears as plain text.
Environment
- OpenClaw version: 2026.2.3-1
- Channel: Telegram (
streamMode: "partial")
- TTS config:
auto: "inbound", provider: "edge"
- Default model:
minimax-cn/MiniMax-M2.1 (OpenAI Completions API)
- Test model:
anthropic/claude-opus-4-5 (Anthropic Messages API) — switched via /model
- OS: macOS (Apple Silicon)
Steps to Reproduce
- Configure
messages.tts.auto: "inbound" with Edge TTS provider
- Set default model to a non-Anthropic provider (e.g., MiniMax via OpenAI Completions API)
- Switch active model to
anthropic/claude-opus-4-5 via /model opus
- Send a voice message from Telegram
- Model calls
tts tool → gets MEDIA:/path/to/voice.mp3
- Model includes
MEDIA: line in reply
Expected: Audio sent as voice note attachment
Actual: MEDIA: path appears as plain text, no audio played
Systematic Test Results
All tests performed under anthropic/claude-opus-4-5 (switched from default MiniMax):
| # |
Method |
Result |
| 1 |
Pure MEDIA: line (no other text) |
❌ No audio |
| 2 |
Short text + MEDIA: line at end |
❌ No audio |
| 3 |
Long text + markdown + MEDIA: line |
❌ No audio |
| 4 |
[[tts:text]] tag |
❌ No audio |
| 5 |
message tool with asVoice: true + filePath |
✅ Audio plays |
Root Cause Analysis
The TTS docs state:
"When enabled, OpenClaw: skips TTS if the reply already contains media or a MEDIA: directive."
This creates a deadlock when the model uses the tts tool:
User sends voice → auto: "inbound" triggers
→ Model calls tts tool → reply contains MEDIA: line
→ Auto-TTS detects MEDIA: → skips auto conversion
→ MEDIA: directive itself is NOT processed as attachment
→ No audio delivered
The design conflict: the system prompt instructs the model to call the tts tool when the user sends voice, but doing so blocks auto-TTS while the MEDIA: directive fails to deliver audio on its own.
Additional Observations
- In previous sessions, MiniMax (OpenAI Completions API) occasionally succeeded with
MEDIA: lines
- Gemini Flash (Google API) also succeeded in one instance
- Anthropic API (Opus) failed consistently across all
MEDIA: delivery methods
- The
message tool with filePath + asVoice: true works 100% as a workaround
Suggested Fix
Consider one or more of:
- Process
MEDIA: directives reliably regardless of model API type
- Auto-send audio when the
tts tool is called successfully, instead of relying on the model to place the MEDIA: line correctly
- Clarify the intended flow — if
auto: "inbound" handles TTS at the system level, the system prompt should not instruct the model to also call the tts tool (as this blocks auto-TTS)
Workaround
Use the message tool to send the TTS-generated audio directly:
1. Call tts tool → get MEDIA: path
2. Use message tool: action=send, filePath=<path>, asVoice=true
This bypasses both the MEDIA: directive and auto-TTS mechanisms entirely.
Bug Description
When
messages.tts.autois set to"inbound", the model'sttstool call generates audio successfully, but theMEDIA:directive in the reply is not processed as an audio attachment. This creates a conflict where:MEDIA:directive in the replyMEDIA:directive itself is not processed into an audio attachmentResult: No audio is sent to the user. The
MEDIA:path appears as plain text.Environment
streamMode: "partial")auto: "inbound",provider: "edge"minimax-cn/MiniMax-M2.1(OpenAI Completions API)anthropic/claude-opus-4-5(Anthropic Messages API) — switched via/modelSteps to Reproduce
messages.tts.auto: "inbound"with Edge TTS provideranthropic/claude-opus-4-5via/model opusttstool → getsMEDIA:/path/to/voice.mp3MEDIA:line in replyExpected: Audio sent as voice note attachment
Actual:
MEDIA:path appears as plain text, no audio playedSystematic Test Results
All tests performed under
anthropic/claude-opus-4-5(switched from default MiniMax):MEDIA:line (no other text)MEDIA:line at endMEDIA:line[[tts:text]]tagmessagetool withasVoice: true+filePathRoot Cause Analysis
The TTS docs state:
This creates a deadlock when the model uses the
ttstool:The design conflict: the system prompt instructs the model to call the
ttstool when the user sends voice, but doing so blocks auto-TTS while theMEDIA:directive fails to deliver audio on its own.Additional Observations
MEDIA:linesMEDIA:delivery methodsmessagetool withfilePath+asVoice: trueworks 100% as a workaroundSuggested Fix
Consider one or more of:
MEDIA:directives reliably regardless of model API typettstool is called successfully, instead of relying on the model to place theMEDIA:line correctlyauto: "inbound"handles TTS at the system level, the system prompt should not instruct the model to also call thettstool (as this blocks auto-TTS)Workaround
Use the
messagetool to send the TTS-generated audio directly:This bypasses both the
MEDIA:directive and auto-TTS mechanisms entirely.