mirror of https://github.com/microsoft/vscode.git
Support chat participants in agent mode (#256113)
* Allow participants in any mode Fix #255921 * Get rid of unneeded context keys * Preserve modes for default agents * Fix tests * Fix test
This commit is contained in:
parent
9abb71c178
commit
d8af289890
|
@ -75,6 +75,9 @@
|
|||
"name": "hello",
|
||||
"description": "Hello"
|
||||
}
|
||||
],
|
||||
"modes": [
|
||||
"agent", "ask", "edit"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -208,8 +208,8 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
metadata: revive(metadata),
|
||||
slashCommands: [],
|
||||
disambiguation: [],
|
||||
locations: [ChatAgentLocation.Panel], // TODO all dynamic participants are panel only?
|
||||
modes: [ChatModeKind.Ask]
|
||||
locations: [ChatAgentLocation.Panel],
|
||||
modes: [ChatModeKind.Ask, ChatModeKind.Agent, ChatModeKind.Edit],
|
||||
},
|
||||
impl);
|
||||
} else {
|
||||
|
|
|
@ -155,10 +155,7 @@ abstract class OpenChatGlobalAction extends Action2 {
|
|||
}
|
||||
|
||||
const switchToModeInput = opts?.mode ?? this.mode;
|
||||
let switchToMode = switchToModeInput && (chatModeService.findModeById(switchToModeInput) ?? chatModeService.findModeByName(switchToModeInput));
|
||||
if (!switchToMode) {
|
||||
switchToMode = opts?.query?.startsWith('@') ? ChatMode.Ask : undefined;
|
||||
}
|
||||
const switchToMode = switchToModeInput && (chatModeService.findModeById(switchToModeInput) ?? chatModeService.findModeByName(switchToModeInput));
|
||||
if (switchToMode) {
|
||||
await this.handleSwitchToMode(switchToMode, chatWidget, instaService, commandService);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ export function registerNewChatActions() {
|
|||
title: localize2('chat.newEdits.label', "New Chat"),
|
||||
category: CHAT_CATEGORY,
|
||||
icon: Codicon.plus,
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.enabled),
|
||||
f1: true,
|
||||
menu: [{
|
||||
id: MenuId.ChatContext,
|
||||
|
@ -142,7 +142,7 @@ export function registerNewChatActions() {
|
|||
title: localize2('chat.undoEdit.label', "Undo Last Request"),
|
||||
category: CHAT_CATEGORY,
|
||||
icon: Codicon.discard,
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanUndo, ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanUndo, ChatContextKeys.enabled),
|
||||
f1: true,
|
||||
menu: [{
|
||||
id: MenuId.ViewTitle,
|
||||
|
@ -166,7 +166,7 @@ export function registerNewChatActions() {
|
|||
title: localize2('chat.redoEdit.label', "Redo Checkpoint Restore"),
|
||||
category: CHAT_CATEGORY,
|
||||
icon: Codicon.redo,
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled),
|
||||
f1: true,
|
||||
menu: [
|
||||
{
|
||||
|
@ -191,7 +191,7 @@ export function registerNewChatActions() {
|
|||
id: 'workbench.action.chat.redoEdit2',
|
||||
title: localize2('chat.redoEdit.label2', "Redo Checkpoint Restore"),
|
||||
category: CHAT_CATEGORY,
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
|
||||
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled),
|
||||
f1: true,
|
||||
menu: [{
|
||||
id: MenuId.ChatMessageRestoreCheckpoint,
|
||||
|
|
|
@ -247,6 +247,11 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (providerDescriptor.isDefault && !providerDescriptor.modes?.length) {
|
||||
extension.collector.error(`Extension '${extension.description.identifier.value}' CANNOT register default participant without modes.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (providerDescriptor.locations && !isProposedApiEnabled(extension.description, 'chatParticipantAdditions')) {
|
||||
extension.collector.error(`Extension '${extension.description.identifier.value}' CANNOT use API proposal: chatParticipantAdditions.`);
|
||||
continue;
|
||||
|
@ -291,7 +296,7 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
|||
locations: isNonEmptyArray(providerDescriptor.locations) ?
|
||||
providerDescriptor.locations.map(ChatAgentLocation.fromRaw) :
|
||||
[ChatAgentLocation.Panel],
|
||||
modes: providerDescriptor.modes ?? [ChatModeKind.Ask],
|
||||
modes: providerDescriptor.isDefault ? providerDescriptor.modes! : [ChatModeKind.Agent, ChatModeKind.Ask, ChatModeKind.Edit],
|
||||
slashCommands: providerDescriptor.commands ?? [],
|
||||
disambiguation: coalesce(participantsDisambiguation.flat()),
|
||||
} satisfies IChatAgentData));
|
||||
|
|
|
@ -59,6 +59,7 @@ export interface IChatAgentData {
|
|||
metadata: IChatAgentMetadata;
|
||||
slashCommands: IChatAgentCommand[];
|
||||
locations: ChatAgentLocation[];
|
||||
/** This is only relevant for isDefault agents. Others should have all modes available. */
|
||||
modes: ChatModeKind[];
|
||||
disambiguation: { category: string; description: string; examples: string[] }[];
|
||||
}
|
||||
|
@ -232,7 +233,6 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|||
private readonly _hasDefaultAgent: IContextKey<boolean>;
|
||||
private readonly _extensionAgentRegistered: IContextKey<boolean>;
|
||||
private readonly _defaultAgentRegistered: IContextKey<boolean>;
|
||||
private readonly _editingAgentRegistered: IContextKey<boolean>;
|
||||
private _hasToolsAgent = false;
|
||||
|
||||
private _chatParticipantDetectionProviders = new Map<number, IChatParticipantDetectionProvider>();
|
||||
|
@ -245,7 +245,6 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|||
this._hasDefaultAgent = ChatContextKeys.enabled.bindTo(this.contextKeyService);
|
||||
this._extensionAgentRegistered = ChatContextKeys.extensionParticipantRegistered.bindTo(this.contextKeyService);
|
||||
this._defaultAgentRegistered = ChatContextKeys.panelParticipantRegistered.bindTo(this.contextKeyService);
|
||||
this._editingAgentRegistered = ChatContextKeys.editingParticipantRegistered.bindTo(this.contextKeyService);
|
||||
this._register(contextKeyService.onDidChangeContext((e) => {
|
||||
if (e.affectsSome(this._agentsContextKeys)) {
|
||||
this._updateContextKeys();
|
||||
|
@ -295,7 +294,6 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|||
}
|
||||
|
||||
private _updateContextKeys(): void {
|
||||
let editingAgentRegistered = false;
|
||||
let extensionAgentRegistered = false;
|
||||
let defaultAgentRegistered = false;
|
||||
let toolsAgentRegistered = false;
|
||||
|
@ -304,16 +302,14 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|||
if (!agent.isCore) {
|
||||
extensionAgentRegistered = true;
|
||||
}
|
||||
if (agent.modes.includes(ChatModeKind.Agent)) {
|
||||
if (agent.id === 'chat.setup' || agent.id === 'github.copilot.editsAgent') {
|
||||
// TODO@roblourens firing the event below probably isn't necessary but leave it alone for now
|
||||
toolsAgentRegistered = true;
|
||||
} else if (agent.modes.includes(ChatModeKind.Edit)) {
|
||||
editingAgentRegistered = true;
|
||||
} else {
|
||||
defaultAgentRegistered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._editingAgentRegistered.set(editingAgentRegistered);
|
||||
this._defaultAgentRegistered.set(defaultAgentRegistered);
|
||||
this._extensionAgentRegistered.set(extensionAgentRegistered);
|
||||
if (toolsAgentRegistered !== this._hasToolsAgent) {
|
||||
|
|
|
@ -42,7 +42,6 @@ export namespace ChatContextKeys {
|
|||
|
||||
export const extensionParticipantRegistered = new RawContextKey<boolean>('chatPanelExtensionParticipantRegistered', false, { type: 'boolean', description: localize('chatPanelExtensionParticipantRegistered', "True when a default chat participant is registered for the panel from an extension.") });
|
||||
export const panelParticipantRegistered = new RawContextKey<boolean>('chatPanelParticipantRegistered', false, { type: 'boolean', description: localize('chatParticipantRegistered', "True when a default chat participant is registered for the panel.") });
|
||||
export const editingParticipantRegistered = new RawContextKey<boolean>('chatEditingParticipantRegistered', false, { type: 'boolean', description: localize('chatEditingParticipantRegistered', "True when a default chat participant is registered for editing.") });
|
||||
export const chatEditingCanUndo = new RawContextKey<boolean>('chatEditingCanUndo', false, { type: 'boolean', description: localize('chatEditingCanUndo', "True when it is possible to undo an interaction in the editing panel.") });
|
||||
export const chatEditingCanRedo = new RawContextKey<boolean>('chatEditingCanRedo', false, { type: 'boolean', description: localize('chatEditingCanRedo', "True when it is possible to redo an interaction in the editing panel.") });
|
||||
export const extensionInvalid = new RawContextKey<boolean>('chatExtensionInvalid', false, { type: 'boolean', description: localize('chatExtensionInvalid', "True when the installed chat extension is invalid and needs to be updated.") });
|
||||
|
|
Loading…
Reference in New Issue