Skip to content

Integrate voice mode panel with chat input and improve floating window#321957

Merged
meganrogge merged 66 commits into
mainfrom
meganrogge/voice-mode-integration
Jun 20, 2026
Merged

Integrate voice mode panel with chat input and improve floating window#321957
meganrogge merged 66 commits into
mainfrom
meganrogge/voice-mode-integration

Conversation

@meganrogge

@meganrogge meganrogge commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes microsoft/vscode-internalbacklog#8046

Changes

Chat panel voice bar

  • Moved from below the chat input to inside the input container (above attachments)
  • Replaced mic icon with placeholder text showing PTT keybinding (e.g. "Hold Space to talk") — clicking starts recording
  • Changed popout icon to open-in-window codicon

Floating window

  • Sessions collapsed by default (user expands via chevron)
  • Centered horizontally, anchored toward bottom of screen
  • No longer minimizes the main VS Code window when opened

- 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>
Copilot AI review requested due to automatic review settings June 18, 2026 16:22
@meganrogge meganrogge self-assigned this Jun 18, 2026
@meganrogge meganrogge added this to the 1.126.0 milestone Jun 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Comment thread src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts Outdated
Comment thread src/vs/workbench/contrib/agentsVoice/browser/agentsVoiceWindowService.ts Outdated
Comment thread src/vs/workbench/contrib/agentsVoice/browser/components/headerComponent.ts Outdated
meganrogge and others added 24 commits June 18, 2026 12:28
… 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>
meganrogge and others added 6 commits June 19, 2026 16:48
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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 18/18 changed files
  • Comments generated: 6

Comment thread src/vs/workbench/contrib/agentsVoice/browser/agentsVoiceWidget.ts Outdated
Comment thread src/vs/workbench/contrib/chat/browser/widget/media/chat.css
Comment thread src/vs/workbench/contrib/chat/browser/widgetHosts/viewPane/chatViewPane.ts Outdated
meganrogge and others added 6 commits June 19, 2026 17:22
- 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>
@meganrogge meganrogge marked this pull request as ready for review June 19, 2026 21:35
getByteFrequencyData expects Uint8Array<ArrayBuffer> but the
conditionally-assigned variable widens to ArrayBufferLike.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vs-code-engineering

vs-code-engineering Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

@anthonykim1

Matched files:

  • src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalTool.ts
  • src/vs/workbench/contrib/terminalContrib/chatAgentTools/test/electron-browser/runInTerminalTool.test.ts

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>
@meganrogge meganrogge enabled auto-merge (squash) June 19, 2026 21:41
meganrogge and others added 3 commits June 19, 2026 17:50
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>
Comment thread src/vs/platform/extensions/common/extensionsApiProposals.ts Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@meganrogge meganrogge merged commit 8d8f102 into main Jun 20, 2026
28 checks passed
@meganrogge meganrogge deleted the meganrogge/voice-mode-integration branch June 20, 2026 00:07
super({
id: 'agentsVoice.simulateConnection',
title: nls.localize2('agentsVoice.simulateConnection', "Voice: Simulate Connection (Dev)"),
f1: true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks like a dev-only command which is visible to the user - should it be gated somehow?

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.

3 participants