fix(chat): restore capability-gated voice input - #291
Conversation
|
@coderabbitai full review |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (2)
Summary by CodeRabbit
WalkthroughThe chat shell passes runtime voice capability to Sequence Diagram(s)sequenceDiagram
participant AppShell
participant ChatArea
participant ChatComposer
participant VoiceInput
participant ComposerControls
AppShell->>ChatArea: Pass runtime voice capability
ChatArea->>ChatComposer: Pass voiceEnabled
ChatComposer->>VoiceInput: Initialize voice handling
ComposerControls->>ChatComposer: Start or stop voice input
VoiceInput-->>ChatComposer: Return transcription or error
ChatComposer->>ChatComposer: Update draft or display error
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches✨ Simplify code
Comment |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/routes/Chat/ComposerModeControls.test.ts (1)
37-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDerive the expected label from the translation function.
The assertions hard-code the English string. A copy change in the
chat.voiceInputlocale entry then breaks the test for an unrelated reason. Build the expected attribute fromt("chat.voiceInput").♻️ Proposed refactor
describe("ComposerModeControls", () => { + const voiceLabel = `aria-label="${t("chat.voiceInput")}"` + it("shows voice input when the runtime enables voice", () => { - expect(renderControls(true)).toContain('aria-label="Voice input"') + expect(renderControls(true)).toContain(voiceLabel) }) it("hides voice input when the runtime disables voice", () => { - expect(renderControls(false)).not.toContain('aria-label="Voice input"') + expect(renderControls(false)).not.toContain(voiceLabel) }) })🤖 Prompt for 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. In `@src/routes/Chat/ComposerModeControls.test.ts` around lines 37 - 45, Update the assertions in the ComposerModeControls tests to derive the expected aria-label from the translation function using t("chat.voiceInput") instead of hard-coding “Voice input”; preserve the existing enabled and disabled visibility checks.
🤖 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 `@src/routes/Chat/ComposerTrailingControls.tsx`:
- Around line 200-203: Gate all voice state by voiceEnabled: in
src/routes/Chat/ComposerTrailingControls.tsx lines 200-203, only derive
visibleVoiceError from voiceError or voiceRecorderError when voiceEnabled is
true; in src/routes/Chat/ChatComposer.tsx lines 749-757, gate voiceError,
voiceRecorderError, voiceRetryBlob, voiceStarting, and voiceTranscribing the
same way as voiceActive so composerVoiceControlMode returns idle and no voice
controls render when voice is disabled.
---
Nitpick comments:
In `@src/routes/Chat/ComposerModeControls.test.ts`:
- Around line 37-45: Update the assertions in the ComposerModeControls tests to
derive the expected aria-label from the translation function using
t("chat.voiceInput") instead of hard-coding “Voice input”; preserve the existing
enabled and disabled visibility checks.
🪄 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: b4b91698-f174-4fd7-8fa1-c9ab83e0b8dc
📒 Files selected for processing (6)
src/components/app-shell/AppShell.tsxsrc/routes/Chat/ChatComposer.tsxsrc/routes/Chat/ComposerModeControls.test.tssrc/routes/Chat/ComposerModeControls.tsxsrc/routes/Chat/ComposerTrailingControls.tsxsrc/routes/Chat/index.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/routes/Chat/ComposerTrailingControls.tsx (1)
76-99: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winMove the layout and style reads out of the per-frame draw path.
The draw effect depends on
bars, so it runs on every audio frame while recording. Each run callsgetBoundingClientRect()andgetComputedStyle(). Both force style and layout work in the browser. The size and the resolved color only change whensizeRevisionor the theme changes.Cache the measured width and the fill color in a separate effect keyed on
sizeRevision, then read the cached values in the bars effect.🤖 Prompt for 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. In `@src/routes/Chat/ComposerTrailingControls.tsx` around lines 76 - 99, Separate layout and style reads from the bars drawing effect: add a size/style measurement effect keyed by sizeRevision (and the relevant theme dependency) that caches the canvas width and resolved color, then update the bars effect to use those cached values instead of calling getBoundingClientRect() and getComputedStyle() per frame. Preserve the existing canvas sizing and drawing behavior.
🤖 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 `@src/routes/Chat/ComposerTrailingControls.tsx`:
- Around line 232-264: The two voice controls currently share the same
accessible name during starting and transcribing states. Update the trailing
discard button’s aria-label in the ComposerTrailingControls voice controls to
use a distinct discard translation key such as chat.voiceDiscard, while
preserving chat.voiceCancel for the spinner/cancel control.
---
Nitpick comments:
In `@src/routes/Chat/ComposerTrailingControls.tsx`:
- Around line 76-99: Separate layout and style reads from the bars drawing
effect: add a size/style measurement effect keyed by sizeRevision (and the
relevant theme dependency) that caches the canvas width and resolved color, then
update the bars effect to use those cached values instead of calling
getBoundingClientRect() and getComputedStyle() per frame. Preserve the existing
canvas sizing and drawing behavior.
🪄 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: 1f2f85dd-336a-4b0d-801f-7a31837d7c41
📒 Files selected for processing (6)
src/components/app-shell/AppShell.tsxsrc/routes/Chat/ChatComposer.tsxsrc/routes/Chat/ComposerModeControls.test.tssrc/routes/Chat/ComposerModeControls.tsxsrc/routes/Chat/ComposerTrailingControls.tsxsrc/routes/Chat/index.tsx
|
Addressed the remaining CodeRabbit feedback in c5056c1: capability-gated stale voice state, distinct cancel/discard accessible labels with localized copy, cached waveform layout/style measurements outside the audio update path, and translation-derived test assertions. Added component regressions for the disabled stale-error and accessibility cases. Local lint, format, build, and the full 283-file/2124-test suite pass. |
Summary
Restore voice recording and transcription controls in the chat composer for signed-in OOMOL users.
The microphone button is now driven by the existing runtime voice capability, while local and BYOK
runtime modes continue to hide the OOMOL-only voice feature.
Issue and user impact
Voice recording, WAV encoding, transcription, and error handling remained in the codebase, but the
composer stopped rendering any entry point for them. As a result, signed-in users could no longer
start voice input even though their runtime advertised
voice: trueand the authenticated ASRservice remained available.
Root cause
The local-runtime foundation removed the voice integration from the shared composer to keep the
OOMOL ASR service out of anonymous local mode. The runtime capability model introduced a dedicated
voiceflag at the same time, but that flag was never propagated to the composer. This turned anintended local-mode restriction into a global UI removal.
Fix
runtimeCapabilities.voicefromAppShellthroughChatAreatoChatComposer.transcription-loading controls.
Validation
pnpm run lintpnpm run formatpnpm run buildpnpm test— 282 test files, 2122 tests passed