Skip to content

fix(voice): make Whisper/Piper chips reachable from Voice settings#2821

Merged
sanil-23 merged 3 commits into
tinyhumansai:mainfrom
obchain:fix/2788-voice-local-providers-reachable
May 28, 2026
Merged

fix(voice): make Whisper/Piper chips reachable from Voice settings#2821
sanil-23 merged 3 commits into
tinyhumansai:mainfrom
obchain:fix/2788-voice-local-providers-reachable

Conversation

@obchain
Copy link
Copy Markdown
Contributor

@obchain obchain commented May 28, 2026

Summary

Re-enables the Whisper (Local) and Piper (Local) chips in the Voice settings panel so users can install and route to local STT/TTS without editing ~/.openhuman/users/<user-id>/config.toml by hand.

  • Drops the hardcoded disabled "coming soon" Whisper / Piper chip blocks in VoicePanel.tsx (lines 521–573 on main).
  • Wires both chips through the existing local-provider install modal — same flow the panel already uses on click, just unreached today because the chips were inert.
  • Chip click semantics now mirror the external provider chips: off → open install/enable modal; on → route the STT (Whisper) / TTS (Piper) slot back to managed cloud.

No backend, RPC, or capability-catalog changes. voice_install_whisper, voice_install_piper, voice_status, and voice_update_provider_settings were already live; the routing dropdowns already conditionally render whisper / piper options when sttProvider === 'whisper' / ttsProvider === 'piper'.

Problem

Closes #2788.

Starting in v0.55.0 (and still in v0.56.0), the new chip-based Voice settings UI introduced in #2586 ships Whisper (Local) and Piper (Local) as disabled "coming soon" chips with no install button and no entry in the Voice Routing dropdowns. The previous release (v0.54.x) had functional Local Whisper / Local Piper dropdowns with one-click Install / Reinstall locally. From the user's perspective, free self-hosted STT/TTS is no longer reachable from the UI, even though the backend factory (voice/factory.rs), install RPCs, capability catalog, and the panel's own install modal are all intact. #2586 explicitly named this as a known follow-up that never landed.

The manual workaround — editing config.toml [local_ai] stt_provider="whisper" / tts_provider="piper" — is honoured at runtime but gets overwritten the moment the user touches the Voice Routing Save button.

Solution

File Change
app/src/components/settings/panels/VoicePanel.tsx Replace the two disabled chip blocks with active chips that open the existing install/enable modal on click and route back to cloud when toggled off. aria-checked reflects sttProvider==='whisper' / ttsProvider==='piper'. Disabled only while the corresponding install is in flight.
app/src/components/settings/panels/__tests__/VoicePanel.test.tsx Flip the chips are disabled (coming soon) assertion to its inverse, plus three new tests: click-opens-modal (Whisper), click-opens-modal (Piper), chip-on when routing is set to whisper.

The local-provider modal that handles install + enable already lives in VoicePanel.tsx:650–797 and is unchanged — it drives voice_install_whisper / voice_install_piper, surfaces the voice_status install state, and calls voice_update_provider_settings with the literal "whisper" / "piper" strings (already accepted by validate_stt_provider / validate_tts_provider).

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy — chip-renders-enabled (regression assertion), click-opens-modal × 2 (Whisper + Piper), chip-on-when-routed (round-trip with sttProvider.kind === 'local').
  • Diff coverage ≥ 80% — the two chip blocks are exercised by the new render + click tests; the modal flow they delegate to is already covered by the existing loadVoiceSettings tests.
  • Coverage matrix updated — N/A: the affected feature row already covers the Voice settings panel; the matrix is keyed at panel granularity, not per-chip.
  • All affected feature IDs from the matrix are listed in the PR description under ## RelatedN/A: chip-level change inside an existing covered feature.
  • No new external network dependencies introduced (mock backend used per Testing Strategy) — tests use the existing voiceInstallApi mocks (whisperInstallStatus, piperInstallStatus, installWhisper, installPiper).
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: Voice settings panel is not on the release-cut smoke path.
  • Linked issue closed via Closes #NNN in the ## Related section.

Impact

  • Runtime / platform: none on backend. UI change only.
  • Performance: zero — chip render path is the same size as the previous disabled block.
  • Security: no new permission surface. The local install RPCs were already callable; the chip is just the doorway that feat(voice): add voice provider registry with third-party STT/TTS support #2586 forgot to wire.
  • Migration / compatibility: backwards-compatible. Users who never enable the chips see the same cloud routing as today; users who upgraded from v0.54.x with stt_provider="whisper" / tts_provider="piper" already in their config see the chip turn on automatically.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: N/A
  • Commit SHA: N/A

Validation Run

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: the Whisper (Local) and Piper (Local) chips become active controls. Clicking an off chip opens the existing install/enable modal that drives voice_install_whisper / voice_install_piper and finalises via voice_update_provider_settings. Clicking an on chip routes the slot back to managed cloud.
  • User-visible effect: free self-hosted STT/TTS becomes reachable from Settings → AI → Voice again on v0.55+, restoring parity with v0.54.x.

