Path: blob/main/src/vs/workbench/contrib/chat/browser/chat.contribution.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { timeout } from '../../../../base/common/async.js';6import { Event } from '../../../../base/common/event.js';7import { MarkdownString, isMarkdownString } from '../../../../base/common/htmlContent.js';8import { Disposable } from '../../../../base/common/lifecycle.js';9import { Schemas } from '../../../../base/common/network.js';10import { isMacintosh } from '../../../../base/common/platform.js';11import { assertDefined } from '../../../../base/common/types.js';12import { registerEditorFeature } from '../../../../editor/common/editorFeatures.js';13import * as nls from '../../../../nls.js';14import { AccessibleViewRegistry } from '../../../../platform/accessibility/browser/accessibleViewRegistry.js';15import { registerAction2 } from '../../../../platform/actions/common/actions.js';16import { ICommandService } from '../../../../platform/commands/common/commands.js';17import { Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationNode, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';18import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';19import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';20import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';21import { McpAccessValue, McpAutoStartValue, mcpAccessConfig, mcpAutoStartConfig, mcpGalleryServiceUrlConfig } from '../../../../platform/mcp/common/mcpManagement.js';22import { Registry } from '../../../../platform/registry/common/platform.js';23import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';24import { Extensions, IConfigurationMigrationRegistry } from '../../../common/configuration.js';25import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';26import { EditorExtensions, IEditorFactoryRegistry } from '../../../common/editor.js';27import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js';28import { IEditorResolverService, RegisteredEditorPriority } from '../../../services/editor/common/editorResolverService.js';29import { AddConfigurationType, AssistedTypes } from '../../mcp/browser/mcpCommandsAddConfiguration.js';30import { allDiscoverySources, discoverySourceSettingsLabel, mcpDiscoverySection, mcpServerSamplingSection } from '../../mcp/common/mcpConfiguration.js';31import { ChatAgentNameService, ChatAgentService, IChatAgentNameService, IChatAgentService } from '../common/chatAgents.js';32import { CodeMapperService, ICodeMapperService } from '../common/chatCodeMapperService.js';33import '../common/chatColors.js';34import { IChatEditingService } from '../common/chatEditingService.js';35import { ChatEntitlement, ChatEntitlementService, IChatEntitlementService } from '../common/chatEntitlementService.js';36import { ChatModeService, IChatModeService } from '../common/chatModes.js';37import { ChatResponseResourceFileSystemProvider } from '../common/chatResponseResourceFileSystemProvider.js';38import { IChatService } from '../common/chatService.js';39import { ChatService } from '../common/chatServiceImpl.js';40import { ChatSlashCommandService, IChatSlashCommandService } from '../common/chatSlashCommands.js';41import { ChatTodoListService, IChatTodoListService } from '../common/chatTodoListService.js';42import { ChatTransferService, IChatTransferService } from '../common/chatTransferService.js';43import { IChatVariablesService } from '../common/chatVariables.js';44import { ChatWidgetHistoryService, IChatWidgetHistoryService } from '../common/chatWidgetHistoryService.js';45import { ChatAgentLocation, ChatConfiguration, ChatModeKind } from '../common/constants.js';46import { ILanguageModelIgnoredFilesService, LanguageModelIgnoredFilesService } from '../common/ignoredFiles.js';47import { ILanguageModelsService, LanguageModelsService } from '../common/languageModels.js';48import { ILanguageModelStatsService, LanguageModelStatsService } from '../common/languageModelStats.js';49import { ILanguageModelToolsService } from '../common/languageModelToolsService.js';50import { PromptsConfig } from '../common/promptSyntax/config/config.js';51import { INSTRUCTIONS_DEFAULT_SOURCE_FOLDER, INSTRUCTION_FILE_EXTENSION, MODE_DEFAULT_SOURCE_FOLDER, MODE_FILE_EXTENSION, PROMPT_DEFAULT_SOURCE_FOLDER, PROMPT_FILE_EXTENSION } from '../common/promptSyntax/config/promptFileLocations.js';52import { registerPromptFileContributions } from '../common/promptSyntax/promptFileContributions.js';53import { INSTRUCTIONS_DOCUMENTATION_URL, MODE_DOCUMENTATION_URL, PROMPT_DOCUMENTATION_URL } from '../common/promptSyntax/promptTypes.js';54import { IPromptsService } from '../common/promptSyntax/service/promptsService.js';55import { PromptsService } from '../common/promptSyntax/service/promptsServiceImpl.js';56import { LanguageModelToolsExtensionPointHandler } from '../common/tools/languageModelToolsContribution.js';57import { BuiltinToolsContribution } from '../common/tools/tools.js';58import { IVoiceChatService, VoiceChatService } from '../common/voiceChatService.js';59import { AgentChatAccessibilityHelp, EditsChatAccessibilityHelp, PanelChatAccessibilityHelp, QuickChatAccessibilityHelp } from './actions/chatAccessibilityHelp.js';60import { registerChatAccessibilityActions } from './actions/chatAccessibilityActions.js';61import { ACTION_ID_NEW_CHAT, CopilotTitleBarMenuRendering, registerChatActions } from './actions/chatActions.js';62import { registerNewChatActions } from './actions/chatClearActions.js';63import { CodeBlockActionRendering, registerChatCodeBlockActions, registerChatCodeCompareBlockActions } from './actions/chatCodeblockActions.js';64import { ChatContextContributions } from './actions/chatContext.js';65import { registerChatContextActions } from './actions/chatContextActions.js';66import { registerChatCopyActions } from './actions/chatCopyActions.js';67import { registerChatDeveloperActions } from './actions/chatDeveloperActions.js';68import { ChatSubmitAction, registerChatExecuteActions } from './actions/chatExecuteActions.js';69import { registerChatFileTreeActions } from './actions/chatFileTreeActions.js';70import { ChatGettingStartedContribution } from './actions/chatGettingStarted.js';71import { registerChatExportActions } from './actions/chatImportExport.js';72import { registerLanguageModelActions } from './actions/chatLanguageModelActions.js';73import { registerMoveActions } from './actions/chatMoveActions.js';74import { registerQuickChatActions } from './actions/chatQuickInputActions.js';75import { registerChatTitleActions } from './actions/chatTitleActions.js';76import { registerChatToolActions } from './actions/chatToolActions.js';77import { ChatTransferContribution } from './actions/chatTransfer.js';78import { IChatAccessibilityService, IChatCodeBlockContextProviderService, IChatWidgetService, IQuickChatService } from './chat.js';79import { ChatAccessibilityService } from './chatAccessibilityService.js';80import './chatAttachmentModel.js';81import { ChatAttachmentResolveService, IChatAttachmentResolveService } from './chatAttachmentResolveService.js';82import { ChatMarkdownAnchorService, IChatMarkdownAnchorService } from './chatContentParts/chatMarkdownAnchorService.js';83import { ChatContextPickService, IChatContextPickService } from './chatContextPickService.js';84import { ChatInputBoxContentProvider } from './chatEdinputInputContentProvider.js';85import { ChatEditingEditorAccessibility } from './chatEditing/chatEditingEditorAccessibility.js';86import { registerChatEditorActions } from './chatEditing/chatEditingEditorActions.js';87import { ChatEditingEditorContextKeys } from './chatEditing/chatEditingEditorContextKeys.js';88import { ChatEditingEditorOverlay } from './chatEditing/chatEditingEditorOverlay.js';89import { ChatEditingService } from './chatEditing/chatEditingServiceImpl.js';90import { ChatEditingNotebookFileSystemProviderContrib } from './chatEditing/notebook/chatEditingNotebookFileSystemProvider.js';91import { SimpleBrowserOverlay } from './chatEditing/simpleBrowserEditorOverlay.js';92import { ChatEditor, IChatEditorOptions } from './chatEditor.js';93import { ChatEditorInput, ChatEditorInputSerializer } from './chatEditorInput.js';94import { agentSlashCommandToMarkdown, agentToMarkdown } from './chatMarkdownDecorationsRenderer.js';95import { ChatOutputRendererService, IChatOutputRendererService } from './chatOutputItemRenderer.js';96import { ChatCompatibilityNotifier, ChatExtensionPointHandler } from './chatParticipant.contribution.js';97import { ChatPasteProvidersFeature } from './chatPasteProviders.js';98import { QuickChatService } from './chatQuick.js';99import { ChatResponseAccessibleView } from './chatResponseAccessibleView.js';100import { ChatSessionsView } from './chatSessions.js';101import { ChatSetupContribution, ChatTeardownContribution } from './chatSetup.js';102import { ChatStatusBarEntry } from './chatStatus.js';103import { ChatVariablesService } from './chatVariables.js';104import { ChatWidget, ChatWidgetService } from './chatWidget.js';105import { ChatCodeBlockContextProviderService } from './codeBlockContextProviderService.js';106import { ChatDynamicVariableModel } from './contrib/chatDynamicVariables.js';107import { ChatImplicitContextContribution } from './contrib/chatImplicitContext.js';108import './contrib/chatInputCompletions.js';109import './contrib/chatInputEditorContrib.js';110import './contrib/chatInputEditorHover.js';111import { ChatRelatedFilesContribution } from './contrib/chatInputRelatedFilesContrib.js';112import { globalAutoApproveDescription, LanguageModelToolsService } from './languageModelToolsService.js';113import './promptSyntax/promptCodingAgentActionContribution.js';114import './promptSyntax/promptToolsCodeLensProvider.js';115import { PromptUrlHandler } from './promptSyntax/promptUrlHandler.js';116import { SAVE_TO_PROMPT_ACTION_ID, SAVE_TO_PROMPT_SLASH_COMMAND_NAME } from './promptSyntax/saveToPromptAction.js';117import { ConfigureToolSets, UserToolSetsContributions } from './tools/toolSetsContribution.js';118import { ChatViewsWelcomeHandler } from './viewsWelcome/chatViewsWelcomeHandler.js';119import { RenameChatSessionAction, DeleteChatSessionAction, OpenChatSessionInNewEditorGroupAction, OpenChatSessionInSidebarAction, ToggleChatSessionsDescriptionDisplayAction } from './actions/chatSessionActions.js';120import { IChatLayoutService } from '../common/chatLayoutService.js';121import { ChatLayoutService } from './chatLayoutService.js';122123// Register configuration124const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);125configurationRegistry.registerConfiguration({126id: 'chatSidebar',127title: nls.localize('interactiveSessionConfigurationTitle', "Chat"),128type: 'object',129properties: {130'chat.fontSize': {131type: 'number',132description: nls.localize('chat.fontSize', "Controls the font size in pixels in chat messages."),133default: 13,134minimum: 6,135maximum: 100136},137'chat.fontFamily': {138type: 'string',139description: nls.localize('chat.fontFamily', "Controls the font family in chat messages."),140default: 'default'141},142'chat.editor.fontSize': {143type: 'number',144description: nls.localize('interactiveSession.editor.fontSize', "Controls the font size in pixels in chat codeblocks."),145default: isMacintosh ? 12 : 14,146},147'chat.editor.fontFamily': {148type: 'string',149description: nls.localize('interactiveSession.editor.fontFamily', "Controls the font family in chat codeblocks."),150default: 'default'151},152'chat.editor.fontWeight': {153type: 'string',154description: nls.localize('interactiveSession.editor.fontWeight', "Controls the font weight in chat codeblocks."),155default: 'default'156},157'chat.editor.wordWrap': {158type: 'string',159description: nls.localize('interactiveSession.editor.wordWrap', "Controls whether lines should wrap in chat codeblocks."),160default: 'off',161enum: ['on', 'off']162},163'chat.editor.lineHeight': {164type: 'number',165description: nls.localize('interactiveSession.editor.lineHeight', "Controls the line height in pixels in chat codeblocks. Use 0 to compute the line height from the font size."),166default: 0167},168'chat.commandCenter.enabled': {169type: 'boolean',170markdownDescription: nls.localize('chat.commandCenter.enabled', "Controls whether the command center shows a menu for actions to control chat (requires {0}).", '`#window.commandCenter#`'),171default: true172},173'chat.implicitContext.enabled': {174type: 'object',175tags: ['experimental'],176description: nls.localize('chat.implicitContext.enabled.1', "Enables automatically using the active editor as chat context for specified chat locations."),177additionalProperties: {178type: 'string',179enum: ['never', 'first', 'always'],180description: nls.localize('chat.implicitContext.value', "The value for the implicit context."),181enumDescriptions: [182nls.localize('chat.implicitContext.value.never', "Implicit context is never enabled."),183nls.localize('chat.implicitContext.value.first', "Implicit context is enabled for the first interaction."),184nls.localize('chat.implicitContext.value.always', "Implicit context is always enabled.")185]186},187default: {188'panel': 'always',189}190},191'chat.implicitContext.suggestedContext': {192type: 'boolean',193tags: ['experimental'],194markdownDescription: nls.localize('chat.implicitContext.suggestedContext', "Controls whether the new implicit context flow is shown. In Ask and Edit modes, the context will automatically be included. In Agent mode context will be suggested as an attachment. Selections are always included as context."),195default: true,196},197'chat.editing.autoAcceptDelay': {198type: 'number',199markdownDescription: nls.localize('chat.editing.autoAcceptDelay', "Delay after which changes made by chat are automatically accepted. Values are in seconds, `0` means disabled and `100` seconds is the maximum."),200default: 0,201minimum: 0,202maximum: 100203},204'chat.editing.confirmEditRequestRemoval': {205type: 'boolean',206scope: ConfigurationScope.APPLICATION,207markdownDescription: nls.localize('chat.editing.confirmEditRequestRemoval', "Whether to show a confirmation before removing a request and its associated edits."),208default: true,209},210'chat.editing.confirmEditRequestRetry': {211type: 'boolean',212scope: ConfigurationScope.APPLICATION,213markdownDescription: nls.localize('chat.editing.confirmEditRequestRetry', "Whether to show a confirmation before retrying a request and its associated edits."),214default: true,215},216'chat.experimental.detectParticipant.enabled': {217type: 'boolean',218deprecationMessage: nls.localize('chat.experimental.detectParticipant.enabled.deprecated', "This setting is deprecated. Please use `chat.detectParticipant.enabled` instead."),219description: nls.localize('chat.experimental.detectParticipant.enabled', "Enables chat participant autodetection for panel chat."),220default: null221},222'chat.detectParticipant.enabled': {223type: 'boolean',224description: nls.localize('chat.detectParticipant.enabled', "Enables chat participant autodetection for panel chat."),225default: true226},227'chat.renderRelatedFiles': {228type: 'boolean',229description: nls.localize('chat.renderRelatedFiles', "Controls whether related files should be rendered in the chat input."),230default: false231},232'chat.notifyWindowOnConfirmation': {233type: 'boolean',234description: nls.localize('chat.notifyWindowOnConfirmation', "Controls whether a chat session should notify the user when a confirmation is needed while the window is not in focus. This includes a window badge as well as notification toast."),235default: true,236},237[ChatConfiguration.GlobalAutoApprove]: {238default: false,239// HACK: Description duplicated for policy parser. See https://github.com/microsoft/vscode/issues/254526240description: nls.localize('autoApprove2.description',241'Global auto approve also known as "YOLO mode" disables manual approval completely for all tools in all workspaces, allowing the agent to act fully autonomously. This is extremely dangerous and is *never* recommended, even containerized environments like Codespaces and Dev Containers have user keys forwarded into the container that could be compromised.\n\nThis feature disables critical security protections and makes it much easier for an attacker to compromise the machine.'242),243markdownDescription: globalAutoApproveDescription.value,244type: 'boolean',245scope: ConfigurationScope.APPLICATION_MACHINE,246tags: ['experimental'],247policy: {248name: 'ChatToolsAutoApprove',249minimumVersion: '1.99',250value: (account) => account.chat_preview_features_enabled === false ? false : undefined,251}252},253[ChatConfiguration.AutoApproveEdits]: {254default: {255'**/*': true,256'**/.vscode/*.json': false,257'**/.git/**': false,258'**/{package.json,package-lock.json,server.xml,build.rs,web.config,.gitattributes,.env}': false,259'**/*.{csproj,fsproj,vbproj}': false,260},261markdownDescription: nls.localize('chat.tools.autoApprove.edits', "Controls whether edits made by chat are automatically approved. The default is to approve all edits except those made to certain files which have the potential to cause immediate unintended side-effects, such as `**/.vscode/*.json`.\n\nFiles are matched against the glob patterns in the order they are specified."),262type: 'object',263additionalProperties: {264type: 'boolean',265}266},267'chat.sendElementsToChat.enabled': {268default: true,269description: nls.localize('chat.sendElementsToChat.enabled', "Controls whether elements can be sent to chat from the Simple Browser."),270type: 'boolean',271tags: ['experimental']272},273'chat.sendElementsToChat.attachCSS': {274default: true,275markdownDescription: nls.localize('chat.sendElementsToChat.attachCSS', "Controls whether CSS of the selected element will be added to the chat. {0} must be enabled.", '`#chat.sendElementsToChat.enabled#`'),276type: 'boolean',277tags: ['experimental']278},279'chat.sendElementsToChat.attachImages': {280default: true,281markdownDescription: nls.localize('chat.sendElementsToChat.attachImages', "Controls whether a screenshot of the selected element will be added to the chat. {0} must be enabled.", '`#chat.sendElementsToChat.enabled#`'),282type: 'boolean',283tags: ['experimental']284},285'chat.undoRequests.restoreInput': {286default: true,287markdownDescription: nls.localize('chat.undoRequests.restoreInput', "Controls whether the input of the chat should be restored when an undo request is made. The input will be filled with the text of the request that was restored."),288type: 'boolean',289tags: ['experimental']290},291'chat.editRequests': {292markdownDescription: nls.localize('chat.editRequests', "Enables editing of requests in the chat. This allows you to change the request content and resubmit it to the model."),293type: 'string',294enum: ['inline', 'hover', 'input', 'none'],295default: 'inline',296},297'chat.emptyChatState.enabled': {298type: 'boolean',299default: true,300description: nls.localize('chat.emptyChatState', "Shows a modified empty chat state with hints in the input placeholder text."),301tags: ['experimental'],302experiment: {303mode: 'startup'304}305},306[ChatConfiguration.EmptyStateHistoryEnabled]: {307type: 'boolean',308default: false,309description: nls.localize('chat.emptyState.history.enabled', "Show recent chat history on the empty chat state."),310tags: ['experimental']311},312'chat.checkpoints.enabled': {313type: 'boolean',314default: true,315description: nls.localize('chat.checkpoints.enabled', "Enables checkpoints in chat. Checkpoints allow you to restore the chat to a previous state."),316},317'chat.checkpoints.showFileChanges': {318type: 'boolean',319description: nls.localize('chat.checkpoints.showFileChanges', "Controls whether to show chat checkpoint file changes."),320default: false321},322[mcpAccessConfig]: {323type: 'string',324description: nls.localize('chat.mcp.access', "Controls access to Model Context Protocol servers."),325enum: [326McpAccessValue.None,327McpAccessValue.Registry,328McpAccessValue.All329],330enumDescriptions: [331nls.localize('chat.mcp.access.none', "No access to MCP servers."),332nls.localize('chat.mcp.access.registry', "Only allow access to MCP servers from the registry."),333nls.localize('chat.mcp.access.any', "Allow access to any MCP server.")334],335default: McpAccessValue.All,336policy: {337name: 'ChatMCP',338minimumVersion: '1.99',339value: (account) => {340if (account.mcp === false) {341return McpAccessValue.None;342}343if (account.mcpAccess === 'registry_only') {344return McpAccessValue.Registry;345}346return undefined;347},348}349},350[mcpAutoStartConfig]: {351type: 'string',352description: nls.localize('chat.mcp.autostart', "Controls whether MCP servers should be automatically started when the chat messages are submitted."),353default: McpAutoStartValue.Never,354enum: [355McpAutoStartValue.Never,356McpAutoStartValue.OnlyNew,357McpAutoStartValue.NewAndOutdated358],359enumDescriptions: [360nls.localize('chat.mcp.autostart.never', "Never automatically start MCP servers."),361nls.localize('chat.mcp.autostart.onlyNew', "Only automatically start new MCP servers that have never been run."),362nls.localize('chat.mcp.autostart.newAndOutdated', "Automatically start new and outdated MCP servers that are not yet running.")363],364tags: ['experimental'],365},366[mcpServerSamplingSection]: {367type: 'object',368description: nls.localize('chat.mcp.serverSampling', "Configures which models are exposed to MCP servers for sampling (making model requests in the background). This setting can be edited in a graphical way under the `{0}` command.", 'MCP: ' + nls.localize('mcp.list', 'List Servers')),369scope: ConfigurationScope.RESOURCE,370additionalProperties: {371type: 'object',372properties: {373allowedDuringChat: {374type: 'boolean',375description: nls.localize('chat.mcp.serverSampling.allowedDuringChat', "Whether this server is make sampling requests during its tool calls in a chat session."),376default: true,377},378allowedOutsideChat: {379type: 'boolean',380description: nls.localize('chat.mcp.serverSampling.allowedOutsideChat', "Whether this server is allowed to make sampling requests outside of a chat session."),381default: false,382},383allowedModels: {384type: 'array',385items: {386type: 'string',387description: nls.localize('chat.mcp.serverSampling.model', "A model the MCP server has access to."),388},389}390}391},392},393[AssistedTypes[AddConfigurationType.NuGetPackage].enabledConfigKey]: {394type: 'boolean',395description: nls.localize('chat.mcp.assisted.nuget.enabled.description', "Enables NuGet packages for AI-assisted MCP server installation. Used to install MCP servers by name from the central registry for .NET packages (NuGet.org)."),396default: false,397tags: ['experimental'],398experiment: {399mode: 'startup'400}401},402[ChatConfiguration.UseFileStorage]: {403type: 'boolean',404description: nls.localize('chat.useFileStorage', "Enables storing chat sessions on disk instead of in the storage service. Enabling this does a one-time per-workspace migration of existing sessions to the new format."),405default: true,406tags: ['experimental'],407},408[ChatConfiguration.Edits2Enabled]: {409type: 'boolean',410description: nls.localize('chat.edits2Enabled', "Enable the new Edits mode that is based on tool-calling. When this is enabled, models that don't support tool-calling are unavailable for Edits mode."),411default: false,412},413[ChatConfiguration.ExtensionToolsEnabled]: {414type: 'boolean',415description: nls.localize('chat.extensionToolsEnabled', "Enable using tools contributed by third-party extensions."),416default: true,417policy: {418name: 'ChatAgentExtensionTools',419minimumVersion: '1.99',420description: nls.localize('chat.extensionToolsPolicy', "Enable using tools contributed by third-party extensions."),421}422},423[ChatConfiguration.AgentEnabled]: {424type: 'boolean',425description: nls.localize('chat.agent.enabled.description', "Enable agent mode for chat. When this is enabled, agent mode can be activated via the dropdown in the view."),426default: true,427policy: {428name: 'ChatAgentMode',429minimumVersion: '1.99',430value: (account) => account.chat_agent_enabled === false ? false : undefined,431}432},433[ChatConfiguration.EnableMath]: {434type: 'boolean',435description: nls.localize('chat.mathEnabled.description', "Enable math rendering in chat responses using KaTeX."),436default: true,437tags: ['preview'],438},439[ChatConfiguration.AgentSessionsViewLocation]: {440type: 'string',441enum: ['disabled', 'view'],442description: nls.localize('chat.sessionsViewLocation.description', "Controls where to show the agent sessions menu."),443default: 'disabled',444tags: ['experimental'],445experiment: {446mode: 'auto'447}448},449[mcpDiscoverySection]: {450type: 'object',451properties: Object.fromEntries(allDiscoverySources.map(k => [k, { type: 'boolean', description: discoverySourceSettingsLabel[k] }])),452additionalProperties: false,453default: Object.fromEntries(allDiscoverySources.map(k => [k, false])),454markdownDescription: nls.localize('mcp.discovery.enabled', "Configures discovery of Model Context Protocol servers from configuration from various other applications."),455},456[mcpGalleryServiceUrlConfig]: {457type: 'string',458description: nls.localize('mcp.gallery.serviceUrl', "Configure the MCP Gallery service URL to connect to"),459default: '',460scope: ConfigurationScope.APPLICATION,461tags: ['usesOnlineServices'],462included: false,463policy: {464name: 'McpGalleryServiceUrl',465minimumVersion: '1.101',466value: (account) => account.mcpRegistryUrl467},468},469[PromptsConfig.KEY]: {470type: 'boolean',471title: nls.localize(472'chat.reusablePrompts.config.enabled.title',473"Prompt Files",474),475markdownDescription: nls.localize(476'chat.reusablePrompts.config.enabled.description',477"Enable reusable prompt (`*{0}`) and instruction files (`*{1}`) in Chat sessions. [Learn More]({2}).",478PROMPT_FILE_EXTENSION,479INSTRUCTION_FILE_EXTENSION,480PROMPT_DOCUMENTATION_URL,481),482default: true,483restricted: true,484disallowConfigurationDefault: true,485tags: ['experimental', 'prompts', 'reusable prompts', 'prompt snippets', 'instructions'],486policy: {487name: 'ChatPromptFiles',488minimumVersion: '1.99',489description: nls.localize('chat.promptFiles.policy', "Enables reusable prompt and instruction files in Chat sessions.")490}491},492[PromptsConfig.INSTRUCTIONS_LOCATION_KEY]: {493type: 'object',494title: nls.localize(495'chat.instructions.config.locations.title',496"Instructions File Locations",497),498markdownDescription: nls.localize(499'chat.instructions.config.locations.description',500"Specify location(s) of instructions files (`*{0}`) that can be attached in Chat sessions. [Learn More]({1}).\n\nRelative paths are resolved from the root folder(s) of your workspace.",501INSTRUCTION_FILE_EXTENSION,502INSTRUCTIONS_DOCUMENTATION_URL,503),504default: {505[INSTRUCTIONS_DEFAULT_SOURCE_FOLDER]: true,506},507additionalProperties: { type: 'boolean' },508restricted: true,509tags: ['experimental', 'prompts', 'reusable prompts', 'prompt snippets', 'instructions'],510examples: [511{512[INSTRUCTIONS_DEFAULT_SOURCE_FOLDER]: true,513},514{515[INSTRUCTIONS_DEFAULT_SOURCE_FOLDER]: true,516'/Users/vscode/repos/instructions': true,517},518],519},520[PromptsConfig.PROMPT_LOCATIONS_KEY]: {521type: 'object',522title: nls.localize(523'chat.reusablePrompts.config.locations.title',524"Prompt File Locations",525),526markdownDescription: nls.localize(527'chat.reusablePrompts.config.locations.description',528"Specify location(s) of reusable prompt files (`*{0}`) that can be run in Chat sessions. [Learn More]({1}).\n\nRelative paths are resolved from the root folder(s) of your workspace.",529PROMPT_FILE_EXTENSION,530PROMPT_DOCUMENTATION_URL,531),532default: {533[PROMPT_DEFAULT_SOURCE_FOLDER]: true,534},535additionalProperties: { type: 'boolean' },536unevaluatedProperties: { type: 'boolean' },537restricted: true,538tags: ['experimental', 'prompts', 'reusable prompts', 'prompt snippets', 'instructions'],539examples: [540{541[PROMPT_DEFAULT_SOURCE_FOLDER]: true,542},543{544[PROMPT_DEFAULT_SOURCE_FOLDER]: true,545'/Users/vscode/repos/prompts': true,546},547],548},549[PromptsConfig.MODE_LOCATION_KEY]: {550type: 'object',551title: nls.localize(552'chat.mode.config.locations.title',553"Mode File Locations",554),555markdownDescription: nls.localize(556'chat.mode.config.locations.description',557"Specify location(s) of custom chat mode files (`*{0}`). [Learn More]({1}).\n\nRelative paths are resolved from the root folder(s) of your workspace.",558MODE_FILE_EXTENSION,559MODE_DOCUMENTATION_URL,560),561default: {562[MODE_DEFAULT_SOURCE_FOLDER]: true,563},564additionalProperties: { type: 'boolean' },565unevaluatedProperties: { type: 'boolean' },566restricted: true,567tags: ['experimental', 'prompts', 'reusable prompts', 'prompt snippets', 'instructions'],568examples: [569{570[MODE_DEFAULT_SOURCE_FOLDER]: true,571},572{573[MODE_DEFAULT_SOURCE_FOLDER]: true,574'/Users/vscode/repos/chatmodes': true,575},576],577},578[PromptsConfig.USE_AGENT_MD]: {579type: 'boolean',580title: nls.localize('chat.useAgentMd.title', "Use AGENTS.MD file",),581markdownDescription: nls.localize('chat.useAgentMd.description', "Controls whether instructions from `AGENTS.MD` file found in a workspace roots are added to all chat requests.",),582default: true,583restricted: true,584disallowConfigurationDefault: true,585tags: ['experimental', 'prompts', 'reusable prompts', 'prompt snippets', 'instructions']586},587[PromptsConfig.PROMPT_FILES_SUGGEST_KEY]: {588type: 'object',589title: nls.localize(590'chat.promptFilesRecommendations.title',591"Prompt File Recommendations",592),593markdownDescription: nls.localize(594'chat.promptFilesRecommendations.description',595"Configure which prompt files to recommend in the chat welcome view. Each key is a prompt file name, and the value can be `true` to always recommend, `false` to never recommend, or a [when clause](https://aka.ms/vscode-when-clause) expression like `resourceExtname == .js` or `resourceLangId == markdown`.",596),597default: {},598additionalProperties: {599oneOf: [600{ type: 'boolean' },601{ type: 'string' }602]603},604tags: ['experimental'],605examples: [606{607'plan': true,608'a11y-audit': 'resourceExtname == .html',609'document': 'resourceLangId == markdown'610}611],612},613'chat.setup.signInDialogVariant': { // TODO@bpasero remove me eventually614type: 'string',615enum: ['default', 'apple'],616description: nls.localize('chat.signInDialogVariant', "Control variations of the sign-in dialog."),617default: 'default',618tags: ['experimental'],619experiment: {620mode: 'auto'621}622},623'chat.todoListTool.enabled': {624type: 'boolean',625default: false,626description: nls.localize('chat.todoListTool.enabled', "Enables todo lists in chat, which the agent uses as a tool for planning, progress tracking, and context management for complex development workflows."),627tags: ['experimental'],628experiment: {629mode: 'auto'630}631},632'chat.todoListTool.writeOnly': {633type: 'boolean',634default: false,635description: nls.localize('chat.todoListTool.writeOnly', "When enabled, the todo tool operates in write-only mode, requiring the agent to remember todos in context."),636tags: ['experimental']637},638[ChatConfiguration.ThinkingStyle]: {639type: 'string',640default: 'collapsedPreview',641enum: ['collapsed', 'collapsedPreview', 'expanded', 'none'],642enumDescriptions: [643nls.localize('chat.agent.thinkingMode.collapsed', "Thinking parts will be collapsed by default."),644nls.localize('chat.agent.thinkingMode.collapsedPreview', "Thinking parts will be expanded first, then collapse once we reach a part that is not thinking."),645nls.localize('chat.agent.thinkingMode.expanded', "Thinking parts will be expanded by default."),646nls.localize('chat.agent.thinkingMode.none', "Do not show the thinking"),647],648description: nls.localize('chat.agent.thinkingCollapsedByDefault', "Controls how thinking is rendered."),649tags: ['experimental'],650},651'chat.disableAIFeatures': {652type: 'boolean',653description: nls.localize('chat.disableAIFeatures', "Disable and hide built-in AI features provided by GitHub Copilot, including chat, code completions and next edit suggestions."),654default: false,655scope: ConfigurationScope.WINDOW656},657[ChatConfiguration.UseChatSessionsForCloudButton]: {658type: 'boolean',659description: nls.localize('chat.useChatSessionsForCloudButton', "Controls whether the 'Delegate to coding agent' button uses the new chat sessions API."),660default: false,661tags: ['experimental'],662663},664[ChatConfiguration.ShowAgentSessionsViewDescription]: {665type: 'boolean',666description: nls.localize('chat.showAgentSessionsViewDescription', "Controls whether session descriptions are displayed on a second row in the Chat Sessions view."),667default: true,668}669}670});671Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(672EditorPaneDescriptor.create(673ChatEditor,674ChatEditorInput.EditorID,675nls.localize('chat', "Chat")676),677[678new SyncDescriptor(ChatEditorInput)679]680);681Registry.as<IConfigurationMigrationRegistry>(Extensions.ConfigurationMigration).registerConfigurationMigrations([682{683key: 'chat.experimental.detectParticipant.enabled',684migrateFn: (value, _accessor) => ([685['chat.experimental.detectParticipant.enabled', { value: undefined }],686['chat.detectParticipant.enabled', { value: value !== false }]687])688},689{690key: mcpDiscoverySection,691migrateFn: (value: unknown) => {692if (typeof value === 'boolean') {693return { value: Object.fromEntries(allDiscoverySources.map(k => [k, value])) };694}695696return { value };697}698},699]);700701class ChatResolverContribution extends Disposable {702703static readonly ID = 'workbench.contrib.chatResolver';704705constructor(706@IEditorResolverService editorResolverService: IEditorResolverService,707@IInstantiationService instantiationService: IInstantiationService,708) {709super();710711this._register(editorResolverService.registerEditor(712`{${Schemas.vscodeChatEditor},${Schemas.vscodeChatSession}}:**/**`,713{714id: ChatEditorInput.EditorID,715label: nls.localize('chat', "Chat"),716priority: RegisteredEditorPriority.builtin717},718{719singlePerResource: true,720canSupportResource: resource => resource.scheme === Schemas.vscodeChatEditor || resource.scheme === Schemas.vscodeChatSession,721},722{723createEditorInput: ({ resource, options }) => {724return { editor: instantiationService.createInstance(ChatEditorInput, resource, options as IChatEditorOptions), options };725}726}727));728}729}730731class ChatAgentSettingContribution extends Disposable implements IWorkbenchContribution {732733static readonly ID = 'workbench.contrib.chatAgentSetting';734735constructor(736@IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService,737@IChatEntitlementService private readonly entitlementService: IChatEntitlementService,738) {739super();740this.registerMaxRequestsSetting();741}742743744private registerMaxRequestsSetting(): void {745let lastNode: IConfigurationNode | undefined;746const registerMaxRequestsSetting = () => {747const treatmentId = this.entitlementService.entitlement === ChatEntitlement.Free ?748'chatAgentMaxRequestsFree' :749'chatAgentMaxRequestsPro';750this.experimentService.getTreatment<number>(treatmentId).then(value => {751const defaultValue = value ?? (this.entitlementService.entitlement === ChatEntitlement.Free ? 25 : 25);752const node: IConfigurationNode = {753id: 'chatSidebar',754title: nls.localize('interactiveSessionConfigurationTitle', "Chat"),755type: 'object',756properties: {757'chat.agent.maxRequests': {758type: 'number',759markdownDescription: nls.localize('chat.agent.maxRequests', "The maximum number of requests to allow per-turn in agent mode. When the limit is reached, will ask to confirm to continue."),760default: defaultValue,761},762}763};764configurationRegistry.updateConfigurations({ remove: lastNode ? [lastNode] : [], add: [node] });765lastNode = node;766});767};768this._register(Event.runAndSubscribe(Event.debounce(this.entitlementService.onDidChangeEntitlement, () => { }, 1000), () => registerMaxRequestsSetting()));769}770}771772AccessibleViewRegistry.register(new ChatResponseAccessibleView());773AccessibleViewRegistry.register(new PanelChatAccessibilityHelp());774AccessibleViewRegistry.register(new QuickChatAccessibilityHelp());775AccessibleViewRegistry.register(new EditsChatAccessibilityHelp());776AccessibleViewRegistry.register(new AgentChatAccessibilityHelp());777778registerEditorFeature(ChatInputBoxContentProvider);779780class ChatSlashStaticSlashCommandsContribution extends Disposable {781782static readonly ID = 'workbench.contrib.chatSlashStaticSlashCommands';783784constructor(785@IChatSlashCommandService slashCommandService: IChatSlashCommandService,786@ICommandService commandService: ICommandService,787@IChatAgentService chatAgentService: IChatAgentService,788@IChatWidgetService chatWidgetService: IChatWidgetService,789@IInstantiationService instantiationService: IInstantiationService,790) {791super();792this._store.add(slashCommandService.registerSlashCommand({793command: 'clear',794detail: nls.localize('clear', "Start a new chat"),795sortText: 'z2_clear',796executeImmediately: true,797locations: [ChatAgentLocation.Panel]798}, async () => {799commandService.executeCommand(ACTION_ID_NEW_CHAT);800}));801this._store.add(slashCommandService.registerSlashCommand({802command: SAVE_TO_PROMPT_SLASH_COMMAND_NAME,803detail: nls.localize('save-chat-to-prompt-file', "Save chat to a prompt file"),804sortText: `z3_${SAVE_TO_PROMPT_SLASH_COMMAND_NAME}`,805executeImmediately: true,806silent: true,807locations: [ChatAgentLocation.Panel]808}, async () => {809const { lastFocusedWidget } = chatWidgetService;810assertDefined(811lastFocusedWidget,812'No currently active chat widget found.',813);814const options = { chat: lastFocusedWidget };815return commandService.executeCommand(SAVE_TO_PROMPT_ACTION_ID, options,);816}));817this._store.add(slashCommandService.registerSlashCommand({818command: 'help',819detail: '',820sortText: 'z1_help',821executeImmediately: true,822locations: [ChatAgentLocation.Panel],823modes: [ChatModeKind.Ask]824}, async (prompt, progress) => {825const defaultAgent = chatAgentService.getDefaultAgent(ChatAgentLocation.Panel);826const agents = chatAgentService.getAgents();827828// Report prefix829if (defaultAgent?.metadata.helpTextPrefix) {830if (isMarkdownString(defaultAgent.metadata.helpTextPrefix)) {831progress.report({ content: defaultAgent.metadata.helpTextPrefix, kind: 'markdownContent' });832} else {833progress.report({ content: new MarkdownString(defaultAgent.metadata.helpTextPrefix), kind: 'markdownContent' });834}835progress.report({ content: new MarkdownString('\n\n'), kind: 'markdownContent' });836}837838// Report agent list839const agentText = (await Promise.all(agents840.filter(a => !a.isDefault && !a.isCore)841.filter(a => a.locations.includes(ChatAgentLocation.Panel))842.map(async a => {843const description = a.description ? `- ${a.description}` : '';844const agentMarkdown = instantiationService.invokeFunction(accessor => agentToMarkdown(a, true, accessor));845const agentLine = `- ${agentMarkdown} ${description}`;846const commandText = a.slashCommands.map(c => {847const description = c.description ? `- ${c.description}` : '';848return `\t* ${agentSlashCommandToMarkdown(a, c)} ${description}`;849}).join('\n');850851return (agentLine + '\n' + commandText).trim();852}))).join('\n');853progress.report({ content: new MarkdownString(agentText, { isTrusted: { enabledCommands: [ChatSubmitAction.ID] } }), kind: 'markdownContent' });854855// Report help text ending856if (defaultAgent?.metadata.helpTextPostfix) {857progress.report({ content: new MarkdownString('\n\n'), kind: 'markdownContent' });858if (isMarkdownString(defaultAgent.metadata.helpTextPostfix)) {859progress.report({ content: defaultAgent.metadata.helpTextPostfix, kind: 'markdownContent' });860} else {861progress.report({ content: new MarkdownString(defaultAgent.metadata.helpTextPostfix), kind: 'markdownContent' });862}863}864865// Without this, the response will be done before it renders and so it will not stream. This ensures that if the response starts866// rendering during the next 200ms, then it will be streamed. Once it starts streaming, the whole response streams even after867// it has received all response data has been received.868await timeout(200);869}));870}871}872Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(ChatEditorInput.TypeID, ChatEditorInputSerializer);873874registerWorkbenchContribution2(ChatResolverContribution.ID, ChatResolverContribution, WorkbenchPhase.BlockStartup);875registerWorkbenchContribution2(ChatSlashStaticSlashCommandsContribution.ID, ChatSlashStaticSlashCommandsContribution, WorkbenchPhase.Eventually);876registerWorkbenchContribution2(ChatExtensionPointHandler.ID, ChatExtensionPointHandler, WorkbenchPhase.BlockStartup);877registerWorkbenchContribution2(LanguageModelToolsExtensionPointHandler.ID, LanguageModelToolsExtensionPointHandler, WorkbenchPhase.BlockRestore);878registerWorkbenchContribution2(ChatCompatibilityNotifier.ID, ChatCompatibilityNotifier, WorkbenchPhase.Eventually);879registerWorkbenchContribution2(CopilotTitleBarMenuRendering.ID, CopilotTitleBarMenuRendering, WorkbenchPhase.BlockRestore);880registerWorkbenchContribution2(CodeBlockActionRendering.ID, CodeBlockActionRendering, WorkbenchPhase.BlockRestore);881registerWorkbenchContribution2(ChatImplicitContextContribution.ID, ChatImplicitContextContribution, WorkbenchPhase.Eventually);882registerWorkbenchContribution2(ChatRelatedFilesContribution.ID, ChatRelatedFilesContribution, WorkbenchPhase.Eventually);883registerWorkbenchContribution2(ChatViewsWelcomeHandler.ID, ChatViewsWelcomeHandler, WorkbenchPhase.BlockStartup);884registerWorkbenchContribution2(ChatGettingStartedContribution.ID, ChatGettingStartedContribution, WorkbenchPhase.Eventually);885registerWorkbenchContribution2(ChatSetupContribution.ID, ChatSetupContribution, WorkbenchPhase.BlockRestore);886registerWorkbenchContribution2(ChatTeardownContribution.ID, ChatTeardownContribution, WorkbenchPhase.AfterRestored);887registerWorkbenchContribution2(ChatStatusBarEntry.ID, ChatStatusBarEntry, WorkbenchPhase.BlockRestore);888registerWorkbenchContribution2(BuiltinToolsContribution.ID, BuiltinToolsContribution, WorkbenchPhase.Eventually);889registerWorkbenchContribution2(ChatAgentSettingContribution.ID, ChatAgentSettingContribution, WorkbenchPhase.AfterRestored);890registerWorkbenchContribution2(ChatEditingEditorAccessibility.ID, ChatEditingEditorAccessibility, WorkbenchPhase.AfterRestored);891registerWorkbenchContribution2(ChatEditingEditorOverlay.ID, ChatEditingEditorOverlay, WorkbenchPhase.AfterRestored);892registerWorkbenchContribution2(SimpleBrowserOverlay.ID, SimpleBrowserOverlay, WorkbenchPhase.AfterRestored);893registerWorkbenchContribution2(ChatEditingEditorContextKeys.ID, ChatEditingEditorContextKeys, WorkbenchPhase.AfterRestored);894registerWorkbenchContribution2(ChatTransferContribution.ID, ChatTransferContribution, WorkbenchPhase.BlockRestore);895registerWorkbenchContribution2(ChatContextContributions.ID, ChatContextContributions, WorkbenchPhase.AfterRestored);896registerWorkbenchContribution2(ChatResponseResourceFileSystemProvider.ID, ChatResponseResourceFileSystemProvider, WorkbenchPhase.AfterRestored);897registerWorkbenchContribution2(PromptUrlHandler.ID, PromptUrlHandler, WorkbenchPhase.BlockRestore);898registerWorkbenchContribution2(ChatSessionsView.ID, ChatSessionsView, WorkbenchPhase.AfterRestored);899registerWorkbenchContribution2(ChatEditingNotebookFileSystemProviderContrib.ID, ChatEditingNotebookFileSystemProviderContrib, WorkbenchPhase.BlockStartup);900registerWorkbenchContribution2(UserToolSetsContributions.ID, UserToolSetsContributions, WorkbenchPhase.Eventually);901902registerChatActions();903registerChatAccessibilityActions();904registerChatCopyActions();905registerChatCodeBlockActions();906registerChatCodeCompareBlockActions();907registerChatFileTreeActions();908registerChatTitleActions();909registerChatExecuteActions();910registerQuickChatActions();911registerChatExportActions();912registerMoveActions();913registerNewChatActions();914registerChatContextActions();915registerChatDeveloperActions();916registerChatEditorActions();917registerChatToolActions();918registerLanguageModelActions();919920registerEditorFeature(ChatPasteProvidersFeature);921922923registerSingleton(IChatTransferService, ChatTransferService, InstantiationType.Delayed);924registerSingleton(IChatService, ChatService, InstantiationType.Delayed);925registerSingleton(IChatWidgetService, ChatWidgetService, InstantiationType.Delayed);926registerSingleton(IQuickChatService, QuickChatService, InstantiationType.Delayed);927registerSingleton(IChatAccessibilityService, ChatAccessibilityService, InstantiationType.Delayed);928registerSingleton(IChatWidgetHistoryService, ChatWidgetHistoryService, InstantiationType.Delayed);929registerSingleton(ILanguageModelsService, LanguageModelsService, InstantiationType.Delayed);930registerSingleton(ILanguageModelStatsService, LanguageModelStatsService, InstantiationType.Delayed);931registerSingleton(IChatSlashCommandService, ChatSlashCommandService, InstantiationType.Delayed);932registerSingleton(IChatAgentService, ChatAgentService, InstantiationType.Delayed);933registerSingleton(IChatAgentNameService, ChatAgentNameService, InstantiationType.Delayed);934registerSingleton(IChatVariablesService, ChatVariablesService, InstantiationType.Delayed);935registerSingleton(ILanguageModelToolsService, LanguageModelToolsService, InstantiationType.Delayed);936registerSingleton(IVoiceChatService, VoiceChatService, InstantiationType.Delayed);937registerSingleton(IChatCodeBlockContextProviderService, ChatCodeBlockContextProviderService, InstantiationType.Delayed);938registerSingleton(ICodeMapperService, CodeMapperService, InstantiationType.Delayed);939registerSingleton(IChatEditingService, ChatEditingService, InstantiationType.Delayed);940registerSingleton(IChatMarkdownAnchorService, ChatMarkdownAnchorService, InstantiationType.Delayed);941registerSingleton(ILanguageModelIgnoredFilesService, LanguageModelIgnoredFilesService, InstantiationType.Delayed);942registerSingleton(IChatEntitlementService, ChatEntitlementService, InstantiationType.Delayed);943registerSingleton(IPromptsService, PromptsService, InstantiationType.Delayed);944registerSingleton(IChatContextPickService, ChatContextPickService, InstantiationType.Delayed);945registerSingleton(IChatModeService, ChatModeService, InstantiationType.Delayed);946registerSingleton(IChatAttachmentResolveService, ChatAttachmentResolveService, InstantiationType.Delayed);947registerSingleton(IChatTodoListService, ChatTodoListService, InstantiationType.Delayed);948registerSingleton(IChatOutputRendererService, ChatOutputRendererService, InstantiationType.Delayed);949registerSingleton(IChatLayoutService, ChatLayoutService, InstantiationType.Delayed);950951952registerPromptFileContributions();953954955registerAction2(ConfigureToolSets);956registerAction2(RenameChatSessionAction);957registerAction2(DeleteChatSessionAction);958registerAction2(OpenChatSessionInNewEditorGroupAction);959registerAction2(OpenChatSessionInSidebarAction);960registerAction2(ToggleChatSessionsDescriptionDisplayAction);961962ChatWidget.CONTRIBS.push(ChatDynamicVariableModel);963964965