Merge pull request #210488 from microsoft/roblou/chat-agent-hover

Add a nicer hover for chat participants
This commit is contained in:
Rob Lourens 2024-04-19 14:11:21 -07:00 committed by GitHub
commit 629408958c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 225 additions and 27 deletions

View file

@ -256,7 +256,7 @@ function createGitIndexVinyls(paths) {
cp.exec(
process.platform === 'win32' ? `git show :${relativePath}` : `git show ':${relativePath}'`,
{ maxBuffer: 2000 * 1024, encoding: 'buffer' },
{ maxBuffer: stat.size, encoding: 'buffer' },
(err, out) => {
if (err) {
return e(err);

View file

@ -137,6 +137,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
name: dynamicProps.name,
description: dynamicProps.description,
extensionId: extension,
extensionDisplayName: extensionDescription?.displayName ?? extension.value,
extensionPublisher: extensionDescription?.publisherDisplayName ?? extension.value,
metadata: revive(metadata),
slashCommands: [],

View file

@ -0,0 +1,83 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { h } from 'vs/base/browser/dom';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { CancellationToken } from 'vs/base/common/cancellation';
import { FileAccess } from 'vs/base/common/network';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI } from 'vs/base/common/uri';
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { verifiedPublisherIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
export class ChatAgentHover {
public readonly domNode: HTMLElement;
constructor(
id: string,
@IChatAgentService private readonly chatAgentService: IChatAgentService,
@IExtensionsWorkbenchService private readonly extensionService: IExtensionsWorkbenchService,
) {
const agent = this.chatAgentService.getAgent(id)!;
const hoverElement = h(
'.chat-agent-hover@root',
[
h('.chat-agent-hover-header', [
h('.chat-agent-hover-icon@icon'),
h('.chat-agent-hover-details', [
h('.chat-agent-hover-name@name'),
h('.chat-agent-hover-extension', [
h('.chat-agent-hover-extension-name@extensionName'),
h('.chat-agent-hover-separator@separator'),
h('.chat-agent-hover-publisher@publisher'),
]),
]),
]),
h('.chat-agent-hover-description@description'),
]);
this.domNode = hoverElement.root;
if (agent.metadata.icon instanceof URI) {
const avatarIcon = dom.$<HTMLImageElement>('img.icon');
avatarIcon.src = FileAccess.uriToBrowserUri(agent.metadata.icon).toString(true);
hoverElement.icon.replaceChildren(dom.$('.avatar', undefined, avatarIcon));
} else if (agent.metadata.themeIcon) {
const avatarIcon = dom.$(ThemeIcon.asCSSSelector(agent.metadata.themeIcon));
hoverElement.icon.replaceChildren(dom.$('.avatar.codicon-avatar', undefined, avatarIcon));
}
hoverElement.name.textContent = `@${agent.name}`;
hoverElement.extensionName.textContent = agent.extensionDisplayName;
hoverElement.separator.textContent = '|';
const verifiedBadge = dom.$('span.extension-verified-publisher', undefined, renderIcon(verifiedPublisherIcon));
verifiedBadge.style.display = 'none';
dom.append(
hoverElement.publisher,
verifiedBadge,
agent.extensionPublisher);
const description = agent.description && !agent.description.endsWith('.') ?
`${agent.description}. ` :
(agent.description || '');
hoverElement.description.textContent = description;
// const marketplaceLink = document.createElement('a');
// marketplaceLink.setAttribute('href', `command:${showExtensionsWithIdsCommandId}?${encodeURIComponent(JSON.stringify([agent.extensionId.value]))}`);
// marketplaceLink.textContent = localize('marketplaceLabel', "View in Marketplace") + '.';
// hoverElement.description.appendChild(marketplaceLink);
this.extensionService.getExtensions([{ id: agent.extensionId.value }], CancellationToken.None).then(extensions => {
const extension = extensions[0];
if (extension?.publisherDomain?.verified) {
verifiedBadge.style.display = '';
}
});
}
}

View file

@ -7,6 +7,7 @@ import * as dom from 'vs/base/browser/dom';
import { IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { Button } from 'vs/base/browser/ui/button/button';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeCompressionDelegate } from 'vs/base/browser/ui/tree/asyncDataTree';
@ -16,6 +17,7 @@ import { IAsyncDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/t
import { IAction } from 'vs/base/common/actions';
import { distinct } from 'vs/base/common/arrays';
import { disposableTimeout } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Codicon } from 'vs/base/common/codicons';
import { Emitter, Event } from 'vs/base/common/event';
import { FuzzyScore } from 'vs/base/common/filters';
@ -24,13 +26,18 @@ import { Disposable, DisposableStore, IDisposable, IReference, toDisposable } fr
import { ResourceMap } from 'vs/base/common/map';
import { FileAccess, Schemas, matchesSomeScheme } from 'vs/base/common/network';
import { clamp } from 'vs/base/common/numbers';
import { IObservable, autorun, constObservable } from 'vs/base/common/observable';
import { basename } from 'vs/base/common/path';
import { basenameOrAuthority } from 'vs/base/common/resources';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { ThemeIcon } from 'vs/base/common/themables';
import { isUndefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';
import { Range } from 'vs/editor/common/core/range';
import { TextEdit } from 'vs/editor/common/languages';
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
import { IModelService } from 'vs/editor/common/services/model';
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
import { localize } from 'vs/nls';
import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
@ -40,6 +47,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { FileKind, FileType } from 'vs/platform/files/common/files';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { WorkbenchCompressibleAsyncDataTree, WorkbenchList } from 'vs/platform/list/browser/listService';
@ -50,6 +58,7 @@ import { ColorScheme } from 'vs/platform/theme/common/theme';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
import { ChatTreeItem, GeneratingPhrase, IChatCodeBlockInfo, IChatFileTreeInfo } from 'vs/workbench/contrib/chat/browser/chat';
import { ChatAgentHover } from 'vs/workbench/contrib/chat/browser/chatAgentHover';
import { ChatFollowups } from 'vs/workbench/contrib/chat/browser/chatFollowups';
import { ChatMarkdownDecorationsRenderer } from 'vs/workbench/contrib/chat/browser/chatMarkdownDecorationsRenderer';
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
@ -66,17 +75,12 @@ import { createFileIconThemableTreeContainerScope } from 'vs/workbench/contrib/f
import { IFilesConfiguration } from 'vs/workbench/contrib/files/common/files';
import { IMarkdownVulnerability, annotateSpecialMarkdownContent } from '../common/annotations';
import { CodeBlockModelCollection } from '../common/codeBlockModelCollection';
import { IModelService } from 'vs/editor/common/services/model';
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
import { TextEdit } from 'vs/editor/common/languages';
import { IChatListItemRendererOptions } from './chat';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { autorun, constObservable, IObservable } from 'vs/base/common/observable';
import { isUndefined } from 'vs/base/common/types';
const $ = dom.$;
interface IChatListItemTemplate {
currentElement?: ChatTreeItem;
readonly rowContainer: HTMLElement;
readonly titleToolbar?: MenuWorkbenchToolBar;
readonly avatarContainer: HTMLElement;
@ -148,6 +152,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
@ICommandService private readonly commandService: ICommandService,
@ITextModelService private readonly textModelService: ITextModelService,
@IModelService private readonly modelService: IModelService,
@IHoverService private readonly hoverService: IHoverService,
@IChatAgentNameService private readonly chatAgentNameService: IChatAgentNameService,
) {
super();
@ -286,6 +291,16 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}
}));
}
templateDisposables.add(this.hoverService.setupUpdatableHover(getDefaultHoverDelegate('mouse'), header, () => {
if (isResponseVM(template.currentElement) && template.currentElement.agent) {
const hover = this.instantiationService.createInstance(ChatAgentHover, template.currentElement.agent.id);
return hover.domNode;
}
return undefined;
}));
const template: IChatListItemTemplate = { avatarContainer, agentAvatarContainer, username, detail, referencesListContainer, value, rowContainer, elementDisposables, titleToolbar, templateDisposables, contextKeyService };
return template;
}
@ -295,6 +310,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}
renderChatTreeItem(element: ChatTreeItem, index: number, templateData: IChatListItemTemplate): void {
templateData.currentElement = element;
const kind = isRequestVM(element) ? 'request' :
isResponseVM(element) ? 'response' :
'welcome';
@ -416,11 +432,6 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}
templateData.detail.textContent = progressMsg;
if (element.agent) {
templateData.detail.title = progressMsg + (element.slashCommand?.description ? `\n${element.slashCommand.description}` : '');
} else {
templateData.detail.title = '';
}
}
private renderAvatar(element: ChatTreeItem, templateData: IChatListItemTemplate): void {
@ -1038,7 +1049,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
disposables.add(toDisposable(() => this.codeBlocksByResponseId.delete(element.id)));
}
this.markdownDecorationsRenderer.walkTreeAndAnnotateReferenceLinks(result.element);
disposables.add(this.markdownDecorationsRenderer.walkTreeAndAnnotateReferenceLinks(result.element));
orderedDisposablesList.reverse().forEach(d => disposables.add(d));
return {

View file

@ -5,17 +5,23 @@
import * as dom from 'vs/base/browser/dom';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { revive } from 'vs/base/common/marshalling';
import { URI } from 'vs/base/common/uri';
import { Location } from 'vs/editor/common/languages';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
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 { ChatAgentHover } from 'vs/workbench/contrib/chat/browser/chatAgentHover';
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';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
const variableRefUrl = 'http://_vscodedecoration_';
const agentRefUrl = 'http://_chatagent_';
export class ChatMarkdownDecorationsRenderer {
constructor(
@ -23,6 +29,8 @@ export class ChatMarkdownDecorationsRenderer {
@ILabelService private readonly labelService: ILabelService,
@ILogService private readonly logService: ILogService,
@IChatAgentService private readonly chatAgentService: IChatAgentService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IHoverService private readonly hoverService: IHoverService,
) { }
convertParsedRequestToMarkdown(parsedRequest: IParsedChatRequest): string {
@ -30,6 +38,14 @@ export class ChatMarkdownDecorationsRenderer {
for (const part of parsedRequest.parts) {
if (part instanceof ChatRequestTextPart) {
result += part.text;
} else if (part instanceof ChatRequestAgentPart) {
let text = part.text;
const isDupe = this.chatAgentService.getAgentsByName(part.agent.name).length > 1;
if (isDupe) {
text += ` (${part.agent.extensionPublisher})`;
}
result += `[${text}](${agentRefUrl}?${encodeURIComponent(part.agent.id)})`;
} else {
const uri = part instanceof ChatRequestDynamicVariablePart && part.data.map(d => d.value).find((d): d is URI => d instanceof URI)
|| undefined;
@ -37,14 +53,7 @@ export class ChatMarkdownDecorationsRenderer {
part instanceof ChatRequestAgentPart ? part.agent.id :
'';
let text = part.text;
if (part instanceof ChatRequestAgentPart) {
const isDupe = this.chatAgentService.getAgentsByName(part.agent.name).length > 1;
if (isDupe) {
text += ` (${part.agent.extensionPublisher})`;
}
}
const text = part.text;
result += `[${text}](${variableRefUrl}?${title})`;
}
}
@ -52,11 +61,17 @@ export class ChatMarkdownDecorationsRenderer {
return result;
}
walkTreeAndAnnotateReferenceLinks(element: HTMLElement): void {
walkTreeAndAnnotateReferenceLinks(element: HTMLElement): IDisposable {
const store = new DisposableStore();
element.querySelectorAll('a').forEach(a => {
const href = a.getAttribute('data-href');
if (href) {
if (href.startsWith(variableRefUrl)) {
if (href.startsWith(agentRefUrl)) {
const title = decodeURIComponent(href.slice(agentRefUrl.length + 1));
a.parentElement!.replaceChild(
this.renderAgentWidget(a.textContent!, title, store),
a);
} else if (href.startsWith(variableRefUrl)) {
const title = decodeURIComponent(href.slice(variableRefUrl.length + 1));
a.parentElement!.replaceChild(
this.renderResourceWidget(a.textContent!, title),
@ -68,6 +83,18 @@ export class ChatMarkdownDecorationsRenderer {
}
}
});
return store;
}
private renderAgentWidget(name: string, id: string, store: DisposableStore): HTMLElement {
const container = dom.$('span.chat-resource-widget', undefined, dom.$('span', undefined, name));
store.add(this.hoverService.setupUpdatableHover(getDefaultHoverDelegate('element'), container, () => {
const hover = this.instantiationService.createInstance(ChatAgentHover, id);
return hover.domNode;
}));
return container;
}
private renderFileWidget(href: string, a: HTMLAnchorElement): void {

View file

@ -203,6 +203,7 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
{
extensionId: extension.description.identifier,
extensionPublisher: extension.description.publisherDisplayName ?? extension.description.publisher, // May not be present in OSS
extensionDisplayName: extension.description.displayName ?? extension.description.name,
id: providerDescriptor.id,
description: providerDescriptor.description,
metadata: {

View file

@ -14,6 +14,7 @@ import { isEqual } from 'vs/base/common/resources';
import { isDefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/chat';
import 'vs/css!./media/chatHover';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { MenuId } from 'vs/platform/actions/common/actions';

View file

@ -101,7 +101,7 @@
width: 24px;
height: 24px;
border-radius: 50%;
outline: 1px solid var(--vscode-chat-requestBorder)
outline: 1px solid var(--vscode-chat-requestBorder);
}
.interactive-item-container .header .avatar.codicon-avatar {

View file

@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.chat-agent-hover {
line-height: unset;
padding: 6px 0px;
}
.chat-agent-hover-header {
display: flex;
gap: 5px;
}
.chat-agent-hover-icon img,
.chat-agent-hover-icon .codicon {
width: 32px;
height: 32px;
border-radius: 50%;
outline: 1px solid var(--vscode-chat-requestBorder);
}
.monaco-hover .markdown-hover .hover-contents .chat-agent-hover-icon .codicon {
font-size: 23px;
display: flex;
justify-content: center;
align-items: center;
}
.chat-agent-hover-publisher {
display: flex;
gap: 4px;
}
.monaco-hover .chat-agent-hover .chat-agent-hover-publisher .codicon.codicon-extensions-verified-publisher {
color: var(--vscode-extensionIcon-verifiedForeground);
}
.chat-agent-hover-header .chat-agent-hover-name {
font-size: 15px;
font-weight: 600;
}
.chat-agent-hover-extension {
display: flex;
gap: 6px;
}
.chat-agent-hover-separator {
opacity: 0.7;
}
.chat-agent-hover-description {
font-size: 13px;
}

View file

@ -60,6 +60,7 @@ export interface IChatAgentData {
description?: string;
extensionId: ExtensionIdentifier;
extensionPublisher: string;
extensionDisplayName: string;
/** The agent invoked when no agent is specified */
isDefault?: boolean;
metadata: IChatAgentMetadata;
@ -325,6 +326,7 @@ export class MergedChatAgent implements IChatAgent {
get description(): string { return this.data.description ?? ''; }
get extensionId(): ExtensionIdentifier { return this.data.extensionId; }
get extensionPublisher(): string { return this.data.extensionPublisher; }
get extensionDisplayName(): string { return this.data.extensionDisplayName; }
get isDefault(): boolean | undefined { return this.data.isDefault; }
get metadata(): IChatAgentMetadata { return this.data.metadata; }
get slashCommands(): IChatAgentCommand[] { return this.data.slashCommands; }

View file

@ -33,6 +33,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -33,6 +33,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -19,6 +19,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -19,6 +19,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -19,6 +19,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -19,6 +19,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -19,6 +19,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [

View file

@ -29,6 +29,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [ ]
@ -65,6 +66,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: { },
slashCommands: [ ]

View file

@ -28,6 +28,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: {
requester: { name: "test" },
@ -68,6 +69,7 @@
_lower: "nullextensiondescription"
},
extensionPublisher: "",
extensionDisplayName: "",
locations: [ "panel" ],
metadata: {
requester: { name: "test" },

View file

@ -115,7 +115,7 @@ suite('ChatRequestParser', () => {
});
const getAgentWithSlashCommands = (slashCommands: IChatAgentCommand[]) => {
return { id: 'agent', name: 'agent', extensionId: nullExtensionDescription.identifier, extensionPublisher: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands } satisfies IChatAgentData;
return { id: 'agent', name: 'agent', extensionId: nullExtensionDescription.identifier, extensionPublisher: '', extensionDisplayName: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands } satisfies IChatAgentData;
};
test('agent with subcommand after text', async () => {

View file

@ -36,6 +36,7 @@ const chatAgentWithUsedContext: IChatAgent = {
name: chatAgentWithUsedContextId,
extensionId: nullExtensionDescription.identifier,
extensionPublisher: '',
extensionDisplayName: '',
locations: [ChatAgentLocation.Panel],
metadata: {},
slashCommands: [],
@ -90,8 +91,8 @@ suite('ChatService', () => {
return {};
},
} satisfies IChatAgentImplementation;
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.registerAgent('testAgent', { name: 'testAgent', id: 'testAgent', isDefault: true, extensionId: nullExtensionDescription.identifier, extensionPublisher: '', extensionDisplayName: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [] }));
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContextId, { name: chatAgentWithUsedContextId, id: chatAgentWithUsedContextId, extensionId: nullExtensionDescription.identifier, extensionPublisher: '', extensionDisplayName: '', locations: [ChatAgentLocation.Panel], metadata: {}, slashCommands: [] }));
testDisposables.add(chatAgentService.registerAgentImplementation('testAgent', agent));
chatAgentService.updateAgent('testAgent', { requester: { name: 'test' }, fullName: 'test' });
});

View file

@ -28,6 +28,7 @@ suite('VoiceChat', () => {
extensionId: ExtensionIdentifier = nullExtensionDescription.identifier;
extensionPublisher = '';
extensionDisplayName = '';
locations: ChatAgentLocation[] = [ChatAgentLocation.Panel];
public readonly name: string;
constructor(readonly id: string, readonly slashCommands: IChatAgentCommand[]) {

View file

@ -318,6 +318,7 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService {
name: 'editor',
extensionId: nullExtensionDescription.identifier,
extensionPublisher: '',
extensionDisplayName: '',
isDefault: true,
locations: [ChatAgentLocation.Editor],
get slashCommands(): IChatAgentCommand[] {

View file

@ -181,6 +181,7 @@ suite('InteractiveChatController', function () {
store.add(chatAgentService.registerDynamicAgent({
extensionId: nullExtensionDescription.identifier,
extensionPublisher: '',
extensionDisplayName: '',
id: 'testAgent',
name: 'testAgent',
isDefault: true,

View file

@ -128,6 +128,7 @@ suite('InlineChatSession', function () {
instaService.get(IChatAgentService).registerDynamicAgent({
extensionId: nullExtensionDescription.identifier,
extensionPublisher: '',
extensionDisplayName: '',
id: 'testAgent',
name: 'testAgent',
isDefault: true,