From 437a79c17ec3d3bf6d1e05309b110a4548547c8d Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 9 Apr 2024 19:39:53 -0300 Subject: [PATCH] Render publisher with dupe chat participant names (#209983) * Render publisher with dupe chat participant names * Use publisher for suggest as well --- .../workbench/api/browser/mainThreadChatAgents2.ts | 4 ++++ .../browser/chatMarkdownDecorationsRenderer.ts | 14 ++++++++++++-- .../chat/browser/chatParticipantContributions.ts | 1 + .../chat/browser/contrib/chatInputEditorContrib.ts | 8 ++++---- src/vs/workbench/contrib/chat/common/chatAgents.ts | 2 ++ src/vs/workbench/contrib/chat/common/chatModel.ts | 12 +++++++++++- ...arser_agent_and_subcommand_after_newline.0.snap | 3 ++- ...t_and_subcommand_with_leading_whitespace.0.snap | 3 ++- ...atRequestParser_agent_with_question_mark.0.snap | 3 ++- ...tParser_agent_with_subcommand_after_text.0.snap | 3 ++- .../ChatRequestParser_agents__subCommand.0.snap | 3 ++- ...arser_agents_and_variables_and_multiline.0.snap | 3 ++- ...gents_and_variables_and_multiline__part2.0.snap | 3 ++- .../ChatService_can_deserialize.0.snap | 3 ++- .../__snapshots__/ChatService_can_serialize.1.snap | 3 ++- .../chat/test/common/chatRequestParser.test.ts | 2 +- .../contrib/chat/test/common/chatService.test.ts | 5 +++-- .../contrib/chat/test/common/voiceChat.test.ts | 1 + .../browser/inlineChatSessionServiceImpl.ts | 1 + .../test/browser/inlineChatController.test.ts | 1 + .../test/browser/inlineChatSession.test.ts | 1 + 21 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index f34bcdb116b..c4c35bb3977 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -26,6 +26,7 @@ import { ChatRequestAgentPart } from 'vs/workbench/contrib/chat/common/chatParse import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser'; import { IChatFollowup, IChatProgress, IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; interface AgentData { dispose: () => void; @@ -51,6 +52,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA @IChatWidgetService private readonly _chatWidgetService: IChatWidgetService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @ILogService private readonly _logService: ILogService, + @IExtensionService private readonly _extensionService: IExtensionService, ) { super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2); @@ -128,12 +130,14 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA let disposable: IDisposable; if (!staticAgentRegistration && dynamicProps) { + const extensionDescription = this._extensionService.extensions.find(e => ExtensionIdentifier.equals(e.identifier, extension)); disposable = this._chatAgentService.registerDynamicAgent( { id, name: dynamicProps.name, description: dynamicProps.description, extensionId: extension, + extensionPublisher: extensionDescription?.publisherDisplayName ?? extension.value, metadata: revive(metadata), slashCommands: [], locations: [ChatAgentLocation.Panel] // TODO all dynamic participants are panel only? diff --git a/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts index bbacc39b7c8..029fa947dda 100644 --- a/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer.ts @@ -11,6 +11,7 @@ import { Location } from 'vs/editor/common/languages'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; +import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestAgentPart, ChatRequestDynamicVariablePart, ChatRequestTextPart, IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { contentRefUrl } from '../common/annotations'; @@ -20,7 +21,8 @@ export class ChatMarkdownDecorationsRenderer { constructor( @IKeybindingService private readonly keybindingService: IKeybindingService, @ILabelService private readonly labelService: ILabelService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IChatAgentService private readonly chatAgentService: IChatAgentService, ) { } convertParsedRequestToMarkdown(parsedRequest: IParsedChatRequest): string { @@ -35,7 +37,15 @@ export class ChatMarkdownDecorationsRenderer { part instanceof ChatRequestAgentPart ? part.agent.id : ''; - result += `[${part.text}](${variableRefUrl}?${title})`; + let text = part.text; + if (part instanceof ChatRequestAgentPart) { + const isDupe = this.chatAgentService.getAgentsByName(part.agent.name).length > 1; + if (isDupe) { + text += ` (${part.agent.extensionPublisher})`; + } + } + + result += `[${text}](${variableRefUrl}?${title})`; } } diff --git a/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts b/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts index f51280b2cb1..ceacef4c8aa 100644 --- a/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts +++ b/src/vs/workbench/contrib/chat/browser/chatParticipantContributions.ts @@ -202,6 +202,7 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution { providerDescriptor.id, { extensionId: extension.description.identifier, + extensionPublisher: extension.description.publisherDisplayName ?? extension.description.publisher, // May not be present in OSS id: providerDescriptor.id, description: providerDescriptor.description, metadata: { diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index 45bdb56ceca..9a8c0d27e9a 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -213,8 +213,8 @@ class InputEditorDecorations extends Disposable { const textDecorations: IDecorationOptions[] | undefined = []; if (agentPart) { const isDupe = !!this.chatAgentService.getAgents().find(other => other.name === agentPart.agent.name && other.id !== agentPart.agent.id); - const id = isDupe ? `(${agentPart.agent.id}) ` : ''; - const agentHover = `${id}${agentPart.agent.description}`; + const publisher = isDupe ? `(${agentPart.agent.extensionPublisher}) ` : ''; + const agentHover = `${publisher}${agentPart.agent.description}`; textDecorations.push({ range: agentPart.editorRange, hoverMessage: new MarkdownString(agentHover) }); if (agentSubcommandPart) { textDecorations.push({ range: agentSubcommandPart.editorRange, hoverMessage: new MarkdownString(agentSubcommandPart.command.description) }); @@ -361,7 +361,7 @@ class AgentCompletions extends Disposable { return { // Leading space is important because detail has no space at the start by design label: isDupe ? - { label: withAt, description: a.description, detail: ` (${a.id})` } : + { label: withAt, description: a.description, detail: ` (${a.extensionPublisher})` } : withAt, insertText: `${withAt} `, detail: a.description, @@ -452,7 +452,7 @@ class AgentCompletions extends Disposable { return { label: isDupe ? - { label: agentLabel, description: agent.description, detail: ` (${agent.id})` } : + { label: agentLabel, description: agent.description, detail: ` (${agent.extensionPublisher})` } : agentLabel, detail, filterText: `${chatSubcommandLeader}${agent.name}`, diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 36e52267612..89d3d9ba692 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -51,6 +51,7 @@ export interface IChatAgentData { name: string; description?: string; extensionId: ExtensionIdentifier; + extensionPublisher: string; /** The agent invoked when no agent is specified */ isDefault?: boolean; metadata: IChatAgentMetadata; @@ -315,6 +316,7 @@ export class MergedChatAgent implements IChatAgent { get name(): string { return this.data.name ?? ''; } get description(): string { return this.data.description ?? ''; } get extensionId(): ExtensionIdentifier { return this.data.extensionId; } + get extensionPublisher(): string { return this.data.extensionPublisher; } get isDefault(): boolean | undefined { return this.data.isDefault; } get metadata(): IChatAgentMetadata { return this.data.metadata; } get slashCommands(): IChatAgentCommand[] { return this.data.slashCommands; } diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 9f39ecc6ef3..3be0bf42f85 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -831,7 +831,17 @@ export class ChatModel extends Disposable implements IChatModel { vote: r.response?.vote, agent: r.response?.agent ? // May actually be the full IChatAgent instance, just take the data props. slashCommands don't matter here. - { id: r.response.agent.id, name: r.response.agent.name, description: r.response.agent.description, extensionId: r.response.agent.extensionId, metadata: r.response.agent.metadata, slashCommands: [], locations: r.response.agent.locations, isDefault: r.response.agent.isDefault } + { + id: r.response.agent.id, + name: r.response.agent.name, + description: r.response.agent.description, + extensionId: r.response.agent.extensionId, + metadata: r.response.agent.metadata, + slashCommands: [], + locations: r.response.agent.locations, + isDefault: r.response.agent.isDefault, + extensionPublisher: r.response.agent.extensionPublisher + } : undefined, slashCommand: r.response?.slashCommand, usedContext: r.response?.usedContext, diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap index 913d93883a3..5b3382f7f9b 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_after_newline.0.snap @@ -32,8 +32,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap index 847804842be..b94fff763b8 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_and_subcommand_with_leading_whitespace.0.snap @@ -32,8 +32,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap index 42a9e4e71d0..328e3c25f2f 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_question_mark.0.snap @@ -18,8 +18,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap index 50301b0cf1c..3c728f2cddb 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agent_with_subcommand_after_text.0.snap @@ -18,8 +18,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap index 8de370325aa..a86a14bc12e 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatRequestParser_agents__subCommand.0.snap @@ -18,8 +18,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", 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 index 855c14d6033..d9477191ad8 100644 --- 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 @@ -18,8 +18,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", 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 index c33398a6d33..0fd12d19d28 100644 --- 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 @@ -18,8 +18,9 @@ value: "nullExtensionDescription", _lower: "nullextensiondescription" }, + extensionPublisher: "", locations: [ "panel" ], - metadata: { description: "" }, + metadata: { }, slashCommands: [ { name: "subCommand", diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_deserialize.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_deserialize.0.snap index 898e6805877..d4140a40acf 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_deserialize.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_deserialize.0.snap @@ -62,7 +62,8 @@ metadata: { }, slashCommands: [ ], locations: [ "panel" ], - isDefault: undefined + isDefault: undefined, + extensionPublisher: "" }, slashCommand: undefined, usedContext: { diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_serialize.1.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_serialize.1.snap index b561861abb8..f90048cac64 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_serialize.1.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/ChatService_can_serialize.1.snap @@ -68,7 +68,8 @@ }, slashCommands: [ ], locations: [ "panel" ], - isDefault: undefined + isDefault: undefined, + extensionPublisher: "" }, slashCommand: undefined, usedContext: { 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 09f5ee0af0d..1f00d288001 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatRequestParser.test.ts @@ -115,7 +115,7 @@ suite('ChatRequestParser', () => { }); const getAgentWithSlashCommands = (slashCommands: IChatAgentCommand[]) => { - return { id: 'agent', name: 'agent', extensionId: nullExtensionDescription.identifier, locations: [ChatAgentLocation.Panel], metadata: { description: '' }, slashCommands }; + return { id: 'agent', name: 'agent', extensionId: nullExtensionDescription.identifier, extensionPublisher: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands } satisfies IChatAgentData; }; test('agent with subcommand after text', async () => { diff --git a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts index f55f6d17fed..48701f493c2 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts @@ -35,6 +35,7 @@ const chatAgentWithUsedContext: IChatAgent = { id: chatAgentWithUsedContextId, name: chatAgentWithUsedContextId, extensionId: nullExtensionDescription.identifier, + extensionPublisher: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [], @@ -89,8 +90,8 @@ suite('ChatService', () => { return {}; }, } satisfies IChatAgentImplementation; - testDisposables.add(chatAgentService.registerAgent('testAgent', { name: 'testAgent', id: 'testAgent', isDefault: true, extensionId: nullExtensionDescription.identifier, locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [] })); - testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContextId, { name: chatAgentWithUsedContextId, id: chatAgentWithUsedContextId, extensionId: nullExtensionDescription.identifier, locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [] })); + testDisposables.add(chatAgentService.registerAgent('testAgent', { name: 'testAgent', id: 'testAgent', isDefault: true, extensionId: nullExtensionDescription.identifier, extensionPublisher: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [] })); + testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContextId, { name: chatAgentWithUsedContextId, id: chatAgentWithUsedContextId, extensionId: nullExtensionDescription.identifier, extensionPublisher: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [] })); testDisposables.add(chatAgentService.registerAgentImplementation('testAgent', agent)); chatAgentService.updateAgent('testAgent', { requester: { name: 'test' }, fullName: 'test' }); }); diff --git a/src/vs/workbench/contrib/chat/test/common/voiceChat.test.ts b/src/vs/workbench/contrib/chat/test/common/voiceChat.test.ts index da6d6b2b02e..37298159727 100644 --- a/src/vs/workbench/contrib/chat/test/common/voiceChat.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/voiceChat.test.ts @@ -27,6 +27,7 @@ suite('VoiceChat', () => { class TestChatAgent implements IChatAgent { extensionId: ExtensionIdentifier = nullExtensionDescription.identifier; + extensionPublisher = ''; locations: ChatAgentLocation[] = [ChatAgentLocation.Panel]; public readonly name: string; constructor(readonly id: string, readonly slashCommands: IChatAgentCommand[]) { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts index 35a3b2f9f0b..bc7a8c3d2df 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts @@ -273,6 +273,7 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { id: _bridgeAgentId, name: 'editor', extensionId: nullExtensionDescription.identifier, + extensionPublisher: '', isDefault: true, locations: [ChatAgentLocation.Editor], get slashCommands(): IChatAgentCommand[] { diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts index 5b1528d3604..9c65a30b47e 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatController.test.ts @@ -181,6 +181,7 @@ suite('InteractiveChatController', function () { store.add(chatAgentService.registerDynamicAgent({ extensionId: nullExtensionDescription.identifier, + extensionPublisher: '', id: 'testAgent', name: 'testAgent', isDefault: true, diff --git a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts index b362b16f002..054de63daef 100644 --- a/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts +++ b/src/vs/workbench/contrib/inlineChat/test/browser/inlineChatSession.test.ts @@ -127,6 +127,7 @@ suite('InlineChatSession', function () { instaService.get(IChatAgentService).registerDynamicAgent({ extensionId: nullExtensionDescription.identifier, + extensionPublisher: '', id: 'testAgent', name: 'testAgent', isDefault: true,