diff --git a/src/vs/workbench/contrib/agentsVoice/browser/agentsVoice.contribution.ts b/src/vs/workbench/contrib/agentsVoice/browser/agentsVoice.contribution.ts index a254b31da13c45..fc7facacdc4f95 100644 --- a/src/vs/workbench/contrib/agentsVoice/browser/agentsVoice.contribution.ts +++ b/src/vs/workbench/contrib/agentsVoice/browser/agentsVoice.contribution.ts @@ -36,7 +36,7 @@ import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 import { ConfigurationKeyValuePairs, IConfigurationMigrationRegistry, Extensions as WorkbenchConfigurationExtensions } from '../../../common/configuration.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; -import { AgentsVoiceSettingId, AgentsVoiceStorageKeys, AGENTS_VOICE_CONNECTED, AGENTS_VOICE_CONNECTING, AGENTS_VOICE_ENABLED, AGENTS_VOICE_ENTITLED, AGENTS_VOICE_LISTENING, AGENTS_VOICE_RECONNECTING, getAgentsVoicePolicyValue } from '../common/agentsVoice.js'; +import { AgentsVoiceSettingId, AgentsVoiceStorageKeys, AGENTS_VOICE_CONNECTED, AGENTS_VOICE_CONNECTING, AGENTS_VOICE_ENABLED, AGENTS_VOICE_ENTITLED, AGENTS_VOICE_LISTENING, AGENTS_VOICE_MUTED, AGENTS_VOICE_RECONNECTING, getAgentsVoicePolicyValue } from '../common/agentsVoice.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IChatEntitlementService } from '../../../services/chat/common/chatEntitlementService.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; @@ -103,11 +103,13 @@ class AgentsVoiceConnectedKeyContribution extends Disposable implements IWorkben const connectingKey = AGENTS_VOICE_CONNECTING.bindTo(contextKeyService); const listeningKey = AGENTS_VOICE_LISTENING.bindTo(contextKeyService); const reconnectingKey = AGENTS_VOICE_RECONNECTING.bindTo(contextKeyService); + const mutedKey = AGENTS_VOICE_MUTED.bindTo(contextKeyService); this._register(autorun(reader => { connectedKey.set(voiceSessionController.isConnected.read(reader)); connectingKey.set(voiceSessionController.isConnecting.read(reader)); reconnectingKey.set(voiceSessionController.isReconnecting.read(reader)); listeningKey.set(voiceSessionController.voiceState.read(reader) === 'listening'); + mutedKey.set(voiceSessionController.isMuted.read(reader)); })); } } @@ -422,6 +424,46 @@ registerAction2(class extends Action2 { } }); +// --- Toggle Mute Microphone (command palette + keybinding) --- +// +// Voice Mode is always listening while connected, so it can pick up +// conversations the user is having with others. Muting keeps the session +// connected (so the user can resume instantly) while dropping captured audio. +// Expose it as a keybindable command so users can mute/unmute without reaching +// for the mute button. + +registerAction2(class extends Action2 { + constructor() { + super({ + id: 'agentsVoice.toggleMute', + title: nls.localize2('agentsVoice.toggleMute', "Voice Mode: Toggle Mute Microphone"), + f1: true, + toggled: { + condition: AGENTS_VOICE_MUTED.isEqualTo(true), + title: nls.localize('agentsVoice.unmuteMic', "Unmute Microphone"), + }, + precondition: ContextKeyExpr.and( + AGENTS_VOICE_ENABLED, + AGENTS_VOICE_CONNECTED.isEqualTo(true), + ), + keybinding: { + weight: KeybindingWeight.WorkbenchContrib + 1, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyM, + when: ContextKeyExpr.and( + AGENTS_VOICE_ENABLED, + AGENTS_VOICE_CONNECTED.isEqualTo(true), + VOICE_ACTIVE_ON_SURFACE, + ChatContextKeys.inputHasFocus, + ), + }, + }); + } + async run(accessor: ServicesAccessor): Promise { + const voiceController = accessor.get(IVoiceSessionController); + voiceController.setMuted(!voiceController.isMuted.get()); + } +}); + // --- Cancel Active Request via Escape (while voice-connected in the chat input) --- // // The Disconnect-on-Escape action above deliberately does NOTHING while a diff --git a/src/vs/workbench/contrib/agentsVoice/common/agentsVoice.ts b/src/vs/workbench/contrib/agentsVoice/common/agentsVoice.ts index 47d9306e21da2f..f5c4541455dc78 100644 --- a/src/vs/workbench/contrib/agentsVoice/common/agentsVoice.ts +++ b/src/vs/workbench/contrib/agentsVoice/common/agentsVoice.ts @@ -20,6 +20,7 @@ export const AGENTS_VOICE_CONNECTED = new RawContextKey('agentsVoiceCon export const AGENTS_VOICE_CONNECTING = new RawContextKey('agentsVoiceConnecting', false); export const AGENTS_VOICE_RECONNECTING = new RawContextKey('agentsVoiceReconnecting', false); export const AGENTS_VOICE_LISTENING = new RawContextKey('agentsVoiceListening', false); +export const AGENTS_VOICE_MUTED = new RawContextKey('agentsVoiceMuted', false); /** * True when the current Copilot entitlement permits Voice Mode. This is a single * key set imperatively from `IChatEntitlementService` (see