Skip to main content
Speak the agent’s plain-text reply back as a native voice note β€” the outbound counterpart to inbound speech-to-text, off by default and opt-in per channel.
One YAML line closes the voice loop β€” the bot listens and speaks.
Voice reply mirrors inbound Voice Notes (Speech-to-Text), but it is off by default. Set voice.mode: match_inbound for the intuitive β€œspeak in / speak out” symmetry.

Quick Start

1

Level 1 β€” Bool shorthand

voice: true turns replies into voice notes for every message (mode: always).
2

Level 2 β€” Mode shorthand

A bare mode implies enabled: true. Use match_inbound to speak back only when the user sent a voice memo.
3

Level 3 β€” Dict

Tune the voice, model, speed, format, and length cap.
4

Level 4 β€” TtsConfigSchema

Build the channel config in Python with the validated schema.
The tts: block is an accepted alias for voice: anywhere. voice: true is shorthand for {enabled: true, mode: always}.

How It Works

The gateway synthesises the reply after the text is already sent, so voice is always a bonus β€” never a blocker.

Graceful degradation

Voice reply is best-effort β€” the text reply is always delivered first.
  • Empty / whitespace text β†’ skipped silently.
  • Reply longer than max_chars β†’ skipped, INFO log entry.
  • TTS tool import fails (missing openai/litellm deps) β†’ skipped, WARNING log entry.
  • Synthesis error β†’ skipped, ERROR log entry.
  • Adapter send_voice fails β†’ logged; the text reply already went out.

Configuration Options

Fields from TtsConfig / TtsConfigSchema.

Bool shorthand

Resolution order

The effective policy is resolved from, in order:
  1. config.metadata["voice"] (operator override),
  2. config.metadata["tts"] (alias),
  3. a direct config.voice attribute (schema-backed configs),
  4. a direct config.tts attribute, then
  5. the off-by-default TtsConfig().

Choosing a Mode

Pick the mode that matches how chatty your users want the bot to be.
mode: match-inbound (hyphen) normalises to match_inbound automatically.

Per-Platform YAML

Telegram is wired today; other adapters share the same _tts helper and can adopt it without further core changes.

Platform Support

The [[audio_as_voice]] manual escape hatch continues to work for pre-rendered audio on Telegram.

User Interaction Flow

A voice-in / voice-out conversation on Telegram with mode: match_inbound.
  1. The user taps πŸŽ™οΈ and records a voice note on Telegram.
  2. Inbound STT transcribes it β†’ the agent processes the text β†’ produces a plain-text reply.
  3. The gateway sees voice.mode: match_inbound and that the inbound was a voice memo β†’ synthesises the reply with openai/tts-1.
  4. The user receives both: the text reply and a native voice note they can play right in the chat.
  5. If the user next sends a text message, they get only a text reply β€” no unnecessary audio.

Best Practices

match_inbound speaks back only when the user spoke first β€” the symmetry users expect. Reserve always for voice-first or accessibility bots.
Set max_chars low so long analytical replies don’t become multi-minute audio clips. The text reply still carries the full answer.
openai/tts-1 is the default, so set OPENAI_API_KEY. Any LiteLLM-supported TTS model works via the model: field.
Voice reply is best-effort β€” the plain-text reply is always delivered first, so users never lose a message even when synthesis fails.
The [[audio_as_voice]] marker still works on Telegram for audio you’ve already produced β€” e.g. a recording pulled from a knowledge base.

Voice Notes (Speech-to-Text)

The inbound counterpart β€” transcribe voice notes into text for the agent.

Audio Tools

tts_tool, stt_tool, and AudioAgent.speech.

Voice Notes

The inbound voice-notes doc for gateway bots.

Gateway

The overall gateway pattern β€” voice reply is one of several channel features.