From 0996c242334a55672a89464b93b9c59a5d9501fe Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 6 Feb 2025 17:25:07 -0800 Subject: [PATCH 01/12] Implement "toolIds" on chat open action --- .../chat/browser/actions/chatActions.ts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts index b7177da3eb9b2..d89a06ad7c01b 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatActions.ts @@ -37,15 +37,15 @@ import { EXTENSIONS_CATEGORY, IExtensionsWorkbenchService } from '../../../exten import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { extractAgentAndCommand } from '../../common/chatParserTypes.js'; -import { IChatQuotasService, OPEN_CHAT_QUOTA_EXCEEDED_DIALOG, quotaToButtonMessage } from '../chatQuotasService.js'; import { IChatDetail, IChatService } from '../../common/chatService.js'; -import { IChatVariablesService } from '../../common/chatVariables.js'; import { IChatRequestViewModel, IChatResponseViewModel, isRequestVM } from '../../common/chatViewModel.js'; import { IChatWidgetHistoryService } from '../../common/chatWidgetHistoryService.js'; import { CopilotUsageExtensionFeatureId } from '../../common/languageModelStats.js'; +import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; import { ChatViewId, IChatWidget, IChatWidgetService, showChatView } from '../chat.js'; import { IChatEditorOptions } from '../chatEditor.js'; import { ChatEditorInput } from '../chatEditorInput.js'; +import { IChatQuotasService, OPEN_CHAT_QUOTA_EXCEEDED_DIALOG, quotaToButtonMessage } from '../chatQuotasService.js'; import { ChatViewPane } from '../chatViewPane.js'; import { convertBufferToScreenshotVariable } from '../contrib/screenshot.js'; import { clearChatEditor } from './chatClear.js'; @@ -63,9 +63,9 @@ export interface IChatViewOpenOptions { */ isPartialQuery?: boolean; /** - * A list of simple variables that will be resolved and attached if they exist. + * A list of tools IDs with `canBeReferencedInPrompt` that will be resolved and attached if they exist. */ - variableIds?: string[]; + toolIds?: string[]; /** * Any previous chat requests and responses that should be shown in the chat view. */ @@ -112,7 +112,7 @@ class OpenChatGlobalAction extends Action2 { opts = typeof opts === 'string' ? { query: opts } : opts; const chatService = accessor.get(IChatService); - const chatVariablesService = accessor.get(IChatVariablesService); + const toolsService = accessor.get(ILanguageModelToolsService); const viewsService = accessor.get(IViewsService); const hostService = accessor.get(IHostService); @@ -138,17 +138,17 @@ class OpenChatGlobalAction extends Action2 { chatWidget.acceptInput(opts.query); } } - if (opts?.variableIds && opts.variableIds.length > 0) { - const actualVariables = chatVariablesService.getVariables(); - for (const actualVariable of actualVariables) { - if (opts.variableIds.includes(actualVariable.id)) { + if (opts?.toolIds && opts.toolIds.length > 0) { + for (const toolId of opts.toolIds) { + const tool = toolsService.getTool(toolId); + if (tool) { chatWidget.attachmentModel.addContext({ - range: undefined, - id: actualVariable.id ?? '', + id: tool.id, + name: tool.displayName, + fullName: tool.displayName, value: undefined, - fullName: actualVariable.fullName, - name: actualVariable.name, - icon: actualVariable.icon + icon: ThemeIcon.isThemeIcon(tool.icon) ? tool.icon : undefined, + isTool: true }); } } From 6bece95baf5cea1c90524f34dfab5b0712b55b8b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 6 Feb 2025 17:33:30 -0800 Subject: [PATCH 02/12] Start deleting IChatVariableService --- .../chatReferencesContentPart.ts | 10 +- .../contrib/chat/browser/chatVariables.ts | 16 --- .../browser/contrib/chatDynamicVariables.ts | 25 ++--- .../contrib/chat/common/chatAgents.ts | 1 - .../contrib/chat/common/chatVariables.ts | 3 - .../chat/test/browser/chatVariables.test.ts | 97 ----------------- .../test/common/chatRequestParser.test.ts | 100 +++++++++--------- .../chat/test/common/mockChatVariables.ts | 10 +- 8 files changed, 66 insertions(+), 196 deletions(-) delete mode 100644 src/vs/workbench/contrib/chat/test/browser/chatVariables.test.ts diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts index 04ec43faa61ad..f66b7217d5a7b 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts @@ -303,7 +303,6 @@ class CollapsibleListRenderer implements IListRenderer { - this._resolver.delete(key); - }); - } - async attachContext(name: string, value: string | URI | Location, location: ChatAgentLocation) { if (location !== ChatAgentLocation.Panel && location !== ChatAgentLocation.EditingSession) { return; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts index e25bcbb6c824b..854304dc7ebf5 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts @@ -15,18 +15,18 @@ import { ITextModelService } from '../../../../../editor/common/services/resolve import { localize } from '../../../../../nls.js'; import { Action2, registerAction2 } from '../../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; +import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { IInstantiationService, ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js'; import { ILabelService } from '../../../../../platform/label/common/label.js'; import { ILogService } from '../../../../../platform/log/common/log.js'; -import { AnythingQuickAccessProviderRunOptions, IQuickAccessOptions } from '../../../../../platform/quickinput/common/quickAccess.js'; +import { IQuickAccessOptions } from '../../../../../platform/quickinput/common/quickAccess.js'; import { IQuickInputService } from '../../../../../platform/quickinput/common/quickInput.js'; +import { ISymbolQuickPickItem } from '../../../search/browser/symbolsQuickAccess.js'; +import { IChatRequestVariableValue, IDynamicVariable } from '../../common/chatVariables.js'; +import { PromptFilesConfig } from '../../common/promptSyntax/config.js'; import { IChatWidget } from '../chat.js'; import { ChatWidget, IChatWidgetContrib } from '../chatWidget.js'; -import { IChatRequestVariableValue, IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; -import { ISymbolQuickPickItem } from '../../../search/browser/symbolsQuickAccess.js'; import { ChatFileReference } from './chatDynamicVariables/chatFileReference.js'; -import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; -import { PromptFilesConfig } from '../../common/promptSyntax/config.js'; export const dynamicVariableDecorationType = 'chat-dynamic-variable'; @@ -228,7 +228,6 @@ export class SelectAndInsertFileAction extends Action2 { const textModelService = accessor.get(ITextModelService); const logService = accessor.get(ILogService); const quickInputService = accessor.get(IQuickInputService); - const chatVariablesService = accessor.get(IChatVariablesService); const context = args[0]; if (!isSelectAndInsertActionContext(context)) { @@ -244,12 +243,14 @@ export class SelectAndInsertFileAction extends Action2 { // If we have a `files` variable, add an option to select all files in the picker. // This of course assumes that the `files` variable has the behavior that it searches // through files in the workspace. - if (chatVariablesService.hasVariable(SelectAndInsertFileAction.Name)) { - const providerOptions: AnythingQuickAccessProviderRunOptions = { - additionPicks: [SelectAndInsertFileAction.Item, { type: 'separator' }] - }; - options = { providerOptions }; - } + + // TODO This meant to include the "codebase" variable (now a tool), do we still need this? + // if (chatVariablesService.hasVariable(SelectAndInsertFileAction.Name)) { + // const providerOptions: AnythingQuickAccessProviderRunOptions = { + // additionPicks: [SelectAndInsertFileAction.Item, { type: 'separator' }] + // }; + // options = { providerOptions }; + // } // TODO: have dedicated UX for this instead of using the quick access picker const picks = await quickInputService.quickAccess.pick('', options); if (!picks?.length) { diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 2a0c9041319f5..633010ae07e51 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -145,7 +145,6 @@ export interface IChatAgentMetadata { followupPlaceholder?: string; isSticky?: boolean; requester?: IChatRequesterInformation; - supportsSlowVariables?: boolean; } diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index 170a2e133671d..91c0b6fb61f72 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from '../../../../base/common/cancellation.js'; -import { IDisposable } from '../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { URI } from '../../../../base/common/uri.js'; import { IRange } from '../../../../editor/common/core/range.js'; @@ -40,8 +39,6 @@ export const IChatVariablesService = createDecorator('ICh export interface IChatVariablesService { _serviceBrand: undefined; - registerVariable(data: IChatVariableData, resolver: IChatVariableResolver): IDisposable; - hasVariable(name: string): boolean; getVariable(name: string): IChatVariableData | undefined; getVariables(): Iterable>; getDynamicVariables(sessionId: string): ReadonlyArray; // should be its own service? diff --git a/src/vs/workbench/contrib/chat/test/browser/chatVariables.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatVariables.test.ts deleted file mode 100644 index 8d40f6310dfbd..0000000000000 --- a/src/vs/workbench/contrib/chat/test/browser/chatVariables.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import assert from 'assert'; -import { CancellationToken } from '../../../../../base/common/cancellation.js'; -import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; -import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js'; -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 { ChatVariablesService } from '../../browser/chatVariables.js'; -import { ChatAgentService, IChatAgentService } from '../../common/chatAgents.js'; -import { ChatRequestParser } from '../../common/chatRequestParser.js'; -import { IChatService } from '../../common/chatService.js'; -import { IChatVariablesService } from '../../common/chatVariables.js'; -import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; -import { MockChatWidgetService } from './mockChatWidget.js'; -import { MockChatService } from '../common/mockChatService.js'; -import { MockLanguageModelToolsService } from '../common/mockLanguageModelToolsService.js'; -import { IExtensionService } from '../../../../services/extensions/common/extensions.js'; -import { TestViewsService } from '../../../../test/browser/workbenchTestServices.js'; -import { TestExtensionService, TestStorageService } from '../../../../test/common/workbenchTestServices.js'; - -suite('ChatVariables', function () { - - let service: ChatVariablesService; - let instantiationService: TestInstantiationService; - const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); - - setup(function () { - service = new ChatVariablesService(new MockChatWidgetService(), new TestViewsService()); - instantiationService = testDisposables.add(new TestInstantiationService()); - instantiationService.stub(IStorageService, testDisposables.add(new TestStorageService())); - instantiationService.stub(ILogService, new NullLogService()); - instantiationService.stub(IExtensionService, new TestExtensionService()); - instantiationService.stub(IChatVariablesService, service); - instantiationService.stub(IChatService, new MockChatService()); - instantiationService.stub(IContextKeyService, new MockContextKeyService()); - instantiationService.stub(ILanguageModelToolsService, new MockLanguageModelToolsService()); - instantiationService.stub(IChatAgentService, testDisposables.add(instantiationService.createInstance(ChatAgentService))); - }); - - test('ChatVariables - resolveVariables', async function () { - - const v1 = service.registerVariable({ id: 'id', name: 'foo', description: 'bar' }, async () => 'farboo'); - const v2 = service.registerVariable({ id: 'id', name: 'far', description: 'boo' }, async () => 'farboo'); - - const parser = instantiationService.createInstance(ChatRequestParser); - - const resolveVariables = async (text: string) => { - const result = parser.parseChatRequest('1', text); - return await service.resolveVariables(result, undefined, null!, () => { }, CancellationToken.None); - }; - - { - const data = await resolveVariables('Hello #foo and#far'); - assert.strictEqual(data.variables.length, 1); - assert.deepEqual(data.variables.map(v => v.name), ['foo']); - } - { - const data = await resolveVariables('#foo Hello'); - assert.strictEqual(data.variables.length, 1); - assert.deepEqual(data.variables.map(v => v.name), ['foo']); - } - { - const data = await resolveVariables('Hello #foo'); - assert.strictEqual(data.variables.length, 1); - assert.deepEqual(data.variables.map(v => v.name), ['foo']); - } - { - const data = await resolveVariables('Hello #foo?'); - assert.strictEqual(data.variables.length, 1); - assert.deepEqual(data.variables.map(v => v.name), ['foo']); - } - { - const data = await resolveVariables('Hello #foo and#far #foo'); - assert.strictEqual(data.variables.length, 2); - assert.deepEqual(data.variables.map(v => v.name), ['foo', 'foo']); - } - { - const data = await resolveVariables('Hello #foo and #far #foo'); - assert.strictEqual(data.variables.length, 3); - assert.deepEqual(data.variables.map(v => v.name), ['foo', 'far', 'foo']); - } - { - const data = await resolveVariables('Hello #foo and #far #foo #unknown'); - assert.strictEqual(data.variables.length, 3); - assert.deepEqual(data.variables.map(v => v.name), ['foo', 'far', 'foo']); - } - - v1.dispose(); - v2.dispose(); - }); -}); diff --git a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts index 6340cc2c311f2..5f429380df64f 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts @@ -90,34 +90,34 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); - test('variables', async () => { - varService.hasVariable.returns(true); - varService.getVariable.returns({ id: 'copilot.selection' }); - - parser = instantiationService.createInstance(ChatRequestParser); - const text = 'What does #selection mean?'; - const result = parser.parseChatRequest('1', text); - await assertSnapshot(result); - }); - - test('variable with question mark', async () => { - varService.hasVariable.returns(true); - varService.getVariable.returns({ id: 'copilot.selection' }); - - parser = instantiationService.createInstance(ChatRequestParser); - const text = 'What is #selection?'; - const result = parser.parseChatRequest('1', text); - await assertSnapshot(result); - }); - - test('invalid variables', async () => { - varService.hasVariable.returns(false); - - parser = instantiationService.createInstance(ChatRequestParser); - const text = 'What does #selection mean?'; - const result = parser.parseChatRequest('1', text); - await assertSnapshot(result); - }); + // test('variables', async () => { + // varService.hasVariable.returns(true); + // varService.getVariable.returns({ id: 'copilot.selection' }); + + // parser = instantiationService.createInstance(ChatRequestParser); + // const text = 'What does #selection mean?'; + // const result = parser.parseChatRequest('1', text); + // await assertSnapshot(result); + // }); + + // test('variable with question mark', async () => { + // varService.hasVariable.returns(true); + // varService.getVariable.returns({ id: 'copilot.selection' }); + + // parser = instantiationService.createInstance(ChatRequestParser); + // const text = 'What is #selection?'; + // const result = parser.parseChatRequest('1', text); + // await assertSnapshot(result); + // }); + + // test('invalid variables', async () => { + // varService.hasVariable.returns(false); + + // parser = instantiationService.createInstance(ChatRequestParser); + // const text = 'What does #selection mean?'; + // const result = parser.parseChatRequest('1', text); + // await assertSnapshot(result); + // }); const getAgentWithSlashCommands = (slashCommands: IChatAgentCommand[]) => { return { id: 'agent', name: 'agent', extensionId: nullExtensionDescription.identifier, publisherDisplayName: '', extensionDisplayName: '', extensionPublisherId: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands, disambiguation: [] } satisfies IChatAgentData; @@ -183,31 +183,31 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); - test('agents and variables and multiline', async () => { - const agentsService = mockObject()({}); - agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); - instantiationService.stub(IChatAgentService, agentsService as any); + // test('agents and variables and multiline', async () => { + // const agentsService = mockObject()({}); + // agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); + // instantiationService.stub(IChatAgentService, agentsService as any); - varService.hasVariable.returns(true); - varService.getVariable.onCall(0).returns({ id: 'copilot.selection' }); - varService.getVariable.onCall(1).returns({ id: 'copilot.debugConsole' }); + // varService.hasVariable.returns(true); + // varService.getVariable.onCall(0).returns({ id: 'copilot.selection' }); + // varService.getVariable.onCall(1).returns({ id: 'copilot.debugConsole' }); - parser = instantiationService.createInstance(ChatRequestParser); - const result = parser.parseChatRequest('1', '@agent /subCommand \nPlease do with #selection\nand #debugConsole'); - await assertSnapshot(result); - }); + // parser = instantiationService.createInstance(ChatRequestParser); + // const result = parser.parseChatRequest('1', '@agent /subCommand \nPlease do with #selection\nand #debugConsole'); + // await assertSnapshot(result); + // }); - test('agents and variables and multiline, part2', async () => { - const agentsService = mockObject()({}); - agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); - instantiationService.stub(IChatAgentService, agentsService as any); + // test('agents and variables and multiline, part2', async () => { + // const agentsService = mockObject()({}); + // agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); + // instantiationService.stub(IChatAgentService, agentsService as any); - varService.hasVariable.returns(true); - varService.getVariable.onCall(0).returns({ id: 'copilot.selection' }); - varService.getVariable.onCall(1).returns({ id: 'copilot.debugConsole' }); + // varService.hasVariable.returns(true); + // varService.getVariable.onCall(0).returns({ id: 'copilot.selection' }); + // varService.getVariable.onCall(1).returns({ id: 'copilot.debugConsole' }); - parser = instantiationService.createInstance(ChatRequestParser); - const result = parser.parseChatRequest('1', '@agent Please \ndo /subCommand with #selection\nand #debugConsole'); - await assertSnapshot(result); - }); + // parser = instantiationService.createInstance(ChatRequestParser); + // const result = parser.parseChatRequest('1', '@agent Please \ndo /subCommand with #selection\nand #debugConsole'); + // await assertSnapshot(result); + // }); }); diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts index 265db696262ef..f2df896c34419 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts @@ -4,26 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from '../../../../../base/common/cancellation.js'; -import { IDisposable } from '../../../../../base/common/lifecycle.js'; import { ChatAgentLocation } from '../../common/chatAgents.js'; import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from '../../common/chatModel.js'; import { IParsedChatRequest } from '../../common/chatParserTypes.js'; -import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolver, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; +import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; export class MockChatVariablesService implements IChatVariablesService { _serviceBrand: undefined; - registerVariable(data: IChatVariableData, resolver: IChatVariableResolver): IDisposable { - throw new Error('Method not implemented.'); - } getVariable(name: string): IChatVariableData | undefined { throw new Error('Method not implemented.'); } - hasVariable(name: string): boolean { - throw new Error('Method not implemented.'); - } - getVariables(): Iterable> { throw new Error('Method not implemented.'); } From 9f4c7557cfebf37cf048aa35639b5a6c86907a36 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 6 Feb 2025 18:17:48 -0800 Subject: [PATCH 03/12] Delete references to ChatRequestVariablePart --- .../api/common/extHostChatAgents2.ts | 9 +-- .../browser/actions/chatContextActions.ts | 4 +- .../chatMarkdownDecorationsRenderer.ts | 9 +-- .../contrib/chat/browser/chatVariables.ts | 25 +----- .../browser/contrib/chatInputCompletions.ts | 80 +------------------ .../browser/contrib/chatInputEditorContrib.ts | 15 ++-- .../contrib/chat/common/chatParserTypes.ts | 3 +- .../contrib/chat/common/chatRequestParser.ts | 15 +--- .../contrib/chat/common/chatVariables.ts | 2 - .../chat/test/common/mockChatVariables.ts | 4 - 10 files changed, 20 insertions(+), 146 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 0806fa58b72ad..9f31c6ea067f9 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -704,7 +704,6 @@ class ExtHostChatAgent { private _welcomeMessageProvider?: vscode.ChatWelcomeMessageProvider | undefined; private _titleProvider?: vscode.ChatTitleProvider | undefined; private _requester: vscode.ChatRequesterInformation | undefined; - private _supportsSlowReferences: boolean | undefined; private _pauseStateEmitter = new Emitter(); constructor( @@ -817,7 +816,6 @@ class ExtHostChatAgent { helpTextPostfix: (!this._helpTextPostfix || typeof this._helpTextPostfix === 'string') ? this._helpTextPostfix : typeConvert.MarkdownString.from(this._helpTextPostfix), supportIssueReporting: this._supportIssueReporting, requester: this._requester, - supportsSlowVariables: this._supportsSlowReferences, }); updateScheduled = false; }); @@ -948,13 +946,10 @@ class ExtHostChatAgent { return that._requester; }, set supportsSlowReferences(v) { - checkProposedApiEnabled(that.extension, 'chatParticipantPrivate'); - that._supportsSlowReferences = v; - updateMetadataSoon(); + // TODO API }, get supportsSlowReferences() { - checkProposedApiEnabled(that.extension, 'chatParticipantPrivate'); - return that._supportsSlowReferences; + return false; }, dispose() { disposed = true; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index e070c3bbfd373..ba340d68b5c14 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -673,12 +673,10 @@ export class AttachContextAction extends Action2 { } const chatEditingService = widget.location === ChatAgentLocation.EditingSession ? accessor.get(IChatEditingService) : undefined; - const usedAgent = widget.parsedInput.parts.find(p => p instanceof ChatRequestAgentPart); - const slowSupported = usedAgent ? usedAgent.agent.metadata.supportsSlowVariables : true; const quickPickItems: IAttachmentQuickPickItem[] = []; if (!context || !context.showFilesOnly) { for (const variable of chatVariablesService.getVariables()) { - if (variable.fullName && (!variable.isSlow || slowSupported)) { + if (variable.fullName) { quickPickItems.push({ kind: 'variable', variable, diff --git a/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts index 46a068ee3dce4..0c3186b3b9fd7 100644 --- a/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts @@ -20,9 +20,8 @@ import { asCssVariable } from '../../../../platform/theme/common/colorUtils.js'; import { contentRefUrl } from '../common/annotations.js'; import { getFullyQualifiedId, IChatAgentCommand, IChatAgentData, IChatAgentNameService, IChatAgentService } from '../common/chatAgents.js'; import { chatSlashCommandBackground, chatSlashCommandForeground } from '../common/chatColors.js'; -import { chatAgentLeader, ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicVariablePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestToolPart, ChatRequestVariablePart, chatSubcommandLeader, IParsedChatRequest, IParsedChatRequestPart } from '../common/chatParserTypes.js'; +import { chatAgentLeader, ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicVariablePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestToolPart, chatSubcommandLeader, IParsedChatRequest, IParsedChatRequestPart } from '../common/chatParserTypes.js'; import { IChatMarkdownContent, IChatService } from '../common/chatService.js'; -import { IChatVariablesService } from '../common/chatVariables.js'; import { ILanguageModelToolsService } from '../common/languageModelToolsService.js'; import { IChatWidgetService } from './chat.js'; import { ChatAgentHover, getChatAgentHoverOptions } from './chatAgentHover.js'; @@ -86,7 +85,6 @@ export class ChatMarkdownDecorationsRenderer { @IChatService private readonly chatService: IChatService, @IChatWidgetService private readonly chatWidgetService: IChatWidgetService, @ICommandService private readonly commandService: ICommandService, - @IChatVariablesService private readonly chatVariablesService: IChatVariablesService, @ILabelService private readonly labelService: ILabelService, @ILanguageModelToolsService private readonly toolsService: ILanguageModelToolsService, @IChatMarkdownAnchorService private readonly chatMarkdownAnchorService: IChatMarkdownAnchorService, @@ -114,9 +112,8 @@ export class ChatMarkdownDecorationsRenderer { const title = uri ? this.labelService.getUriLabel(uri, { relative: true }) : part instanceof ChatRequestSlashCommandPart ? part.slashCommand.detail : part instanceof ChatRequestAgentSubcommandPart ? part.command.description : - part instanceof ChatRequestVariablePart ? (this.chatVariablesService.getVariable(part.variableName)?.description) : - part instanceof ChatRequestToolPart ? (this.toolsService.getTool(part.toolId)?.userDescription) : - ''; + part instanceof ChatRequestToolPart ? (this.toolsService.getTool(part.toolId)?.userDescription) : + ''; const args: IDecorationWidgetArgs = { title }; const text = part.text; diff --git a/src/vs/workbench/contrib/chat/browser/chatVariables.ts b/src/vs/workbench/contrib/chat/browser/chatVariables.ts index e99a2e122b8ac..fc66d9082d0f9 100644 --- a/src/vs/workbench/contrib/chat/browser/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/chatVariables.ts @@ -13,7 +13,7 @@ import { Location } from '../../../../editor/common/languages.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { ChatAgentLocation } from '../common/chatAgents.js'; import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from '../common/chatModel.js'; -import { ChatRequestDynamicVariablePart, ChatRequestToolPart, ChatRequestVariablePart, IParsedChatRequest } from '../common/chatParserTypes.js'; +import { ChatRequestDynamicVariablePart, ChatRequestToolPart, IParsedChatRequest } from '../common/chatParserTypes.js'; import { IChatContentReference } from '../common/chatService.js'; import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolver, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; import { IChatWidgetService, showChatView, showEditsView } from './chat.js'; @@ -41,24 +41,7 @@ export class ChatVariablesService implements IChatVariablesService { prompt.parts .forEach((part, i) => { - if (part instanceof ChatRequestVariablePart) { - const data = this._resolver.get(part.variableName.toLowerCase()); - if (data) { - const references: IChatContentReference[] = []; - const variableProgressCallback = (item: IChatVariableResolverProgress) => { - if (item.kind === 'reference') { - references.push(item); - return; - } - progress(item); - }; - jobs.push(data.resolver(prompt.text, part.variableArg, model, variableProgressCallback, token).then(value => { - if (value) { - resolvedVariables[i] = { id: data.data.id, modelDescription: data.data.modelDescription, name: part.variableName, range: part.range, value, references, fullName: data.data.fullName, icon: data.data.icon }; - } - }).catch(onUnexpectedExternalError)); - } - } else if (part instanceof ChatRequestDynamicVariablePart) { + if (part instanceof ChatRequestDynamicVariablePart) { resolvedVariables[i] = { id: part.id, name: part.referenceText, range: part.range, value: part.data, fullName: part.fullName, icon: part.icon, isFile: part.isFile }; } else if (part instanceof ChatRequestToolPart) { resolvedVariables[i] = { id: part.toolId, name: part.toolName, range: part.range, value: undefined, isTool: true, icon: ThemeIcon.isThemeIcon(part.icon) ? part.icon : undefined, fullName: part.displayName }; @@ -114,10 +97,6 @@ export class ChatVariablesService implements IChatVariablesService { return (await data.resolver(promptText, undefined, model, progress, token)); } - getVariable(name: string): IChatVariableData | undefined { - return this._resolver.get(name.toLowerCase())?.data; - } - getVariables(): Iterable> { const all = Iterable.map(this._resolver.values(), data => data.data); return all; diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts index 4e3fc6dd1e7db..b55b548a8673c 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts @@ -34,10 +34,9 @@ import { QueryBuilder } from '../../../../services/search/common/queryBuilder.js import { ISearchService } from '../../../../services/search/common/search.js'; import { ChatAgentLocation, IChatAgentData, IChatAgentNameService, IChatAgentService, getFullyQualifiedId } from '../../common/chatAgents.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestTextPart, ChatRequestToolPart, ChatRequestVariablePart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from '../../common/chatParserTypes.js'; +import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestTextPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from '../../common/chatParserTypes.js'; import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; -import { IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; -import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; +import { IDynamicVariable } from '../../common/chatVariables.js'; import { ChatEditingSessionSubmitAction, ChatSubmitAction } from '../actions/chatExecuteActions.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; import { ChatInputPart } from '../chatInputPart.js'; @@ -825,78 +824,3 @@ function isEmptyUpToCompletionWord(model: ITextModel, rangeResult: IChatCompleti const startToCompletionWordStart = new Range(1, 1, rangeResult.replace.startLineNumber, rangeResult.replace.startColumn); return !!model.getValueInRange(startToCompletionWordStart).match(/^\s*$/); } - -class VariableCompletions extends Disposable { - - private static readonly VariableNameDef = new RegExp(`(?<=^|\\s)${chatVariableLeader}\\w*`, 'g'); // MUST be using `g`-flag - - constructor( - @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, - @IChatWidgetService private readonly chatWidgetService: IChatWidgetService, - @IChatVariablesService private readonly chatVariablesService: IChatVariablesService, - @ILanguageModelToolsService toolsService: ILanguageModelToolsService - ) { - super(); - - this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { - _debugDisplayName: 'chatVariables', - triggerCharacters: [chatVariableLeader], - provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { - const widget = this.chatWidgetService.getWidgetByInputUri(model.uri); - if (!widget) { - return null; - } - - const range = computeCompletionRanges(model, position, VariableCompletions.VariableNameDef, true); - if (!range) { - return null; - } - - const usedAgent = widget.parsedInput.parts.find(p => p instanceof ChatRequestAgentPart); - const slowSupported = usedAgent ? usedAgent.agent.metadata.supportsSlowVariables : true; - - const usedVariables = widget.parsedInput.parts.filter((p): p is ChatRequestVariablePart => p instanceof ChatRequestVariablePart); - const usedVariableNames = new Set(usedVariables.map(v => v.variableName)); - const variableItems = Array.from(this.chatVariablesService.getVariables()) - // This doesn't look at dynamic variables like `file`, where multiple makes sense. - .filter(v => !usedVariableNames.has(v.name)) - .filter(v => !v.isSlow || slowSupported) - .map((v): CompletionItem => { - const withLeader = `${chatVariableLeader}${v.name}`; - return { - label: withLeader, - range, - insertText: withLeader + ' ', - documentation: v.description, - kind: CompletionItemKind.Text, // The icons are disabled here anyway - sortText: 'z' - }; - }); - - const usedTools = widget.parsedInput.parts.filter((p): p is ChatRequestToolPart => p instanceof ChatRequestToolPart); - const usedToolNames = new Set(usedTools.map(v => v.toolName)); - const toolItems: CompletionItem[] = []; - toolItems.push(...Array.from(toolsService.getTools()) - .filter(t => t.canBeReferencedInPrompt) - .filter(t => !usedToolNames.has(t.toolReferenceName ?? '')) - .map((t): CompletionItem => { - const withLeader = `${chatVariableLeader}${t.toolReferenceName}`; - return { - label: withLeader, - range, - insertText: withLeader + ' ', - documentation: t.userDescription, - kind: CompletionItemKind.Text, - sortText: 'z' - }; - })); - - return { - suggestions: [...variableItems, ...toolItems] - }; - } - })); - } -} - -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(VariableCompletions, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index 313e90a2567bf..e0997913f21d5 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -11,13 +11,13 @@ import { IDecorationOptions } from '../../../../../editor/common/editorCommon.js import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { inputPlaceholderForeground } from '../../../../../platform/theme/common/colorRegistry.js'; import { IThemeService } from '../../../../../platform/theme/common/themeService.js'; -import { IChatWidget } from '../chat.js'; -import { ChatWidget } from '../chatWidget.js'; -import { dynamicVariableDecorationType } from './chatDynamicVariables.js'; import { IChatAgentCommand, IChatAgentData, IChatAgentService } from '../../common/chatAgents.js'; import { chatSlashCommandBackground, chatSlashCommandForeground } from '../../common/chatColors.js'; -import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestToolPart, ChatRequestVariablePart, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader } from '../../common/chatParserTypes.js'; +import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestToolPart, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader } from '../../common/chatParserTypes.js'; import { ChatRequestParser } from '../../common/chatRequestParser.js'; +import { IChatWidget } from '../chat.js'; +import { ChatWidget } from '../chatWidget.js'; +import { dynamicVariableDecorationType } from './chatDynamicVariables.js'; const decorationDescription = 'chat'; const placeholderDecorationType = 'chat-session-detail'; @@ -226,11 +226,6 @@ class InputEditorDecorations extends Disposable { this.widget.inputEditor.setDecorationsByType(decorationDescription, slashCommandTextDecorationType, textDecorations); const varDecorations: IDecorationOptions[] = []; - const variableParts = parsedRequest.filter((p): p is ChatRequestVariablePart => p instanceof ChatRequestVariablePart); - for (const variable of variableParts) { - varDecorations.push({ range: variable.editorRange }); - } - const toolParts = parsedRequest.filter((p): p is ChatRequestToolPart => p instanceof ChatRequestToolPart); for (const tool of toolParts) { varDecorations.push({ range: tool.editorRange }); @@ -309,7 +304,7 @@ class ChatTokenDeleter extends Disposable { const previousParsedValue = parser.parseChatRequest(this.widget.viewModel.sessionId, previousInputValue, widget.location, { selectedAgent: previousSelectedAgent }); // For dynamic variables, this has to happen in ChatDynamicVariableModel with the other bookkeeping - const deletableTokens = previousParsedValue.parts.filter(p => p instanceof ChatRequestAgentPart || p instanceof ChatRequestAgentSubcommandPart || p instanceof ChatRequestSlashCommandPart || p instanceof ChatRequestVariablePart || p instanceof ChatRequestToolPart); + const deletableTokens = previousParsedValue.parts.filter(p => p instanceof ChatRequestAgentPart || p instanceof ChatRequestAgentSubcommandPart || p instanceof ChatRequestSlashCommandPart || p instanceof ChatRequestToolPart); deletableTokens.forEach(token => { const deletedRangeOfToken = Range.intersectRanges(token.editorRange, change.range); // Part of this token was deleted, or the space after it was deleted, and the deletion range doesn't go off the front of the token, for simpler math diff --git a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts index 04099d3e1a551..0dff77c6e12e8 100644 --- a/src/vs/workbench/contrib/chat/common/chatParserTypes.ts +++ b/src/vs/workbench/contrib/chat/common/chatParserTypes.ts @@ -52,8 +52,9 @@ export const chatSubcommandLeader = '/'; /** * An invocation of a static variable that can be resolved by the variable service + * @deprecated, but kept for backwards compatibility with old persisted chat requests */ -export class ChatRequestVariablePart implements IParsedChatRequestPart { +class ChatRequestVariablePart implements IParsedChatRequestPart { static readonly Kind = 'var'; readonly kind = ChatRequestVariablePart.Kind; constructor(readonly range: OffsetRange, readonly editorRange: IRange, readonly variableName: string, readonly variableArg: string, readonly variableId: string) { } diff --git a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts index d660bbd0df240..b710d18bd3108 100644 --- a/src/vs/workbench/contrib/chat/common/chatRequestParser.ts +++ b/src/vs/workbench/contrib/chat/common/chatRequestParser.ts @@ -7,7 +7,7 @@ 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 { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynamicVariablePart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestToolPart, ChatRequestVariablePart, IParsedChatRequest, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from './chatParserTypes.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 { ILanguageModelToolsService } from './languageModelToolsService.js'; @@ -92,7 +92,7 @@ export class ChatRequestParser { }; } - private tryToParseAgent(message: string, fullMessage: string, offset: number, position: IPosition, parts: Array, location: ChatAgentLocation, context: IChatParserContext | undefined): ChatRequestAgentPart | ChatRequestVariablePart | undefined { + private tryToParseAgent(message: string, fullMessage: string, offset: number, position: IPosition, parts: Array, location: ChatAgentLocation, context: IChatParserContext | undefined): ChatRequestAgentPart | undefined { const nextAgentMatch = message.match(agentReg); if (!nextAgentMatch) { return; @@ -139,24 +139,15 @@ export class ChatRequestParser { return new ChatRequestAgentPart(agentRange, agentEditorRange, agent); } - private tryToParseVariable(message: string, offset: number, position: IPosition, parts: ReadonlyArray): ChatRequestAgentPart | ChatRequestVariablePart | ChatRequestToolPart | undefined { + private tryToParseVariable(message: string, offset: number, position: IPosition, parts: ReadonlyArray): ChatRequestAgentPart | ChatRequestToolPart | undefined { const nextVariableMatch = message.match(variableReg); if (!nextVariableMatch) { return; } const [full, name] = nextVariableMatch; - const variableArg = nextVariableMatch[2] ?? ''; const varRange = new OffsetRange(offset, offset + full.length); const varEditorRange = new Range(position.lineNumber, position.column, position.lineNumber, position.column + full.length); - const usedAgent = parts.find((p): p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart); - const allowSlow = !usedAgent || usedAgent.agent.metadata.supportsSlowVariables; - - // TODO - not really handling duplicate variables names yet - const variable = this.variableService.getVariable(name); - if (variable && (!variable.isSlow || allowSlow)) { - return new ChatRequestVariablePart(varRange, varEditorRange, name, variableArg, variable.id); - } const tool = this.toolsService.getToolByName(name); if (tool && tool.canBeReferencedInPrompt) { diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index 91c0b6fb61f72..cdb40836bd4aa 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -21,7 +21,6 @@ export interface IChatVariableData { fullName?: string; description: string; modelDescription?: string; - isSlow?: boolean; canTakeArgument?: boolean; } @@ -39,7 +38,6 @@ export const IChatVariablesService = createDecorator('ICh export interface IChatVariablesService { _serviceBrand: undefined; - getVariable(name: string): IChatVariableData | undefined; getVariables(): Iterable>; getDynamicVariables(sessionId: string): ReadonlyArray; // should be its own service? attachContext(name: string, value: string | URI | Location | unknown, location: ChatAgentLocation): void; diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts index f2df896c34419..1f88b8bfa8abf 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts @@ -12,10 +12,6 @@ import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProg export class MockChatVariablesService implements IChatVariablesService { _serviceBrand: undefined; - getVariable(name: string): IChatVariableData | undefined { - throw new Error('Method not implemented.'); - } - getVariables(): Iterable> { throw new Error('Method not implemented.'); } From 1dde29b93c0918c293b0678d297970f64b47efbb Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 6 Feb 2025 18:20:05 -0800 Subject: [PATCH 04/12] More --- .../workbench/contrib/chat/browser/chatVariables.ts | 11 +---------- src/vs/workbench/contrib/chat/common/chatVariables.ts | 3 +-- .../contrib/chat/test/common/mockChatVariables.ts | 6 +----- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatVariables.ts b/src/vs/workbench/contrib/chat/browser/chatVariables.ts index fc66d9082d0f9..fc9e9041ced13 100644 --- a/src/vs/workbench/contrib/chat/browser/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/chatVariables.ts @@ -15,7 +15,7 @@ import { ChatAgentLocation } from '../common/chatAgents.js'; import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from '../common/chatModel.js'; import { ChatRequestDynamicVariablePart, ChatRequestToolPart, IParsedChatRequest } from '../common/chatParserTypes.js'; import { IChatContentReference } from '../common/chatService.js'; -import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolver, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; +import { IChatVariableData, IChatVariableResolver, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; import { IChatWidgetService, showChatView, showEditsView } from './chat.js'; import { ChatDynamicVariableModel } from './contrib/chatDynamicVariables.js'; @@ -88,15 +88,6 @@ export class ChatVariablesService implements IChatVariablesService { }; } - async resolveVariable(variableName: string, promptText: string, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise { - const data = this._resolver.get(variableName.toLowerCase()); - if (!data) { - return undefined; - } - - return (await data.resolver(promptText, undefined, model, progress, token)); - } - getVariables(): Iterable> { const all = Iterable.map(this._resolver.values(), data => data.data); return all; diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index cdb40836bd4aa..64b429895e57e 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -38,7 +38,7 @@ export const IChatVariablesService = createDecorator('ICh export interface IChatVariablesService { _serviceBrand: undefined; - getVariables(): Iterable>; + // getVariables(): Iterable>; getDynamicVariables(sessionId: string): ReadonlyArray; // should be its own service? attachContext(name: string, value: string | URI | Location | unknown, location: ChatAgentLocation): void; @@ -46,7 +46,6 @@ export interface IChatVariablesService { * Resolves all variables that occur in `prompt` */ resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise; - resolveVariable(variableName: string, promptText: string, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise; } export interface IDynamicVariable { diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts index 1f88b8bfa8abf..0183f38458173 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts @@ -7,7 +7,7 @@ import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { ChatAgentLocation } from '../../common/chatAgents.js'; import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from '../../common/chatModel.js'; import { IParsedChatRequest } from '../../common/chatParserTypes.js'; -import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; +import { IChatVariableData, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; export class MockChatVariablesService implements IChatVariablesService { _serviceBrand: undefined; @@ -29,8 +29,4 @@ export class MockChatVariablesService implements IChatVariablesService { attachContext(name: string, value: unknown, location: ChatAgentLocation): void { throw new Error('Method not implemented.'); } - - resolveVariable(variableName: string, promptText: string, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise { - throw new Error('Method not implemented.'); - } } From ad3247e35c2d090abf2f5ea4e5b0543ffe11dc05 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 09:44:33 -0800 Subject: [PATCH 05/12] Simplify resolveVariables --- .../contrib/chat/browser/chatVariables.ts | 49 ++----------------- .../contrib/chat/common/chatServiceImpl.ts | 2 +- .../contrib/chat/common/chatVariables.ts | 5 +- .../chat/test/common/mockChatVariables.ts | 11 ++--- 4 files changed, 10 insertions(+), 57 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatVariables.ts b/src/vs/workbench/contrib/chat/browser/chatVariables.ts index fc9e9041ced13..e44dfb0e73222 100644 --- a/src/vs/workbench/contrib/chat/browser/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/chatVariables.ts @@ -4,40 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import { coalesce } from '../../../../base/common/arrays.js'; -import { CancellationToken } from '../../../../base/common/cancellation.js'; -import { onUnexpectedExternalError } from '../../../../base/common/errors.js'; -import { Iterable } from '../../../../base/common/iterator.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { URI } from '../../../../base/common/uri.js'; import { Location } from '../../../../editor/common/languages.js'; import { IViewsService } from '../../../services/views/common/viewsService.js'; import { ChatAgentLocation } from '../common/chatAgents.js'; -import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from '../common/chatModel.js'; +import { IChatRequestVariableData, IChatRequestVariableEntry } from '../common/chatModel.js'; import { ChatRequestDynamicVariablePart, ChatRequestToolPart, IParsedChatRequest } from '../common/chatParserTypes.js'; -import { IChatContentReference } from '../common/chatService.js'; -import { IChatVariableData, IChatVariableResolver, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; +import { IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js'; import { IChatWidgetService, showChatView, showEditsView } from './chat.js'; import { ChatDynamicVariableModel } from './contrib/chatDynamicVariables.js'; -interface IChatData { - data: IChatVariableData; - resolver: IChatVariableResolver; -} - export class ChatVariablesService implements IChatVariablesService { declare _serviceBrand: undefined; - private _resolver = new Map(); - constructor( @IChatWidgetService private readonly chatWidgetService: IChatWidgetService, @IViewsService private readonly viewsService: IViewsService, ) { } - async resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise { + resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined): IChatRequestVariableData { let resolvedVariables: IChatRequestVariableEntry[] = []; - const jobs: Promise[] = []; prompt.parts .forEach((part, i) => { @@ -51,28 +39,11 @@ export class ChatVariablesService implements IChatVariablesService { const resolvedAttachedContext: IChatRequestVariableEntry[] = []; attachedContextVariables ?.forEach((attachment, i) => { - const data = this._resolver.get(attachment.name?.toLowerCase()); - if (data) { - const references: IChatContentReference[] = []; - const variableProgressCallback = (item: IChatVariableResolverProgress) => { - if (item.kind === 'reference') { - references.push(item); - return; - } - progress(item); - }; - jobs.push(data.resolver(prompt.text, '', model, variableProgressCallback, token).then(value => { - if (value) { - resolvedAttachedContext[i] = { id: data.data.id, modelDescription: data.data.modelDescription, name: attachment.name, fullName: attachment.fullName, range: attachment.range, value, references, icon: attachment.icon }; - } - }).catch(onUnexpectedExternalError)); - } else if (attachment.isDynamic || attachment.isTool) { + if (attachment.isDynamic || attachment.isTool) { resolvedAttachedContext[i] = attachment; } }); - await Promise.allSettled(jobs); - // Make array not sparse resolvedVariables = coalesce(resolvedVariables); @@ -88,11 +59,6 @@ export class ChatVariablesService implements IChatVariablesService { }; } - getVariables(): Iterable> { - const all = Iterable.map(this._resolver.values(), data => data.data); - return all; - } - getDynamicVariables(sessionId: string): ReadonlyArray { // This is slightly wrong... the parser pulls dynamic references from the input widget, but there is no guarantee that message came from the input here. // Need to ... @@ -130,12 +96,5 @@ export class ChatVariablesService implements IChatVariablesService { widget.attachmentModel.addFile(uri, range); return; } - - const resolved = this._resolver.get(key); - if (!resolved) { - return; - } - - widget.attachmentModel.addContext({ ...resolved.data, value }); } } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index f7365f520e4ac..45665df982e6b 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -639,7 +639,7 @@ export class ChatService extends Disposable implements IChatService { variableData = chatRequest.variableData; message = getPromptText(request.message).message; } else { - variableData = await this.chatVariablesService.resolveVariables(parsedRequest, request.attachedContext, model, progressCallback, token); + variableData = this.chatVariablesService.resolveVariables(parsedRequest, request.attachedContext); for (const variable of variableData.variables) { if (request.workingSet && variable.isFile && URI.isUri(variable.value)) { request.workingSet.push(variable.value); diff --git a/src/vs/workbench/contrib/chat/common/chatVariables.ts b/src/vs/workbench/contrib/chat/common/chatVariables.ts index 64b429895e57e..de02d68cf919b 100644 --- a/src/vs/workbench/contrib/chat/common/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/common/chatVariables.ts @@ -38,14 +38,13 @@ export const IChatVariablesService = createDecorator('ICh export interface IChatVariablesService { _serviceBrand: undefined; - // getVariables(): Iterable>; - getDynamicVariables(sessionId: string): ReadonlyArray; // should be its own service? + getDynamicVariables(sessionId: string): ReadonlyArray; attachContext(name: string, value: string | URI | Location | unknown, location: ChatAgentLocation): void; /** * Resolves all variables that occur in `prompt` */ - resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise; + resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined): IChatRequestVariableData; } export interface IDynamicVariable { diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts index 0183f38458173..9a59dc5e5ed9a 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatVariables.ts @@ -3,24 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from '../../../../../base/common/cancellation.js'; import { ChatAgentLocation } from '../../common/chatAgents.js'; -import { IChatModel, IChatRequestVariableData, IChatRequestVariableEntry } from '../../common/chatModel.js'; +import { IChatRequestVariableData, IChatRequestVariableEntry } from '../../common/chatModel.js'; import { IParsedChatRequest } from '../../common/chatParserTypes.js'; -import { IChatVariableData, IChatVariableResolverProgress, IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; +import { IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js'; export class MockChatVariablesService implements IChatVariablesService { _serviceBrand: undefined; - getVariables(): Iterable> { - throw new Error('Method not implemented.'); - } - getDynamicVariables(sessionId: string): readonly IDynamicVariable[] { return []; } - async resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined, model: IChatModel, progress: (part: IChatVariableResolverProgress) => void, token: CancellationToken): Promise { + resolveVariables(prompt: IParsedChatRequest, attachedContextVariables: IChatRequestVariableEntry[] | undefined): IChatRequestVariableData { return { variables: [] }; From ded43d8018e758d6753e58d8e5dbfcb8ca617c99 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 15:53:40 -0800 Subject: [PATCH 06/12] More --- .../browser/actions/chatContextActions.ts | 32 +---------- .../contrib/chat/browser/chat.contribution.ts | 1 - .../contrib/chat/browser/chatVariables.ts | 14 ++--- .../browser/contrib/chatInputCompletions.ts | 56 ++++++++++++++++++- 4 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index ba340d68b5c14..41c3b211cf759 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -49,7 +49,7 @@ import { ChatContextKeys } from '../../common/chatContextKeys.js'; import { IChatEditingService, WorkingSetEntryState } from '../../common/chatEditingService.js'; import { IChatRequestVariableEntry } from '../../common/chatModel.js'; import { ChatRequestAgentPart } from '../../common/chatParserTypes.js'; -import { IChatVariableData, IChatVariablesService } from '../../common/chatVariables.js'; +import { IChatVariablesService } from '../../common/chatVariables.js'; import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; import { DOCUMENTATION_URL, PROMPT_FILE_EXTENSION } from '../../common/promptSyntax/constants.js'; import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView, showEditsView } from '../chat.js'; @@ -71,7 +71,7 @@ export function registerChatContextActions() { * We fill the quickpick with these types, and enable some quick access providers */ type IAttachmentQuickPickItem = ICommandVariableQuickPickItem | IQuickAccessQuickPickItem | IToolQuickPickItem | - IImageQuickPickItem | IVariableQuickPickItem | IOpenEditorsQuickPickItem | ISearchResultsQuickPickItem | + IImageQuickPickItem | IOpenEditorsQuickPickItem | ISearchResultsQuickPickItem | IScreenShotQuickPickItem | IRelatedFilesQuickPickItem | IPromptInstructionsQuickPickItem; /** @@ -166,11 +166,6 @@ interface IToolQuickPickItem extends IQuickPickItem { icon?: ThemeIcon; } -interface IVariableQuickPickItem extends IQuickPickItem { - kind: 'variable'; - variable: IChatVariableData; -} - interface IQuickAccessQuickPickItem extends IQuickPickItem { kind: 'quickaccess'; id: string; @@ -626,16 +621,6 @@ export class AttachContextAction extends Action2 { isDynamic: true, isImage: true }); - } else if (attachmentPick.kind === 'variable') { - // All other dynamic variables and static variables - toAttach.push({ - range: undefined, - id: pick.id ?? '', - value: undefined, - fullName: pick.label, - name: attachmentPick.variable.name, - icon: attachmentPick.variable.icon - }); } } } @@ -651,7 +636,6 @@ export class AttachContextAction extends Action2 { override async run(accessor: ServicesAccessor, ...args: any[]): Promise { const quickInputService = accessor.get(IQuickInputService); const chatAgentService = accessor.get(IChatAgentService); - const chatVariablesService = accessor.get(IChatVariablesService); const commandService = accessor.get(ICommandService); const widgetService = accessor.get(IChatWidgetService); const languageModelToolsService = accessor.get(ILanguageModelToolsService); @@ -675,18 +659,6 @@ export class AttachContextAction extends Action2 { const quickPickItems: IAttachmentQuickPickItem[] = []; if (!context || !context.showFilesOnly) { - for (const variable of chatVariablesService.getVariables()) { - if (variable.fullName) { - quickPickItems.push({ - kind: 'variable', - variable, - label: variable.fullName, - id: variable.id, - iconClass: variable.icon ? ThemeIcon.asClassName(variable.icon) : undefined, - }); - } - } - if (extensionService.extensions.some(ext => isProposedApiEnabled(ext, 'chatReferenceBinaryData'))) { const imageData = await clipboardService.readImage(); if (isImage(imageData)) { diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 3b7fbef3bb9a3..dcdef6b9cb49d 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -350,7 +350,6 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable { } const variables = [ - ...chatVariablesService.getVariables(), { name: 'file', description: nls.localize('file', "Choose a file in the workspace") } ]; const variableText = variables diff --git a/src/vs/workbench/contrib/chat/browser/chatVariables.ts b/src/vs/workbench/contrib/chat/browser/chatVariables.ts index e44dfb0e73222..dde6ec6e59f7a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/chatVariables.ts @@ -36,22 +36,16 @@ export class ChatVariablesService implements IChatVariablesService { } }); - const resolvedAttachedContext: IChatRequestVariableEntry[] = []; - attachedContextVariables - ?.forEach((attachment, i) => { - if (attachment.isDynamic || attachment.isTool) { - resolvedAttachedContext[i] = attachment; - } - }); - // Make array not sparse resolvedVariables = coalesce(resolvedVariables); // "reverse", high index first so that replacement is simple resolvedVariables.sort((a, b) => b.range!.start - a.range!.start); - // resolvedAttachedContext is a sparse array - resolvedVariables.push(...coalesce(resolvedAttachedContext)); + if (attachedContextVariables) { + // attachments not in the prompt + resolvedVariables.push(...attachedContextVariables); + } return { diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts index b55b548a8673c..269eb565ba042 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts @@ -34,9 +34,10 @@ import { QueryBuilder } from '../../../../services/search/common/queryBuilder.js import { ISearchService } from '../../../../services/search/common/search.js'; import { ChatAgentLocation, IChatAgentData, IChatAgentNameService, IChatAgentService, getFullyQualifiedId } from '../../common/chatAgents.js'; import { IChatEditingService } from '../../common/chatEditingService.js'; -import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestTextPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from '../../common/chatParserTypes.js'; +import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestTextPart, ChatRequestToolPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from '../../common/chatParserTypes.js'; import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; import { IDynamicVariable } from '../../common/chatVariables.js'; +import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; import { ChatEditingSessionSubmitAction, ChatSubmitAction } from '../actions/chatExecuteActions.js'; import { IChatWidget, IChatWidgetService } from '../chat.js'; import { ChatInputPart } from '../chatInputPart.js'; @@ -824,3 +825,56 @@ function isEmptyUpToCompletionWord(model: ITextModel, rangeResult: IChatCompleti const startToCompletionWordStart = new Range(1, 1, rangeResult.replace.startLineNumber, rangeResult.replace.startColumn); return !!model.getValueInRange(startToCompletionWordStart).match(/^\s*$/); } + +class ToolCompletions extends Disposable { + + private static readonly VariableNameDef = new RegExp(`(?<=^|\\s)${chatVariableLeader}\\w*`, 'g'); // MUST be using `g`-flag + + constructor( + @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, + @IChatWidgetService private readonly chatWidgetService: IChatWidgetService, + @ILanguageModelToolsService toolsService: ILanguageModelToolsService + ) { + super(); + + this._register(this.languageFeaturesService.completionProvider.register({ scheme: ChatInputPart.INPUT_SCHEME, hasAccessToAllModels: true }, { + _debugDisplayName: 'chatVariables', + triggerCharacters: [chatVariableLeader], + provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, _token: CancellationToken) => { + const widget = this.chatWidgetService.getWidgetByInputUri(model.uri); + if (!widget) { + return null; + } + + const range = computeCompletionRanges(model, position, ToolCompletions.VariableNameDef, true); + if (!range) { + return null; + } + + const usedTools = widget.parsedInput.parts.filter((p): p is ChatRequestToolPart => p instanceof ChatRequestToolPart); + const usedToolNames = new Set(usedTools.map(v => v.toolName)); + const toolItems: CompletionItem[] = []; + toolItems.push(...Array.from(toolsService.getTools()) + .filter(t => t.canBeReferencedInPrompt) + .filter(t => !usedToolNames.has(t.toolReferenceName ?? '')) + .map((t): CompletionItem => { + const withLeader = `${chatVariableLeader}${t.toolReferenceName}`; + return { + label: withLeader, + range, + insertText: withLeader + ' ', + documentation: t.userDescription, + kind: CompletionItemKind.Text, + sortText: 'z' + }; + })); + + return { + suggestions: toolItems + }; + } + })); + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ToolCompletions, LifecyclePhase.Eventually); From 4ca10eacab17848a7ce6323b94d7c99359017b2b Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 15:55:10 -0800 Subject: [PATCH 07/12] Remove supportsSlowReferences --- src/vs/workbench/api/common/extHostChatAgents2.ts | 6 ------ src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts | 5 ----- 2 files changed, 11 deletions(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 9f31c6ea067f9..fadac236faf56 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -945,12 +945,6 @@ class ExtHostChatAgent { get requester() { return that._requester; }, - set supportsSlowReferences(v) { - // TODO API - }, - get supportsSlowReferences() { - return false; - }, dispose() { disposed = true; that._followupProvider = undefined; diff --git a/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts b/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts index e9311b26f3849..37ff3a27ab512 100644 --- a/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts +++ b/src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts @@ -81,11 +81,6 @@ declare module 'vscode' { export interface ChatParticipant { supportIssueReporting?: boolean; - - /** - * Temp, support references that are slow to resolve and should be tools rather than references. - */ - supportsSlowReferences?: boolean; } export interface ChatErrorDetails { From 51aef4799f4c7f8e594011dff4676275608d5fb8 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 16:08:44 -0800 Subject: [PATCH 08/12] Remove 'isDynamic' --- .../chat/browser/actions/chatContextActions.ts | 11 ----------- .../contrib/chat/browser/chatAttachmentModel.ts | 1 - .../chatInstructionAttachmentsModel.ts | 1 - .../workbench/contrib/chat/browser/chatDragAndDrop.ts | 3 --- .../workbench/contrib/chat/browser/chatInputPart.ts | 1 - .../contrib/chat/browser/chatPasteProviders.ts | 2 -- .../chat/browser/contrib/chatImplicitContext.ts | 3 --- .../contrib/chat/browser/contrib/screenshot.ts | 2 -- src/vs/workbench/contrib/chat/common/chatModel.ts | 8 -------- .../workbench/contrib/chat/common/chatServiceImpl.ts | 8 ++------ .../controller/chat/notebook.chat.contribution.ts | 1 - 11 files changed, 2 insertions(+), 39 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts index 41c3b211cf759..c93544a39a4b0 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatContextActions.ts @@ -154,7 +154,6 @@ interface ICommandVariableQuickPickItem extends IQuickPickItem { command: Command; name?: string; value: unknown; - isDynamic: true; icon?: ThemeIcon; } @@ -469,7 +468,6 @@ export class AttachContextAction extends Action2 { symbolKind: pick.symbol.kind, fullName: pick.label, name: pick.symbol.name, - isDynamic: true }); } else if (isIQuickPickItemWithResource(pick) && pick.resource) { if (/\.(png|jpg|jpeg|bmp|gif|tiff)$/i.test(pick.resource.path)) { @@ -483,7 +481,6 @@ export class AttachContextAction extends Action2 { name: pick.label, fullName: pick.label, value: resizedImage, - isDynamic: true, isImage: true }); } @@ -497,7 +494,6 @@ export class AttachContextAction extends Action2 { value: pick.resource, name: pick.label, isFile: true, - isDynamic: true, }); } } @@ -508,7 +504,6 @@ export class AttachContextAction extends Action2 { value: { uri: pick.uri, range: pick.range.decoration }, fullName: pick.label, name: pick.symbolName!, - isDynamic: true }); } else if (isIOpenEditorsQuickPickItem(pick)) { for (const editor of editorService.editors.filter(e => e instanceof FileEditorInput || e instanceof DiffEditorInput || e instanceof UntitledTextEditorInput || e instanceof NotebookEditorInput)) { @@ -522,7 +517,6 @@ export class AttachContextAction extends Action2 { value: uri, name: labelService.getUriBasenameLabel(uri), isFile: true, - isDynamic: true }); } } @@ -538,7 +532,6 @@ export class AttachContextAction extends Action2 { value: result.resource, name: labelService.getUriBasenameLabel(result.resource), isFile: true, - isDynamic: true }); } } @@ -596,7 +589,6 @@ export class AttachContextAction extends Action2 { } toAttach.push({ ...attachmentPick, - isDynamic: attachmentPick.isDynamic, value: attachmentPick.value, name: `${typeof attachmentPick.value === 'string' && attachmentPick.value.startsWith('#') ? attachmentPick.value.slice(1) : ''}${selection}`, // Apply the original icon with the new name @@ -618,7 +610,6 @@ export class AttachContextAction extends Action2 { name: localize('pastedImage', 'Pasted Image'), fullName: localize('pastedImage', 'Pasted Image'), value: fileBuffer, - isDynamic: true, isImage: true }); } @@ -695,7 +686,6 @@ export class AttachContextAction extends Action2 { icon: variable.icon, iconClass: variable.icon ? ThemeIcon.asClassName(variable.icon) : undefined, value: variable.value, - isDynamic: true, name: variable.name }); } else { @@ -735,7 +725,6 @@ export class AttachContextAction extends Action2 { quickPickItems.push({ kind: 'command', id: 'chatContext.notebook.kernelVariable', - isDynamic: true, icon: ThemeIcon.fromId(Codicon.serverEnvironment.id), iconClass: ThemeIcon.asClassName(Codicon.serverEnvironment), value: 'kernelVariable', diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts index 739be7f185d49..14a991bee4ac2 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel.ts @@ -69,7 +69,6 @@ export class ChatAttachmentModel extends Disposable { id: uri.toString() + (range?.toString() ?? ''), name: basename(uri), isFile: true, - isDynamic: true, isMarkedReadonly, }; } diff --git a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatInstructionAttachmentsModel.ts b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatInstructionAttachmentsModel.ts index f4c1c40284d87..d689f04abd5f5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatInstructionAttachmentsModel.ts +++ b/src/vs/workbench/contrib/chat/browser/chatAttachmentModel/chatInstructionAttachmentsModel.ts @@ -56,7 +56,6 @@ export const toChatVariable = ( isSelection: false, enabled: true, isFile: true, - isDynamic: true, isMarkedReadonly: isPromptSnippet, }; }; diff --git a/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts b/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts index 2550c96d86c6c..aa4bd05e22060 100644 --- a/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts +++ b/src/vs/workbench/contrib/chat/browser/chatDragAndDrop.ts @@ -296,7 +296,6 @@ export class ChatDragAndDrop extends Themable { symbolKind: symbol.kind, fullName: `$(${SymbolKinds.toIcon(symbol.kind).id}) ${symbol.name}`, name: symbol.name, - isDynamic: true }; }); } @@ -422,7 +421,6 @@ function getResourceAttachContext(resource: URI, isDirectory: boolean): IChatReq name: basename(resource), isFile: !isDirectory, isDirectory, - isDynamic: true }; } @@ -441,7 +439,6 @@ async function getImageAttachContext(editor: EditorInput | IDraggedResourceEdito fullName: editor.resource.path, value: resizedImage, icon: Codicon.fileMedia, - isDynamic: true, isImage: true, isFile: false, references: [{ reference: editor.resource, kind: 'reference' }] diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index 0dcc74fe0cf9c..192f823c8ccb5 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -183,7 +183,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge name: uri.fsPath, value: uri, isFile: false, - isDynamic: true, }); } diff --git a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts index 5550d3d33b9cb..fc71eeb1bdc82 100644 --- a/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts +++ b/src/vs/workbench/contrib/chat/browser/chatPasteProviders.ts @@ -125,7 +125,6 @@ async function getImageAttachContext(data: Uint8Array, mimeType: string, token: name: displayName, isImage: true, icon: Codicon.fileMedia, - isDynamic: true, mimeType }; } @@ -250,7 +249,6 @@ function getCopiedContext(code: string, file: URI, language: string, range: IRan id: `${fileName}${start}${end}${range.startColumn}${range.endColumn}`, name: `${fileName} ${pastedLines}`, icon: Codicon.code, - isDynamic: true, pastedLines, language, fileName: file.toString(), diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts index ed33aec41d9c9..aeb6c1911d1b8 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatImplicitContext.ts @@ -161,8 +161,6 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli } } - // TODO@roblourens - readonly isDynamic = true; readonly isFile = true; private _isSelection = false; @@ -205,7 +203,6 @@ export class ChatImplicitContext extends Disposable implements IChatRequestImpli name: this.name, value: this.value, isFile: true, - isDynamic: true, modelDescription: this.modelDescription }; } diff --git a/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts b/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts index 2d8add2aa1ba6..ca08338bb4344 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/screenshot.ts @@ -14,7 +14,5 @@ export function convertBufferToScreenshotVariable(buffer: ArrayBufferLike): ICha name: localize('screenshot', 'Screenshot'), value: new Uint8Array(buffer), isImage: true, - isDynamic: true }; } - diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 9f99ef9067864..21fdccfc11409 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -39,10 +39,6 @@ export interface IBaseChatRequestVariableEntry { // TODO these represent different kinds, should be extracted to new interfaces with kind tags kind?: never; - /** - * True if the variable has a value vs being a reference to a variable - */ - isDynamic?: boolean; isFile?: boolean; isDirectory?: boolean; isTool?: boolean; @@ -51,7 +47,6 @@ export interface IBaseChatRequestVariableEntry { export interface IChatRequestImplicitVariableEntry extends Omit { readonly kind: 'implicit'; - readonly isDynamic: true; readonly isFile: true; readonly value: URI | Location | undefined; readonly isSelection: boolean; @@ -76,19 +71,16 @@ export interface IChatRequestPasteVariableEntry extends Omit { readonly kind: 'symbol'; - readonly isDynamic: true; readonly value: Location; readonly symbolKind: SymbolKind; } export interface ICommandResultVariableEntry extends Omit { readonly kind: 'command'; - readonly isDynamic: true; } export interface ILinkVariableEntry extends Omit { readonly kind: 'link'; - readonly isDynamic: true; readonly value: URI; } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 45665df982e6b..0284f87694c57 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -832,10 +832,8 @@ export class ChatService extends Disposable implements IChatService { // 'range' is range within the prompt text if (v.isTool) { return 'toolInPrompt'; - } else if (v.isDynamic) { - return 'fileInPrompt'; } else { - return 'variableInPrompt'; + return 'fileInPrompt'; } } else if (v.kind === 'command') { return 'command'; @@ -847,7 +845,7 @@ export class ChatService extends Disposable implements IChatService { return 'directory'; } else if (v.isTool) { return 'tool'; - } else if (v.isDynamic) { + } else { if (URI.isUri(v.value)) { return 'file'; } else if (isLocation(v.value)) { @@ -855,8 +853,6 @@ export class ChatService extends Disposable implements IChatService { } else { return 'otherAttachment'; } - } else { - return 'variableAttachment'; } }); } 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 74f0bdae36254..e5b51d97092c5 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 @@ -223,7 +223,6 @@ export class SelectAndInsertKernelVariableAction extends Action2 { name: variableName, value: variableName, icon: codiconsLibrary.variable, - isDynamic: true }); } } From 3c414c85e64cdeb308a6eb39f2707407fa65851c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 16:22:35 -0800 Subject: [PATCH 09/12] Remove todo --- .../browser/chatContentParts/chatReferencesContentPart.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts index f66b7217d5a7b..a5a9bd5902df1 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatReferencesContentPart.ts @@ -362,8 +362,9 @@ class CollapsibleListRenderer implements IListRenderer Date: Fri, 7 Feb 2025 16:23:14 -0800 Subject: [PATCH 10/12] Remove todo --- .../chat/browser/contrib/chatDynamicVariables.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts index 854304dc7ebf5..d5fbbd548ebaa 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables.ts @@ -240,17 +240,6 @@ export class SelectAndInsertFileAction extends Action2 { }; let options: IQuickAccessOptions | undefined; - // If we have a `files` variable, add an option to select all files in the picker. - // This of course assumes that the `files` variable has the behavior that it searches - // through files in the workspace. - - // TODO This meant to include the "codebase" variable (now a tool), do we still need this? - // if (chatVariablesService.hasVariable(SelectAndInsertFileAction.Name)) { - // const providerOptions: AnythingQuickAccessProviderRunOptions = { - // additionPicks: [SelectAndInsertFileAction.Item, { type: 'separator' }] - // }; - // options = { providerOptions }; - // } // TODO: have dedicated UX for this instead of using the quick access picker const picks = await quickInputService.quickAccess.pick('', options); if (!picks?.length) { From 52fd6f3a97a5a165b210da743d108f5546cbadf4 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 16:29:22 -0800 Subject: [PATCH 11/12] Fix up tests --- ...rser_agents_and_tools_and_multiline.0.snap | 131 ++++++++++++++++++ ...ents_and_tools_and_multiline__part2.0.snap | 100 +++++++++++++ .../test/common/chatRequestParser.test.ts | 55 ++++---- 3 files changed, 257 insertions(+), 29 deletions(-) create mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline.0.snap create mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline__part2.0.snap diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline.0.snap new file mode 100644 index 0000000000000..27552be87ba8e --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline.0.snap @@ -0,0 +1,131 @@ +{ + parts: [ + { + range: { + start: 0, + endExclusive: 6 + }, + editorRange: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 7 + }, + agent: { + id: "agent", + name: "agent", + extensionId: { + value: "nullExtensionDescription", + _lower: "nullextensiondescription" + }, + publisherDisplayName: "", + extensionDisplayName: "", + extensionPublisherId: "", + locations: [ "panel" ], + metadata: { }, + slashCommands: [ + { + name: "subCommand", + description: "" + } + ], + disambiguation: [ ] + }, + kind: "agent" + }, + { + range: { + start: 6, + endExclusive: 7 + }, + editorRange: { + startLineNumber: 1, + startColumn: 7, + endLineNumber: 1, + endColumn: 8 + }, + text: " ", + kind: "text" + }, + { + range: { + start: 7, + endExclusive: 18 + }, + editorRange: { + startLineNumber: 1, + startColumn: 8, + endLineNumber: 1, + endColumn: 19 + }, + command: { + name: "subCommand", + description: "" + }, + kind: "subcommand" + }, + { + range: { + start: 18, + endExclusive: 35 + }, + editorRange: { + startLineNumber: 1, + startColumn: 19, + endLineNumber: 2, + endColumn: 16 + }, + text: " \nPlease do with ", + kind: "text" + }, + { + range: { + start: 35, + endExclusive: 45 + }, + editorRange: { + startLineNumber: 2, + startColumn: 16, + endLineNumber: 2, + endColumn: 26 + }, + toolName: "selection", + toolId: "get_selection", + displayName: "", + icon: undefined, + kind: "tool" + }, + { + range: { + start: 45, + endExclusive: 50 + }, + editorRange: { + startLineNumber: 2, + startColumn: 26, + endLineNumber: 3, + endColumn: 5 + }, + text: "\nand ", + kind: "text" + }, + { + range: { + start: 50, + endExclusive: 63 + }, + editorRange: { + startLineNumber: 3, + startColumn: 5, + endLineNumber: 3, + endColumn: 18 + }, + toolName: "debugConsole", + toolId: "get_debugConsole", + displayName: "", + icon: undefined, + kind: "tool" + } + ], + text: "@agent /subCommand \nPlease do with #selection\nand #debugConsole" +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline__part2.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline__part2.0.snap new file mode 100644 index 0000000000000..5617c8a068017 --- /dev/null +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_tools_and_multiline__part2.0.snap @@ -0,0 +1,100 @@ +{ + parts: [ + { + range: { + start: 0, + endExclusive: 6 + }, + editorRange: { + startLineNumber: 1, + startColumn: 1, + endLineNumber: 1, + endColumn: 7 + }, + agent: { + id: "agent", + name: "agent", + extensionId: { + value: "nullExtensionDescription", + _lower: "nullextensiondescription" + }, + publisherDisplayName: "", + extensionDisplayName: "", + extensionPublisherId: "", + locations: [ "panel" ], + metadata: { }, + slashCommands: [ + { + name: "subCommand", + description: "" + } + ], + disambiguation: [ ] + }, + kind: "agent" + }, + { + range: { + start: 6, + endExclusive: 35 + }, + editorRange: { + startLineNumber: 1, + startColumn: 7, + endLineNumber: 2, + endColumn: 21 + }, + text: " Please \ndo /subCommand with ", + kind: "text" + }, + { + range: { + start: 35, + endExclusive: 45 + }, + editorRange: { + startLineNumber: 2, + startColumn: 21, + endLineNumber: 2, + endColumn: 31 + }, + toolName: "selection", + toolId: "get_selection", + displayName: "", + icon: undefined, + kind: "tool" + }, + { + range: { + start: 45, + endExclusive: 50 + }, + editorRange: { + startLineNumber: 2, + startColumn: 31, + endLineNumber: 3, + endColumn: 5 + }, + text: "\nand ", + kind: "text" + }, + { + range: { + start: 50, + endExclusive: 63 + }, + editorRange: { + startLineNumber: 3, + startColumn: 5, + endLineNumber: 3, + endColumn: 18 + }, + toolName: "debugConsole", + toolId: "get_debugConsole", + displayName: "", + icon: undefined, + kind: "tool" + } + ], + text: "@agent Please \ndo /subCommand with #selection\nand #debugConsole" +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts index 5f429380df64f..7a2714635a635 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts @@ -18,9 +18,9 @@ import { ChatRequestParser } from '../../common/chatRequestParser.js'; import { IChatService } from '../../common/chatService.js'; import { IChatSlashCommandService } from '../../common/chatSlashCommands.js'; import { IChatVariablesService } from '../../common/chatVariables.js'; -import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js'; +import { ILanguageModelToolsService, IToolData } from '../../common/languageModelToolsService.js'; import { MockChatService } from './mockChatService.js'; -import { MockLanguageModelToolsService } from './mockLanguageModelToolsService.js'; +import { MockChatVariablesService } from './mockChatVariables.js'; suite('ChatRequestParser', () => { const testDisposables = ensureNoDisposablesAreLeakedInTestSuite(); @@ -28,7 +28,7 @@ suite('ChatRequestParser', () => { let instantiationService: TestInstantiationService; let parser: ChatRequestParser; - let varService: MockObject; + let toolsService: MockObject; setup(async () => { instantiationService = testDisposables.add(new TestInstantiationService()); instantiationService.stub(IStorageService, testDisposables.add(new TestStorageService())); @@ -36,12 +36,11 @@ suite('ChatRequestParser', () => { instantiationService.stub(IExtensionService, new TestExtensionService()); instantiationService.stub(IChatService, new MockChatService()); instantiationService.stub(IContextKeyService, new MockContextKeyService()); - instantiationService.stub(ILanguageModelToolsService, new MockLanguageModelToolsService()); + instantiationService.stub(IChatVariablesService, new MockChatVariablesService()); instantiationService.stub(IChatAgentService, testDisposables.add(instantiationService.createInstance(ChatAgentService))); - varService = mockObject()({}); - varService.getDynamicVariables.returns([]); - instantiationService.stub(IChatVariablesService, varService as any); + toolsService = mockObject()({}); + instantiationService.stub(ILanguageModelToolsService, toolsService as any); }); test('plain text', async () => { @@ -183,31 +182,29 @@ suite('ChatRequestParser', () => { await assertSnapshot(result); }); - // test('agents and variables and multiline', async () => { - // const agentsService = mockObject()({}); - // agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); - // instantiationService.stub(IChatAgentService, agentsService as any); + test('agents and tools and multiline', async () => { + const agentsService = mockObject()({}); + agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); + instantiationService.stub(IChatAgentService, agentsService as any); - // varService.hasVariable.returns(true); - // varService.getVariable.onCall(0).returns({ id: 'copilot.selection' }); - // varService.getVariable.onCall(1).returns({ id: 'copilot.debugConsole' }); + toolsService.getToolByName.onCall(0).returns({ id: 'get_selection', canBeReferencedInPrompt: true, displayName: '', modelDescription: '' } satisfies IToolData); + toolsService.getToolByName.onCall(1).returns({ id: 'get_debugConsole', canBeReferencedInPrompt: true, displayName: '', modelDescription: '' } satisfies IToolData); - // parser = instantiationService.createInstance(ChatRequestParser); - // const result = parser.parseChatRequest('1', '@agent /subCommand \nPlease do with #selection\nand #debugConsole'); - // await assertSnapshot(result); - // }); + parser = instantiationService.createInstance(ChatRequestParser); + const result = parser.parseChatRequest('1', '@agent /subCommand \nPlease do with #selection\nand #debugConsole'); + await assertSnapshot(result); + }); - // test('agents and variables and multiline, part2', async () => { - // const agentsService = mockObject()({}); - // agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); - // instantiationService.stub(IChatAgentService, agentsService as any); + test('agents and tools and multiline, part2', async () => { + const agentsService = mockObject()({}); + agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]); + instantiationService.stub(IChatAgentService, agentsService as any); - // varService.hasVariable.returns(true); - // varService.getVariable.onCall(0).returns({ id: 'copilot.selection' }); - // varService.getVariable.onCall(1).returns({ id: 'copilot.debugConsole' }); + toolsService.getToolByName.onCall(0).returns({ id: 'get_selection', canBeReferencedInPrompt: true, displayName: '', modelDescription: '' } satisfies IToolData); + toolsService.getToolByName.onCall(1).returns({ id: 'get_debugConsole', canBeReferencedInPrompt: true, displayName: '', modelDescription: '' } satisfies IToolData); - // parser = instantiationService.createInstance(ChatRequestParser); - // const result = parser.parseChatRequest('1', '@agent Please \ndo /subCommand with #selection\nand #debugConsole'); - // await assertSnapshot(result); - // }); + parser = instantiationService.createInstance(ChatRequestParser); + const result = parser.parseChatRequest('1', '@agent Please \ndo /subCommand with #selection\nand #debugConsole'); + await assertSnapshot(result); + }); }); From 01f069f52ad21511440dae4f246a9d7ddd15849d Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 7 Feb 2025 16:30:21 -0800 Subject: [PATCH 12/12] clean up snapshots --- ..._agents_and_variables_and_multiline.0.snap | 129 ------------------ ..._and_variables_and_multiline__part2.0.snap | 98 ------------- ...ChatRequestParser_invalid_variables.0.snap | 19 --- ...tParser_variable_with_question_mark.0.snap | 49 ------- .../ChatRequestParser_variables.0.snap | 49 ------- 5 files changed, 344 deletions(-) delete mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap delete mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap delete mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_invalid_variables.0.snap delete mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variable_with_question_mark.0.snap delete mode 100644 src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variables.0.snap diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap deleted file mode 100644 index c2d6131922c32..0000000000000 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline.0.snap +++ /dev/null @@ -1,129 +0,0 @@ -{ - parts: [ - { - range: { - start: 0, - endExclusive: 6 - }, - editorRange: { - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 7 - }, - agent: { - id: "agent", - name: "agent", - extensionId: { - value: "nullExtensionDescription", - _lower: "nullextensiondescription" - }, - publisherDisplayName: "", - extensionDisplayName: "", - extensionPublisherId: "", - locations: [ "panel" ], - metadata: { }, - slashCommands: [ - { - name: "subCommand", - description: "" - } - ], - disambiguation: [ ] - }, - kind: "agent" - }, - { - range: { - start: 6, - endExclusive: 7 - }, - editorRange: { - startLineNumber: 1, - startColumn: 7, - endLineNumber: 1, - endColumn: 8 - }, - text: " ", - kind: "text" - }, - { - range: { - start: 7, - endExclusive: 18 - }, - editorRange: { - startLineNumber: 1, - startColumn: 8, - endLineNumber: 1, - endColumn: 19 - }, - command: { - name: "subCommand", - description: "" - }, - kind: "subcommand" - }, - { - range: { - start: 18, - endExclusive: 35 - }, - editorRange: { - startLineNumber: 1, - startColumn: 19, - endLineNumber: 2, - endColumn: 16 - }, - text: " \nPlease do with ", - kind: "text" - }, - { - range: { - start: 35, - endExclusive: 45 - }, - editorRange: { - startLineNumber: 2, - startColumn: 16, - endLineNumber: 2, - endColumn: 26 - }, - variableName: "selection", - variableArg: "", - variableId: "copilot.selection", - kind: "var" - }, - { - range: { - start: 45, - endExclusive: 50 - }, - editorRange: { - startLineNumber: 2, - startColumn: 26, - endLineNumber: 3, - endColumn: 5 - }, - text: "\nand ", - kind: "text" - }, - { - range: { - start: 50, - endExclusive: 63 - }, - editorRange: { - startLineNumber: 3, - startColumn: 5, - endLineNumber: 3, - endColumn: 18 - }, - variableName: "debugConsole", - variableArg: "", - variableId: "copilot.debugConsole", - kind: "var" - } - ], - text: "@agent /subCommand \nPlease do with #selection\nand #debugConsole" -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap deleted file mode 100644 index 2362eb812d39a..0000000000000 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents_and_variables_and_multiline__part2.0.snap +++ /dev/null @@ -1,98 +0,0 @@ -{ - parts: [ - { - range: { - start: 0, - endExclusive: 6 - }, - editorRange: { - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 7 - }, - agent: { - id: "agent", - name: "agent", - extensionId: { - value: "nullExtensionDescription", - _lower: "nullextensiondescription" - }, - publisherDisplayName: "", - extensionDisplayName: "", - extensionPublisherId: "", - locations: [ "panel" ], - metadata: { }, - slashCommands: [ - { - name: "subCommand", - description: "" - } - ], - disambiguation: [ ] - }, - kind: "agent" - }, - { - range: { - start: 6, - endExclusive: 35 - }, - editorRange: { - startLineNumber: 1, - startColumn: 7, - endLineNumber: 2, - endColumn: 21 - }, - text: " Please \ndo /subCommand with ", - kind: "text" - }, - { - range: { - start: 35, - endExclusive: 45 - }, - editorRange: { - startLineNumber: 2, - startColumn: 21, - endLineNumber: 2, - endColumn: 31 - }, - variableName: "selection", - variableArg: "", - variableId: "copilot.selection", - kind: "var" - }, - { - range: { - start: 45, - endExclusive: 50 - }, - editorRange: { - startLineNumber: 2, - startColumn: 31, - endLineNumber: 3, - endColumn: 5 - }, - text: "\nand ", - kind: "text" - }, - { - range: { - start: 50, - endExclusive: 63 - }, - editorRange: { - startLineNumber: 3, - startColumn: 5, - endLineNumber: 3, - endColumn: 18 - }, - variableName: "debugConsole", - variableArg: "", - variableId: "copilot.debugConsole", - kind: "var" - } - ], - text: "@agent Please \ndo /subCommand with #selection\nand #debugConsole" -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_invalid_variables.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_invalid_variables.0.snap deleted file mode 100644 index e7411fc8e9dc5..0000000000000 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_invalid_variables.0.snap +++ /dev/null @@ -1,19 +0,0 @@ -{ - parts: [ - { - range: { - start: 0, - endExclusive: 26 - }, - editorRange: { - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 27 - }, - text: "What does #selection mean?", - kind: "text" - } - ], - text: "What does #selection mean?" -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variable_with_question_mark.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variable_with_question_mark.0.snap deleted file mode 100644 index d826520078af5..0000000000000 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variable_with_question_mark.0.snap +++ /dev/null @@ -1,49 +0,0 @@ -{ - parts: [ - { - range: { - start: 0, - endExclusive: 8 - }, - editorRange: { - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 9 - }, - text: "What is ", - kind: "text" - }, - { - range: { - start: 8, - endExclusive: 18 - }, - editorRange: { - startLineNumber: 1, - startColumn: 9, - endLineNumber: 1, - endColumn: 19 - }, - variableName: "selection", - variableArg: "", - variableId: "copilot.selection", - kind: "var" - }, - { - range: { - start: 18, - endExclusive: 19 - }, - editorRange: { - startLineNumber: 1, - startColumn: 19, - endLineNumber: 1, - endColumn: 20 - }, - text: "?", - kind: "text" - } - ], - text: "What is #selection?" -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variables.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variables.0.snap deleted file mode 100644 index 8334f7ba2b07d..0000000000000 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_variables.0.snap +++ /dev/null @@ -1,49 +0,0 @@ -{ - parts: [ - { - range: { - start: 0, - endExclusive: 10 - }, - editorRange: { - startLineNumber: 1, - startColumn: 1, - endLineNumber: 1, - endColumn: 11 - }, - text: "What does ", - kind: "text" - }, - { - range: { - start: 10, - endExclusive: 20 - }, - editorRange: { - startLineNumber: 1, - startColumn: 11, - endLineNumber: 1, - endColumn: 21 - }, - variableName: "selection", - variableArg: "", - variableId: "copilot.selection", - kind: "var" - }, - { - range: { - start: 20, - endExclusive: 26 - }, - editorRange: { - startLineNumber: 1, - startColumn: 21, - endLineNumber: 1, - endColumn: 27 - }, - text: " mean?", - kind: "text" - } - ], - text: "What does #selection mean?" -} \ No newline at end of file