Integrate voice mode panel with chat input and improve floating window#321957
Merged
Conversation
- Move voice panel from below chat input to inside the input container, above attachments, for tighter integration with the chat UI - Replace mic icon with placeholder text showing PTT keybinding (e.g. 'Hold Space to talk') that starts recording on click - Change popout icon from link-external to open-in-window codicon - Floating window: sessions collapsed by default - Floating window: centered horizontally, anchored toward bottom - Floating window: no longer minimizes the main VS Code window Fixes microsoft/vscode-internalbacklog#8046 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Integrates the Agents Voice UI more tightly with the chat panel by moving the voice bar into the chat input container, updating the voice header affordances, and refining the floating voice window’s default behavior/placement.
Changes:
- Move the chat panel’s voice bar from a dedicated bottom area into the chat input container (above attachments).
- Update Agents Voice header to include clickable placeholder PTT text and switch the popout icon to
open-in-window. - Adjust floating window defaults: sessions collapsed by default, horizontally centered near the bottom, and stop minimizing the main VS Code window.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/media/chatViewPane.css | Updates voice bar styling for new placement; removes now-unused bottom-area styling. |
| src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts | Reparents voice bar into the chat input container and updates relayout behavior accordingly. |
| src/vs/workbench/contrib/agentsVoice/browser/components/headerComponent.ts | Adds clickable placeholder PTT text and updates the popout icon. |
| src/vs/workbench/contrib/agentsVoice/browser/agentsVoiceWindowService.ts | Removes main-window minimize behavior, changes default expanded state, and updates default bounds. |
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 4
… window The expand chevron in the floating voice window now opens a quickpick that mirrors the 'show agent sessions' pattern. Each session item has a mic button to 'Set as voice target', allowing users to select which session receives voice transcriptions. - Add AgentsVoiceSessionsPicker based on AgentSessionsPicker pattern - Add showSessionsPicker callback to VoiceWidgetCallbacks - Wire chevron click to open the picker in floating window mode Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When voice sends a transcription to a target session that isn't currently displayed in the chat panel, the response is now surfaced in the floating voice window transcript instead of being invisible to the user. - Modified _sendTranscriptionToChat to detect whether the target session is the currently visible one - If target is NOT visible: send directly via chatService.sendRequest, watch the response model for content, and stream a preview (first 200 chars) into the floating window transcript - Open the floating window automatically so the user sees the reply - Added _agentsVoice.openWindow internal command (open-only, not toggle) - Removed the forced chat panel focus when sending to a non-visible target Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of rendering the transcript in a separate component above the input, add a positioned overlay inside the input container that shows the animated transcript text directly over the editor area when voice is actively transcribing. The overlay: - Appears when voice is connected and transcript turns are non-empty - Shows user text with committed (solid) + partial (pulsing) spans - Shows assistant text in description foreground color - Hides when voice disconnects or transcript clears - Uses pointer-events:none so the editor remains interactive underneath Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Hide the voice agent bar panel (no longer visible in input container) - Add mic button to ChatExecute toolbar that toggles voice connection - Move transcript overlay to its own method, rendered inside input container - Remove unused resize observer for hidden voice bar Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The _updateVoiceBar was overriding display:none. Now the container is always hidden and createVoiceAgentBar is no longer called. Only the command bridges are registered for VoiceSessionController. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Mic button now calls real connect() with error notification on failure - Added 'Voice: Simulate Connection (Dev)' command for UI testing - Removed dead createVoiceAgentBar method from chatViewPane Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Overlay now leaves bottom 36px for toolbar actions (Agent, model, mic) - Added voice-active/voice-listening CSS classes on input container - Purple glow when connected, blue pulsing glow when listening - Reads voiceState observable to toggle listening animation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When switching sessions, the chat model reference is released, which triggers _cleanupSessionTerminals to dispose ALL tool terminals for that session. This incorrectly disposes terminals the user explicitly revealed. Skip terminals that are in foregroundInstances (user-revealed) during cleanup, following the same pattern already used in background terminal completion cleanup. Fixes #321049 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Split IVoiceSessionController context key into a separate Eventually-phase contribution to avoid breaking the main contribution file with early instantiation of delayed services - Mic button now toggles voice mode: click to connect (+ start listening), click again to disconnect (icon swaps between mic/micFilled) - Added Space keybinding in chat input (when empty) to toggle voice mode - Start listening (pttDown) immediately after successful connection so backend VAD detects speech without manual PTT - Fixed isConnecting state not clearing on fatal WS close during handshake - Added 'Listening...' hint in transcript overlay when connected but idle - Properly await WebSocket handshake before showing connection errors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously, pttDown() was called immediately after connect, which set _suppressIncomingAudio=true and killed any in-progress TTS. This suppressed the voice greeting from the backend. Now we wait for the greeting audio to finish playing (via onPlaybackStopped) before enabling PTT. Falls back to a 3s timeout if no greeting arrives. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Single mic button toggles voice mode on/off (no separate disconnect button) - Click mic when disconnected: connects, plays greeting, then enters continuous listening mode (pttDown after greeting finishes) - Click mic when connected: disconnects - Space keybinding in empty chat input also toggles - Backend VAD handles speech boundary detection — no manual stop needed - After backend responds, automatically returns to listening state - Disconnect command remains in command palette for discoverability Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Mic button (unfilled): shown when disconnected, connects on click - Mic button (filled): shown when connected, disconnects on click - Space keybinding in aux window triggers PTT (hold to talk) - Backend requires pttUp() to finalize transcription, so continuous listening without explicit stop doesn't work - Greeting plays on connect, then user uses PTT to talk - Removed unused ITtsPlaybackService import Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- First click: connect + open aux window (greeting plays) - Subsequent clicks when connected: pttDown (tap-to-toggle recording) - Separate disconnect button (debug-disconnect icon) shows when connected - Removed unused INotificationService import Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Split mic button into two actions with different when clauses: - mic (unfilled): shown when not connected, click to connect + open aux - mic-filled: shown when connected, click to toggle PTT - PTT tap simulates pttDown+pttUp (enters toggle mode on first tap, finishes recording on second tap) - Disconnect button remains separate (debug-disconnect icon) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mic-filled was confusing when shown just for being connected (not actively recording). Now the mic is always unfilled — the disconnect button appearing is the visual indicator that voice mode is active. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add AGENTS_VOICE_LISTENING context key that tracks voiceState === 'listening'. Mic icon swaps to filled only during active recording, unfilled otherwise. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The voice backend only narrates state transitions for the active session. When sending from aux window to a non-focused session, is_active was always false, so the backend skipped narration. Now _buildSessionContext uses _targetSession to set is_active: true on the session the user selected in the aux window. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clicking a session in the aux window's session list now also switches the chat panel to show that session. This ensures voice responses are visible in the panel and the backend can properly track/narrate them. Also: debounce aux window resize (100ms) and clamp to screen bounds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When session list is expanded in aux window, cap it at 200px with overflow-y:auto so the toolbar and transcript below are always visible regardless of how many sessions exist. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… list Selecting a session now reveals it in the chat panel automatically, making the explicit open button redundant. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Property CSS declarations must be at document level to work properly. Moving the style injection from the container div to the aux window's document head fixes the comet border beam animation not rendering. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Handle AudioContext.resume() rejection (catch and ignore) - Reuse Uint8Array buffer in glow animation loop to reduce GC pressure Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace hardcoded #58a6ff/#a371f7/#3fb950 with theme variables (charts-blue, charts-purple, charts-green) with fallbacks - Remove !important from voice icon color rules for theme compatibility - Rename .voice-agent-bar to .voice-agent-bar-host (it's a hidden command-registration host, not a visible widget) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The setting was used but never registered. Add it with tags: ['advanced'] so it's hidden from the default settings UI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The dev-only simulateConnection() used raw setTimeout which kept closures alive after disconnect(). Switch to disposableTimeout added to _voiceEventDisposables so they're cancelled when disconnect() clears that store. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Widget: Replace raw addEventListener with dom.addDisposableListener + this._register() so closures are disposed with the widget. Window service: Remove periodic bounds saving interval since loadBounds() always returns fresh defaults (dead code/storage churn). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
getByteFrequencyData expects Uint8Array<ArrayBuffer> but the conditionally-assigned variable widens to ArrayBufferLike. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
📬 CODENOTIFYThe following users are being notified based on files changed in this PR: @anthonykim1Matched files:
|
The toolbar sets icon color via inline styles or high-specificity rules that override our class-based selectors without !important. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use scrollbar-width: none to hide the ugly native scrollbar while keeping the list scrollable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Toolbar is now at the top with all actions - Transcript shows below toolbar (above session list) when expanded - Only shows most recent turn in expanded view (chatStyle mode) - Uses foreground theme colors instead of blue/purple when expanded - Hides input box placeholder when transcript component is visible Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dmitrivMS
reviewed
Jun 19, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dmitrivMS
approved these changes
Jun 20, 2026
dmitrivMS
reviewed
Jun 20, 2026
| super({ | ||
| id: 'agentsVoice.simulateConnection', | ||
| title: nls.localize2('agentsVoice.simulateConnection', "Voice: Simulate Connection (Dev)"), | ||
| f1: true, |
Contributor
There was a problem hiding this comment.
This looks like a dev-only command which is visible to the user - should it be gated somehow?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes microsoft/vscode-internalbacklog#8046
Changes
Chat panel voice bar
open-in-windowcodiconFloating window