feat(voice): Settings → Service "Voice input" group (VOICE-4) #782
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!782
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev/776"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds the Voice input settings group to the Settings page, backed by
service_config.speech_json.Test plan
speech_jsoncolumn toservice_config; idempotent ALTER TABLE guardGET /service-config/speechreturns resolved speech config (global over builtin defaults)PATCH /service-config/speechupdates only theglobalrow — no file writes, no localStorageGET /architect/transcribe/healthprobes speaches reachability with 30 s cache;?refresh=1bypasses cachespeech.*fields, save/discard draft buttonsdefault_languagechange fires PATCH with correct field key (4 tests pass)docs/workspace.mdcallout:systemctl --user enable --now speachesCloses #776
TanStack Router's Route type doesn't overlap with { component: () => ReactNode }, making the direct cast a TS error. Access the component via Route.options.component (consistent with settings.agent-config.test.tsx line 85). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>The test mocks createFileRoute as () => (opts) => opts, so Route at runtime is the raw options object {component: SettingsRoute} — no .options property. Route.options.component crashes at runtime; casting through unknown gives a shape that works for both tsc and the mock. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>behavior
config/service.json:47— key isallowed_languages_jsonbutSpeechConfigandSPEECH_CONFIG_DEFAULTSuseallowed_languages(no_jsonsuffix). When builtin-sync runs it serialises thespeechblock verbatim, so the DB storesallowed_languages_json; butgetSpeechConfig()spreadsSPEECH_CONFIG_DEFAULTS(which hasallowed_languages) over the DB row — the builtin-configured list is silently ignored. Fix: rename the key inconfig/service.jsontoallowed_languages.test-gap / missing-ac
settings.index.tsx— AC requires "Reset-to-builtin per field — same affordance SVC-3 ships for every other field." The PR ships only a "Discard" button (reverts unsaved draft), not per-field reset-to-builtin. Add a per-field reset control matching the SVC-3 pattern.config/service.json:47— key is stillallowed_languages_jsonbutSpeechConfigusesallowed_languages.upsertServiceConfigRowstores the speech blob verbatim (JSON.stringify(cfg.speech)), so the builtin DB row hasallowed_languages_jsonas the key.getSpeechConfigthen spreads{ ...SPEECH_CONFIG_DEFAULTS, ...fromDb }— since the keys differ, the builtin list is silently dropped andSPEECH_CONFIG_DEFAULTS.allowed_languagesis used instead. Any future change toconfig/service.json's language list will be ignored. Fix: rename"allowed_languages_json"→"allowed_languages"on line 47 ofconfig/service.json.Fixed: renamed
allowed_languages_json→allowed_languagesinconfig/service.json(242217e). The key now matchesSpeechConfigso builtin-sync stores the correct field andgetSpeechConfig()merges it properly.242217ecf3d87d8b63fcFix landed:
allowed_languages_json→allowed_languagesinconfig/service.json. CI green. LGTM.