Parity Contract

  • Legacy behavior preserved: yes — the modal, install RPCs, routing dropdowns, and voice_update_provider_settings validation are unchanged. Users on cloud routing see no behavioural change.
  • Guard/fallback/dispatch parity checks: effective_stt_provider / effective_tts_provider precedence (config.stt_provider → config.local_ai.stt_provider → "cloud") is unchanged.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none.
  • Canonical PR: this PR.
  • Resolution: N/A.

Summary by CodeRabbit

  • New Features
    • Whisper and Piper local voice providers are now enabled as toggleable options in Voice Settings.
    • Toggling a provider opens the configuration/install modal when needed.
    • Providers are temporarily disabled during their local installation.
    • Disabling routes audio processing back to cloud automatically.
  • Tests
    • Added tests verifying toggles, click behavior, modal opening, and routing-state updates.

Review Change Stack

The chip-based Voice settings panel introduced in tinyhumansai#2586 hardcoded the
local Whisper and Piper chips as disabled 'coming soon' switches with
no install button and no entry in the Voice Routing dropdowns. The
backend RPCs (voice_install_whisper, voice_install_piper, voice_status,
voice_update_provider_settings) and the install/enable modal at the
bottom of VoicePanel were already wired — only the chips themselves
gated the path.

Replace the disabled blocks with active chips that mirror the external
provider chip behaviour: clicking an off chip opens the existing modal
(which still drives the install RPCs and routes via
voice_update_provider_settings on Enable), clicking an on chip routes
the STT/TTS slot back to the managed cloud provider. The Voice Routing
dropdowns already conditionally render the local options when
sttProvider==='whisper' / ttsProvider==='piper', so no change is needed
there.

Closes tinyhumansai#2788.
@obchain obchain requested a review from a team May 28, 2026 06:19
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b1d77550-f7b0-4ac0-bc85-6ecbebed8905

📥 Commits

Reviewing files that changed from the base of the PR and between bed4284 and 35578ea.

📒 Files selected for processing (1)
  • app/src/components/settings/panels/__tests__/VoicePanel.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/components/settings/panels/tests/VoicePanel.test.tsx

📝 Walkthrough

Walkthrough

VoicePanel replaces disabled "coming soon" Whisper/Piper chips with functional local provider toggles that reflect routing state, disable during installation, route back to cloud on disable, and open the provider key/install modal; tests cover enabled state, click-to-open modal, and routing-bound checked state.

Changes

Local Whisper and Piper Provider Routing

Layer / File(s) Summary
Local provider routing chips
app/src/components/settings/panels/VoicePanel.tsx
Whisper and Piper chips transition from disabled placeholders to actionable local provider toggles. Each chip reflects its routing state, is disabled during installation, routes back to cloud on disable, and opens the provider key/install modal (sets pendingKeySlug) on enable.
Provider chip tests
app/src/components/settings/panels/__tests__/VoicePanel.test.tsx
Tests updated to assert chips are enabled and initially unchecked, verify clicking either chip opens the provider key/install modal, and confirm routing-state binding (Whisper/Piper chips checked when STT/TTS routing is set to Whisper/Piper).

Sequence Diagram

sequenceDiagram
  participant User
  participant VoicePanel
  participant ProviderModal
  User->>VoicePanel: click Whisper/Piper chip
  VoicePanel->>ProviderModal: set pendingKeySlug ('whisper'/'piper') and open
  ProviderModal-->>VoicePanel: provide key / initiate install
  VoicePanel->>VoicePanel: update provider routing and install state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2257: Modifies VoicePanel and VoicePanel.test.tsx to make Local Whisper/Piper selections actionable by removing disabled/coming-soon behavior and updating tests for provider selection logic.
  • tinyhumansai/openhuman#1821: Related changes to VoicePanel.tsx around TTS/Piper conditional rendering and ElevenLabs picker behavior.

Suggested reviewers

  • graycyrus

Poem

