Skip to content

feat(voices): capped in-host voice menus, HD tier signalling, settings voice catalog (Patch A)#470

Merged
rosscado merged 1 commit into
mainfrom
feat/voice-menu-patch-a
Jul 2, 2026
Merged

feat(voices): capped in-host voice menus, HD tier signalling, settings voice catalog (Patch A)#470
rosscado merged 1 commit into
mainfrom
feat/voice-menu-patch-a

Conversation

@rosscado

@rosscado rosscado commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Why

The voice catalog is about to grow 4–7x: 10 OpenAI voices are merged-and-dormant behind the API kill-switch (saypi-api #92/#215), and a third provider is under discussion (#305). On flip day, claude.ai's /voices payload becomes 20 voices — today's flat menu would render all of them, with raw credit chips (50/1k cr) as the only guidance. This PR implements Patch A of the voice-selection design (committed here, with its companion rollout plan): the catalog scales; the menu never does.

What

src/tts/VoiceCuration.ts (new, pure, unit-tested) — tier derivation from powered_by + credits (no API change needed, per the rollout plan's confirmed contract), a popularity-ranked featured set for value voices (Coral, Nova, Ash, Onyx — from community/vendor-signal research; Alloy deliberately last), a gender-diverse HD pair, and pin-current-first capped shortlists. Ranking is keyed by voice id so a future server re-skin of display names (design §7.3) can't silently degrade curation.

claude.ai menu — capped at 6 rows + a muted "More voices…" door that deep-links to the settings AI Chat tab. The raw credit chip is replaced by a single [HD] chip on premium rows plus one muted footer line ("HD voices use your monthly allowance about 20× faster"), both rendered only while tiers actually coexist. The user's stored voice is pinned first and can never vanish from the menu; the pin persists on the instance and is never applied by tearing down a menu the user has open.

pi.ai menu — the SayPi block is capped at 5 with a quiet HD suffix and the same door; Pi's native rows, its extra built-ins (voice7/8), and the PiVoiceSettings grid are untouched.

Settings → AI Chat → Voices (new) — the door's destination: the full per-host catalog on HD/Everyday shelves with descriptions and per-host selection (explicit chatbot ids — the settings page resolves to web otherwise), auth-aware empty states. Selections propagate to open host tabs via the existing voicePreferences storage listener.

openSettings(tab?) — one-shot deep link through chrome.storage.local (content scripts can't reach the settings page's localStorage); no background changes.

What you'll see today vs flip day

Pre-flip (single-tier catalogs) this is nearly dormant: no chips, no footer — just the door rows (claude.ai already serves 10 voices, so its menu tightens to 6 + door) and the new settings catalog. Flip day adds the HD signalling automatically.

Process

TDD fail-first throughout (58 new/updated assertions across 6 spec files, incl. the OpenAI + Claude catalog fixtures the rollout plan flagged as a gap). An 8-angle adversarial review pass found 7 correctness bugs pre-commit (door duplication, pin wiped by addMissingPiVoices, pin re-render deleting Pi 7/8, open-menu teardown race, stale pins, wrong sign-in prompt for authed users, throw on malformed catalog entries) — each is fixed and pinned by a test. npm test fully green (tsc + Jest + Vitest, 1664 tests).

Follow-ups (not in this PR)

  • Pre-release: npm run translate for the 11 new _locales/en keys (needs translate-cli + OPENAI_API_KEY; English fallback until then).
  • Free canned preview clips (sample_url) + the metered introduceVoice fix — gated on the saypi-api asset pipeline (design §4).
  • Server manifest fields (featured/recommended/sibling_id) — design §5; tier badges for the PiVoiceSettings grid.
  • Real-host L4 verification of the door row rendering natively on claude.ai/pi.ai.

🤖 Generated with Claude Code

https://claude.ai/code/session_012DZR4Vp9B1RiKVrkfYiM1o

…s voice catalog (Patch A)

Implements the client-only slice of doc/plans/2026-07-02-voice-selection-ux.md:
the catalog scales, the in-host menus never do.

- New src/tts/VoiceCuration.ts: tier derivation from powered_by + price (no
  API change needed), popularity-ranked featured set (Coral/Nova/Ash/Onyx),
  gender-diverse HD pair, pin-current-first capped shortlists (Claude 6, Pi 5).
- ClaudeVoiceMenu: shortlist cap + "More voices…" door (deep-links to the
  settings AI Chat tab), single [HD] chip replacing the raw credit chip, one
  muted footer line when tiers coexist, persisted pin so a stored voice never
  vanishes (and never tears down an open menu).
- Pi menu: SayPi block capped with quiet HD suffix + door; Pi's built-in rows
  and PiVoiceSettings grid untouched; idempotent door; pin survives the
  addMissingPiVoices partial populate.
- Settings AI Chat tab: full per-host voice catalog (HD/Everyday shelves,
  per-host selection, auth-aware empty state) — the door's destination.
- openSettings(tab?) one-shot deep link via chrome.storage.local.

Dormant-safe pre-flip: with today's single-tier catalogs there are no HD
chips/footers; the only visible changes are the door rows and the settings
catalog. Flip-day (20 voices on claude.ai) renders 6 rows + door instead of 20.

Pre-release follow-up: run `npm run translate` for the 11 new en keys
(requires translate-cli + OPENAI_API_KEY; English fallback until then).

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012DZR4Vp9B1RiKVrkfYiM1o
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