diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts index c7d1dbf065897b..cf6b1d459705c8 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts @@ -44,6 +44,7 @@ export const enum TerminalChatContextKeyStrings { ChatResponseContainsMultipleCodeBlocks = 'terminalChatResponseContainsMultipleCodeBlocks', ChatResponseSupportsIssueReporting = 'terminalChatResponseSupportsIssueReporting', ChatSessionResponseVote = 'terminalChatSessionResponseVote', + ChatUsesAgentHost = 'terminalChatUsesAgentHost', ChatHasTerminals = 'hasChatTerminals', ChatHasHiddenTerminals = 'hasHiddenChatTerminals', ChatToolHasInstance = 'chatTerminalToolHasInstance', @@ -78,6 +79,9 @@ export namespace TerminalChatContextKeys { /** A chat agent exists for the terminal location */ export const hasChatAgent = new RawContextKey(TerminalChatContextKeyStrings.ChatAgentRegistered, false, localize('chatAgentRegisteredContextKey', "Whether a chat agent is registered for the terminal location.")); + /** Whether the chat session is backed by the Agent Host */ + export const usesAgentHost = new RawContextKey(TerminalChatContextKeyStrings.ChatUsesAgentHost, false, localize('terminalChatUsesAgentHostContextKey', "Whether the terminal chat session is backed by the Agent Host.")); + /** Has terminals created via chat */ export const hasChatTerminals = new RawContextKey(TerminalChatContextKeyStrings.ChatHasTerminals, false, localize('terminalHasChatTerminals', "Whether there are any chat terminals.")); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts index fb1da4e5d6bb2e..dd968d0224c957 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts @@ -300,6 +300,7 @@ registerActiveXtermAction({ ChatContextKeys.enabled, ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalChatContextKeys.requestActive.negate(), + TerminalChatContextKeys.usesAgentHost.negate(), ), icon: Codicon.chatSparkle, menu: [{ @@ -307,7 +308,7 @@ registerActiveXtermAction({ group: 'zzz', order: 1, isHiddenByDefault: true, - when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsCodeBlock, TerminalChatContextKeys.requestActive.negate()), + when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsCodeBlock, TerminalChatContextKeys.requestActive.negate(), TerminalChatContextKeys.usesAgentHost.negate()), }], run: (_xterm, _accessor, activeInstance) => { if (isDetachedTerminalInstance(activeInstance)) { diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts index 7d59ed19721679..0cb7920135c8cb 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts @@ -86,6 +86,7 @@ export class TerminalChatWidget extends Disposable { private readonly _requestActiveContextKey: IContextKey; private readonly _responseContainsCodeBlockContextKey: IContextKey; private readonly _responseContainsMulitpleCodeBlocksContextKey: IContextKey; + private readonly _usesAgentHostContextKey: IContextKey; private _messages = this._store.add(new Emitter()); @@ -130,6 +131,7 @@ export class TerminalChatWidget extends Disposable { this._requestActiveContextKey = TerminalChatContextKeys.requestActive.bindTo(contextKeyService); this._responseContainsCodeBlockContextKey = TerminalChatContextKeys.responseContainsCodeBlock.bindTo(contextKeyService); this._responseContainsMulitpleCodeBlocksContextKey = TerminalChatContextKeys.responseContainsMultipleCodeBlocks.bindTo(contextKeyService); + this._usesAgentHostContextKey = TerminalChatContextKeys.usesAgentHost.bindTo(contextKeyService); this._container = document.createElement('div'); this._container.classList.add('terminal-inline-chat'); @@ -367,10 +369,12 @@ export class TerminalChatWidget extends Disposable { if (lockToAgent) { this._inlineChatWidget.chatWidget.lockToCodingAgent(lockToAgent.name, lockToAgent.displayName, lockToAgent.type, lockToAgent.agentHostProviderId); this._agentHostSessionResource = model.sessionResource; + this._usesAgentHostContextKey.set(true); this._refreshAgentHostSessionMetadata(); } else { this._inlineChatWidget.chatWidget.unlockFromCodingAgent(); this._agentHostSessionResource = undefined; + this._usesAgentHostContextKey.set(false); } this._resetPlaceholder(); }); @@ -425,6 +429,7 @@ export class TerminalChatWidget extends Disposable { this.cancel(); this._model.clear(); this._agentHostSessionResource = undefined; + this._usesAgentHostContextKey.reset(); this._inlineChatWidget.chatWidget.unlockFromCodingAgent(); this._responseContainsCodeBlockContextKey.reset(); this._requestActiveContextKey.reset(); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/test/browser/terminalChatActions.test.ts b/src/vs/workbench/contrib/terminalContrib/chat/test/browser/terminalChatActions.test.ts new file mode 100644 index 00000000000000..f38fd3e09be4bf --- /dev/null +++ b/src/vs/workbench/contrib/terminalContrib/chat/test/browser/terminalChatActions.test.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js'; +import { isIMenuItem, MenuRegistry } from '../../../../../../platform/actions/common/actions.js'; +import { ContextKeyValue, IContext } from '../../../../../../platform/contextkey/common/contextkey.js'; +import '../../browser/terminalChatActions.js'; +import { MENU_TERMINAL_CHAT_WIDGET_STATUS, TerminalChatCommandId, TerminalChatContextKeys } from '../../browser/terminalChat.js'; + +suite('Terminal Chat actions', () => { + + ensureNoDisposablesAreLeakedInTestSuite(); + + function hasViewInChat(overrides: Record): boolean { + const context: IContext = { + getValue: (key: string): T | undefined => overrides[key] as T | undefined, + }; + return MenuRegistry.getMenuItems(MENU_TERMINAL_CHAT_WIDGET_STATUS) + .filter(isIMenuItem) + .some(item => item.command.id === TerminalChatCommandId.ViewInChat && (!item.when || item.when.evaluate(context))); + } + + test('shows View in Chat only for local terminal chat sessions', () => { + const base = { + [TerminalChatContextKeys.responseContainsCodeBlock.key]: true, + [TerminalChatContextKeys.requestActive.key]: false, + }; + + assert.deepStrictEqual({ + local: hasViewInChat({ ...base, [TerminalChatContextKeys.usesAgentHost.key]: false }), + agentHost: hasViewInChat({ ...base, [TerminalChatContextKeys.usesAgentHost.key]: true }), + }, { + local: true, + agentHost: false, + }); + }); +});