mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-13 23:44:09 +01:00
Use ChatWidget.input.selectedToolsModel as source of truth for what tools can be selected for a request (#246590)
re https://github.com/microsoft/vscode/issues/246589
This commit is contained in:
@@ -55,7 +55,6 @@ import { IChatEditingService } from '../../common/chatEditingService.js';
|
||||
import { IChatRequestVariableEntry, IDiagnosticVariableEntryFilterData, OmittedState } from '../../common/chatModel.js';
|
||||
import { ChatRequestAgentPart } from '../../common/chatParserTypes.js';
|
||||
import { ChatAgentLocation } from '../../common/constants.js';
|
||||
import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js';
|
||||
import { IChatWidget, IChatWidgetService, IQuickChatService, showChatView } from '../chat.js';
|
||||
import { imageToHash, isImage } from '../chatPasteProviders.js';
|
||||
import { isQuickChat } from '../chatWidget.js';
|
||||
@@ -682,7 +681,6 @@ export class AttachContextAction extends Action2 {
|
||||
const chatAgentService = accessor.get(IChatAgentService);
|
||||
const commandService = accessor.get(ICommandService);
|
||||
const widgetService = accessor.get(IChatWidgetService);
|
||||
const languageModelToolsService = accessor.get(ILanguageModelToolsService);
|
||||
const quickChatService = accessor.get(IQuickChatService);
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
@@ -749,7 +747,7 @@ export class AttachContextAction extends Action2 {
|
||||
}
|
||||
}
|
||||
|
||||
for (const tool of languageModelToolsService.getTools()) {
|
||||
for (const tool of widget.input.selectedToolsModel.tools.get()) {
|
||||
if (tool.canBeReferencedInPrompt) {
|
||||
const item: IToolQuickPickItem = {
|
||||
kind: 'tool',
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChatVariablesService, IDynamicVariable } from '../common/chatVariables.js';
|
||||
import { IToolData } from '../common/languageModelToolsService.js';
|
||||
import { IChatWidgetService } from './chat.js';
|
||||
import { ChatDynamicVariableModel } from './contrib/chatDynamicVariables.js';
|
||||
|
||||
@@ -32,4 +33,12 @@ export class ChatVariablesService implements IChatVariablesService {
|
||||
return model.variables;
|
||||
}
|
||||
|
||||
getSelectedTools(sessionId: string): ReadonlyArray<IToolData> {
|
||||
const widget = this.chatWidgetService.getWidgetBySessionId(sessionId);
|
||||
if (!widget) {
|
||||
return [];
|
||||
}
|
||||
return widget.input.selectedToolsModel.tools.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -985,6 +985,10 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
this.renderWelcomeViewContentIfNeeded();
|
||||
this.refreshParsedInput();
|
||||
}));
|
||||
this._register(autorun(r => {
|
||||
this.input.selectedToolsModel.tools.read(r); // SIGNAL
|
||||
this.refreshParsedInput();
|
||||
}));
|
||||
}
|
||||
|
||||
private onDidStyleChange(): void {
|
||||
|
||||
@@ -42,7 +42,6 @@ import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestTextPa
|
||||
import { IChatSlashCommandService } from '../../common/chatSlashCommands.js';
|
||||
import { IDynamicVariable } from '../../common/chatVariables.js';
|
||||
import { ChatAgentLocation, ChatMode } from '../../common/constants.js';
|
||||
import { ILanguageModelToolsService } from '../../common/languageModelToolsService.js';
|
||||
import { ChatSubmitAction } from '../actions/chatExecuteActions.js';
|
||||
import { IChatWidget, IChatWidgetService } from '../chat.js';
|
||||
import { ChatInputPart } from '../chatInputPart.js';
|
||||
@@ -887,7 +886,6 @@ class ToolCompletions extends Disposable {
|
||||
constructor(
|
||||
@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,
|
||||
@IChatWidgetService private readonly chatWidgetService: IChatWidgetService,
|
||||
@ILanguageModelToolsService toolsService: ILanguageModelToolsService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -908,7 +906,7 @@ class ToolCompletions extends Disposable {
|
||||
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())
|
||||
toolItems.push(...widget.input.selectedToolsModel.tools.get()
|
||||
.filter(t => t.canBeReferencedInPrompt)
|
||||
.filter(t => !usedToolNames.has(t.toolReferenceName ?? ''))
|
||||
.map((t): CompletionItem => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestDynami
|
||||
import { IChatSlashCommandService } from './chatSlashCommands.js';
|
||||
import { IChatVariablesService, IDynamicVariable } from './chatVariables.js';
|
||||
import { ChatAgentLocation, ChatMode } from './constants.js';
|
||||
import { ILanguageModelToolsService } from './languageModelToolsService.js';
|
||||
import { IToolData } from './languageModelToolsService.js';
|
||||
|
||||
const agentReg = /^@([\w_\-\.]+)(?=(\s|$|\b))/i; // An @-agent
|
||||
const variableReg = /^#([\w_\-]+)(:\d+)?(?=(\s|$|\b))/i; // A #-variable with an optional numeric : arg (@response:2)
|
||||
@@ -28,12 +28,12 @@ export class ChatRequestParser {
|
||||
@IChatAgentService private readonly agentService: IChatAgentService,
|
||||
@IChatVariablesService private readonly variableService: IChatVariablesService,
|
||||
@IChatSlashCommandService private readonly slashCommandService: IChatSlashCommandService,
|
||||
@ILanguageModelToolsService private readonly toolsService: ILanguageModelToolsService,
|
||||
) { }
|
||||
|
||||
parseChatRequest(sessionId: string, message: string, location: ChatAgentLocation = ChatAgentLocation.Panel, context?: IChatParserContext): IParsedChatRequest {
|
||||
const parts: IParsedChatRequestPart[] = [];
|
||||
const references = this.variableService.getDynamicVariables(sessionId); // must access this list before any async calls
|
||||
const toolsByName = new Map<string, IToolData>((this.variableService.getSelectedTools(sessionId)).filter(t => t.toolReferenceName).map(t => [t.toolReferenceName!, t]));
|
||||
|
||||
let lineNumber = 1;
|
||||
let column = 1;
|
||||
@@ -43,7 +43,7 @@ export class ChatRequestParser {
|
||||
let newPart: IParsedChatRequestPart | undefined;
|
||||
if (previousChar.match(/\s/) || i === 0) {
|
||||
if (char === chatVariableLeader) {
|
||||
newPart = this.tryToParseVariable(message.slice(i), i, new Position(lineNumber, column), parts);
|
||||
newPart = this.tryToParseVariable(message.slice(i), i, new Position(lineNumber, column), parts, toolsByName);
|
||||
} else if (char === chatAgentLeader) {
|
||||
newPart = this.tryToParseAgent(message.slice(i), message, i, new Position(lineNumber, column), parts, location, context);
|
||||
} else if (char === chatSubcommandLeader) {
|
||||
@@ -141,7 +141,7 @@ export class ChatRequestParser {
|
||||
return new ChatRequestAgentPart(agentRange, agentEditorRange, agent);
|
||||
}
|
||||
|
||||
private tryToParseVariable(message: string, offset: number, position: IPosition, parts: ReadonlyArray<IParsedChatRequestPart>): ChatRequestAgentPart | ChatRequestToolPart | undefined {
|
||||
private tryToParseVariable(message: string, offset: number, position: IPosition, parts: ReadonlyArray<IParsedChatRequestPart>, toolsByName: ReadonlyMap<string, IToolData>): ChatRequestAgentPart | ChatRequestToolPart | undefined {
|
||||
const nextVariableMatch = message.match(variableReg);
|
||||
if (!nextVariableMatch) {
|
||||
return;
|
||||
@@ -151,7 +151,7 @@ export class ChatRequestParser {
|
||||
const varRange = new OffsetRange(offset, offset + full.length);
|
||||
const varEditorRange = new Range(position.lineNumber, position.column, position.lineNumber, position.column + full.length);
|
||||
|
||||
const tool = this.toolsService.getToolByName(name);
|
||||
const tool = toolsByName.get(name);
|
||||
if (tool && tool.canBeReferencedInPrompt) {
|
||||
return new ChatRequestToolPart(varRange, varEditorRange, name, tool.id, tool.displayName, tool.icon);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Location } from '../../../../editor/common/languages.js';
|
||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { IChatModel, IDiagnosticVariableEntryFilterData } from './chatModel.js';
|
||||
import { IChatContentReference, IChatProgressMessage } from './chatService.js';
|
||||
import { IToolData } from './languageModelToolsService.js';
|
||||
|
||||
export interface IChatVariableData {
|
||||
id: string;
|
||||
@@ -45,6 +46,7 @@ export const IChatVariablesService = createDecorator<IChatVariablesService>('ICh
|
||||
export interface IChatVariablesService {
|
||||
_serviceBrand: undefined;
|
||||
getDynamicVariables(sessionId: string): ReadonlyArray<IDynamicVariable>;
|
||||
getSelectedTools(sessionId: string): ReadonlyArray<IToolData>;
|
||||
}
|
||||
|
||||
export interface IDynamicVariable {
|
||||
|
||||
@@ -19,9 +19,8 @@ import { IChatService } from '../../common/chatService.js';
|
||||
import { IChatSlashCommandService } from '../../common/chatSlashCommands.js';
|
||||
import { IChatVariablesService } from '../../common/chatVariables.js';
|
||||
import { ChatMode, ChatAgentLocation } from '../../common/constants.js';
|
||||
import { ILanguageModelToolsService, IToolData } from '../../common/languageModelToolsService.js';
|
||||
import { IToolData } from '../../common/languageModelToolsService.js';
|
||||
import { MockChatService } from './mockChatService.js';
|
||||
import { MockChatVariablesService } from './mockChatVariables.js';
|
||||
|
||||
suite('ChatRequestParser', () => {
|
||||
const testDisposables = ensureNoDisposablesAreLeakedInTestSuite();
|
||||
@@ -29,7 +28,7 @@ suite('ChatRequestParser', () => {
|
||||
let instantiationService: TestInstantiationService;
|
||||
let parser: ChatRequestParser;
|
||||
|
||||
let toolsService: MockObject<ILanguageModelToolsService>;
|
||||
let variableService: MockObject<IChatVariablesService>;
|
||||
setup(async () => {
|
||||
instantiationService = testDisposables.add(new TestInstantiationService());
|
||||
instantiationService.stub(IStorageService, testDisposables.add(new TestStorageService()));
|
||||
@@ -37,11 +36,13 @@ suite('ChatRequestParser', () => {
|
||||
instantiationService.stub(IExtensionService, new TestExtensionService());
|
||||
instantiationService.stub(IChatService, new MockChatService());
|
||||
instantiationService.stub(IContextKeyService, new MockContextKeyService());
|
||||
instantiationService.stub(IChatVariablesService, new MockChatVariablesService());
|
||||
instantiationService.stub(IChatAgentService, testDisposables.add(instantiationService.createInstance(ChatAgentService)));
|
||||
|
||||
toolsService = mockObject<ILanguageModelToolsService>()({});
|
||||
instantiationService.stub(ILanguageModelToolsService, toolsService as any);
|
||||
variableService = mockObject<IChatVariablesService>()();
|
||||
variableService.getDynamicVariables.returns([]);
|
||||
variableService.getSelectedTools.returns([]);
|
||||
|
||||
instantiationService.stub(IChatVariablesService, variableService as any);
|
||||
});
|
||||
|
||||
test('plain text', async () => {
|
||||
@@ -198,8 +199,10 @@ suite('ChatRequestParser', () => {
|
||||
agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]);
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
toolsService.getToolByName.onCall(0).returns({ id: 'get_selection', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } } satisfies IToolData);
|
||||
toolsService.getToolByName.onCall(1).returns({ id: 'get_debugConsole', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } } satisfies IToolData);
|
||||
variableService.getSelectedTools.returns([
|
||||
{ id: 'get_selection', toolReferenceName: 'selection', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } },
|
||||
{ id: 'get_debugConsole', toolReferenceName: 'debugConsole', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } }
|
||||
] satisfies IToolData[]);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
const result = parser.parseChatRequest('1', '@agent /subCommand \nPlease do with #selection\nand #debugConsole');
|
||||
@@ -211,8 +214,10 @@ suite('ChatRequestParser', () => {
|
||||
agentsService.getAgentsByName.returns([getAgentWithSlashCommands([{ name: 'subCommand', description: '' }])]);
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
toolsService.getToolByName.onCall(0).returns({ id: 'get_selection', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } } satisfies IToolData);
|
||||
toolsService.getToolByName.onCall(1).returns({ id: 'get_debugConsole', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } } satisfies IToolData);
|
||||
variableService.getSelectedTools.returns([
|
||||
{ id: 'get_selection', toolReferenceName: 'selection', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } },
|
||||
{ id: 'get_debugConsole', toolReferenceName: 'debugConsole', canBeReferencedInPrompt: true, displayName: '', modelDescription: '', source: { type: 'internal' } }
|
||||
] satisfies IToolData[]);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
const result = parser.parseChatRequest('1', '@agent Please \ndo /subCommand with #selection\nand #debugConsole');
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChatVariablesService, IDynamicVariable } from '../../common/chatVariables.js';
|
||||
import { IToolData } from '../../common/languageModelToolsService.js';
|
||||
|
||||
export class MockChatVariablesService implements IChatVariablesService {
|
||||
_serviceBrand: undefined;
|
||||
@@ -11,4 +12,8 @@ export class MockChatVariablesService implements IChatVariablesService {
|
||||
getDynamicVariables(sessionId: string): readonly IDynamicVariable[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
getSelectedTools(sessionId: string): readonly IToolData[] {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user