🐰 The chips awoke from "coming soon"—
Whisper hummed, Piper crooned a tune.
A rabbit clicked, the modal flew,
Keys entered, installs queued—woohoo!
Hoppity hops for UI new!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: enabling Whisper/Piper chips in Voice settings UI for local provider access.
Linked Issues check ✅ Passed Code changes fully address all primary objectives from #2788: chips are now enabled and functional, wired to install modals, disabled during install, display correct state based on routing, and test coverage validates the behavior.
Out of Scope Changes check ✅ Passed All changes directly support the stated objective of making local Whisper/Piper provider chips reachable; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/settings/panels/VoicePanel.tsx`:
- Around line 542-543: The toggles in VoicePanel.tsx are only disabled during
the short RPC kickoff (isInstallingWhisper / isInstalling*), but remain enabled
while polling reports installStatus.state === 'installing', allowing routing
changes mid-install; update the disabled props for the Whisper and the other
install-related toggles to combine both conditions (e.g.,
disabled={isInstallingWhisper || installStatus?.state === 'installing'}) so they
stay disabled for the full install-in-flight window, and make the same change
for the other toggle(s) referenced around the other occurrence (the lines using
isInstalling* / disabled).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 70bbe0a2-4f76-40d3-83f6-e0a3776d317e

📥 Commits

Reviewing files that changed from the base of the PR and between 3f2e2f2 and 8ba7062.

📒 Files selected for processing (2)
  • app/src/components/settings/panels/VoicePanel.tsx
  • app/src/components/settings/panels/__tests__/VoicePanel.test.tsx

Comment thread app/src/components/settings/panels/VoicePanel.tsx Outdated
The Whisper / Piper chip toggles were disabled only during the short
RPC kickoff (isInstalling{Whisper,Piper}), which clears as soon as
voice_install_{whisper,piper} returns. The actual install continues
until voice_install_status reports 'installed' / 'error', so the
chips become re-clickable mid-install and a user could route STT/TTS
away from the engine that is still being staged.

Disable the chips whenever either the RPC kickoff is in flight OR the
polled install state is 'installing'.
@obchain
Copy link
Copy Markdown
Contributor Author

obchain commented May 28, 2026

Addressed in bed4284f — both chips now use disabled={isInstalling* || install?.state === 'installing'} so they stay disabled for the full install window (RPC kickoff + status-poll installing), not just the brief RPC kickoff.Note: the failing Rust Core Coverage check is an upstream flake unrelated to this PR — openhuman::approval::gate::tests::pending_for_thread_tracks_request_under_chat_context_and_clears panicked at src/openhuman/approval/gate.rs:687 under cargo-llvm-cov instrumentation while none of the security/approval code is touched in this diff. The CI rerun on the new commit should clear it; if it persists, happy to bundle an upstream-unblock fix in a follow-up commit if you want.

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 28, 2026
@oxoxDev oxoxDev self-assigned this May 28, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

@obchain hey! the code looks good to me — clean fix, exactly the right scope, and CodeRabbit's install-window guard concern was addressed nicely. CI has a few checks still pending (Build Tauri App, Rust Tauri Shell Tests, E2E on Windows/macOS), so i'll hold off on approving until those finish. once they're green, i'll come back and approve this.

One minor observation while i was reading the tests: the new chip-on-when-routed test only covers the Whisper/STT case. Since the Piper/TTS chip follows the exact same logic, a symmetric test (renders the Piper chip as on when TTS routing is set to piper) would round out the coverage — not blocking, but worth adding.

Let me know if you need any help with the CI failures!

Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

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

Summary

Re-enables Whisper (Local) and Piper (Local) chips in Voice settings panel, wiring them to the existing install/enable modal. Fixes regression from #2586 where both chips were hardcoded disabled/"coming soon", making free self-hosted STT/TTS inaccessible from the UI despite backend RPC + factory being intact.

What it does: Drops hardcoded disabled blocks, wires onClick handlers to existing install modal.

Breaking risk: Zero. UI-only change; no backend, RPC, shared type, or config format changes. Existing cloud-routing users see no behavioural change.

Security risk: Zero. No new permission surface — the local install RPCs were already callable. No secrets, injection surfaces, or auth changes.

Code Review

  • Two-file change: VoicePanel.tsx (removes "coming soon" badges, adds onClick handlers with install guard), VoicePanel.test.tsx (regression test + 3 new tests)
  • Install guard logic: Both chips disabled during full install window—catching both the kickoff flag (isInstallingWhisper) and the polling state (whisperInstall?.state === "installing")
  • Test coverage: Good—regression assertion (chips now enabled), modal-open tests (×2), chip-on-when-routed test (whisper)
  • CodeRabbit dedup: CodeRabbit flagged install window guard; already addressed with the combined state check

Minor Finding

[minor] Test asymmetry: Missing symmetric renders the Piper chip as on when TTS routing is set to piper test (only Whisper routing test present). Non-blocking.


All else clean. CI pending (Build Tauri App, Rust Core Coverage, E2E Windows/macOS)—code is ready to ship. Will approve once CI is green.

@oxoxDev oxoxDev removed their assignment May 28, 2026
@obchain
Copy link
Copy Markdown
Contributor Author

obchain commented May 28, 2026

@graycyrus added the symmetric Piper assertion in 35578ea6renders the Piper chip as on when TTS routing is set to piper mirrors the existing Whisper test.

@obchain obchain requested a review from graycyrus May 28, 2026 10:30
@sanil-23 sanil-23 self-assigned this May 28, 2026
Copy link
Copy Markdown
Contributor

@sanil-23 sanil-23 left a comment

Choose a reason for hiding this comment

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

Whisper/Piper chip reachability fix verified — 26/0 CI green, CodeRabbit APPROVED, graycyrus's Piper symmetry test landed. LGTM.

@sanil-23 sanil-23 merged commit b9c2387 into tinyhumansai:main May 28, 2026
31 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.

v0.55+ regression: local Whisper/Piper unreachable from Voice settings UI (PR #2586 follow-up)

4 participants