Skip to content

Commit d8af289

Browse files
authored
Support chat participants in agent mode (microsoft#256113)
* Allow participants in any mode Fix microsoft#255921 * Get rid of unneeded context keys * Preserve modes for default agents * Fix tests * Fix test
1 parent 9abb71c commit d8af289

File tree

7 files changed

+19
-19
lines changed

7 files changed

+19
-19
lines changed

extensions/vscode-api-tests/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
"name": "hello",
7676
"description": "Hello"
7777
}
78+
],
79+
"modes": [
80+
"agent", "ask", "edit"
7881
]
7982
},
8083
{

src/vs/workbench/api/browser/mainThreadChatAgents2.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
208208
metadata: revive(metadata),
209209
slashCommands: [],
210210
disambiguation: [],
211-
locations: [ChatAgentLocation.Panel], // TODO all dynamic participants are panel only?
212-
modes: [ChatModeKind.Ask]
211+
locations: [ChatAgentLocation.Panel],
212+
modes: [ChatModeKind.Ask, ChatModeKind.Agent, ChatModeKind.Edit],
213213
},
214214
impl);
215215
} else {

src/vs/workbench/contrib/chat/browser/actions/chatActions.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,7 @@ abstract class OpenChatGlobalAction extends Action2 {
155155
}
156156

157157
const switchToModeInput = opts?.mode ?? this.mode;
158-
let switchToMode = switchToModeInput && (chatModeService.findModeById(switchToModeInput) ?? chatModeService.findModeByName(switchToModeInput));
159-
if (!switchToMode) {
160-
switchToMode = opts?.query?.startsWith('@') ? ChatMode.Ask : undefined;
161-
}
158+
const switchToMode = switchToModeInput && (chatModeService.findModeById(switchToModeInput) ?? chatModeService.findModeByName(switchToModeInput));
162159
if (switchToMode) {
163160
await this.handleSwitchToMode(switchToMode, chatWidget, instaService, commandService);
164161
}

src/vs/workbench/contrib/chat/browser/actions/chatClearActions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export function registerNewChatActions() {
7171
title: localize2('chat.newEdits.label', "New Chat"),
7272
category: CHAT_CATEGORY,
7373
icon: Codicon.plus,
74-
precondition: ContextKeyExpr.and(ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
74+
precondition: ContextKeyExpr.and(ChatContextKeys.enabled),
7575
f1: true,
7676
menu: [{
7777
id: MenuId.ChatContext,
@@ -142,7 +142,7 @@ export function registerNewChatActions() {
142142
title: localize2('chat.undoEdit.label', "Undo Last Request"),
143143
category: CHAT_CATEGORY,
144144
icon: Codicon.discard,
145-
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanUndo, ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
145+
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanUndo, ChatContextKeys.enabled),
146146
f1: true,
147147
menu: [{
148148
id: MenuId.ViewTitle,
@@ -166,7 +166,7 @@ export function registerNewChatActions() {
166166
title: localize2('chat.redoEdit.label', "Redo Checkpoint Restore"),
167167
category: CHAT_CATEGORY,
168168
icon: Codicon.redo,
169-
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
169+
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled),
170170
f1: true,
171171
menu: [
172172
{
@@ -191,7 +191,7 @@ export function registerNewChatActions() {
191191
id: 'workbench.action.chat.redoEdit2',
192192
title: localize2('chat.redoEdit.label2', "Redo Checkpoint Restore"),
193193
category: CHAT_CATEGORY,
194-
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled, ChatContextKeys.editingParticipantRegistered),
194+
precondition: ContextKeyExpr.and(ChatContextKeys.chatEditingCanRedo, ChatContextKeys.enabled),
195195
f1: true,
196196
menu: [{
197197
id: MenuId.ChatMessageRestoreCheckpoint,

src/vs/workbench/contrib/chat/browser/chatParticipant.contribution.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
247247
continue;
248248
}
249249

250+
if (providerDescriptor.isDefault && !providerDescriptor.modes?.length) {
251+
extension.collector.error(`Extension '${extension.description.identifier.value}' CANNOT register default participant without modes.`);
252+
continue;
253+
}
254+
250255
if (providerDescriptor.locations && !isProposedApiEnabled(extension.description, 'chatParticipantAdditions')) {
251256
extension.collector.error(`Extension '${extension.description.identifier.value}' CANNOT use API proposal: chatParticipantAdditions.`);
252257
continue;
@@ -291,7 +296,7 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
291296
locations: isNonEmptyArray(providerDescriptor.locations) ?
292297
providerDescriptor.locations.map(ChatAgentLocation.fromRaw) :
293298
[ChatAgentLocation.Panel],
294-
modes: providerDescriptor.modes ?? [ChatModeKind.Ask],
299+
modes: providerDescriptor.isDefault ? providerDescriptor.modes! : [ChatModeKind.Agent, ChatModeKind.Ask, ChatModeKind.Edit],
295300
slashCommands: providerDescriptor.commands ?? [],
296301
disambiguation: coalesce(participantsDisambiguation.flat()),
297302
} satisfies IChatAgentData));

src/vs/workbench/contrib/chat/common/chatAgents.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export interface IChatAgentData {
5959
metadata: IChatAgentMetadata;
6060
slashCommands: IChatAgentCommand[];
6161
locations: ChatAgentLocation[];
62+
/** This is only relevant for isDefault agents. Others should have all modes available. */
6263
modes: ChatModeKind[];
6364
disambiguation: { category: string; description: string; examples: string[] }[];
6465
}
@@ -232,7 +233,6 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
232233
private readonly _hasDefaultAgent: IContextKey<boolean>;
233234
private readonly _extensionAgentRegistered: IContextKey<boolean>;
234235
private readonly _defaultAgentRegistered: IContextKey<boolean>;
235-
private readonly _editingAgentRegistered: IContextKey<boolean>;
236236
private _hasToolsAgent = false;
237237

238238
private _chatParticipantDetectionProviders = new Map<number, IChatParticipantDetectionProvider>();
@@ -245,7 +245,6 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
245245
this._hasDefaultAgent = ChatContextKeys.enabled.bindTo(this.contextKeyService);
246246
this._extensionAgentRegistered = ChatContextKeys.extensionParticipantRegistered.bindTo(this.contextKeyService);
247247
this._defaultAgentRegistered = ChatContextKeys.panelParticipantRegistered.bindTo(this.contextKeyService);
248-
this._editingAgentRegistered = ChatContextKeys.editingParticipantRegistered.bindTo(this.contextKeyService);
249248
this._register(contextKeyService.onDidChangeContext((e) => {
250249
if (e.affectsSome(this._agentsContextKeys)) {
251250
this._updateContextKeys();
@@ -295,7 +294,6 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
295294
}
296295

297296
private _updateContextKeys(): void {
298-
let editingAgentRegistered = false;
299297
let extensionAgentRegistered = false;
300298
let defaultAgentRegistered = false;
301299
let toolsAgentRegistered = false;
@@ -304,16 +302,14 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
304302
if (!agent.isCore) {
305303
extensionAgentRegistered = true;
306304
}
307-
if (agent.modes.includes(ChatModeKind.Agent)) {
305+
if (agent.id === 'chat.setup' || agent.id === 'github.copilot.editsAgent') {
306+
// TODO@roblourens firing the event below probably isn't necessary but leave it alone for now
308307
toolsAgentRegistered = true;
309-
} else if (agent.modes.includes(ChatModeKind.Edit)) {
310-
editingAgentRegistered = true;
311308
} else {
312309
defaultAgentRegistered = true;
313310
}
314311
}
315312
}
316-
this._editingAgentRegistered.set(editingAgentRegistered);
317313
this._defaultAgentRegistered.set(defaultAgentRegistered);
318314
this._extensionAgentRegistered.set(extensionAgentRegistered);
319315
if (toolsAgentRegistered !== this._hasToolsAgent) {

src/vs/workbench/contrib/chat/common/chatContextKeys.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ export namespace ChatContextKeys {
4242

4343
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.") });
4444
export const panelParticipantRegistered = new RawContextKey<boolean>('chatPanelParticipantRegistered', false, { type: 'boolean', description: localize('chatParticipantRegistered', "True when a default chat participant is registered for the panel.") });
45-
export const editingParticipantRegistered = new RawContextKey<boolean>('chatEditingParticipantRegistered', false, { type: 'boolean', description: localize('chatEditingParticipantRegistered', "True when a default chat participant is registered for editing.") });
4645
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.") });
4746
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.") });
4847
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.") });

0 commit comments

Comments
 (0)