Transformer Pipelines

July 31, 2026 · View on GitHub

Transformers are ordered chains that rewrite an artifact at a fixed point in the voice pipeline: raw audio before STT, utterances after STT, message context before intent matching, the selected intent before dispatch, dialog text before TTS, and synthesized audio before playback.

ovos_plugin_manager.transformer_services has the canonical runner services that load, order, and chain transformer plugins. ovos-core, ovos-audio, ovos-dinkum-listener, ovos-tts-server, ovos-stt-server, hivemind-core, hivemind-audio-binary-protocol, and the HiveMind satellites all use these services, so the same plugin works unmodified in each of them.

The six chains

Runner servicePlugin base classConfig sectionRuns
AudioTransformersServiceAudioTransformeraudio_transformerson raw audio before STT
UtteranceTransformersServiceUtteranceTransformerutterance_transformerson transcripts before intent matching
MetadataTransformersServiceMetadataTransformermetadata_transformerson message context before intent matching
IntentTransformersServiceIntentTransformerintent_transformerson the selected intent before its handler
DialogTransformersServiceDialogTransformerdialog_transformerson dialog text before TTS
TTSTransformersServiceTTSTransformertts_transformerson synthesized audio before playback

Configuration

Loading is config-gated and opt-in. A plugin loads only when its name appears in the chain's config section. You can disable an entry with "active": false without removing its config.

{
  "utterance_transformers": {
    "ovos-utterance-normalizer": {},
    "ovos-utterance-corrections-plugin": {"active": true}
  },
  "dialog_transformers": {
    "ovos-dialog-transformer-openai-plugin": {"rewrite_prompt": "rewrite the text as if you were explaining it to a 5 year old"}
  },
  "tts_transformers": {
    "ovos-tts-transformer-sox-plugin": {"pitch": 300}
  }
}

Ordering

Chains run in ascending priority order (OVOS-TRANSFORM §4): a plugin with priority = 1 runs before one with priority = 50. The default is 50. A later plugin sees, and may override, an earlier plugin's output.

A deployer can bypass priorities entirely with an explicit order list. A loaded plugin that is absent from the list does not run:

{
  "utterance_transformers": {
    "order": ["plugin-that-must-run-first", "plugin-that-runs-second"]
  }
}

Cancellation

A transformer can cancel the whole lifecycle (OVOS-TRANSFORM §8.1) by returning both "canceled": true and a "cancel_reason" in its context. The runner stamps cancel_by with the emitting plugin's name and stops the chain. The consumer then ends the lifecycle (for example, ovos-core emits ovos.utterance.cancelled, then ovos.utterance.handled). Stop-word plugins such as ovos-utterance-plugin-cancel use this mechanism.

Error handling

A plugin exception never stops the chain. The runner logs the exception and the chain continues with the previous plugin's output.

Where chains run — and surprise interactions

The same chain type can run in more than one process. That is by design, but enable each plugin in exactly one place per deployment. Otherwise its effect applies twice.

SurfaceChains it can run
ovos-dinkum-listeneraudio
ovos-coreutterance, metadata, intent
ovos-audiodialog, tts
ovos-stt-serveraudio, utterance
ovos-tts-serverdialog, tts
hivemind-core (text path)utterance, metadata, dialog
hivemind-audio-binary-protocolaudio, utterance, metadata, dialog, tts
HiveMind satellites (on device)audio (pre-send), utterance (relay), tts (pre-playback)

Moving a chain to a server is a deliberate way to centralize behavior. Enable a dialog transformer on ovos-tts-server, and every device that synthesizes through it gets the same tone or persona rewrite. The server then returns audio for different text than the client sent. This looks surprising from the client, but it is the intended effect. The same applies to a shared STT server that corrects transcripts for every client, or a HiveMind server that cancels utterances by policy for the whole mesh.

Guidelines:

  • For a per-device effect (denoise for one bad microphone, a voice effect on one speaker), enable the plugin on the device or satellite.
  • For a fleet-wide effect (a global persona or tone, shared transcript corrections, policy stop-words), enable the plugin on the server everyone uses.
  • Never enable the same plugin on both sides of a connection.

Consuming the runners

from ovos_plugin_manager.transformer_services import UtteranceTransformersService

# config may be the full core configuration (the section is extracted)
# or the section mapping itself — handy for non-mycroft.conf consumers
service = UtteranceTransformersService(bus=bus, config={"my-plugin": {}})
utterances, context = service.transform(["hello world"], {"lang": "en-US"})
service.shutdown()

All runners accept an optional bus, which they bind to plugins that support it, or you can bind it later with set_bus(). Each runner exposes plugins (execution order), get_available_plugins(), transform(...), and shutdown().


← Configuration · Home · Voice Cloning →