From 0190f2853bb9db5b84b982977e8b0dc0c3258fc7 Mon Sep 17 00:00:00 2001 From: Eugene Vyborov Date: Thu, 25 Jun 2026 13:25:53 +0200 Subject: [PATCH] feat(voip): add Gacrux to the Gemini Live voice picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the "Gacrux — Mature" prebuilt voice to the per-agent VoIP voice selector (and the shared AgentWorkspace per-session picker, which reads the same list). Updated in lockstep across the three mirrored sources so the frontend↔backend parity test stays green: - src/frontend/src/constants/voices.js — single frontend source of truth - src/backend/config.py GEMINI_VOICE_NAMES — write-validation allowlist + read-path fallback - tests/unit/test_28_voip_voice_config.py — hardcoded parity tuple Follow-up to #1323 (per-agent VoIP config panel + persisted voice). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/backend/config.py | 2 +- src/frontend/src/constants/voices.js | 1 + tests/unit/test_28_voip_voice_config.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/config.py b/src/backend/config.py index 4e35e3b9..77e56ef6 100644 --- a/src/backend/config.py +++ b/src/backend/config.py @@ -191,7 +191,7 @@ # picker). DEFAULT_VOICE_NAME is the historical hardcoded default and the # fallback for an unset or no-longer-valid persisted value. DEFAULT_VOICE_NAME = "Kore" -GEMINI_VOICE_NAMES = ("Kore", "Zephyr", "Puck", "Aoede", "Charon", "Fenrir") +GEMINI_VOICE_NAMES = ("Kore", "Zephyr", "Puck", "Aoede", "Charon", "Fenrir", "Gacrux") # Gemini text/audio models (#1130). Hardcoded `gemini-2.0-flash` was retired by # Google (404 NOT_FOUND) with no config escape hatch — these env overrides make diff --git a/src/frontend/src/constants/voices.js b/src/frontend/src/constants/voices.js index f634dc30..9edadc7a 100644 --- a/src/frontend/src/constants/voices.js +++ b/src/frontend/src/constants/voices.js @@ -11,6 +11,7 @@ export const VOICES = [ { id: 'Aoede', label: 'Aoede — Breezy' }, { id: 'Charon', label: 'Charon — Informational' }, { id: 'Fenrir', label: 'Fenrir — Excitable' }, + { id: 'Gacrux', label: 'Gacrux — Mature' }, ] export const VOICE_IDS = VOICES.map((v) => v.id) diff --git a/tests/unit/test_28_voip_voice_config.py b/tests/unit/test_28_voip_voice_config.py index f9ca5b98..baf7ff1d 100644 --- a/tests/unit/test_28_voip_voice_config.py +++ b/tests/unit/test_28_voip_voice_config.py @@ -143,7 +143,7 @@ def test_backend_defaults(self): assert config.DEFAULT_VOICE_NAME == "Kore" assert config.DEFAULT_VOICE_NAME in config.GEMINI_VOICE_NAMES assert config.GEMINI_VOICE_NAMES == ( - "Kore", "Zephyr", "Puck", "Aoede", "Charon", "Fenrir", + "Kore", "Zephyr", "Puck", "Aoede", "Charon", "Fenrir", "Gacrux", ) def test_frontend_voice_list_matches_backend(self):