Skip to main content
Custom Text-to-Speech lets you connect Rapida to a WebSocket speech synthesis service that is not available as a built-in provider. You configure the provider URL, handshake headers, audio settings, and a small JSON DSL that maps assistant text packets to your provider’s WebSocket protocol. Use Custom TTS when your provider can receive text over WebSocket and return audio as binary frames or base64 audio in JSON frames. Provider identifier: custom-tts
Custom TTS is an end-user configuration feature. You do not need to write a new Rapida transformer when your provider can be described with the WebSocket DSL below.

Setup flow

1

Create the Custom TTS credential

Open Credentials or Integrations > Models, choose Custom TTS, and create a credential with your WebSocket connection details.
2

Select Custom TTS in Voice Output

Open your assistant deployment, go to Voice Output, and select Custom TTS as the text-to-speech provider.
3

Set audio and DSL arguments

Configure audio encoding, sample rate, query parameters, request rules, and response rules so Rapida can send text and interpret provider audio correctly.
4

Write WebSocket DSL rules

Define query parameters, request rules, and response rules so Rapida knows how to send text and receive audio.
5

Test interruption behavior

Run a test conversation and interrupt the assistant while it is speaking. Add an interrupt rule if your provider requires explicit cancellation.

Credential fields

The runtime also accepts snake case keys: api_compatibility and base_url.
Headers are copied from the credential as static values. The DSL cannot template headers or change the WebSocket path dynamically.

TTS arguments

DSL sections

Custom TTS has three DSL sections: The DSL is intentionally small. It does not run JavaScript, call functions, read environment variables, use regex, concatenate strings, or perform compound conditions.

Query parameters

Use speak.ws.query_params when your provider expects configuration in the WebSocket URL. Supported variables:
Rules:
  • Query params must be a flat JSON object.
  • Values must resolve to a primitive: string, number, boolean, or null.
  • Existing query params in baseUrl are preserved unless the rendered DSL uses the same key.
  • text is not a supported query parameter variable. Use packet.text in request rules instead.
The Custom TTS UI exposes audio and DSL fields. If your provider needs a voice, model, or language, set those as static values in request rules or provide the optional metadata keys through API-driven configuration.

Request rules

Request rules are evaluated for normalized TTS packets produced by Rapida. Supported outbound frames:

One-shot synthesis

Use this when the provider synthesizes each text packet immediately.

Text, done, and interrupt

Use this when the provider expects text payloads, an explicit final message, and an explicit cancel message.
Add an interrupt rule if your provider needs an explicit cancel or clear message. Without it, queued provider audio can continue after the user starts speaking.

Response rules

Response rules parse provider WebSocket frames into Rapida audio packets. The first matching rule is evaluated and later rules are skipped for that frame. Supported inbound frames: Supported emit keys:

Binary audio response

Use this when the provider streams raw audio as binary WebSocket frames.

JSON base64 audio response

Use $decode when the provider returns base64-encoded audio inside JSON.

Operators

Every operator object must contain only that operator and its required fields. Unsupported for Custom TTS:
  • Text response frames
  • $frame: "text"
  • $frame: "json"
  • Decode formats other than base64

Cast behavior

Path behavior

$path uses dot-separated paths.
Objects are traversed by key. Arrays are traversed by numeric index.
Limits:
  • Keys containing a literal dot are not addressable.
  • Request rules can only read from config and packet.
  • Response rules can use $path only with JSON response frames.
  • A missing path in when.path means the rule does not match.
  • A missing path in emit or send.body is an error.

Runtime behavior

  • The connection URL is built from baseUrl and speak.ws.query_params.
  • A connection is opened per active message or context. A new context closes the previous connection.
  • text packets open the WebSocket connection if needed.
  • done and interrupt rules are optional. If no rule exists for that packet, nothing is sent.
  • On interruption, Rapida sends the optional interrupt rule first, then closes the connection.
  • Audio returned by the provider is interpreted as speak.audio.encoding and speak.audio.sample_rate, then resampled internally when needed.
  • If no response rule matches an inbound frame, the frame is ignored.
  • If a response emits error, Rapida emits a TTS error packet.
  • If a response emits done, Rapida closes the connection and emits a TTS end packet.

Current limits

  • No regex, contains, starts-with, greater-than, or compound match conditions.
  • No string interpolation or concatenation.
  • No fallback values inside expressions.
  • No dynamic headers or dynamic URL path segments.
  • No text response handling for TTS.
  • No $frame: "json" selector in emit rules.
  • $decode supports only base64.

Troubleshooting

Text-to-Speech

Configure standard TTS providers and speech delivery.

Custom STT

Configure a custom WebSocket STT provider.

Speak

See how TTS fits into spoken output configuration.

Open-source runtime reference

Review the assistant-api implementation reference.