diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index 37e32ea1a8229..220e9c2854f62 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -24,11 +24,12 @@ import { ILogService } from '../../../platform/log/common/log.js'; import { IChatWidgetService } from '../../contrib/chat/browser/chat.js'; import { ChatInputPart } from '../../contrib/chat/browser/chatInputPart.js'; import { AddDynamicVariableAction, IAddDynamicVariableContext } from '../../contrib/chat/browser/contrib/chatDynamicVariables.js'; -import { ChatAgentLocation, IChatAgentHistoryEntry, IChatAgentImplementation, IChatAgentRequest, IChatAgentService } from '../../contrib/chat/common/chatAgents.js'; +import { IChatAgentHistoryEntry, IChatAgentImplementation, IChatAgentRequest, IChatAgentService } from '../../contrib/chat/common/chatAgents.js'; import { IChatEditingService, IChatRelatedFileProviderMetadata } from '../../contrib/chat/common/chatEditingService.js'; import { ChatRequestAgentPart } from '../../contrib/chat/common/chatParserTypes.js'; import { ChatRequestParser } from '../../contrib/chat/common/chatRequestParser.js'; import { IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatNotebookEdit, IChatProgress, IChatService, IChatTask, IChatWarningMessage } from '../../contrib/chat/common/chatService.js'; +import { ChatAgentLocation } from '../../contrib/chat/common/constants.js'; import { IExtHostContext, extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js'; import { IExtensionService } from '../../services/extensions/common/extensions.js'; import { Dto } from '../../services/extensions/common/proxyIdentifier.js'; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 0d1b41e637a12..0a3a25f0a184c 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -51,12 +51,13 @@ import { WorkspaceTrustRequestOptions } from '../../../platform/workspace/common import { SaveReason } from '../../common/editor.js'; import { IRevealOptions, ITreeItem, IViewBadge } from '../../common/views.js'; import { CallHierarchyItem } from '../../contrib/callHierarchy/common/callHierarchy.js'; -import { ChatAgentLocation, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult, IChatWelcomeMessageContent } from '../../contrib/chat/common/chatAgents.js'; +import { IChatAgentMetadata, IChatAgentRequest, IChatAgentResult, IChatWelcomeMessageContent } from '../../contrib/chat/common/chatAgents.js'; import { ICodeMapperRequest, ICodeMapperResult } from '../../contrib/chat/common/chatCodeMapperService.js'; import { IChatRelatedFile, IChatRelatedFileProviderMetadata as IChatRelatedFilesProviderMetadata, IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js'; import { IChatProgressHistoryResponseContent } from '../../contrib/chat/common/chatModel.js'; import { IChatContentInlineReference, IChatFollowup, IChatNotebookEdit, IChatProgress, IChatResponseErrorDetails, IChatTask, IChatTaskDto, IChatUserActionEvent, IChatVoteAction } from '../../contrib/chat/common/chatService.js'; import { IChatRequestVariableValue } from '../../contrib/chat/common/chatVariables.js'; +import { ChatAgentLocation } from '../../contrib/chat/common/constants.js'; import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata, ILanguageModelChatSelector, ILanguageModelsChangeEvent } from '../../contrib/chat/common/languageModels.js'; import { IPreparedToolInvocation, IToolData, IToolInvocation, IToolResult } from '../../contrib/chat/common/languageModelToolsService.js'; import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugTestRunReference, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from '../../contrib/debug/common/debug.js'; diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 1c7afac413a55..d765cceec7ce1 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -20,19 +20,20 @@ import { generateUuid } from '../../../base/common/uuid.js'; import { Location } from '../../../editor/common/languages.js'; import { ExtensionIdentifier, IExtensionDescription, IRelaxedExtensionDescription } from '../../../platform/extensions/common/extensions.js'; import { ILogService } from '../../../platform/log/common/log.js'; -import { ChatAgentLocation, IChatAgentRequest, IChatAgentResult, IChatAgentResultTimings, IChatWelcomeMessageContent } from '../../contrib/chat/common/chatAgents.js'; +import { isChatViewTitleActionContext } from '../../contrib/chat/common/chatActions.js'; +import { IChatAgentRequest, IChatAgentResult, IChatAgentResultTimings, IChatWelcomeMessageContent } from '../../contrib/chat/common/chatAgents.js'; +import { IChatRelatedFile, IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js'; import { ChatAgentVoteDirection, IChatContentReference, IChatFollowup, IChatResponseErrorDetails, IChatUserActionEvent, IChatVoteAction } from '../../contrib/chat/common/chatService.js'; +import { ChatAgentLocation } from '../../contrib/chat/common/constants.js'; import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js'; import { Dto } from '../../services/extensions/common/proxyIdentifier.js'; import { ExtHostChatAgentsShape2, IChatAgentCompletionItem, IChatAgentHistoryEntryDto, IChatProgressDto, IExtensionChatAgentMetadata, IMainContext, MainContext, MainThreadChatAgentsShape2 } from './extHost.protocol.js'; import { CommandsConverter, ExtHostCommands } from './extHostCommands.js'; +import { ExtHostDiagnostics } from './extHostDiagnostics.js'; import { ExtHostDocuments } from './extHostDocuments.js'; import { ExtHostLanguageModels } from './extHostLanguageModels.js'; import * as typeConvert from './extHostTypeConverters.js'; import * as extHostTypes from './extHostTypes.js'; -import { isChatViewTitleActionContext } from '../../contrib/chat/common/chatActions.js'; -import { IChatRelatedFile, IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js'; -import { ExtHostDiagnostics } from './extHostDiagnostics.js'; class ChatAgentResponseStream { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 5e96a687c55f9..f92096730c68d 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -39,7 +39,7 @@ import { IMarkerData, IRelatedInformation, MarkerSeverity, MarkerTag } from '../ import { ProgressLocation as MainProgressLocation } from '../../../platform/progress/common/progress.js'; import { DEFAULT_EDITOR_ASSOCIATION, SaveReason } from '../../common/editor.js'; import { IViewBadge } from '../../common/views.js'; -import { ChatAgentLocation, IChatAgentRequest, IChatAgentResult } from '../../contrib/chat/common/chatAgents.js'; +import { IChatAgentRequest, IChatAgentResult } from '../../contrib/chat/common/chatAgents.js'; import { IChatRequestDraft } from '../../contrib/chat/common/chatEditingService.js'; import { IChatRequestVariableEntry } from '../../contrib/chat/common/chatModel.js'; import { IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatMoveMessage, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatTaskDto, IChatTaskResult, IChatTextEdit, IChatTreeData, IChatUserActionEvent, IChatWarningMessage } from '../../contrib/chat/common/chatService.js'; @@ -62,6 +62,7 @@ import { CommandsConverter } from './extHostCommands.js'; import { getPrivateApiFor } from './extHostTestingPrivateApi.js'; import * as types from './extHostTypes.js'; import { LanguageModelPromptTsxPart, LanguageModelTextPart } from './extHostTypes.js'; +import { ChatAgentLocation } from '../../contrib/chat/common/constants.js'; export namespace Command { diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.ts b/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.ts index 2278a17524777..674c15f327f6a 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.ts @@ -15,8 +15,8 @@ import { IKeybindingService } from '../../../../../platform/keybinding/common/ke import { ActiveAuxiliaryContext } from '../../../../common/contextkeys.js'; import { AccessibilityVerbositySettingId } from '../../../accessibility/browser/accessibilityConfiguration.js'; import { INLINE_CHAT_ID } from '../../../inlineChat/common/inlineChat.js'; -import { ChatAgentLocation } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { IChatWidgetService } from '../chat.js'; export class PanelChatAccessibilityHelp implements IAccessibleViewImplementation { diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index eeb033f261227..749e7bde173f6 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -35,7 +35,8 @@ import { ACTIVE_GROUP, IEditorService } from '../../../../services/editor/common import { IHostService } from '../../../../services/host/browser/host.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { EXTENSIONS_CATEGORY, IExtensionsWorkbenchService } from '../../../extensions/common/extensions.js'; -import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; +import { IChatAgentService } from '../../common/chatAgents.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { extractAgentAndCommand } from '../../common/chatParserTypes.js'; import { IChatDetail, IChatService } from '../../common/chatService.js'; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts index 85b6746bd261f..829019d5bd023 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts @@ -15,10 +15,9 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb import { ActiveEditorContext } from '../../../../common/contextkeys.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { isChatViewTitleActionContext } from '../../common/chatActions.js'; -import { ChatAgentLocation } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingSession, WorkingSetEntryState } from '../../common/chatEditingService.js'; -import { ChatMode } from '../../common/constants.js'; +import { ChatAgentLocation, ChatMode } from '../../common/constants.js'; import { ChatViewId, EditsViewId, IChatWidget, IChatWidgetService } from '../chat.js'; import { EditingSessionAction } from '../chatEditing/chatEditingActions.js'; import { ctxIsGlobalEditingSession } from '../chatEditing/chatEditingEditorContextKeys.js'; @@ -348,12 +347,16 @@ export function registerNewChatActions() { precondition: ChatContextKeys.Setup.hidden.toNegated(), menu: [{ id: MenuId.ViewTitle, - when: ContextKeyExpr.and(ContextKeyExpr.equals('view', ChatViewId), ChatContextKeys.editingParticipantRegistered, + when: ContextKeyExpr.and( + ContextKeyExpr.equals('view', ChatViewId), + ChatContextKeys.editingParticipantRegistered, ContextKeyExpr.equals(`view.${EditsViewId}.visible`, false), ContextKeyExpr.or( ContextKeyExpr.and(ContextKeyExpr.equals(`workbench.panel.chat.defaultViewContainerLocation`, true), ContextKeyExpr.equals(`workbench.panel.chatEditing.defaultViewContainerLocation`, false)), ContextKeyExpr.and(ContextKeyExpr.equals(`workbench.panel.chat.defaultViewContainerLocation`, false), ContextKeyExpr.equals(`workbench.panel.chatEditing.defaultViewContainerLocation`, true)), - )), + ), + ChatContextKeys.inUnifiedChat.negate() + ), group: 'navigation', order: 1 }, { @@ -380,17 +383,18 @@ export function registerNewChatActions() { async run(accessor: ServicesAccessor, opts?: string | IChatViewOpenOptions) { opts = typeof opts === 'string' ? { query: opts } : opts; const viewsService = accessor.get(IViewsService); - const chatView = await viewsService.openView(EditsViewId) as ChatViewPane; + const chatView = await viewsService.openView(EditsViewId) + ?? await viewsService.openView(ChatViewId); if (opts?.query) { if (opts.isPartialQuery) { - chatView.widget.setInput(opts.query); + chatView?.widget.setInput(opts.query); } else { - chatView.widget.acceptInput(opts.query); + chatView?.widget.acceptInput(opts.query); } } - chatView.widget.focusInput(); + chatView?.widget.focusInput(); } }); } diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index aa90fc63047dc..7e6a74fba2109 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -29,10 +29,10 @@ import { IEditorService } from '../../../../services/editor/common/editorService import { accessibleViewInCodeBlock } from '../../../accessibility/browser/accessibilityConfiguration.js'; import { reviewEdits } from '../../../inlineChat/browser/inlineChatController.js'; import { ITerminalEditorService, ITerminalGroupService, ITerminalService } from '../../../terminal/browser/terminal.js'; -import { ChatAgentLocation } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { ChatCopyKind, IChatService } from '../../common/chatService.js'; import { IChatResponseViewModel, isResponseVM } from '../../common/chatViewModel.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { IChatCodeBlockContextProviderService, IChatWidgetService } from '../chat.js'; import { DefaultChatTextEditor, ICodeBlockActionContext, ICodeCompareBlockActionContext } from '../codeBlockPart.js'; import { CHAT_CATEGORY } from './chatActions.js'; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts index df2139fb6b1e2..d02d3be48bd71 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts @@ -13,17 +13,17 @@ import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contex import { IDialogService } from '../../../../../platform/dialogs/common/dialogs.js'; import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; -import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; -import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { IChatAgentService } from '../../common/chatAgents.js'; +import { ChatContextKeyExprs, ChatContextKeys } from '../../common/chatContextKeys.js'; import { IChatEditingService, IChatEditingSession, WorkingSetEntryState } from '../../common/chatEditingService.js'; import { chatAgentLeader, extractAgentAndCommand } from '../../common/chatParserTypes.js'; import { IChatService } from '../../common/chatService.js'; -import { ChatMode } from '../../common/constants.js'; +import { ChatAgentLocation, ChatMode } from '../../common/constants.js'; import { EditsViewId, IChatWidget, IChatWidgetService } from '../chat.js'; -import { discardAllEditsWithConfirmation, EditingSessionAction } from '../chatEditing/chatEditingActions.js'; +import { discardAllEditsWithConfirmation, getEditingSessionContext } from '../chatEditing/chatEditingActions.js'; import { ChatViewPane } from '../chatViewPane.js'; import { CHAT_CATEGORY } from './chatActions.js'; -import { ChatDoneActionId } from './chatClearActions.js'; +import { ACTION_ID_NEW_CHAT, ChatDoneActionId } from './chatClearActions.js'; export interface IVoiceChatExecuteActionContext { readonly disableTimeout?: boolean; @@ -93,29 +93,31 @@ export class ChatSubmitAction extends SubmitAction { export const ToggleAgentModeActionId = 'workbench.action.chat.toggleAgentMode'; -export interface IToggleAgentModeArgs { - agentMode: boolean; +export interface IToggleChatModeArgs { + mode: ChatMode; } -export class ToggleAgentModeAction extends EditingSessionAction { +class ToggleChatModeAction extends Action2 { static readonly ID = ToggleAgentModeActionId; constructor() { super({ - id: ToggleAgentModeAction.ID, - title: localize2('interactive.toggleMode.label', "Toggle Chat Mode (Experimental)"), + id: ToggleChatModeAction.ID, + title: localize2('interactive.toggleAgent.label', "Set Chat Mode (Experimental)"), f1: true, category: CHAT_CATEGORY, precondition: ContextKeyExpr.and( ChatContextKeys.enabled, - ChatContextKeys.Editing.hasToolsAgent, + ContextKeyExpr.or( + ChatContextKeys.Editing.hasToolsAgent, + ChatContextKeyExprs.unifiedChatEnabled), ChatContextKeys.requestInProgress.negate()), tooltip: localize('setChatMode', "Set Mode (Experimental)"), keybinding: { when: ContextKeyExpr.and( ChatContextKeys.inChatInput, - ChatContextKeys.location.isEqualTo(ChatAgentLocation.EditingSession)), + ChatContextKeyExprs.inEditsOrUnified), primary: KeyMod.CtrlCmd | KeyCode.Period, weight: KeybindingWeight.EditorContrib }, @@ -123,33 +125,42 @@ export class ToggleAgentModeAction extends EditingSessionAction { { id: MenuId.ChatExecute, order: 1, - when: ContextKeyExpr.and( - ChatContextKeys.location.isEqualTo(ChatAgentLocation.EditingSession), - ChatContextKeys.Editing.hasToolsAgent), + // Either in edits with agent mode available, or in unified chat view + when: ContextKeyExpr.or( + ContextKeyExpr.and( + ChatContextKeys.location.isEqualTo(ChatAgentLocation.EditingSession), + ChatContextKeys.Editing.hasToolsAgent, + ), + ChatContextKeys.inUnifiedChat), group: 'navigation', }, ] }); } - override async runEditingSessionAction(accessor: ServicesAccessor, currentEditingSession: IChatEditingSession, chatWidget: IChatWidget, ...args: any[]) { - + async run(accessor: ServicesAccessor, ...args: any[]) { const chatService = accessor.get(IChatService); const commandService = accessor.get(ICommandService); const dialogService = accessor.get(IDialogService); - const entries = currentEditingSession.entries.get(); - if (entries.length > 0 && entries.some(entry => entry.state.get() === WorkingSetEntryState.Modified)) { - if (!await discardAllEditsWithConfirmation(accessor, currentEditingSession)) { + const context = getEditingSessionContext(accessor, args); + if (!context?.chatWidget) { + return; + } + + // TODO will not require discarding the session when we are able to switch modes mid-session + const entries = context.editingSession?.entries.get(); + if (context.editingSession && entries && entries.length > 0 && entries.some(entry => entry.state.get() === WorkingSetEntryState.Modified)) { + if (!await discardAllEditsWithConfirmation(accessor, context.editingSession)) { // User cancelled return; } } else { - const chatSession = chatService.getSession(currentEditingSession.chatSessionId); + const chatSession = context.chatWidget.viewModel?.model; if (chatSession?.getRequests().length) { const confirmation = await dialogService.confirm({ title: localize('agent.newSession', "Start new session?"), - message: localize('agent.newSessionMessage', "Toggling agent mode will start a new session. Would you like to continue?"), + message: localize('agent.newSessionMessage', "Changing the chat mode will start a new session. Would you like to continue?"), primaryButton: localize('agent.newSession.confirm', "Yes"), type: 'info' }); @@ -159,13 +170,24 @@ export class ToggleAgentModeAction extends EditingSessionAction { } } - const arg = args[0] as IToggleAgentModeArgs | undefined; - const setTo = arg ? - (arg.agentMode ? ChatMode.Agent : ChatMode.Edit) : - (chatWidget.input.toolsAgentModeEnabled ? ChatMode.Edit : ChatMode.Agent); - chatWidget.input.setChatMode(setTo); + const arg = args[0] as IToggleChatModeArgs | undefined; + if (arg?.mode) { + context.chatWidget.input.setChatMode(arg.mode); + } else { + const modes = [ChatMode.Agent, ChatMode.Edit]; + if (context.chatWidget.location === ChatAgentLocation.Panel) { + modes.push(ChatMode.Chat); + } + + const modeIndex = modes.indexOf(context.chatWidget.input.currentMode); + const newMode = modes[(modeIndex + 1) % modes.length]; + context.chatWidget.input.setChatMode(newMode); + } - await commandService.executeCommand(ChatDoneActionId); + if (context.chatWidget.viewModel?.model.getRequests().length) { + const clearAction = chatService.unifiedViewEnabled ? ACTION_ID_NEW_CHAT : ChatDoneActionId; + await commandService.executeCommand(clearAction); + } } } @@ -576,7 +598,7 @@ export function registerChatExecuteActions() { registerAction2(SendToNewChatAction); registerAction2(ChatSubmitSecondaryAgentAction); registerAction2(SendToChatEditingAction); - registerAction2(ToggleAgentModeAction); + registerAction2(ToggleChatModeAction); registerAction2(ToggleRequestPausedAction); registerAction2(SwitchToNextModelAction); } diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts index 511e7216583e4..27a41546c72cd 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts @@ -29,12 +29,13 @@ import { MENU_INLINE_CHAT_WIDGET_SECONDARY } from '../../../inlineChat/common/in import { INotebookEditor } from '../../../notebook/browser/notebookBrowser.js'; import { CellEditType, CellKind, NOTEBOOK_EDITOR_ID } from '../../../notebook/common/notebookCommon.js'; import { NOTEBOOK_IS_ACTIVE_EDITOR } from '../../../notebook/common/notebookContextKeys.js'; -import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; -import { ChatContextKeys } from '../../common/chatContextKeys.js'; +import { IChatAgentService } from '../../common/chatAgents.js'; +import { ChatContextKeyExprs, ChatContextKeys } from '../../common/chatContextKeys.js'; import { applyingChatEditsFailedContextKey, ChatEditingSessionState, IChatEditingService, isChatEditingActionContext } from '../../common/chatEditingService.js'; import { IChatRequestModel } from '../../common/chatModel.js'; import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatService } from '../../common/chatService.js'; import { isRequestVM, isResponseVM } from '../../common/chatViewModel.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { ChatTreeItem, EditsViewId, IChatWidgetService } from '../chat.js'; import { ChatViewPane } from '../chatViewPane.js'; import { CHAT_CATEGORY } from './chatActions.js'; @@ -408,12 +409,17 @@ export function registerChatTitleActions() { f1: false, category: CHAT_CATEGORY, icon: Codicon.goToEditingSession, - precondition: ContextKeyExpr.and(ChatContextKeys.editingParticipantRegistered, ChatContextKeys.requestInProgress.toNegated(), ChatContextKeys.location.isEqualTo(ChatAgentLocation.Panel)), + precondition: ContextKeyExpr.and( + ChatContextKeys.editingParticipantRegistered, + ChatContextKeys.requestInProgress.toNegated(), + ChatContextKeys.location.isEqualTo(ChatAgentLocation.Panel), + ChatContextKeyExprs.unifiedChatEnabled.negate() + ), menu: { id: MenuId.ChatMessageFooter, group: 'navigation', order: 4, - when: ContextKeyExpr.and(ChatContextKeys.enabled, ChatContextKeys.isResponse, ChatContextKeys.editingParticipantRegistered, ChatContextKeys.location.isEqualTo(ChatAgentLocation.Panel)) + when: ContextKeyExpr.and(ChatContextKeys.enabled, ChatContextKeys.isResponse, ChatContextKeys.editingParticipantRegistered, ChatContextKeys.location.isEqualTo(ChatAgentLocation.Panel), ChatContextKeyExprs.unifiedChatEnabled.negate()) } }); } diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 005c3152255dc..1f857bda55255 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -102,6 +102,7 @@ import { Event } from '../../../../base/common/event.js'; import { ChatEditingNotebookFileSystemProviderContrib } from './chatEditing/notebook/chatEditingNotebookFileSystemProvider.js'; import { mcpConfigurationSection, mcpSchemaExampleServers } from '../../mcp/common/mcpConfiguration.js'; import { mcpSchemaId } from '../../../services/configuration/common/configuration.js'; +import { ChatConfiguration } from '../common/constants.js'; // Register configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -210,6 +211,12 @@ configurationRegistry.registerConfiguration({ description: nls.localize('workspaceConfig.mcp.description', "Model Context Protocol server configurations"), $ref: mcpSchemaId }, + [ChatConfiguration.UnifiedChatView]: { + type: 'boolean', + description: nls.localize('chat.experimental.unifiedChatView', "Enables the unified view with Chat, Edit, and Agent in one place."), + default: false, + tags: ['experimental'], + }, [PromptsConfig.CONFIG_KEY]: { type: 'boolean', title: nls.localize( diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index 250b763f45180..8bf9eeaa09416 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -14,11 +14,12 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta import { IViewDescriptorService, ViewContainerLocation } from '../../../common/views.js'; import { IWorkbenchLayoutService, Parts } from '../../../services/layout/browser/layoutService.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; -import { ChatAgentLocation, IChatAgentCommand, IChatAgentData } from '../common/chatAgents.js'; +import { IChatAgentCommand, IChatAgentData } from '../common/chatAgents.js'; import { IChatResponseModel } from '../common/chatModel.js'; import { IParsedChatRequest } from '../common/chatParserTypes.js'; import { CHAT_PROVIDER_ID } from '../common/chatParticipantContribTypes.js'; import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel } from '../common/chatViewModel.js'; +import { ChatAgentLocation, ChatMode } from '../common/constants.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; import { ChatInputPart } from './chatInputPart.js'; import { ChatViewPane } from './chatViewPane.js'; @@ -155,17 +156,16 @@ export type ChatTreeItem = IChatRequestViewModel | IChatResponseViewModel; export interface IChatListItemRendererOptions { readonly renderStyle?: 'compact' | 'minimal'; readonly noHeader?: boolean; - readonly noPadding?: boolean; readonly editableCodeBlock?: boolean; - readonly renderCodeBlockPills?: boolean; + readonly renderCodeBlockPills?: boolean | ((mode: ChatMode) => boolean); readonly renderDetectedCommandsWithRequest?: boolean; readonly renderTextEditsAsSummary?: (uri: URI) => boolean; - readonly referencesExpandedWhenEmptyResponse?: boolean; - readonly progressMessageAtBottomOfResponse?: boolean; + readonly referencesExpandedWhenEmptyResponse?: boolean | ((mode: ChatMode) => boolean); + readonly progressMessageAtBottomOfResponse?: boolean | ((mode: ChatMode) => boolean); } export interface IChatWidgetViewOptions { - autoScroll?: boolean; + autoScroll?: boolean | ((mode: ChatMode) => boolean); renderInputOnTop?: boolean; renderFollowups?: boolean; renderStyle?: 'compact' | 'minimal'; @@ -191,6 +191,7 @@ export interface IChatWidgetViewOptions { editorOverflowWidgetsDomNode?: HTMLElement; enableImplicitContext?: boolean; enableWorkingSet?: 'explicit' | 'implicit'; + supportsChangingModes?: boolean; } export interface IChatViewViewContext { diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts index 88eb081dff9dd..d1f9a69662047 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts @@ -26,11 +26,11 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb import { IListService } from '../../../../../platform/list/browser/listService.js'; import { GroupsOrder, IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; -import { ChatAgentLocation } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { applyingChatEditsFailedContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingResourceContextKey, chatEditingWidgetFileStateContextKey, decidedChatEditingResourceContextKey, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, WorkingSetEntryRemovalReason, WorkingSetEntryState } from '../../common/chatEditingService.js'; import { IChatService } from '../../common/chatService.js'; import { isRequestVM, isResponseVM } from '../../common/chatViewModel.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { CHAT_CATEGORY } from '../actions/chatActions.js'; import { ChatTreeItem, IChatWidget, IChatWidgetService } from '../chat.js'; @@ -48,26 +48,37 @@ export abstract class EditingSessionAction extends Action2 { } run(accessor: ServicesAccessor, ...args: any[]) { - const context: IEditingSessionActionContext | undefined = args[0]; - - const chatEditingService = accessor.get(IChatEditingService); - const chatWidget = context?.widget ?? accessor.get(IChatWidgetService).getWidgetsByLocations(ChatAgentLocation.EditingSession).at(0); - - if (!chatWidget?.viewModel) { + const context = getEditingSessionContext(accessor, args); + if (!context || !context.editingSession) { return; } - const chatSessionId = chatWidget.viewModel.model.sessionId; - const editingSession = chatEditingService.getEditingSession(chatSessionId); + return this.runEditingSessionAction(accessor, context.editingSession, context.chatWidget, ...args); + } - if (!editingSession) { - return; - } + abstract runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession, chatWidget: IChatWidget, ...args: any[]): any; +} + +export function getEditingSessionContext(accessor: ServicesAccessor, args: any[]): { editingSession?: IChatEditingSession; chatWidget: IChatWidget } | undefined { + const context: IEditingSessionActionContext | undefined = args[0]; - return this.runEditingSessionAction(accessor, editingSession, chatWidget, ...args); + const chatService = accessor.get(IChatService); + const chatEditingService = accessor.get(IChatEditingService); + const editingLocation = chatService.unifiedViewEnabled ? ChatAgentLocation.Panel : ChatAgentLocation.EditingSession; + const chatWidget = context?.widget ?? accessor.get(IChatWidgetService).getWidgetsByLocations(editingLocation).at(0); + + if (!chatWidget?.viewModel) { + return; } - abstract runEditingSessionAction(accessor: ServicesAccessor, editingSession: IChatEditingSession, chatWidget: IChatWidget, ...args: any[]): any; + const chatSessionId = chatWidget.viewModel.model.sessionId; + const editingSession = chatEditingService.getEditingSession(chatSessionId); + + if (!editingSession) { + return; + } + + return { editingSession, chatWidget }; } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingServiceImpl.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingServiceImpl.ts index 34c2ac94cced1..40e2e0d81ea26 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingServiceImpl.ts @@ -33,10 +33,11 @@ import { IExtensionService } from '../../../../services/extensions/common/extens import { ILifecycleService } from '../../../../services/lifecycle/common/lifecycle.js'; import { IMultiDiffSourceResolver, IMultiDiffSourceResolverService, IResolvedMultiDiffSource, MultiDiffEditorItem } from '../../../multiDiffEditor/browser/multiDiffSourceResolverService.js'; import { CellUri } from '../../../notebook/common/notebookCommon.js'; -import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; +import { IChatAgentService } from '../../common/chatAgents.js'; import { CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingAgentSupportsReadonlyReferencesContextKey, chatEditingResourceContextKey, ChatEditingSessionState, chatEditingSnapshotScheme, IChatEditingService, IChatEditingSession, IChatRelatedFile, IChatRelatedFilesProvider, IModifiedFileEntry, inChatEditingSessionContextKey, IStreamingEdits, WorkingSetEntryState } from '../../common/chatEditingService.js'; import { IChatResponseModel, isCellTextEditOperation } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { AbstractChatEditingModifiedFileEntry } from './chatEditingModifiedFileEntry.js'; import { ChatEditingSession } from './chatEditingSession.js'; import { ChatEditingSnapshotTextModelContentProvider, ChatEditingTextModelContentProvider } from './chatEditingTextModelContentProviders.js'; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditor.ts b/src/vs/workbench/contrib/chat/browser/chatEditor.ts index 19280d5133db1..cccd397d87ed9 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditor.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditor.ts @@ -19,11 +19,11 @@ import { Memento } from '../../../common/memento.js'; import { clearChatEditor } from './actions/chatClear.js'; import { ChatEditorInput } from './chatEditorInput.js'; import { ChatWidget, IChatViewState } from './chatWidget.js'; -import { ChatAgentLocation } from '../common/chatAgents.js'; import { IChatModel, IExportableChatData, ISerializableChatData } from '../common/chatModel.js'; import { CHAT_PROVIDER_ID } from '../common/chatParticipantContribTypes.js'; import { IEditorGroup } from '../../../services/editor/common/editorGroupsService.js'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from '../../../common/theme.js'; +import { ChatAgentLocation } from '../common/constants.js'; export interface IChatEditorOptions extends IEditorOptions { target?: { sessionId: string } | { data: IExportableChatData | ISerializableChatData }; diff --git a/src/vs/workbench/contrib/chat/browser/chatFollowups.ts b/src/vs/workbench/contrib/chat/browser/chatFollowups.ts index d600d02a79053..f4d55df96e4af 100644 --- a/src/vs/workbench/contrib/chat/browser/chatFollowups.ts +++ b/src/vs/workbench/contrib/chat/browser/chatFollowups.ts @@ -8,9 +8,10 @@ import { Button, IButtonStyles } from '../../../../base/browser/ui/button/button import { MarkdownString } from '../../../../base/common/htmlContent.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { localize } from '../../../../nls.js'; -import { ChatAgentLocation, IChatAgentService } from '../common/chatAgents.js'; +import { IChatAgentService } from '../common/chatAgents.js'; import { formatChatQuestion } from '../common/chatParserTypes.js'; import { IChatFollowup } from '../common/chatService.js'; +import { ChatAgentLocation } from '../common/constants.js'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 1c755c9ff9005..37a95860b6efd 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -72,13 +72,13 @@ import { ChatContextKeys } from '../common/chatContextKeys.js'; import { IChatEditingSession } from '../common/chatEditingService.js'; import { ChatEntitlement, IChatEntitlementService } from '../common/chatEntitlementService.js'; import { IChatRequestVariableEntry, isImageVariableEntry, isLinkVariableEntry, isPasteVariableEntry } from '../common/chatModel.js'; -import { IChatFollowup } from '../common/chatService.js'; +import { IChatFollowup, IChatService } from '../common/chatService.js'; import { IChatVariablesService } from '../common/chatVariables.js'; import { IChatResponseViewModel } from '../common/chatViewModel.js'; import { ChatInputHistoryMaxEntries, IChatHistoryEntry, IChatInputState, IChatWidgetHistoryService } from '../common/chatWidgetHistoryService.js'; import { ChatMode } from '../common/constants.js'; import { ILanguageModelChatMetadataAndIdentifier, ILanguageModelsService } from '../common/languageModels.js'; -import { CancelAction, ChatSubmitAction, ChatSubmitSecondaryAgentAction, ChatSwitchToNextModelActionId, IChatExecuteActionContext, IToggleAgentModeArgs, ToggleAgentModeActionId } from './actions/chatExecuteActions.js'; +import { CancelAction, ChatSubmitAction, ChatSubmitSecondaryAgentAction, ChatSwitchToNextModelActionId, IChatExecuteActionContext, IToggleChatModeArgs, ToggleAgentModeActionId } from './actions/chatExecuteActions.js'; import { ImplicitContextAttachmentWidget } from './attachments/implicitContextAttachment.js'; import { PromptAttachmentsCollectionWidget } from './attachments/promptAttachments/promptAttachmentsCollectionWidget.js'; import { IChatWidget } from './chat.js'; @@ -117,6 +117,7 @@ interface IChatInputPartOptions { editorOverflowWidgetsDomNode?: HTMLElement; renderWorkingSet?: boolean; enableImplicitContext?: boolean; + supportsChangingModes?: boolean; } export interface IWorkingSetEntry { @@ -302,13 +303,17 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } private _onDidChangeCurrentChatMode = this._register(new Emitter()); - private _currentMode: ChatMode = ChatMode.Chat; - public get toolsAgentModeEnabled(): boolean { - return this._currentMode === ChatMode.Agent; - } + readonly onDidChangeCurrentChatMode = this._onDidChangeCurrentChatMode.event; + private _currentMode: ChatMode = ChatMode.Chat; public get currentMode(): ChatMode { - return this._currentMode === ChatMode.Agent && !this.agentService.hasToolsAgent ? ChatMode.Edit : this._currentMode; + if (this.location === ChatAgentLocation.Panel && !this.chatService.unifiedViewEnabled) { + return ChatMode.Chat; + } + + return this._currentMode === ChatMode.Agent && !this.agentService.hasToolsAgent ? + ChatMode.Edit : + this._currentMode; } private cachedDimensions: dom.Dimension | undefined; @@ -373,6 +378,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge @ILabelService private readonly labelService: ILabelService, @IChatVariablesService private readonly variableService: IChatVariablesService, @IChatAgentService private readonly agentService: IChatAgentService, + @IChatService private readonly chatService: IChatService, ) { super(); @@ -469,13 +475,17 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } setChatMode(mode: ChatMode): void { + if (!this.options.supportsChangingModes) { + return; + } + this._currentMode = mode; this._onDidChangeCurrentChatMode.fire(); } private modelSupportedForDefaultAgent(model: ILanguageModelChatMetadataAndIdentifier): boolean { // Probably this logic could live in configuration on the agent, or somewhere else, if it gets more complex - if (this._currentMode === ChatMode.Agent) { + if (this.currentMode === ChatMode.Agent) { if (this.configurationService.getValue('chat.agent.allModels')) { return true; } @@ -557,9 +567,15 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } if (state.inputState?.chatMode) { - this._currentMode = state.inputState.chatMode; + this.setChatMode(state.inputState.chatMode); } else if (this.location === ChatAgentLocation.EditingSession) { - this._currentMode = ChatMode.Edit; + this.setChatMode(ChatMode.Edit); + } + + if (state.inputState?.chatMode) { + this.setChatMode(state.inputState.chatMode); + } else if (this.location === ChatAgentLocation.EditingSession) { + this.setChatMode(ChatMode.Edit); } } @@ -933,10 +949,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge } } else if (action.id === ToggleAgentModeActionId && action instanceof MenuItemAction) { const delegate: IModePickerDelegate = { - getMode: () => this._currentMode, + getMode: () => this.currentMode, onDidChangeMode: this._onDidChangeCurrentChatMode.event }; - return this.instantiationService.createInstance(ToggleAgentActionViewItem, action, delegate); + return this.instantiationService.createInstance(ToggleChatModeActionViewItem, action, delegate); } return undefined; @@ -1501,13 +1517,14 @@ interface IModePickerDelegate { getMode(): ChatMode; } -class ToggleAgentActionViewItem extends DropdownMenuActionViewItemWithKeybinding { +class ToggleChatModeActionViewItem extends DropdownMenuActionViewItemWithKeybinding { constructor( action: MenuItemAction, private readonly delegate: IModePickerDelegate, @IContextMenuService contextMenuService: IContextMenuService, @IKeybindingService keybindingService: IKeybindingService, @IContextKeyService contextKeyService: IContextKeyService, + @IChatService chatService: IChatService, ) { const makeAction = (mode: ChatMode): IAction => ({ ...action, @@ -1517,7 +1534,7 @@ class ToggleAgentActionViewItem extends DropdownMenuActionViewItemWithKeybinding enabled: true, checked: delegate.getMode() === mode, run: async () => { - const result = await action.run({ agentMode: mode === ChatMode.Agent } satisfies IToggleAgentModeArgs); + const result = await action.run({ mode } satisfies IToggleChatModeArgs); this.renderLabel(this.element!); return result; } @@ -1529,12 +1546,15 @@ class ToggleAgentActionViewItem extends DropdownMenuActionViewItemWithKeybinding makeAction(ChatMode.Agent), makeAction(ChatMode.Edit), ]; + if (chatService.unifiedViewEnabled) { + agentStateActions.unshift(makeAction(ChatMode.Chat)); + } + return agentStateActions; } }; super(action, actionProvider, contextMenuService, undefined, keybindingService, contextKeyService); - this._register(delegate.onDidChangeMode(() => this.renderLabel(this.element!))); } @@ -1553,8 +1573,8 @@ class ToggleAgentActionViewItem extends DropdownMenuActionViewItemWithKeybinding // Can't call super.renderLabel because it has a hack of forcing the 'codicon' class this.setAriaLabelAttributes(element); - const state = this.delegate.getMode(); - dom.reset(element, dom.$('span.chat-model-label', undefined, this.modeToString(state)), ...renderLabelWithIcons(`$(chevron-down)`)); + const state = this.modeToString(this.delegate.getMode()); + dom.reset(element, dom.$('span.chat-model-label', undefined, state), ...renderLabelWithIcons(`$(chevron-down)`)); return null; } diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 7bc69accb60cf..964295f9f2eee 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -43,14 +43,16 @@ import { ColorScheme } from '../../../../platform/theme/common/theme.js'; import { IThemeService } from '../../../../platform/theme/common/themeService.js'; import { IWorkbenchIssueService } from '../../issue/common/issue.js'; import { annotateSpecialMarkdownContent } from '../common/annotations.js'; -import { ChatAgentLocation, IChatAgentMetadata } from '../common/chatAgents.js'; +import { checkModeOption } from '../common/chat.js'; +import { IChatAgentMetadata } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { IChatRequestVariableEntry, IChatTextEditGroup } from '../common/chatModel.js'; import { chatSubcommandLeader } from '../common/chatParserTypes.js'; -import { ChatAgentVoteDirection, ChatAgentVoteDownReason, ChatErrorLevel, IChatConfirmation, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatTask, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop } from '../common/chatService.js'; +import { ChatAgentVoteDirection, ChatAgentVoteDownReason, ChatErrorLevel, IChatConfirmation, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatService, IChatTask, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop } from '../common/chatService.js'; import { IChatCodeCitations, IChatReferences, IChatRendererContent, IChatRequestViewModel, IChatResponseViewModel, IChatWorkingProgress, isRequestVM, isResponseVM } from '../common/chatViewModel.js'; import { getNWords } from '../common/chatWordCounter.js'; import { CodeBlockModelCollection } from '../common/codeBlockModelCollection.js'; +import { ChatMode } from '../common/constants.js'; import { MarkUnhelpfulActionId } from './actions/chatTitleActions.js'; import { ChatTreeItem, IChatCodeBlockInfo, IChatFileTreeInfo, IChatListItemRendererOptions, IChatWidgetService } from './chat.js'; import { ChatAgentHover, getChatAgentHoverOptions } from './chatAgentHover.js'; @@ -105,6 +107,7 @@ const forceVerboseLayoutTracing = false export interface IChatRendererDelegate { container: HTMLElement; getListLength(): number; + currentChatMode(): ChatMode; readonly onDidScroll?: Event; } @@ -162,6 +165,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { this.updateItemHeight(templateData); })); @@ -1053,7 +1055,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer { diff --git a/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts b/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts index 3256369a754a6..00b345093aebd 100644 --- a/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts @@ -21,7 +21,7 @@ import { Registry } from '../../../../platform/registry/common/platform.js'; import { ViewPaneContainer } from '../../../browser/parts/views/viewPaneContainer.js'; import { IWorkbenchContribution } from '../../../common/contributions.js'; import { IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation, Extensions as ViewExtensions } from '../../../common/views.js'; -import { IExtensionFeatureTableRenderer, IRenderedData, ITableData, IRowData, IExtensionFeaturesRegistry, Extensions } from '../../../services/extensionManagement/common/extensionFeatures.js'; +import { Extensions, IExtensionFeaturesRegistry, IExtensionFeatureTableRenderer, IRenderedData, IRowData, ITableData } from '../../../services/extensionManagement/common/extensionFeatures.js'; import { isProposedApiEnabled } from '../../../services/extensions/common/extensions.js'; import * as extensionsRegistry from '../../../services/extensions/common/extensionsRegistry.js'; import { showExtensionsWithIdsCommandId } from '../../extensions/browser/extensionsActions.js'; @@ -29,6 +29,7 @@ import { IExtension, IExtensionsWorkbenchService } from '../../extensions/common import { ChatAgentLocation, IChatAgentData, IChatAgentService } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { IRawChatParticipantContribution } from '../common/chatParticipantContribTypes.js'; +import { ChatConfiguration } from '../common/constants.js'; import { ChatViewId } from './chat.js'; import { CHAT_EDITING_SIDEBAR_PANEL_ID, CHAT_SIDEBAR_PANEL_ID, ChatViewPane } from './chatViewPane.js'; @@ -107,10 +108,13 @@ const editsViewDescriptor: IViewDescriptor[] = [{ order: 2 }, ctorDescriptor: new SyncDescriptor(ChatViewPane, [{ location: ChatAgentLocation.EditingSession }]), - when: ContextKeyExpr.or( - ChatContextKeys.Setup.hidden.negate(), - ChatContextKeys.Setup.installed, - ChatContextKeys.editingParticipantRegistered + when: ContextKeyExpr.and( + ContextKeyExpr.has(`config.${ChatConfiguration.UnifiedChatView}`).negate(), + ContextKeyExpr.or( + ChatContextKeys.Setup.hidden.negate(), + ChatContextKeys.Setup.installed, + ChatContextKeys.editingParticipantRegistered + ) ) }]; Registry.as(ViewExtensions.ViewsRegistry).registerViews(editsViewDescriptor, editsViewContainer); diff --git a/src/vs/workbench/contrib/chat/browser/chatQuick.ts b/src/vs/workbench/contrib/chat/browser/chatQuick.ts index a4af4355058f0..137fc14757b19 100644 --- a/src/vs/workbench/contrib/chat/browser/chatQuick.ts +++ b/src/vs/workbench/contrib/chat/browser/chatQuick.ts @@ -19,12 +19,12 @@ import { IQuickInputService, IQuickWidget } from '../../../../platform/quickinpu import { editorBackground, inputBackground, quickInputBackground, quickInputForeground } from '../../../../platform/theme/common/colorRegistry.js'; import { IQuickChatOpenOptions, IQuickChatService, showChatView } from './chat.js'; import { ChatWidget } from './chatWidget.js'; -import { ChatAgentLocation } from '../common/chatAgents.js'; import { ChatModel, isCellTextEditOperation } from '../common/chatModel.js'; import { IParsedChatRequest } from '../common/chatParserTypes.js'; import { IChatProgress, IChatService } from '../common/chatService.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from '../../../common/theme.js'; +import { ChatAgentLocation } from '../common/constants.js'; export class QuickChatService extends Disposable implements IQuickChatService { readonly _serviceBrand: undefined; diff --git a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts index 57b36dcfa1d06..3cf5196fdd410 100644 --- a/src/vs/workbench/contrib/chat/browser/chatViewPane.ts +++ b/src/vs/workbench/contrib/chat/browser/chatViewPane.ts @@ -25,12 +25,12 @@ import { Memento } from '../../../common/memento.js'; import { SIDE_BAR_FOREGROUND } from '../../../common/theme.js'; import { IViewDescriptorService } from '../../../common/views.js'; import { IChatViewTitleActionContext } from '../common/chatActions.js'; -import { ChatAgentLocation, IChatAgentService } from '../common/chatAgents.js'; +import { IChatAgentService } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { ChatModelInitState, IChatModel } from '../common/chatModel.js'; import { CHAT_PROVIDER_ID } from '../common/chatParticipantContribTypes.js'; import { IChatService } from '../common/chatService.js'; -import { ChatMode } from '../common/constants.js'; +import { ChatAgentLocation, ChatMode } from '../common/constants.js'; import { ChatWidget, IChatViewState } from './chatWidget.js'; import { ChatViewWelcomeController, IViewWelcomeDelegate } from './viewsWelcome/chatViewWelcomeController.js'; @@ -174,21 +174,22 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate { this.chatOptions.location, { viewId: this.id }, { - autoScroll: this.chatOptions.location === ChatAgentLocation.EditingSession, + autoScroll: mode => mode !== ChatMode.Chat, renderFollowups: this.chatOptions.location === ChatAgentLocation.Panel, supportsFileReferences: true, supportsAdditionalParticipants: this.chatOptions.location === ChatAgentLocation.Panel, rendererOptions: { - renderCodeBlockPills: this.chatOptions.location === ChatAgentLocation.EditingSession, + renderCodeBlockPills: mode => mode !== ChatMode.Chat, renderTextEditsAsSummary: (uri) => { - return this.chatOptions.location === ChatAgentLocation.EditingSession; + return this.chatService.isEditingLocation(this.chatOptions.location); }, - referencesExpandedWhenEmptyResponse: this.chatOptions.location !== ChatAgentLocation.EditingSession, - progressMessageAtBottomOfResponse: this.chatOptions.location === ChatAgentLocation.EditingSession, + referencesExpandedWhenEmptyResponse: !this.chatService.isEditingLocation(this.chatOptions.location), + progressMessageAtBottomOfResponse: this.chatService.isEditingLocation(this.chatOptions.location), }, editorOverflowWidgetsDomNode: editorOverflowNode, - enableImplicitContext: this.chatOptions.location === ChatAgentLocation.Panel || this.chatOptions.location === ChatAgentLocation.EditingSession, - enableWorkingSet: this.chatOptions.location === ChatAgentLocation.EditingSession ? 'explicit' : undefined + enableImplicitContext: this.chatOptions.location === ChatAgentLocation.Panel || this.chatService.isEditingLocation(this.chatOptions.location), + enableWorkingSet: this.chatService.isEditingLocation(this.chatOptions.location) ? 'explicit' : undefined, + supportsChangingModes: this.chatService.isEditingLocation(this.chatOptions.location), }, { listForeground: SIDE_BAR_FOREGROUND, diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 0be625675db1b..4156b6562920f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -37,7 +37,8 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground } from '../../../../platform/theme/common/colorRegistry.js'; import { asCssVariable } from '../../../../platform/theme/common/colorUtils.js'; import { IThemeService } from '../../../../platform/theme/common/themeService.js'; -import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentService, IChatWelcomeMessageContent, isChatWelcomeMessageContent } from '../common/chatAgents.js'; +import { checkModeOption } from '../common/chat.js'; +import { IChatAgentCommand, IChatAgentData, IChatAgentService, IChatWelcomeMessageContent, isChatWelcomeMessageContent } from '../common/chatAgents.js'; import { ChatContextKeys } from '../common/chatContextKeys.js'; import { applyingChatEditsFailedContextKey, decidedChatEditingResourceContextKey, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, inChatEditingSessionContextKey, WorkingSetEntryState } from '../common/chatEditingService.js'; import { ChatPauseState, IChatModel, IChatRequestVariableEntry, IChatResponseModel } from '../common/chatModel.js'; @@ -48,7 +49,7 @@ import { IChatSlashCommandService } from '../common/chatSlashCommands.js'; import { ChatViewModel, IChatResponseViewModel, isRequestVM, isResponseVM } from '../common/chatViewModel.js'; import { IChatInputState } from '../common/chatWidgetHistoryService.js'; import { CodeBlockModelCollection } from '../common/codeBlockModelCollection.js'; -import { ChatMode } from '../common/constants.js'; +import { ChatAgentLocation, ChatConfiguration, ChatMode } from '../common/constants.js'; import { ChatTreeItem, IChatAcceptInputOptions, IChatAccessibilityService, IChatCodeBlockInfo, IChatFileTreeInfo, IChatListItemRendererOptions, IChatWidget, IChatWidgetService, IChatWidgetViewContext, IChatWidgetViewOptions } from './chat.js'; import { ChatAccessibilityProvider } from './chatAccessibilityProvider.js'; import { ChatAttachmentModel } from './chatAttachmentModel.js'; @@ -254,6 +255,8 @@ export class ChatWidget extends Disposable implements IChatWidget { ChatContextKeys.inChatSession.bindTo(contextKeyService).set(true); ChatContextKeys.location.bindTo(contextKeyService).set(this._location.location); ChatContextKeys.inQuickChat.bindTo(contextKeyService).set(isQuickChat(this)); + ChatContextKeys.inUnifiedChat.bindTo(contextKeyService) + .set(this._location.location === ChatAgentLocation.Panel && !!this.viewOptions.supportsChangingModes && this.configurationService.getValue(ChatConfiguration.UnifiedChatView)); this.agentInInput = ChatContextKeys.inputHasAgent.bindTo(contextKeyService); this.requestInProgress = ChatContextKeys.requestInProgress.bindTo(contextKeyService); this.isRequestPaused = ChatContextKeys.isRequestPaused.bindTo(contextKeyService); @@ -344,7 +347,7 @@ export class ChatWidget extends Disposable implements IChatWidget { this.renderChatEditingSessionState(); })); - if (this._location.location === ChatAgentLocation.EditingSession) { + if (this._location.location === ChatAgentLocation.EditingSession || this.chatService.unifiedViewEnabled) { let currentEditSession: IChatEditingSession | undefined = undefined; this._register(this.onDidChangeViewModel(async () => { const sessionId = this._viewModel?.sessionId; @@ -696,7 +699,8 @@ export class ChatWidget extends Disposable implements IChatWidget { const rendererDelegate: IChatRendererDelegate = { getListLength: () => this.tree.getNode(null).visibleChildrenCount, onDidScroll: this.onDidScroll, - container: listContainer + container: listContainer, + currentChatMode: () => this.input.currentMode, }; // Create a dom element to hold UI from editor widgets embedded in chat messages @@ -837,7 +841,8 @@ export class ChatWidget extends Disposable implements IChatWidget { menus: { executeToolbar: MenuId.ChatExecute, ...this.viewOptions.menus }, editorOverflowWidgetsDomNode: this.viewOptions.editorOverflowWidgetsDomNode, enableImplicitContext: this.viewOptions.enableImplicitContext, - renderWorkingSet: this.viewOptions.enableWorkingSet === 'explicit' + renderWorkingSet: this.viewOptions.enableWorkingSet === 'explicit', + supportsChangingModes: this.viewOptions.supportsChangingModes, }, this.styles, () => this.collectInputState() @@ -918,6 +923,7 @@ export class ChatWidget extends Disposable implements IChatWidget { // Tools agent loads -> welcome content changes this.renderWelcomeViewContentIfNeeded(); })); + this._register(this.input.onDidChangeCurrentChatMode(() => this.renderWelcomeViewContentIfNeeded())); } private onDidStyleChange(): void { @@ -1079,7 +1085,7 @@ export class ChatWidget extends Disposable implements IChatWidget { if (this.viewModel) { this._onDidAcceptInput.fire(); - if (!this.viewOptions.autoScroll) { + if (!checkModeOption(this.input.currentMode, this.viewOptions.autoScroll)) { this.scrollLock = false; } @@ -1211,8 +1217,10 @@ export class ChatWidget extends Disposable implements IChatWidget { const lastElementVisible = this.tree.scrollTop + this.tree.renderHeight >= this.tree.scrollHeight - 2; const listHeight = Math.max(0, height - inputPartHeight); - if (!this.viewOptions.autoScroll) { + if (!checkModeOption(this.input.currentMode, this.viewOptions.autoScroll)) { this.listContainer.style.setProperty('--chat-current-response-min-height', listHeight * .75 + 'px'); + } else { + this.listContainer.style.removeProperty('--chat-current-response-min-height'); } this.tree.layout(listHeight, width); @@ -1231,7 +1239,7 @@ export class ChatWidget extends Disposable implements IChatWidget { const lastItem = this.viewModel?.getItems().at(-1); const lastResponseIsRendering = isResponseVM(lastItem) && lastItem.renderData; - if (lastElementVisible && (!lastResponseIsRendering || this.viewOptions.autoScroll)) { + if (lastElementVisible && (!lastResponseIsRendering || checkModeOption(this.input.currentMode, this.viewOptions.autoScroll))) { this.scrollToEnd(); } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts index dc70c779fc834..afcd62f22183a 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts @@ -18,10 +18,10 @@ import { IWorkbenchContribution } from '../../../../common/contributions.js'; import { EditorsOrder } from '../../../../common/editor.js'; import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { getNotebookEditorFromEditorPane, INotebookEditor } from '../../../notebook/browser/notebookBrowser.js'; -import { ChatAgentLocation } from '../../common/chatAgents.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; import { IBaseChatRequestVariableEntry, IChatRequestImplicitVariableEntry } from '../../common/chatModel.js'; import { IChatService } from '../../common/chatService.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { ILanguageModelIgnoredFilesService } from '../../common/ignoredFiles.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; diff --git a/src/vs/workbench/contrib/chat/browser/media/chat.css b/src/vs/workbench/contrib/chat/browser/media/chat.css index 68deb3b7c60dc..e1a0d144dfa54 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chat.css +++ b/src/vs/workbench/contrib/chat/browser/media/chat.css @@ -435,11 +435,6 @@ have to be updated for changes to the rules above, or to support more deeply nes padding: 8px 20px; } -.interactive-item-container.interactive-item-compact.no-padding { - padding: unset; - gap: unset; -} - .interactive-item-container.interactive-item-compact .header { height: 16px; } diff --git a/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts b/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts index bbe6404c8faf0..aa765010ffae7 100644 --- a/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts +++ b/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts @@ -17,7 +17,8 @@ import { IInstantiationService } from '../../../../../platform/instantiation/com import { ILogService } from '../../../../../platform/log/common/log.js'; import { IOpenerService } from '../../../../../platform/opener/common/opener.js'; import { defaultButtonStyles } from '../../../../../platform/theme/browser/defaultStyles.js'; -import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; +import { IChatAgentService } from '../../common/chatAgents.js'; +import { ChatAgentLocation } from '../../common/constants.js'; import { chatViewsWelcomeRegistry, IChatViewsWelcomeDescriptor } from './chatViewsWelcome.js'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/chat/common/chat.ts b/src/vs/workbench/contrib/chat/common/chat.ts new file mode 100644 index 0000000000000..7e2b00c0c8f80 --- /dev/null +++ b/src/vs/workbench/contrib/chat/common/chat.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ChatMode } from './constants.js'; + +export function checkModeOption(mode: ChatMode, option: boolean | ((mode: ChatMode) => boolean) | undefined): boolean | undefined { + if (option === undefined) { + return undefined; + } + if (typeof option === 'function') { + return option(mode); + } + return option; +} diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index dca99689801ce..f50d851f493d4 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -25,9 +25,9 @@ import { asJson, IRequestService } from '../../../../platform/request/common/req import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { ChatContextKeys } from './chatContextKeys.js'; import { IChatProgressHistoryResponseContent, IChatRequestVariableData, ISerializableChatAgentData } from './chatModel.js'; -import { IRawChatCommandContribution, RawChatParticipantLocation } from './chatParticipantContribTypes.js'; +import { IRawChatCommandContribution } from './chatParticipantContribTypes.js'; import { IChatFollowup, IChatLocationData, IChatProgress, IChatResponseErrorDetails, IChatTaskDto } from './chatService.js'; -import { ChatMode } from './constants.js'; +import { ChatAgentLocation, ChatMode } from './constants.js'; //#region agent service, commands etc @@ -37,27 +37,6 @@ export interface IChatAgentHistoryEntry { result: IChatAgentResult; } -export enum ChatAgentLocation { - Panel = 'panel', - Terminal = 'terminal', - Notebook = 'notebook', - Editor = 'editor', - EditingSession = 'editing-session', -} - -export namespace ChatAgentLocation { - export function fromRaw(value: RawChatParticipantLocation | string): ChatAgentLocation { - switch (value) { - case 'panel': return ChatAgentLocation.Panel; - case 'terminal': return ChatAgentLocation.Terminal; - case 'notebook': return ChatAgentLocation.Notebook; - case 'editor': return ChatAgentLocation.Editor; - case 'editing-session': return ChatAgentLocation.EditingSession; - } - return ChatAgentLocation.Panel; - } -} - export interface IChatAgentData { id: string; name: string; @@ -400,8 +379,12 @@ export class ChatAgentService extends Disposable implements IChatAgentService { } getDefaultAgent(location: ChatAgentLocation, mode?: ChatMode): IChatAgent | undefined { + if (mode === ChatMode.Edit || mode === ChatMode.Agent) { + location = ChatAgentLocation.EditingSession; + } + return findLast(this.getActivatedAgents(), a => { - if (location === ChatAgentLocation.EditingSession && ((mode === ChatMode.Agent) !== !!a.isToolsAgent)) { + if ((mode === ChatMode.Agent) !== !!a.isToolsAgent) { return false; } @@ -765,3 +748,4 @@ export function reviveSerializedAgent(raw: ISerializableChatAgentData): IChatAge return revive(agent); } +export { ChatAgentLocation }; diff --git a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts index b88c1ac7673e8..b435f0ce1b714 100644 --- a/src/vs/workbench/contrib/chat/common/chatContextKeys.ts +++ b/src/vs/workbench/contrib/chat/common/chatContextKeys.ts @@ -7,7 +7,7 @@ import { localize } from '../../../../nls.js'; import { ContextKeyExpr, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { IsWebContext } from '../../../../platform/contextkey/common/contextkeys.js'; import { RemoteNameContext } from '../../../common/contextkeys.js'; -import { ChatAgentLocation } from './chatAgents.js'; +import { ChatAgentLocation, ChatConfiguration } from './constants.js'; export namespace ChatContextKeys { export const responseVote = new RawContextKey('chatSessionResponseVote', '', { type: 'string', description: localize('interactiveSessionResponseVote', "When the response has been voted up, is set to 'up'. When voted down, is set to 'down'. Otherwise an empty string.") }); @@ -30,6 +30,7 @@ export namespace ChatContextKeys { export const inputHasFocus = new RawContextKey('chatInputHasFocus', false, { type: 'boolean', description: localize('interactiveInputHasFocus', "True when the chat input has focus.") }); export const inChatInput = new RawContextKey('inChatInput', false, { type: 'boolean', description: localize('inInteractiveInput', "True when focus is in the chat input, false otherwise.") }); export const inChatSession = new RawContextKey('inChat', false, { type: 'boolean', description: localize('inChat', "True when focus is in the chat widget, false otherwise.") }); + export const inUnifiedChat = new RawContextKey('inUnifiedChat', false, { type: 'boolean', description: localize('inUnifiedChat', "True when focus is in the unified chat widget, false otherwise.") }); export const instructionsAttached = new RawContextKey('chatInstructionsAttached', false, { type: 'boolean', description: localize('chatInstructionsAttachedContextDescription', "True when the chat has a prompt instructions attached.") }); export const supported = ContextKeyExpr.or(IsWebContext.toNegated(), RemoteNameContext.notEqualsTo('')); // supported on desktop and in web only with a remote connection @@ -87,3 +88,11 @@ export namespace ChatContextKeys { hasToolConfirmation: new RawContextKey('chatHasToolConfirmation', false, { type: 'boolean', description: localize('chatEditingHasToolConfirmation', "True when a tool confirmation is present.") }), }; } + +export namespace ChatContextKeyExprs { + export const unifiedChatEnabled = ContextKeyExpr.has(`config.${ChatConfiguration.UnifiedChatView}`); + + export const inEditsOrUnified = ContextKeyExpr.or( + ChatContextKeys.location.isEqualTo(ChatAgentLocation.EditingSession), + ChatContextKeys.inUnifiedChat); +} diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 5fcbad47af104..8e0a33440ade6 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -24,10 +24,11 @@ import { localize } from '../../../../nls.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { IMarker, MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommon.js'; -import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, IChatWelcomeMessageContent, reviveSerializedAgent } from './chatAgents.js'; +import { IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, IChatWelcomeMessageContent, reviveSerializedAgent } from './chatAgents.js'; import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js'; import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatNotebookEdit, IChatProgress, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js'; import { IChatRequestVariableValue } from './chatVariables.js'; +import { ChatAgentLocation } from './constants.js'; export interface IBaseChatRequestVariableEntry { id: string; diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index 164b87785ef82..2542fa4ca6742 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -7,10 +7,11 @@ import { revive } from '../../../../base/common/marshalling.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { IOffsetRange, OffsetRange } from '../../../../editor/common/core/offsetRange.js'; import { IRange } from '../../../../editor/common/core/range.js'; -import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentService, reviveSerializedAgent } from './chatAgents.js'; +import { IChatAgentCommand, IChatAgentData, IChatAgentService, reviveSerializedAgent } from './chatAgents.js'; import { IChatRequestVariableEntry, IDiagnosticVariableEntryFilterData } from './chatModel.js'; import { IChatSlashData } from './chatSlashCommands.js'; import { IChatRequestProblemsVariable, IChatRequestVariableValue } from './chatVariables.js'; +import { ChatAgentLocation } from './constants.js'; import { IToolData } from './languageModelToolsService.js'; // These are in a separate file to avoid circular dependencies with the dependencies of the parser diff --git a/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts b/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts index 401211b3c4f14..92549dc2480d9 100644 --- a/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParticipantContribTypes.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { RawChatParticipantLocation } from './constants.js'; + export interface IRawChatCommandContribution { name: string; description: string; @@ -13,8 +15,6 @@ export interface IRawChatCommandContribution { disambiguation?: { category: string; categoryName?: string /** Deprecated */; description: string; examples: string[] }[]; } -export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook' | 'editing-session'; - export interface IRawChatParticipantContribution { id: string; name: string; diff --git a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts index c6359f5c4ff54..3050adba33e92 100644 --- a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts +++ b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts @@ -6,11 +6,11 @@ import { OffsetRange } from '../../../../editor/common/core/offsetRange.js'; import { IPosition, Position } from '../../../../editor/common/core/position.js'; import { Range } from '../../../../editor/common/core/range.js'; -import { ChatAgentLocation, IChatAgentData, IChatAgentService } from './chatAgents.js'; +import { IChatAgentData, IChatAgentService } from './chatAgents.js'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicVariablePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestToolPart, IParsedChatRequest, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from './chatParserTypes.js'; import { IChatSlashCommandService } from './chatSlashCommands.js'; import { IChatVariablesService, IDynamicVariable } from './chatVariables.js'; -import { ChatMode } from './constants.js'; +import { ChatAgentLocation, ChatMode } from './constants.js'; import { ILanguageModelToolsService } from './languageModelToolsService.js'; const agentReg = /^@([\w_\-\.]+)(?=(\s|$|\b))/i; // An @-agent diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index e777a648233d9..0c0e740731dff 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -16,12 +16,12 @@ import { FileType } from '../../../../platform/files/common/files.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { ICellEditOperation } from '../../notebook/common/notebookCommon.js'; import { IWorkspaceSymbol } from '../../search/common/search.js'; -import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentResult } from './chatAgents.js'; +import { IChatAgentCommand, IChatAgentData, IChatAgentResult } from './chatAgents.js'; import { ChatModel, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatRequestVariableEntry, IChatResponseModel, IExportableChatData, ISerializableChatData } from './chatModel.js'; import { IParsedChatRequest } from './chatParserTypes.js'; import { IChatParserContext } from './chatRequestParser.js'; import { IChatRequestVariableValue } from './chatVariables.js'; -import { ChatMode } from './constants.js'; +import { ChatAgentLocation, ChatMode } from './constants.js'; import { IPreparedToolInvocation, IToolConfirmationMessages, IToolResult } from './languageModelToolsService.js'; export interface IChatRequest { @@ -507,6 +507,9 @@ export interface IChatService { onDidDisposeSession: Event<{ sessionId: string; reason: 'initializationFailed' | 'cleared' }>; transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void; + + readonly unifiedViewEnabled: boolean; + isEditingLocation(location: ChatAgentLocation): boolean; } export const KEYWORD_ACTIVIATION_SETTING_ID = 'accessibility.voice.keywordActivation'; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 86c8b630ec6e8..1111f0bae4b99 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -5,6 +5,7 @@ import { DeferredPromise } from '../../../../base/common/async.js'; import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js'; +import { memoize } from '../../../../base/common/decorators.js'; import { toErrorMessage } from '../../../../base/common/errorMessage.js'; import { ErrorNoTelemetry } from '../../../../base/common/errors.js'; import { Emitter, Event } from '../../../../base/common/event.js'; @@ -25,7 +26,7 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; -import { ChatAgentLocation, IChatAgent, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from './chatAgents.js'; +import { IChatAgent, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from './chatAgents.js'; import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData, ISerializableChatDataIn, ISerializableChatsData, normalizeSerializableChatData, toChatHistoryContent, updateRanges } from './chatModel.js'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest, chatAgentLeader, chatSubcommandLeader, getPromptText } from './chatParserTypes.js'; import { ChatRequestParser } from './chatRequestParser.js'; @@ -33,7 +34,7 @@ import { IChatCompleteResponse, IChatDetail, IChatFollowup, IChatProgress, IChat import { ChatServiceTelemetry } from './chatServiceTelemetry.js'; import { IChatSlashCommandService } from './chatSlashCommands.js'; import { IChatVariablesService } from './chatVariables.js'; -import { ChatMode } from './constants.js'; +import { ChatAgentLocation, ChatConfiguration, ChatMode } from './constants.js'; import { ChatMessageRole, IChatMessage } from './languageModels.js'; import { ILanguageModelToolsService } from './languageModelToolsService.js'; @@ -135,6 +136,11 @@ export class ChatService extends Disposable implements IChatService { private readonly _sessionFollowupCancelTokens = this._register(new DisposableMap()); private readonly _chatServiceTelemetry: ChatServiceTelemetry; + @memoize + public get unifiedViewEnabled(): boolean { + return !!this.configurationService.getValue(ChatConfiguration.UnifiedChatView); + } + constructor( @IStorageService private readonly storageService: IStorageService, @ILogService private readonly logService: ILogService, @@ -703,7 +709,7 @@ export class ChatService extends Disposable implements IChatService { } satisfies IChatAgentRequest; }; - if (this.configurationService.getValue('chat.detectParticipant.enabled') !== false && this.chatAgentService.hasChatParticipantDetectionProviders() && !agentPart && !commandPart && !agentSlashCommandPart && enableCommandDetection) { + if (this.configurationService.getValue('chat.detectParticipant.enabled') !== false && this.chatAgentService.hasChatParticipantDetectionProviders() && !agentPart && !commandPart && !agentSlashCommandPart && enableCommandDetection && options?.mode !== ChatMode.Agent && options?.mode !== ChatMode.Edit) { // We have no agent or command to scope history with, pass the full history to the participant detection provider const defaultAgentHistory = this.getHistoryEntriesFromModel(requests, model.sessionId, location, defaultAgent.id); @@ -1039,6 +1045,10 @@ export class ChatService extends Disposable implements IChatService { this.storageService.store(globalChatKey, JSON.stringify(existingRaw), StorageScope.PROFILE, StorageTarget.MACHINE); this.trace('transferChatSession', `Transferred session ${model.sessionId} to workspace ${toWorkspace.toString()}`); } + + isEditingLocation(location: ChatAgentLocation): boolean { + return location === ChatAgentLocation.EditingSession || this.unifiedViewEnabled; + } } function getCodeBlocks(text: string): string[] { diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index 2edc51c47865c..809d5637c5333 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -9,10 +9,10 @@ import { URI } from '../../../../base/common/uri.js'; import { IRange } from '../../../../editor/common/core/range.js'; import { Location } from '../../../../editor/common/languages.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; -import { ChatAgentLocation } from './chatAgents.js'; import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry, IDiagnosticVariableEntryFilterData } from './chatModel.js'; import { IParsedChatRequest } from './chatParserTypes.js'; import { IChatContentReference, IChatProgressMessage } from './chatService.js'; +import { ChatAgentLocation } from './constants.js'; export interface IChatVariableData { id: string; diff --git a/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts b/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts index 82ba4748b9997..4522c0b7bd33d 100644 --- a/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts +++ b/src/vs/workbench/contrib/chat/common/chatWidgetHistoryService.ts @@ -8,11 +8,10 @@ import { URI } from '../../../../base/common/uri.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { Memento } from '../../../common/memento.js'; -import { ChatAgentLocation } from './chatAgents.js'; import { WorkingSetEntryState } from './chatEditingService.js'; import { IChatRequestVariableEntry } from './chatModel.js'; import { CHAT_PROVIDER_ID } from './chatParticipantContribTypes.js'; -import { ChatMode } from './constants.js'; +import { ChatAgentLocation, ChatMode } from './constants.js'; export interface IChatHistoryEntry { text: string; diff --git a/src/vs/workbench/contrib/chat/common/constants.ts b/src/vs/workbench/contrib/chat/common/constants.ts index 9759e6c631686..9c42f7bc3041a 100644 --- a/src/vs/workbench/contrib/chat/common/constants.ts +++ b/src/vs/workbench/contrib/chat/common/constants.ts @@ -3,8 +3,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +export enum ChatConfiguration { + UnifiedChatView = 'chat.experimental.unifiedChatView', +} + export enum ChatMode { Chat = 'chat', Edit = 'edit', Agent = 'agent' } + +export type RawChatParticipantLocation = 'panel' | 'terminal' | 'notebook' | 'editing-session'; + +export enum ChatAgentLocation { + Panel = 'panel', + Terminal = 'terminal', + Notebook = 'notebook', + Editor = 'editor', + EditingSession = 'editing-session', +} + +export namespace ChatAgentLocation { + export function fromRaw(value: RawChatParticipantLocation | string): ChatAgentLocation { + switch (value) { + case 'panel': return ChatAgentLocation.Panel; + case 'terminal': return ChatAgentLocation.Terminal; + case 'notebook': return ChatAgentLocation.Notebook; + case 'editor': return ChatAgentLocation.Editor; + case 'editing-session': return ChatAgentLocation.EditingSession; + } + return ChatAgentLocation.Panel; + } +} diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts index 220f55e8e4e15..5fed1eb581a65 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts @@ -17,7 +17,7 @@ import { IChatEditingService } from '../../common/chatEditingService.js'; import { assertThrowsAsync, ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; import { IChatVariablesService } from '../../common/chatVariables.js'; import { MockChatVariablesService } from '../common/mockChatVariables.js'; -import { ChatAgentLocation, ChatAgentService, IChatAgentImplementation, IChatAgentService } from '../../common/chatAgents.js'; +import { ChatAgentService, IChatAgentImplementation, IChatAgentService } from '../../common/chatAgents.js'; import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; import { IWorkbenchAssignmentService } from '../../../../services/assignment/common/assignmentService.js'; import { NullWorkbenchAssignmentService } from '../../../../services/assignment/test/common/nullAssignmentService.js'; @@ -31,6 +31,7 @@ import { isEqual } from '../../../../../base/common/resources.js'; import { waitForState } from '../../../../../base/common/observable.js'; import { INotebookService } from '../../../notebook/common/notebookService.js'; import { Range } from '../../../../../editor/common/core/range.js'; +import { ChatAgentLocation } from '../../common/constants.js'; function getAgentData(id: string) { return { diff --git a/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts b/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts index b8e38fcb6cef4..9f5444ca5cdf5 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatModel.test.ts @@ -16,11 +16,12 @@ import { TestInstantiationService } from '../../../../../platform/instantiation/ import { MockContextKeyService } from '../../../../../platform/keybinding/test/common/mockKeybindingService.js'; import { ILogService, NullLogService } from '../../../../../platform/log/common/log.js'; import { IStorageService } from '../../../../../platform/storage/common/storage.js'; -import { ChatAgentLocation, ChatAgentService, IChatAgentService } from '../../common/chatAgents.js'; +import { ChatAgentService, IChatAgentService } from '../../common/chatAgents.js'; import { ChatModel, ISerializableChatData1, ISerializableChatData2, ISerializableChatData3, normalizeSerializableChatData, Response } from '../../common/chatModel.js'; import { ChatRequestTextPart } from '../../common/chatParserTypes.js'; import { IExtensionService } from '../../../../services/extensions/common/extensions.js'; import { TestExtensionService, TestStorageService } from '../../../../test/common/workbenchTestServices.js'; +import { ChatAgentLocation } from '../../common/constants.js'; suite('ChatModel', () => { const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); diff --git a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts index 8334b23f3baa3..8f950258be99c 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts @@ -20,7 +20,7 @@ import { IStorageService } from '../../../../../platform/storage/common/storage. import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js'; import { NullTelemetryService } from '../../../../../platform/telemetry/common/telemetryUtils.js'; import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js'; -import { ChatAgentLocation, ChatAgentService, IChatAgent, IChatAgentImplementation, IChatAgentService } from '../../common/chatAgents.js'; +import { ChatAgentService, IChatAgent, IChatAgentImplementation, IChatAgentService } from '../../common/chatAgents.js'; import { IChatModel, ISerializableChatData } from '../../common/chatModel.js'; import { IChatFollowup, IChatService } from '../../common/chatService.js'; import { ChatService } from '../../common/chatServiceImpl.js'; @@ -34,6 +34,7 @@ import { IExtensionService, nullExtensionDescription } from '../../../../service import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { TestContextService, TestExtensionService, TestStorageService } from '../../../../test/common/workbenchTestServices.js'; import { MarkdownString } from '../../../../../base/common/htmlContent.js'; +import { ChatAgentLocation } from '../../common/constants.js'; const chatAgentWithUsedContextId = 'ChatProviderWithUsedContext'; const chatAgentWithUsedContext: IChatAgent = { diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatService.ts b/src/vs/workbench/contrib/chat/test/common/mockChatService.ts index 4797a66c721c3..df0c99daaf4ce 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatService.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatService.ts @@ -90,4 +90,9 @@ export class MockChatService implements IChatService { setChatSessionTitle(sessionId: string, title: string): void { throw new Error('Method not implemented.'); } + + unifiedViewEnabled = false; + isEditingLocation(location: ChatAgentLocation): boolean { + throw new Error('Method not implemented.'); + } } diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts index 9a59dc5e5ed9a..267af76a9f11c 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ChatAgentLocation } from '../../common/chatAgents.js'; import { IChatRequestVariableData, IChatRequestVariableEntry } from '../../common/chatModel.js'; import { IParsedChatRequest } from '../../common/chatParserTypes.js'; import { IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; +import { ChatAgentLocation } from '../../common/constants.js'; export class MockChatVariablesService implements IChatVariablesService { _serviceBrand: undefined; diff --git a/src/vs/workbench/contrib/codeEditor/browser/emptyTextEditorHint/emptyTextEditorHint.ts b/src/vs/workbench/contrib/codeEditor/browser/emptyTextEditorHint/emptyTextEditorHint.ts index 540a6deec5f7d..e8aedfe3cc5e8 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/emptyTextEditorHint/emptyTextEditorHint.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/emptyTextEditorHint/emptyTextEditorHint.ts @@ -33,9 +33,10 @@ import { LOG_MODE_ID, OUTPUT_MODE_ID } from '../../../../services/output/common/ import { SEARCH_RESULT_LANGUAGE_ID } from '../../../../services/search/common/search.js'; import { getDefaultHoverDelegate } from '../../../../../base/browser/ui/hover/hoverDelegateFactory.js'; import { IHoverService } from '../../../../../platform/hover/browser/hover.js'; -import { ChatAgentLocation, IChatAgent, IChatAgentService } from '../../../chat/common/chatAgents.js'; +import { IChatAgent, IChatAgentService } from '../../../chat/common/chatAgents.js'; import { IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js'; import { StandardMouseEvent } from '../../../../../base/browser/mouseEvent.js'; +import { ChatAgentLocation } from '../../../chat/common/constants.js'; const $ = dom.$; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index b42f3ded57611..e9181c51ce08a 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -41,9 +41,6 @@ import { IEditorService, SIDE_GROUP } from '../../../services/editor/common/edit import { IViewsService } from '../../../services/views/common/viewsService.js'; import { showChatView } from '../../chat/browser/chat.js'; import { IChatWidgetLocationOptions } from '../../chat/browser/chatWidget.js'; -import { ChatAgentLocation } from '../../chat/common/chatAgents.js'; -import { ChatContextKeys } from '../../chat/common/chatContextKeys.js'; -import { IChatEditingService, WorkingSetEntryState } from '../../chat/common/chatEditingService.js'; import { ChatModel, ChatRequestRemovalReason, IChatRequestModel, IChatTextEditGroup, IChatTextEditGroupState, IResponse } from '../../chat/common/chatModel.js'; import { IChatService } from '../../chat/common/chatService.js'; import { INotebookEditorService } from '../../notebook/browser/services/notebookEditorService.js'; @@ -54,6 +51,9 @@ import { InlineChatError } from './inlineChatSessionServiceImpl.js'; import { HunkAction, IEditObserver, LiveStrategy, ProgressingEditsOptions } from './inlineChatStrategies.js'; import { EditorBasedInlineChatWidget } from './inlineChatWidget.js'; import { InlineChatZoneWidget } from './inlineChatZoneWidget.js'; +import { ChatAgentLocation } from '../../chat/common/constants.js'; +import { ChatContextKeys } from '../../chat/common/chatContextKeys.js'; +import { IChatEditingService, WorkingSetEntryState } from '../../chat/common/chatEditingService.js'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts index f2d8cc86365bc..5e2024222e7f4 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts @@ -49,7 +49,7 @@ import { IChatVariablesService } from '../../../chat/common/chatVariables.js'; import { IChatWidgetHistoryService, ChatWidgetHistoryService } from '../../../chat/common/chatWidgetHistoryService.js'; import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { TestExtensionService, TestContextService } from '../../../../test/common/workbenchTestServices.js'; -import { IChatAgentService, ChatAgentService, ChatAgentLocation } from '../../../chat/common/chatAgents.js'; +import { IChatAgentService, ChatAgentService } from '../../../chat/common/chatAgents.js'; import { ChatVariablesService } from '../../../chat/browser/chatVariables.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; import { TestCommandService } from '../../../../../editor/test/browser/editorTestServices.js'; @@ -62,6 +62,7 @@ import { IChatRequestModel } from '../../../chat/common/chatModel.js'; import { assertSnapshot } from '../../../../../base/test/common/snapshot.js'; import { IObservable, constObservable } from '../../../../../base/common/observable.js'; import { IChatEditingService, IChatEditingSession } from '../../../chat/common/chatEditingService.js'; +import { ChatAgentLocation } from '../../../chat/common/constants.js'; suite('InlineChatSession', function () { diff --git a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts index 91607d1621daf..c2f474c103994 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebook.chat.contribution.ts @@ -23,7 +23,8 @@ import { IChatWidget, IChatWidgetService } from '../../../../chat/browser/chat.j import { ChatInputPart } from '../../../../chat/browser/chatInputPart.js'; import { ChatDynamicVariableModel } from '../../../../chat/browser/contrib/chatDynamicVariables.js'; import { computeCompletionRanges } from '../../../../chat/browser/contrib/chatInputCompletions.js'; -import { ChatAgentLocation, IChatAgentService } from '../../../../chat/common/chatAgents.js'; +import { IChatAgentService } from '../../../../chat/common/chatAgents.js'; +import { ChatAgentLocation } from '../../../../chat/common/constants.js'; import { ChatContextKeys } from '../../../../chat/common/chatContextKeys.js'; import { IChatRequestPasteVariableEntry } from '../../../../chat/common/chatModel.js'; import { chatVariableLeader } from '../../../../chat/common/chatParserTypes.js'; diff --git a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts index fd3cd47d6781a..2296896d9d916 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController.ts @@ -29,7 +29,7 @@ import { localize } from '../../../../../../nls.js'; import { IContextKey, IContextKeyService } from '../../../../../../platform/contextkey/common/contextkey.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../../../platform/storage/common/storage.js'; -import { ChatAgentLocation } from '../../../../chat/common/chatAgents.js'; +import { ChatAgentLocation } from '../../../../chat/common/constants.js'; import { ChatModel, IChatModel } from '../../../../chat/common/chatModel.js'; import { IChatService } from '../../../../chat/common/chatService.js'; import { countWords } from '../../../../chat/common/chatWordCounter.js'; diff --git a/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts index 3ab1684b9acca..3ae6694f96466 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts @@ -32,7 +32,8 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { IWorkbenchQuickAccessConfiguration } from '../../../browser/quickaccess.js'; import { CHAT_OPEN_ACTION_ID } from '../../chat/browser/actions/chatActions.js'; import { ASK_QUICK_QUESTION_ACTION_ID } from '../../chat/browser/actions/chatQuickInputActions.js'; -import { ChatAgentLocation, IChatAgentService } from '../../chat/common/chatAgents.js'; +import { IChatAgentService } from '../../chat/common/chatAgents.js'; +import { ChatAgentLocation } from '../../chat/common/constants.js'; import { CommandInformationResult, IAiRelatedInformationService, RelatedInformationType } from '../../../services/aiRelatedInformation/common/aiRelatedInformation.js'; import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index e5b909b90e7b1..450b555b7e502 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -22,6 +22,7 @@ import { IWorkbenchEnvironmentService } from '../../../services/environment/comm import { IProductService } from '../../../../platform/product/common/productService.js'; import { IUserDataSyncEnablementService, IUserDataSyncService, SyncStatus } from '../../../../platform/userDataSync/common/userDataSync.js'; import { IUserDataSyncWorkbenchService } from '../../../services/userDataSync/common/userDataSync.js'; +import { ChatConfiguration } from '../../chat/common/constants.js'; interface IConfiguration extends IWindowsConfiguration { update?: { mode?: string }; @@ -32,6 +33,7 @@ interface IConfiguration extends IWindowsConfiguration { workbench?: { enableExperiments?: boolean }; _extensionsGallery?: { enablePPE?: boolean }; accessibility?: { verbosity?: { debug?: boolean } }; + chat?: { experimental?: { unifiedChatView?: boolean } }; } export class SettingsChangeRelauncher extends Disposable implements IWorkbenchContribution { @@ -48,7 +50,8 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo 'workbench.enableExperiments', '_extensionsGallery.enablePPE', 'security.restrictUNCAccess', - 'accessibility.verbosity.debug' + 'accessibility.verbosity.debug', + ChatConfiguration.UnifiedChatView ]; private readonly titleBarStyle = new ChangeObserver('string'); @@ -63,6 +66,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private readonly enablePPEExtensionsGallery = new ChangeObserver('boolean'); private readonly restrictUNCAccess = new ChangeObserver('boolean'); private readonly accessibilityVerbosityDebug = new ChangeObserver('boolean'); + private readonly unifiedChatView = new ChangeObserver('boolean'); constructor( @IHostService private readonly hostService: IHostService, @@ -141,6 +145,9 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo // Debug accessibility verbosity processChanged(this.accessibilityVerbosityDebug.handleChange(config?.accessibility?.verbosity?.debug)); + + // Unified chat view + processChanged(this.unifiedChatView.handleChange(config.chat?.experimental?.unifiedChatView)); } // Experiments diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts index b2be6193f47cb..25cbfeec6892d 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatWidget.ts @@ -12,7 +12,6 @@ import './media/terminalChatWidget.css'; import { localize } from '../../../../../nls.js'; import { IContextKey, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { ChatAgentLocation } from '../../../chat/common/chatAgents.js'; import { InlineChatWidget } from '../../../inlineChat/browser/inlineChatWidget.js'; import { ITerminalInstance, type IXtermTerminal } from '../../../terminal/browser/terminal.js'; import { MENU_TERMINAL_CHAT_WIDGET_INPUT_SIDE_TOOLBAR, MENU_TERMINAL_CHAT_WIDGET_STATUS, TerminalChatCommandId, TerminalChatContextKeys } from './terminalChat.js'; @@ -28,6 +27,7 @@ import { CancellationTokenSource } from '../../../../../base/common/cancellation import { MenuId } from '../../../../../platform/actions/common/actions.js'; import type { IChatViewState } from '../../../chat/browser/chatWidget.js'; import { autorun, observableValue, type IObservable } from '../../../../../base/common/observable.js'; +import { ChatAgentLocation } from '../../../chat/common/constants.js'; const enum Constants { HorizontalMargin = 10,