Skip to content

feat(voice): configure independent speech endpoints - #359

Merged
johnmatthewtennant merged 34 commits into
mainfrom
jtennant/berd-voice-endpoints
Oct 5, 2026
Merged

johnmatthewtennant merged 34 commits into
mainfrom
jtennant/berd-voice-endpoints

Conversation

@johnmatthewtennant

@johnmatthewtennant johnmatthewtennant commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Teams using local or OpenAI-compatible speech services need to route Realtime, transcription, and synthesis independently without replacing the key used by the default OpenAI endpoints.

Adds independent full URL settings for OpenAI-compatible Realtime, speech-to-text, and text-to-speech endpoints. Each service has one Save action for its URL and key. Keys are stored per URL in macOS Keychain, while the default OpenAI URLs share one key. Settings show “No key set” or a dotted saved-key placeholder without reading the secret. Blank URLs use the OpenAI defaults. Existing STT and TTS routing through BERD_OPENAI_VOICE_BASE_URL retains its shared credential; explicitly saved URLs use their own URL-scoped keys. Native TTS, STT, and Realtime startup capture the destination and its URL-scoped credential together, so a concurrent endpoint save cannot send a key to a different endpoint.

berd-call also accepts session-only --realtime-url, --stt-url, and --tts-url overrides. Realtime dictation continues to use OpenAI's fixed client-secret API; a custom Realtime URL applies to Expert-Spokesperson conversations.

Related issue

N/A

Testing

  1. In Settings → Voice, select “Talk to your coding agent” with OpenAI STT and TTS. Enter ws://127.0.0.1:18870/v1/realtime?intent=transcription for STT and http://127.0.0.1:18870/v1/audio/speech for TTS. Enter a disposable key such as local-test in each key field and click that service's single Save button. No server is needed to verify settings.
  2. Restart Berd and return to Settings → Voice. Both URLs remain saved, both key fields show dots rather than the secret, and each form says “Key saved for this URL in macOS Keychain.” Change one URL to a different loopback path and Save without a new key: that form says “No key set.” Restore its first URL and Save: its saved-key status returns. The other service's URL and key remain unchanged.
  3. Select “Talk through a voice assistant” and repeat the URL-and-key save with ws://127.0.0.1:18870/v1/realtime. It has its own saved-key status. Clear the disposable keys with Remove, then blank each custom URL and Save to return to the OpenAI defaults.

Endpoint routing and call-scoped overrides

After building berd-call, run from the checkout:

uv run scripts/verify-voice-endpoint-routing.py --binary src-tauri/target/debug/berd-call

The script starts local STT, TTS, and Realtime fixtures and runs the CLI against each override URL with a disposable key and a PCM test host. It then starts a new call without URL overrides. Observed requests are /stt, /tts, /realtime, then /default-stt and /default/audio/speech. Synthesis completes, the saved endpoint settings remain unchanged, and the new call uses its defaults. No microphone or speakers are opened.

Screenshots

STT and TTS before: shared OpenAI key

Before: OpenAI TTS uses one API key shared with transcription, with no independent endpoint URL controls

STT and TTS after: independent endpoint controls

STT and TTS custom endpoint URLs with dotted saved-key placeholders

Voice assistant before: shared OpenAI key

Before: voice assistant has one shared OpenAI API key and no custom Realtime endpoint control

Voice assistant after: custom Realtime endpoint and key

Realtime endpoint URL and API key settings in voice-assistant mode

@johnmatthewtennant
johnmatthewtennant marked this pull request as ready for review September 29, 2026 15:42
@johnmatthewtennant
johnmatthewtennant requested a review from a team September 29, 2026 15:42

@morgmart morgmart left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated code review

REQUEST_CHANGES: two blocking regressions remain in the endpoint migration and reset lifecycle. Supplied GitHub evidence shows all ten captured checks completed successfully, but required checks still govern merge readiness.

Deterministic publication result: 2 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.

Comment thread src-tauri/src/commands/openai_voice_endpoints.rs
Comment thread src/features/voice-conversation/ui/OpenAiEndpointField.tsx
morgmart
morgmart previously approved these changes Oct 5, 2026

@morgmart morgmart left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated code review

APPROVE: the exact PR comparison has no publishable Engineering findings. The two prior blocking issues are fixed in the current head and their resolved threads contain substantive author replies. Supplied GitHub evidence is structurally valid; six captured checks passed and two were still in progress, so required checks continue to govern merge readiness.

Deterministic publication result: 0 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.

Pending checks: 2 check(s) are not complete.

This approval reflects the completed code review only; merge readiness remains governed by the repository's required checks.

@morgmart morgmart left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated code review

APPROVE: the exact PR comparison has no publishable Engineering findings. The two prior blocking issues remain fixed, and the latest endpoint-selection change correctly preserves an explicit default OpenAI URL as an override of legacy environment routing with discriminating coverage. All ten captured GitHub checks completed successfully; required checks still govern merge readiness.

Deterministic publication result: 0 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.

Pending checks: 1 check(s) are not complete.

This approval reflects the completed code review only; merge readiness remains governed by the repository's required checks.

@johnmatthewtennant
johnmatthewtennant merged commit 5ac23be into main Oct 5, 2026
10 checks passed
@johnmatthewtennant
johnmatthewtennant deleted the jtennant/berd-voice-endpoints branch October 5, 2026 18:47
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.

2 participants