Skip to content

fix(gateway): Deepgram defaults (unset language, Nova-only detection, Aura default voice); default fillers - #17

Merged
dittops merged 5 commits into
mainfrom
fix/deepgram-unset-language
Oct 3, 2026
Merged

dittops merged 5 commits into
mainfrom
fix/deepgram-unset-language

Conversation

@dittops

@dittops dittops commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Problem

On bud-dev (WaaV 0.1.7), every session of a voice agent with no language set failed with:

The upstream voice provider failed. The gateway said: Failed to start voice manager: STT error: Connection failed: Connection channel closed

The log shows Deepgram refused the handshake: Failed to connect to Deepgram: HTTP error: 400 Bad Request for

wss://api.deepgram.com/v1/listen?model=base&language=multi&...

The agent had no language and neither did its STT deployment (deepgram, model base). Yet WaaV sent language=multi, Deepgram's code-switching token, which only Nova-3 and Nova-2 accept.

Cause

map_language("") resolves an empty string to CanonicalLanguage::Auto, and a vendor that can detect the language gets its auto token. For Deepgram that token is multi, regardless of the model. So "nothing chosen" became "detect", and any Deepgram deployment whose model isn't Nova-3 or Nova-2 failed the handshake.

Fix

  • An unset language is left out wherever the vendor can detect (core/lang::map_language), and the vendor's own default applies. This matches the rule the Deepgram URL builder already states: send only what the caller chose. Vendors that can't detect behave as before.
  • Deepgram detects only on the models that can: nova-3, nova-3-general, nova-2 and nova-2-general. An explicit auto on any other model is left out with a warning (which /ws surfaces as a config_warning) instead of a 400.

Named languages are unchanged.

Second fix, found on retest: Aura family deployment with no voice

With the language fix live on bud-dev, the same agent got past STT, and then every sentence failed:

TTS error: deepgram rejected the request (400 Bad Request): Invalid 'model' value of 'aura-2'.

The TTS deployment is published under the family name aura-2, and the agent keeps the vendor-default voice. With nothing naming a voice, the family went out as Deepgram's model, which Deepgram never accepts for a family. A bare family (aura-2, aura) with no voice now resolves to Deepgram's default voice for that family: aura-2-thalia-en or aura-asteria-en. A chosen voice, and a deployment published under a full voice id, are unchanged.

Default filler script

AgentFillers::default() is now "Hmm...", "One moment.", "Still checking...", matching budapp's new DEFAULT_FILLER_MESSAGES (BudEcosystem/bud-runtime#3126). budapp always publishes the full fillers block, so this default only applies to a projection that lacks one. bud-auth/tests/fixtures/voice_agent_entry.json is budapp's regenerated copy, byte for byte.

Testing

cd gateway
cargo test --lib -- core::lang handlers::ws handlers::endpoint_settings core::stt core::tts handlers::openai_realtime core::agent   # 5003 passed
cargo +1.99.0 clippy --all-targets --features dag-routing,turn-ensemble,noise-filter,openapi -- -D warnings                        # clean
cargo +1.99.0 fmt --all --check && cargo fmt --all --check                                                                         # clean on 1.99 and 1.96

New tests:

  • an_unset_language_is_left_out_not_sent_as_detection
  • deepgram_detects_only_on_the_models_that_can
  • The live case, deepgram + base + empty language, in p2_stt_auto_becomes_provider_default_or_native_token.
  • a_family_with_no_voice_speaks_in_its_default_voice.
  • bud-auth fixture test: asserts the default filler script (cd bud-auth && cargo test: 202 passed).

Mutation checks: removing either part of the language fix, or the family default, fails its tests.

🤖 Generated with Claude Code

dittops and others added 2 commits October 3, 2026 23:25
…ova-3/Nova-2

A voice agent with no language on a Deepgram `base` deployment failed
every session: "Failed to start voice manager: STT error: Connection
failed: Connection channel closed", after Deepgram answered the handshake
with 400 for `model=base&language=multi`.

- An empty language resolved to auto, and a vendor that can detect got
  its auto token. Nothing chosen is not a choice of detection: where the
  vendor can detect, an unset language is now left out and the vendor's
  own default applies.
- Deepgram's auto token `multi` is refused by every model but Nova-3 and
  Nova-2. An explicit auto on another model is left out with a warning
  instead of failing the handshake.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…amily's default voice

Retesting the bud-dev agent with the language fix, every sentence then
failed: "deepgram rejected the request (400 Bad Request): Invalid 'model'
value of 'aura-2'". The deployment is published under the family `aura-2`
and the agent keeps the vendor-default voice, so nothing named a voice and
the family went out as Deepgram's model, which it never accepts.

A bare family (`aura-2`, `aura`) with no voice now resolves to Deepgram's
default voice for it (`aura-2-thalia-en`, `aura-asteria-en`). A chosen
voice and a deployment published under a full voice id are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dittops dittops changed the title fix(gateway): leave an unset language out; Deepgram detects only on Nova-3/Nova-2 fix(gateway): Deepgram defaults - leave an unset language out, detect only on Nova, Aura family default voice Oct 3, 2026
…nt.", "Still checking..."

Matches budapp's new DEFAULT_FILLER_MESSAGES (bud-runtime#3126). budapp
always publishes the full fillers block, so this default applies only to
a projection without one; the shared fixture is budapp's regenerated copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dittops dittops changed the title fix(gateway): Deepgram defaults - leave an unset language out, detect only on Nova, Aura family default voice fix(gateway): Deepgram defaults (unset language, Nova-only detection, Aura default voice); default fillers Oct 3, 2026
dittops and others added 2 commits October 4, 2026 00:41
…s flags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ead, not the process

The coverage run failed TC-WS-13 with "invalid app state config: Invalid
WAAV_EAGER_WARMUP environment variable": a #[serial] test had set
WAAV_EAGER_WARMUP=sometimes in the shared environment, and #[serial] only
orders it against other #[serial] tests, so a parallel test's AppState read
it. Three tests did this (WAAV_EAGER_WARMUP, WAAV_MAX_CONCURRENT_RECONNECTS).

Runtime settings are now read through runtime_env(), which in test builds
looks at a per-thread override first; those tests set the malformed value
for their own thread only. A new test shows another thread does not see it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dittops
dittops merged commit 1782a8d into main Oct 3, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant