Part 5

STT: core

The speech-to-text layer turns the caller's audio into the text the router and LLM act on. Six settings live here, but on-prem collapses most of the choices: one factory, create_stt_service() in base_service.py, reads the dashboard STT config, branches on the provider, and on the on-prem path forces Freya STT plus Language.TR no matter what the dashboard says.

Validator mismatch — read this first The config validator defaults language to multi, but the base config ships en. A freshly created STT config therefore disagrees with itself until the user explicitly picks a provider and language. If a config "looks fine" but transcribes the wrong language, suspect this default-vs-base drift before anything else.
Step 22

STT provider live

What it is. Which STT vendor transcribes the call: Deepgram (cloud default), Freya STT (self-hosted), OpenAI (Whisper), or a custom OpenAI-compatible endpoint. This single choice decides which branch of the factory runs and which downstream settings (language, temperature, prompt, base url) even apply.

sttConfig.provider enum Deepgram | Freya | OpenAI | Custom default Deepgram / on-prem Freya

Runtime. create_stt_service() at base_service.py:598 branches on the provider string: Freya base_service.py:637, Deepgram base_service.py:668, OpenAI base_service.py:696, custom base_service.py:712.

Symptom it fixes: calls transcribe in the wrong language, or hit a cloud vendor on an air-gapped box, because the provider was left on Deepgram/OpenAI when the deployment is on-prem.

Step 23

STT model live

What it is. The model identifier within the chosen provider, e.g. nova-3 for Deepgram or freya-stt for Freya. The factory hands this string straight to the provider SDK constructor.

sttConfig.model string|null, max 100 default nova-3 / on-prem freya-stt

Runtime. Passed as model= into the provider SDK constructor at base_service.py:653,671,699. The dashboard seeds the default additionalSettings object at defaults.ts:160.

Symptom it fixes: SDK constructor errors or unexpectedly poor accuracy from a model id the selected provider does not serve.

Default sttConfig.additionalSettings object (defaults.ts:160) The dashboard seeds STT config with { keyterms: 'Freya', aicEnabled: false, deepFilterEnabled: false, webrtcApmEnabled: false, punctuate: true, diarize: false } — the three filters are false, punctuate is true, diarize is false, and keyterms seeds the single term 'Freya'. The filter and keyterm settings are covered in Part 6 (audio filters) and Part 8 (keyterms); they appear here only so you know what a fresh STT config starts with.
Step 24

STT language on-prem forced

What it is. The language the recognizer expects. Deepgram and OpenAI accept a code or multi. Freya STT is single-language only, and on-prem mode forces Language.TR regardless of dashboard config.

sttConfig.language code or multi validator multi / base en (mismatch)

Runtime. Read at base_service.py:602. The Freya / on-prem branch sets language=Language.TR at base_service.py:645 and again at base_service.py:655, regardless of dashboard config. The dashboard UI hides the language selector and disallows multi-language for Freya STT at stt-config-panel.tsx:415-417 and stt-config-panel.tsx:655.

Symptom it fixes: "it transcribes my Turkish as garbled English" on a multilingual provider — on Freya it can't happen, because lines 645 and 655 pin it to Language.TR.

The big on-prem constraint On-prem deployments force Freya STT and Language.TR regardless of what the dashboard shows. The dashboard UI itself hides the language selector and disallows multi-language for Freya STT (stt-config-panel.tsx:415-417,655), and the agent enforces the same at runtime (base_service.py:645,655). Do not waste time changing provider or language in the dashboard for an on-prem call; the override wins.
Step 25

Temperature live

What it is. Sampling temperature for the STT decoder (OpenAI/Whisper-style). Lower is more deterministic; higher lets the decoder gamble on alternative transcriptions.

additionalSettings.temperature number (model-gated) default unset

Runtime. Passed as temperature= on the OpenAI path at base_service.py:701. Deepgram and Freya STT ignore it.

Symptom it fixes: transcripts that vary run-to-run on the same audio, because temperature was raised above 0.

Step 26

Transcription prompt live

What it is. A style/continuation prompt that biases how the STT model formats and interprets audio — expected domain vocabulary (IBANs, card numbers, Turkish names), punctuation style. It does not run the model differently; it nudges formatting and lexical choices toward the context you describe.

additionalSettings.prompt string default unset

Runtime. Passed as prompt= into the STT service at base_service.py:614,654,702,759,796 across the provider branches.

Symptom it fixes: "it keeps mishearing domain terms" — a transcription prompt plus keyterms (Part 8) is the combined fix.

Step 27

Custom base URL & API key live

What it is. For provider = custom, the OpenAI-compatible STT endpoint and key pointing at a self-hosted Whisper or a third-party STT not natively integrated.

sttConfig.baseUrl sttConfig.apiKey max 2048 / 500, both null

Runtime. Used in the custom branch at base_service.py:712 (URL wiring 713-718), with the API key applied at base_service.py:780 (715,780-798).

Symptom it fixes: custom STT returns 401 / connection errors because base url or api key was left blank or pointed at the wrong host.

Try it — STT resolution explainer

How create_stt_service() resolves provider, model, language & branch

Try it — Transcription-prompt effect (illustrative)

Priming the recognizer with domain context
Ask Claude Code: "Show me where on-prem forces Language.TR in create_stt_service (base_service.py:645,655) and confirm the dashboard hides the language selector for Freya STT at stt-config-panel.tsx:415-417."
Ask Claude Code: "Trace where the transcription prompt= is threaded into each provider branch of base_service.py (lines 614, 654, 702, 759, 796) and tell me which providers actually forward it to the SDK."