Skip to content

fix(voice): a refused escalation tries the everyday role's fallback models before the fast model - #676

Merged
kh0pper merged 2 commits into
mainfrom
fix/voice-escalation-fallback
Oct 30, 2026
Merged

kh0pper merged 2 commits into
mainfrom
fix/voice-escalation-fallback

Conversation

@kh0pper

@kh0pper kh0pper commented Oct 30, 2026

Copy link
Copy Markdown
Owner

A kiosk voice turn ("play a random album") escalated to the everyday role's model, the local 35B, while a long GPU job held the box. The orchestrator refused it (box_reserved), and the turn fell back to the small fast model, which ran out of time (failed: budget). Another capable model was up the whole time.

Model role bindings already store an optional fallback list of role ids; voice ignored it.

  • servers/shared/voice-keys.js: resolveVoiceKeys also returns escalateFallbacks. These are the everyday binding's fallback roles resolved to model keys, in order and de-duplicated, excluding the escalate and fast keys. It's empty when COMPANION_ESCALATION_MODEL is set, when nothing is configured, or on any failure. The module still uses lazy imports only.
  • servers/gateway/voice/turn.js:
    • When it falls back: an escalation refused for box_reserved, serving_class, acquire_failed or unresolved tries each fallback key in order.
    • When it doesn't: a cold start, an abort, or every fallback failing degrades exactly as before.
    • Downstream: prompt fit uses the model that really served the turn.
    • Metrics: the kiosk metrics line gains escalation_fallback (the provider id).
  • Tests:
    • a box-refused primary escalates on the fallback;
    • no fallbacks degrades as before;
    • a cold timeout tries no fallback;
    • resolveVoiceKeys returns, de-duplicates and env-overrides the fallbacks.
    • Voice and kiosk tests: 1785/0.

Nothing changes until a fallback is configured on the everyday binding.

https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp

…allback models before the fast model

A kiosk turn escalated to the local 35B while a GPU job held the box; the
orchestrator refused it and the turn fell to the 4B, which ran out of time,
though another capable model was up. resolveVoiceKeys now returns
escalateFallbacks (the everyday binding's fallback roles, resolved), and an
escalation refused for box_reserved / serving_class / acquire_failed /
unresolved tries them in order. A cold start does not. The kiosk metrics
line records which fallback served (escalation_fallback).

Implemented by the Pi coding agent (deepseek-v4.1-flash).

Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
@kh0pper
kh0pper force-pushed the fix/voice-escalation-fallback branch from ed75238 to 3083417 Compare October 30, 2026 22:18
@kh0pper
kh0pper merged commit 1afd768 into main Oct 30, 2026
4 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