mirror of
https://github.com/Microsoft/vscode
synced 2024-10-01 08:50:48 +00:00
Add chatParticipant contribution point (#206474)
* Add package.json registration for chat agents * Update for tests * Separate static and dynamic chat agent parts * Handle participant registration correctly * Fix tests * Fix test * Remove commented code * Fix more tests * Pluralize * Pluralize test contribution
This commit is contained in:
parent
4e81df7ea9
commit
00abefa3e2
|
@ -64,6 +64,19 @@
|
|||
},
|
||||
"icon": "media/icon.png",
|
||||
"contributes": {
|
||||
"chatParticipants": [
|
||||
{
|
||||
"name": "participant",
|
||||
"description": "test",
|
||||
"isDefault": true,
|
||||
"commands": [
|
||||
{
|
||||
"name": "hello",
|
||||
"description": "Hello"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Test Config",
|
||||
|
|
|
@ -45,11 +45,6 @@ suite('chat', () => {
|
|||
return null;
|
||||
});
|
||||
participant.isDefault = true;
|
||||
participant.commandProvider = {
|
||||
provideCommands: (_token) => {
|
||||
return [{ name: 'hello', description: 'Hello' }];
|
||||
}
|
||||
};
|
||||
disposables.push(participant);
|
||||
return emitter.event;
|
||||
}
|
||||
|
@ -102,11 +97,6 @@ suite('chat', () => {
|
|||
return { metadata: { key: 'value' } };
|
||||
});
|
||||
participant.isDefault = true;
|
||||
participant.commandProvider = {
|
||||
provideCommands: (_token) => {
|
||||
return [{ name: 'hello', description: 'Hello' }];
|
||||
}
|
||||
};
|
||||
participant.followupProvider = {
|
||||
provideFollowups(result, _token) {
|
||||
deferred.complete(result);
|
||||
|
|
|
@ -19,8 +19,8 @@ import { ExtHostChatAgentsShape2, ExtHostContext, IChatProgressDto, IExtensionCh
|
|||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
|
||||
import { AddDynamicVariableAction, IAddDynamicVariableContext } from 'vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables';
|
||||
import { IChatAgentCommand, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatAgentImplementation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
import { ChatRequestAgentPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||
import { IChatFollowup, IChatProgress, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
|
@ -29,7 +29,6 @@ import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/ext
|
|||
type AgentData = {
|
||||
dispose: () => void;
|
||||
name: string;
|
||||
hasSlashCommands?: boolean;
|
||||
hasFollowups?: boolean;
|
||||
};
|
||||
|
||||
|
@ -49,6 +48,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
|
||||
@IChatWidgetService private readonly _chatWidgetService: IChatWidgetService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IChatContributionService private readonly _chatContributionService: IChatContributionService,
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2);
|
||||
|
@ -76,12 +76,13 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
this._agents.deleteAndDispose(handle);
|
||||
}
|
||||
|
||||
$registerAgent(handle: number, extension: ExtensionIdentifier, name: string, metadata: IExtensionChatAgentMetadata): void {
|
||||
const lastSlashCommands: WeakMap<IChatModel, IChatAgentCommand[]> = new WeakMap();
|
||||
const d = this._chatAgentService.registerAgent({
|
||||
id: name,
|
||||
extensionId: extension,
|
||||
metadata: revive(metadata),
|
||||
$registerAgent(handle: number, extension: ExtensionIdentifier, name: string, metadata: IExtensionChatAgentMetadata, allowDynamic: boolean): void {
|
||||
const staticAgentRegistration = this._chatContributionService.registeredParticipants.find(p => p.extensionId.value === extension.value && p.name === name);
|
||||
if (!staticAgentRegistration && !allowDynamic) {
|
||||
throw new Error(`chatParticipant must be declared in package.json: ${name}`);
|
||||
}
|
||||
|
||||
const impl: IChatAgentImplementation = {
|
||||
invoke: async (request, progress, history, token) => {
|
||||
this._pendingProgress.set(request.requestId, progress);
|
||||
try {
|
||||
|
@ -97,31 +98,31 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
|
||||
return this._proxy.$provideFollowups(request, handle, result, token);
|
||||
},
|
||||
getLastSlashCommands: (model: IChatModel) => {
|
||||
return lastSlashCommands.get(model);
|
||||
},
|
||||
provideSlashCommands: async (model, history, token) => {
|
||||
if (!this._agents.get(handle)?.hasSlashCommands) {
|
||||
return []; // save an IPC call
|
||||
}
|
||||
const commands = await this._proxy.$provideSlashCommands(handle, { history }, token);
|
||||
if (model) {
|
||||
lastSlashCommands.set(model, commands);
|
||||
}
|
||||
|
||||
return commands;
|
||||
},
|
||||
provideWelcomeMessage: (token: CancellationToken) => {
|
||||
return this._proxy.$provideWelcomeMessage(handle, token);
|
||||
},
|
||||
provideSampleQuestions: (token: CancellationToken) => {
|
||||
return this._proxy.$provideSampleQuestions(handle, token);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let disposable: IDisposable;
|
||||
if (!staticAgentRegistration && allowDynamic) {
|
||||
disposable = this._chatAgentService.registerDynamicAgent(
|
||||
{
|
||||
id: name,
|
||||
extensionId: extension,
|
||||
metadata: revive(metadata),
|
||||
slashCommands: [],
|
||||
},
|
||||
impl);
|
||||
} else {
|
||||
disposable = this._chatAgentService.registerAgent(name, impl);
|
||||
}
|
||||
|
||||
this._agents.set(handle, {
|
||||
name,
|
||||
dispose: d.dispose,
|
||||
hasSlashCommands: metadata.hasSlashCommands,
|
||||
dispose: disposable.dispose,
|
||||
hasFollowups: metadata.hasFollowups
|
||||
});
|
||||
}
|
||||
|
@ -131,7 +132,6 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
if (!data) {
|
||||
throw new Error(`No agent with handle ${handle} registered`);
|
||||
}
|
||||
data.hasSlashCommands = metadataUpdate.hasSlashCommands;
|
||||
data.hasFollowups = metadataUpdate.hasFollowups;
|
||||
this._chatAgentService.updateAgent(data.name, revive(metadataUpdate));
|
||||
}
|
||||
|
|
|
@ -50,12 +50,12 @@ import * as tasks from 'vs/workbench/api/common/shared/tasks';
|
|||
import { SaveReason } from 'vs/workbench/common/editor';
|
||||
import { IRevealOptions, ITreeItem, IViewBadge } from 'vs/workbench/common/views';
|
||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IChatAgentCommand, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatAgentMetadata, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatProgressResponseContent } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { IChatDynamicRequest, IChatProgress, IChatResponseErrorDetails, IChatUserActionEvent, InteractiveSessionVoteDirection, IChatFollowup } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatDynamicRequest, IChatFollowup, IChatProgress, IChatResponseErrorDetails, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProgress } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
import { DebugConfigurationProviderTriggerKind, MainThreadDebugVisualization, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IInlineChatBulkEditResponse, IInlineChatEditResponse, IInlineChatFollowup, IInlineChatProgressItem, IInlineChatRequest, IInlineChatSession, InlineChatResponseFeedbackKind } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
|
||||
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
|
@ -1196,12 +1196,11 @@ export interface ExtHostLanguageModelsShape {
|
|||
}
|
||||
|
||||
export interface IExtensionChatAgentMetadata extends Dto<IChatAgentMetadata> {
|
||||
hasSlashCommands?: boolean;
|
||||
hasFollowups?: boolean;
|
||||
}
|
||||
|
||||
export interface MainThreadChatAgentsShape2 extends IDisposable {
|
||||
$registerAgent(handle: number, extension: ExtensionIdentifier, name: string, metadata: IExtensionChatAgentMetadata): void;
|
||||
$registerAgent(handle: number, extension: ExtensionIdentifier, name: string, metadata: IExtensionChatAgentMetadata, allowDynamic: boolean): void;
|
||||
$registerAgentCompletionsProvider(handle: number, triggerCharacters: string[]): void;
|
||||
$unregisterAgentCompletionsProvider(handle: number): void;
|
||||
$updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void;
|
||||
|
@ -1228,7 +1227,6 @@ export type IChatAgentHistoryEntryDto = {
|
|||
|
||||
export interface ExtHostChatAgentsShape2 {
|
||||
$invokeAgent(handle: number, request: IChatAgentRequest, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatAgentResult | undefined>;
|
||||
$provideSlashCommands(handle: number, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatAgentCommand[]>;
|
||||
$provideFollowups(request: IChatAgentRequest, handle: number, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]>;
|
||||
$acceptFeedback(handle: number, result: IChatAgentResult, vote: InteractiveSessionVoteDirection, reportIssue?: boolean): void;
|
||||
$acceptAction(handle: number, result: IChatAgentResult, action: IChatUserActionEvent): void;
|
||||
|
|
|
@ -21,7 +21,7 @@ import { ExtHostChatAgentsShape2, IChatAgentCompletionItem, IChatAgentHistoryEnt
|
|||
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IChatAgentCommand, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatFollowup, IChatProgress, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
@ -171,7 +171,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
|||
const agent = new ExtHostChatAgent(extension, name, this._proxy, handle, handler);
|
||||
this._agents.set(handle, agent);
|
||||
|
||||
this._proxy.$registerAgent(handle, extension.identifier, name, {});
|
||||
this._proxy.$registerAgent(handle, extension.identifier, name, {}, isProposedApiEnabled(extension, 'chatParticipantAdditions'));
|
||||
return agent.apiAgent;
|
||||
}
|
||||
|
||||
|
@ -245,23 +245,6 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
|||
this._sessionDisposables.deleteAndDispose(sessionId);
|
||||
}
|
||||
|
||||
async $provideSlashCommands(handle: number, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatAgentCommand[]> {
|
||||
const agent = this._agents.get(handle);
|
||||
if (!agent) {
|
||||
// this is OK, the agent might have disposed while the request was in flight
|
||||
return [];
|
||||
}
|
||||
|
||||
const convertedHistory = await this.prepareHistoryTurns(agent.id, context);
|
||||
try {
|
||||
return await agent.provideSlashCommands({ history: convertedHistory }, token);
|
||||
} catch (err) {
|
||||
const msg = toErrorMessage(err);
|
||||
this._logService.error(`[${agent.extension.identifier.value}] [@${agent.id}] Error while providing slash commands: ${msg}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async $provideFollowups(request: IChatAgentRequest, handle: number, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> {
|
||||
const agent = this._agents.get(handle);
|
||||
if (!agent) {
|
||||
|
@ -276,7 +259,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
|||
this._agents.values(),
|
||||
a => a.id === f.participant && ExtensionIdentifier.equals(a.extension.identifier, agent.extension.identifier));
|
||||
if (!isValid) {
|
||||
this._logService.warn(`[@${agent.id}] ChatFollowup refers to an invalid participant: ${f.participant}`);
|
||||
this._logService.warn(`[@${agent.id}] ChatFollowup refers to an unknown participant: ${f.participant}`);
|
||||
}
|
||||
return isValid;
|
||||
})
|
||||
|
@ -352,7 +335,6 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
|
|||
|
||||
class ExtHostChatAgent {
|
||||
|
||||
private _commandProvider: vscode.ChatCommandProvider | undefined;
|
||||
private _followupProvider: vscode.ChatFollowupProvider | undefined;
|
||||
private _description: string | undefined;
|
||||
private _fullName: string | undefined;
|
||||
|
@ -394,30 +376,6 @@ class ExtHostChatAgent {
|
|||
return await this._agentVariableProvider.provider.provideCompletionItems(query, token) ?? [];
|
||||
}
|
||||
|
||||
async provideSlashCommands(context: vscode.ChatContext, token: CancellationToken): Promise<IChatAgentCommand[]> {
|
||||
if (!this._commandProvider) {
|
||||
return [];
|
||||
}
|
||||
const result = await this._commandProvider.provideCommands(context, token);
|
||||
if (!result) {
|
||||
return [];
|
||||
}
|
||||
return result
|
||||
.map(c => {
|
||||
if ('isSticky2' in c) {
|
||||
checkProposedApiEnabled(this.extension, 'chatParticipantAdditions');
|
||||
}
|
||||
|
||||
return {
|
||||
name: c.name,
|
||||
description: c.description ?? '',
|
||||
followupPlaceholder: c.isSticky2?.placeholder,
|
||||
isSticky: c.isSticky2?.isSticky ?? c.isSticky,
|
||||
sampleRequest: c.sampleRequest
|
||||
} satisfies IChatAgentCommand;
|
||||
});
|
||||
}
|
||||
|
||||
async provideFollowups(result: vscode.ChatResult, token: CancellationToken): Promise<vscode.ChatFollowup[]> {
|
||||
if (!this._followupProvider) {
|
||||
return [];
|
||||
|
@ -485,9 +443,7 @@ class ExtHostChatAgent {
|
|||
'dark' in this._iconPath ? this._iconPath.dark :
|
||||
undefined,
|
||||
themeIcon: this._iconPath instanceof extHostTypes.ThemeIcon ? this._iconPath : undefined,
|
||||
hasSlashCommands: this._commandProvider !== undefined,
|
||||
hasFollowups: this._followupProvider !== undefined,
|
||||
isDefault: this._isDefault,
|
||||
isSecondary: this._isSecondary,
|
||||
helpTextPrefix: (!this._helpTextPrefix || typeof this._helpTextPrefix === 'string') ? this._helpTextPrefix : typeConvert.MarkdownString.from(this._helpTextPrefix),
|
||||
helpTextVariablesPrefix: (!this._helpTextVariablesPrefix || typeof this._helpTextVariablesPrefix === 'string') ? this._helpTextVariablesPrefix : typeConvert.MarkdownString.from(this._helpTextVariablesPrefix),
|
||||
|
@ -535,13 +491,6 @@ class ExtHostChatAgent {
|
|||
assertType(typeof v === 'function', 'Invalid request handler');
|
||||
that._requestHandler = v;
|
||||
},
|
||||
get commandProvider() {
|
||||
return that._commandProvider;
|
||||
},
|
||||
set commandProvider(v) {
|
||||
that._commandProvider = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
get followupProvider() {
|
||||
return that._followupProvider;
|
||||
},
|
||||
|
@ -564,10 +513,6 @@ class ExtHostChatAgent {
|
|||
},
|
||||
set helpTextPrefix(v) {
|
||||
checkProposedApiEnabled(that.extension, 'defaultChatParticipant');
|
||||
if (!that._isDefault) {
|
||||
throw new Error('helpTextPrefix is only available on the default chat agent');
|
||||
}
|
||||
|
||||
that._helpTextPrefix = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
|
@ -577,10 +522,6 @@ class ExtHostChatAgent {
|
|||
},
|
||||
set helpTextVariablesPrefix(v) {
|
||||
checkProposedApiEnabled(that.extension, 'defaultChatParticipant');
|
||||
if (!that._isDefault) {
|
||||
throw new Error('helpTextVariablesPrefix is only available on the default chat agent');
|
||||
}
|
||||
|
||||
that._helpTextVariablesPrefix = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
|
@ -590,10 +531,6 @@ class ExtHostChatAgent {
|
|||
},
|
||||
set helpTextPostfix(v) {
|
||||
checkProposedApiEnabled(that.extension, 'defaultChatParticipant');
|
||||
if (!that._isDefault) {
|
||||
throw new Error('helpTextPostfix is only available on the default chat agent');
|
||||
}
|
||||
|
||||
that._helpTextPostfix = v;
|
||||
updateMetadataSoon();
|
||||
},
|
||||
|
@ -664,7 +601,6 @@ class ExtHostChatAgent {
|
|||
},
|
||||
dispose() {
|
||||
disposed = true;
|
||||
that._commandProvider = undefined;
|
||||
that._followupProvider = undefined;
|
||||
that._onDidReceiveFeedback.dispose();
|
||||
that._proxy.$unregisterAgent(that._handle);
|
||||
|
|
|
@ -3,62 +3,61 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IMarkdownString, MarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor';
|
||||
import { IWorkbenchContributionsRegistry, WorkbenchPhase, Extensions as WorkbenchExtensions, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
|
||||
import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { AccessibilityVerbositySettingId, AccessibleViewProviderId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||
import { alertFocusChange } from 'vs/workbench/contrib/accessibility/browser/accessibilityContributions';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
||||
import { registerChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||
import { ACTION_ID_NEW_CHAT, registerNewChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
|
||||
import { registerChatCodeBlockActions } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions';
|
||||
import { registerChatCopyActions } from 'vs/workbench/contrib/chat/browser/actions/chatCopyActions';
|
||||
import { IChatExecuteActionContext, SubmitAction, registerChatExecuteActions } from 'vs/workbench/contrib/chat/browser/actions/chatExecuteActions';
|
||||
import { registerChatFileTreeActions } from 'vs/workbench/contrib/chat/browser/actions/chatFileTreeActions';
|
||||
import { registerChatExportActions } from 'vs/workbench/contrib/chat/browser/actions/chatImportExport';
|
||||
import { registerMoveActions } from 'vs/workbench/contrib/chat/browser/actions/chatMoveActions';
|
||||
import { registerQuickChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions';
|
||||
import { registerChatTitleActions } from 'vs/workbench/contrib/chat/browser/actions/chatTitleActions';
|
||||
import { registerChatExportActions } from 'vs/workbench/contrib/chat/browser/actions/chatImportExport';
|
||||
import { IChatAccessibilityService, IChatWidget, IChatWidgetService, IQuickChatService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { ChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chatAccessibilityService';
|
||||
import { ChatContributionService } from 'vs/workbench/contrib/chat/browser/chatContributionServiceImpl';
|
||||
import { ChatEditor, IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
|
||||
import { ChatEditorInput, ChatEditorInputSerializer } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
|
||||
import { QuickChatService } from 'vs/workbench/contrib/chat/browser/chatQuick';
|
||||
import { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
||||
import { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
||||
import 'vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib';
|
||||
import 'vs/workbench/contrib/chat/browser/contrib/chatHistoryVariables';
|
||||
import 'vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib';
|
||||
import { ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
import { ChatWelcomeMessageModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { ChatService } from 'vs/workbench/contrib/chat/common/chatServiceImpl';
|
||||
import { ChatSlashCommandService, IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { ChatWidgetHistoryService, IChatWidgetHistoryService } from 'vs/workbench/contrib/chat/common/chatWidgetHistoryService';
|
||||
import { ILanguageModelsService, LanguageModelsService } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { IVoiceChatService, VoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
|
||||
import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import '../common/chatColors';
|
||||
import { registerMoveActions } from 'vs/workbench/contrib/chat/browser/actions/chatMoveActions';
|
||||
import { ACTION_ID_NEW_CHAT, registerNewChatActions } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { ChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chatAccessibilityService';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { AccessibilityVerbositySettingId, AccessibleViewProviderId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||
import { ChatWelcomeMessageModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IMarkdownString, MarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { LanguageModelsService, ILanguageModelsService } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { ChatSlashCommandService, IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||
import { alertFocusChange } from 'vs/workbench/contrib/accessibility/browser/accessibilityContributions';
|
||||
import { AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
import { registerChatFileTreeActions } from 'vs/workbench/contrib/chat/browser/actions/chatFileTreeActions';
|
||||
import { QuickChatService } from 'vs/workbench/contrib/chat/browser/chatQuick';
|
||||
import { ChatAgentService, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { ChatVariablesService } from 'vs/workbench/contrib/chat/browser/chatVariables';
|
||||
import { chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IVoiceChatService, VoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
|
||||
|
||||
// Register configuration
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
|
@ -246,7 +245,7 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
|
|||
executeImmediately: true
|
||||
}, async (prompt, progress) => {
|
||||
const defaultAgent = chatAgentService.getDefaultAgent();
|
||||
const agents = chatAgentService.getAgents();
|
||||
const agents = chatAgentService.getRegisteredAgents();
|
||||
|
||||
// Report prefix
|
||||
if (defaultAgent?.metadata.helpTextPrefix) {
|
||||
|
@ -266,8 +265,7 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable {
|
|||
const actionArg: IChatExecuteActionContext = { inputValue: `${agentWithLeader} ${a.metadata.sampleRequest}` };
|
||||
const urlSafeArg = encodeURIComponent(JSON.stringify(actionArg));
|
||||
const agentLine = `* [\`${agentWithLeader}\`](command:${SubmitAction.ID}?${urlSafeArg}) - ${a.metadata.description}`;
|
||||
const commands = await a.provideSlashCommands(undefined, [], CancellationToken.None);
|
||||
const commandText = commands.map(c => {
|
||||
const commandText = a.slashCommands.map(c => {
|
||||
const actionArg: IChatExecuteActionContext = { inputValue: `${agentWithLeader} ${chatSubcommandLeader}${c.name} ${c.sampleRequest ?? ''}` };
|
||||
const urlSafeArg = encodeURIComponent(JSON.stringify(actionArg));
|
||||
return `\t* [\`${chatSubcommandLeader}${c.name}\`](command:${SubmitAction.ID}?${urlSafeArg}) - ${c.description}`;
|
||||
|
|
|
@ -18,10 +18,9 @@ import { getNewChatAction } from 'vs/workbench/contrib/chat/browser/actions/chat
|
|||
import { getMoveToEditorAction, getMoveToNewWindowAction } from 'vs/workbench/contrib/chat/browser/actions/chatMoveActions';
|
||||
import { getQuickChatActionForProvider } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions';
|
||||
import { CHAT_SIDEBAR_PANEL_ID, ChatViewPane, IChatViewOptions } from 'vs/workbench/contrib/chat/browser/chatViewPane';
|
||||
import { IChatContributionService, IChatProviderContribution, IRawChatProviderContribution } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
import { IChatContributionService, IChatParticipantContribution, IChatProviderContribution, IRawChatParticipantContribution, IRawChatProviderContribution } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
|
||||
|
||||
const chatExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawChatProviderContribution[]>({
|
||||
extensionPoint: 'interactiveSession',
|
||||
jsonSchema: {
|
||||
|
@ -59,6 +58,71 @@ const chatExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensi
|
|||
},
|
||||
});
|
||||
|
||||
const chatParticipantExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawChatParticipantContribution[]>({
|
||||
extensionPoint: 'chatParticipants',
|
||||
jsonSchema: {
|
||||
description: localize('vscode.extension.contributes.chatParticipant', 'Contributes a Chat Participant'),
|
||||
type: 'array',
|
||||
items: {
|
||||
additionalProperties: false,
|
||||
type: 'object',
|
||||
defaultSnippets: [{ body: { name: '', description: '' } }],
|
||||
required: ['name'],
|
||||
properties: {
|
||||
name: {
|
||||
description: localize('chatParticipantName', "Unique name for this Chat Participant."),
|
||||
type: 'string'
|
||||
},
|
||||
description: {
|
||||
description: localize('chatParticipantDescription', "A description of this Chat Participant, shown in the UI."),
|
||||
type: 'string'
|
||||
},
|
||||
isDefault: {
|
||||
markdownDescription: localize('chatParticipantIsDefaultDescription', "**Only** allowed for extensions that have the `defaultChatParticipant` proposal."),
|
||||
type: 'boolean',
|
||||
},
|
||||
commands: {
|
||||
markdownDescription: localize('chatCommandsDescription', "Commands available for this Chat Participant, which the user can invoke with a `/`."),
|
||||
type: 'array',
|
||||
items: {
|
||||
additionalProperties: false,
|
||||
type: 'object',
|
||||
defaultSnippets: [{ body: { name: '', description: '' } }],
|
||||
required: ['name', 'description'],
|
||||
properties: {
|
||||
name: {
|
||||
description: localize('chatCommand', "A short name by which this command is referred to in the UI, e.g. `fix` or * `explain` for commands that fix an issue or explain code. The name should be unique among the commands provided by this participant."),
|
||||
type: 'string'
|
||||
},
|
||||
description: {
|
||||
description: localize('chatCommandDescription', "A description of this command."),
|
||||
type: 'string'
|
||||
},
|
||||
when: {
|
||||
description: localize('chatCommandDescription', "A description of this command."),
|
||||
type: 'string'
|
||||
},
|
||||
sampleRequest: {
|
||||
description: localize('chatCommandDescription', "A description of this command."),
|
||||
type: 'string'
|
||||
},
|
||||
isSticky: {
|
||||
description: localize('chatCommandDescription', "A description of this command."),
|
||||
type: 'boolean'
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
activationEventsGenerator: (contributions: IRawChatParticipantContribution[], result: { push(item: string): void }) => {
|
||||
for (const contrib of contributions) {
|
||||
result.push(`onChatParticipant:${contrib.name}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||
|
||||
static readonly ID = 'workbench.contrib.chatExtensionPointHandler';
|
||||
|
@ -96,6 +160,20 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
chatParticipantExtensionPoint.setHandler((extensions, delta) => {
|
||||
for (const extension of delta.added) {
|
||||
for (const providerDescriptor of extension.value) {
|
||||
this._chatContributionService.registerChatParticipant({ ...providerDescriptor, extensionId: extension.description.identifier });
|
||||
}
|
||||
}
|
||||
|
||||
for (const extension of delta.removed) {
|
||||
for (const providerDescriptor of extension.value) {
|
||||
this._chatContributionService.deregisterChatParticipant({ ...providerDescriptor, extensionId: extension.description.identifier });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerViewContainer(): ViewContainer {
|
||||
|
@ -156,10 +234,15 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
|||
|
||||
registerWorkbenchContribution2(ChatExtensionPointHandler.ID, ChatExtensionPointHandler, WorkbenchPhase.BlockStartup);
|
||||
|
||||
function getParticipantKey(participant: IChatParticipantContribution): string {
|
||||
return `${participant.extensionId.value}_${participant.name}`;
|
||||
}
|
||||
|
||||
export class ChatContributionService implements IChatContributionService {
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
private _registeredProviders = new Map<string, IChatProviderContribution>();
|
||||
private _registeredParticipants = new Map<string, IChatParticipantContribution>();
|
||||
|
||||
constructor(
|
||||
) { }
|
||||
|
@ -176,7 +259,19 @@ export class ChatContributionService implements IChatContributionService {
|
|||
this._registeredProviders.delete(providerId);
|
||||
}
|
||||
|
||||
public registerChatParticipant(participant: IChatParticipantContribution): void {
|
||||
this._registeredParticipants.set(getParticipantKey(participant), participant);
|
||||
}
|
||||
|
||||
public deregisterChatParticipant(participant: IChatParticipantContribution): void {
|
||||
this._registeredParticipants.delete(getParticipantKey(participant));
|
||||
}
|
||||
|
||||
public get registeredProviders(): IChatProviderContribution[] {
|
||||
return Array.from(this._registeredProviders.values());
|
||||
}
|
||||
|
||||
public get registeredParticipants(): IChatParticipantContribution[] {
|
||||
return Array.from(this._registeredParticipants.values());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -360,7 +360,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
|
||||
private renderDetail(element: IChatResponseViewModel, templateData: IChatListItemTemplate): void {
|
||||
let progressMsg: string = '';
|
||||
if (element.agent && !element.agent.metadata.isDefault) {
|
||||
if (element.agent && !element.agent.isDefault) {
|
||||
let usingMsg = chatAgentLeader + element.agent.id;
|
||||
if (element.slashCommand) {
|
||||
usingMsg += ` ${chatSubcommandLeader}${element.slashCommand.name}`;
|
||||
|
@ -394,7 +394,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
templateData.avatarContainer.replaceChildren(dom.$('.avatar.codicon-avatar', undefined, avatarIcon));
|
||||
}
|
||||
|
||||
if (isResponseVM(element) && element.agent && !element.agent.metadata.isDefault) {
|
||||
if (isResponseVM(element) && element.agent && !element.agent.isDefault) {
|
||||
dom.show(templateData.agentAvatarContainer);
|
||||
const icon = this.getAgentIcon(element.agent.metadata);
|
||||
if (icon instanceof URI) {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { raceCancellation } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
|
@ -27,7 +26,6 @@ import { ChatWidget } from 'vs/workbench/contrib/chat/browser/chatWidget';
|
|||
import { SelectAndInsertFileAction, dynamicVariableDecorationType } from 'vs/workbench/contrib/chat/browser/contrib/chatDynamicVariables';
|
||||
import { IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { chatSlashCommandBackground, chatSlashCommandForeground } from 'vs/workbench/contrib/chat/common/chatColors';
|
||||
import { getHistoryEntriesFromModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, ChatRequestTextPart, ChatRequestVariablePart, IParsedChatRequestPart, chatAgentLeader, chatSubcommandLeader, chatVariableLeader } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||
|
@ -347,8 +345,8 @@ class AgentCompletions extends Disposable {
|
|||
return null;
|
||||
}
|
||||
|
||||
const agents = this.chatAgentService.getAgents()
|
||||
.filter(a => !a.metadata.isDefault);
|
||||
const agents = this.chatAgentService.getRegisteredAgents()
|
||||
.filter(a => !a.isDefault);
|
||||
return <CompletionList>{
|
||||
suggestions: agents.map((c, i) => {
|
||||
const withAt = `@${c.id}`;
|
||||
|
@ -399,10 +397,8 @@ class AgentCompletions extends Disposable {
|
|||
}
|
||||
|
||||
const usedAgent = parsedRequest[usedAgentIdx] as ChatRequestAgentPart;
|
||||
const commands = await usedAgent.agent.provideSlashCommands(widget.viewModel.model, getHistoryEntriesFromModel(widget.viewModel.model), token); // Refresh the cache here
|
||||
|
||||
return <CompletionList>{
|
||||
suggestions: commands.map((c, i) => {
|
||||
suggestions: usedAgent.agent.slashCommands.map((c, i) => {
|
||||
const withSlash = `/${c.name}`;
|
||||
return <CompletionItem>{
|
||||
label: withSlash,
|
||||
|
@ -432,16 +428,9 @@ class AgentCompletions extends Disposable {
|
|||
return null;
|
||||
}
|
||||
|
||||
const agents = this.chatAgentService.getAgents();
|
||||
const all = agents.map(agent => agent.provideSlashCommands(viewModel.model, getHistoryEntriesFromModel(viewModel.model), token));
|
||||
const commands = await raceCancellation(Promise.all(all), token);
|
||||
|
||||
if (!commands) {
|
||||
return;
|
||||
}
|
||||
|
||||
const agents = this.chatAgentService.getRegisteredAgents();
|
||||
const justAgents: CompletionItem[] = agents
|
||||
.filter(a => !a.metadata.isDefault)
|
||||
.filter(a => !a.isDefault)
|
||||
.map(agent => {
|
||||
const agentLabel = `${chatAgentLeader}${agent.id}`;
|
||||
return {
|
||||
|
@ -456,7 +445,7 @@ class AgentCompletions extends Disposable {
|
|||
|
||||
return {
|
||||
suggestions: justAgents.concat(
|
||||
agents.flatMap((agent, i) => commands[i].map((c, i) => {
|
||||
agents.flatMap(agent => agent.slashCommands.map((c, i) => {
|
||||
const agentLabel = `${chatAgentLeader}${agent.id}`;
|
||||
const withSlash = `${chatSubcommandLeader}${c.name}`;
|
||||
return {
|
||||
|
|
|
@ -11,9 +11,11 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
|
|||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ProviderResult } from 'vs/editor/common/languages';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IChatModel, IChatProgressResponseContent, IChatRequestVariableData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
import { IChatProgressResponseContent, IChatRequestVariableData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatFollowup, IChatProgress, IChatResponseErrorDetails } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
|
||||
//#region agent service, commands etc
|
||||
|
@ -27,18 +29,21 @@ export interface IChatAgentHistoryEntry {
|
|||
export interface IChatAgentData {
|
||||
id: string;
|
||||
extensionId: ExtensionIdentifier;
|
||||
/** The agent invoked when no agent is specified */
|
||||
isDefault?: boolean;
|
||||
metadata: IChatAgentMetadata;
|
||||
slashCommands: IChatAgentCommand[];
|
||||
}
|
||||
|
||||
export interface IChatAgent extends IChatAgentData {
|
||||
export interface IChatAgentImplementation {
|
||||
invoke(request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentResult>;
|
||||
provideFollowups?(request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]>;
|
||||
getLastSlashCommands(model: IChatModel): IChatAgentCommand[] | undefined;
|
||||
provideSlashCommands(model: IChatModel | undefined, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentCommand[]>;
|
||||
provideWelcomeMessage?(token: CancellationToken): ProviderResult<(string | IMarkdownString)[] | undefined>;
|
||||
provideSampleQuestions?(token: CancellationToken): ProviderResult<IChatFollowup[] | undefined>;
|
||||
}
|
||||
|
||||
export type IChatAgent = IChatAgentData & IChatAgentImplementation;
|
||||
|
||||
export interface IChatAgentCommand {
|
||||
name: string;
|
||||
description: string;
|
||||
|
@ -68,7 +73,6 @@ export interface IChatAgentCommand {
|
|||
|
||||
export interface IChatAgentMetadata {
|
||||
description?: string;
|
||||
isDefault?: boolean; // The agent invoked when no agent is specified
|
||||
helpTextPrefix?: string | IMarkdownString;
|
||||
helpTextVariablesPrefix?: string | IMarkdownString;
|
||||
helpTextPostfix?: string | IMarkdownString;
|
||||
|
@ -108,17 +112,18 @@ export const IChatAgentService = createDecorator<IChatAgentService>('chatAgentSe
|
|||
export interface IChatAgentService {
|
||||
_serviceBrand: undefined;
|
||||
/**
|
||||
* undefined when an agent was removed
|
||||
* undefined when an agent was removed IChatAgent
|
||||
*/
|
||||
readonly onDidChangeAgents: Event<IChatAgent | undefined>;
|
||||
registerAgent(agent: IChatAgent): IDisposable;
|
||||
registerAgent(name: string, agent: IChatAgentImplementation): IDisposable;
|
||||
registerDynamicAgent(data: IChatAgentData, agentImpl: IChatAgentImplementation): IDisposable;
|
||||
invokeAgent(id: string, request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentResult>;
|
||||
getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]>;
|
||||
getAgents(): Array<IChatAgent>;
|
||||
getAgent(id: string): IChatAgent | undefined;
|
||||
getRegisteredAgents(): Array<IChatAgentData>;
|
||||
getActivatedAgents(): Array<IChatAgent>;
|
||||
getRegisteredAgent(id: string): IChatAgentData | undefined;
|
||||
getDefaultAgent(): IChatAgent | undefined;
|
||||
getSecondaryAgent(): IChatAgent | undefined;
|
||||
hasAgent(id: string): boolean;
|
||||
getSecondaryAgent(): IChatAgentData | undefined;
|
||||
updateAgent(id: string, updateMetadata: IChatAgentMetadata): void;
|
||||
}
|
||||
|
||||
|
@ -128,79 +133,160 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
|
|||
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
private readonly _agents = new Map<string, { agent: IChatAgent }>();
|
||||
private readonly _agents = new Map<string, { data: IChatAgentData; impl?: IChatAgentImplementation }>();
|
||||
|
||||
private readonly _onDidChangeAgents = this._register(new Emitter<IChatAgent | undefined>());
|
||||
readonly onDidChangeAgents: Event<IChatAgent | undefined> = this._onDidChangeAgents.event;
|
||||
|
||||
constructor(
|
||||
@IChatContributionService private chatContributionService: IChatContributionService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
this._agents.clear();
|
||||
}
|
||||
|
||||
registerAgent(agent: IChatAgent): IDisposable {
|
||||
if (this._agents.has(agent.id)) {
|
||||
throw new Error(`Already registered an agent with id ${agent.id}`);
|
||||
registerAgent(name: string, agentImpl: IChatAgentImplementation): IDisposable {
|
||||
if (this._agents.has(name)) {
|
||||
// TODO not keyed by name, dupes allowed between extensions
|
||||
throw new Error(`Already registered an agent with id ${name}`);
|
||||
}
|
||||
this._agents.set(agent.id, { agent });
|
||||
this._onDidChangeAgents.fire(agent);
|
||||
|
||||
const data = this.getRegisteredAgent(name);
|
||||
if (!data) {
|
||||
throw new Error(`Unknown agent: ${name}`);
|
||||
}
|
||||
|
||||
const agent = { data: data, impl: agentImpl };
|
||||
this._agents.set(name, agent);
|
||||
this._onDidChangeAgents.fire(new MergedChatAgent(data, agentImpl));
|
||||
|
||||
return toDisposable(() => {
|
||||
if (this._agents.delete(agent.id)) {
|
||||
if (this._agents.delete(name)) {
|
||||
this._onDidChangeAgents.fire(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerDynamicAgent(data: IChatAgentData, agentImpl: IChatAgentImplementation): IDisposable {
|
||||
const agent = { data, impl: agentImpl };
|
||||
this._agents.set(data.id, agent);
|
||||
this._onDidChangeAgents.fire(new MergedChatAgent(data, agentImpl));
|
||||
|
||||
return toDisposable(() => {
|
||||
if (this._agents.delete(data.id)) {
|
||||
this._onDidChangeAgents.fire(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateAgent(id: string, updateMetadata: IChatAgentMetadata): void {
|
||||
const data = this._agents.get(id);
|
||||
if (!data) {
|
||||
throw new Error(`No agent with id ${id} registered`);
|
||||
const agent = this._agents.get(id);
|
||||
if (!agent?.impl) {
|
||||
throw new Error(`No activated agent with id ${id} registered`);
|
||||
}
|
||||
data.agent.metadata = { ...data.agent.metadata, ...updateMetadata };
|
||||
this._onDidChangeAgents.fire(data.agent);
|
||||
agent.data.metadata = { ...agent.data.metadata, ...updateMetadata };
|
||||
this._onDidChangeAgents.fire(new MergedChatAgent(agent.data, agent.impl));
|
||||
}
|
||||
|
||||
getDefaultAgent(): IChatAgent | undefined {
|
||||
return Iterable.find(this._agents.values(), a => !!a.agent.metadata.isDefault)?.agent;
|
||||
return this.getActivatedAgents().find(a => !!a.isDefault);
|
||||
}
|
||||
|
||||
getSecondaryAgent(): IChatAgent | undefined {
|
||||
return Iterable.find(this._agents.values(), a => !!a.agent.metadata.isSecondary)?.agent;
|
||||
getSecondaryAgent(): IChatAgentData | undefined {
|
||||
// TODO also static
|
||||
return Iterable.find(this._agents.values(), a => !!a.data.metadata.isSecondary)?.data;
|
||||
}
|
||||
|
||||
getAgents(): Array<IChatAgent> {
|
||||
return Array.from(this._agents.values(), v => v.agent);
|
||||
getRegisteredAgents(): Array<IChatAgentData> {
|
||||
const that = this;
|
||||
return this.chatContributionService.registeredParticipants.map(p => (
|
||||
{
|
||||
extensionId: p.extensionId,
|
||||
id: p.name,
|
||||
metadata: { description: p.description },
|
||||
isDefault: p.isDefault,
|
||||
get slashCommands() {
|
||||
const commands = p.commands ?? [];
|
||||
return commands.filter(c => !c.when || that.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(c.when)));
|
||||
}
|
||||
} satisfies IChatAgentData));
|
||||
}
|
||||
|
||||
hasAgent(id: string): boolean {
|
||||
return this._agents.has(id);
|
||||
getActivatedAgents(): IChatAgent[] {
|
||||
return Array.from(this._agents.values())
|
||||
.filter(a => !!a.impl)
|
||||
.map(a => new MergedChatAgent(a.data, a.impl!));
|
||||
}
|
||||
|
||||
getAgent(id: string): IChatAgent | undefined {
|
||||
const data = this._agents.get(id);
|
||||
return data?.agent;
|
||||
getRegisteredAgent(id: string): IChatAgentData | undefined {
|
||||
return this.getRegisteredAgents().find(a => a.id === id);
|
||||
}
|
||||
|
||||
async invokeAgent(id: string, request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentResult> {
|
||||
const data = this._agents.get(id);
|
||||
if (!data) {
|
||||
throw new Error(`No agent with id ${id}`);
|
||||
if (!data?.impl) {
|
||||
throw new Error(`No activated agent with id ${id}`);
|
||||
}
|
||||
|
||||
return await data.agent.invoke(request, progress, history, token);
|
||||
return await data.impl.invoke(request, progress, history, token);
|
||||
}
|
||||
|
||||
async getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> {
|
||||
const data = this._agents.get(id);
|
||||
if (!data) {
|
||||
throw new Error(`No agent with id ${id}`);
|
||||
if (!data?.impl) {
|
||||
throw new Error(`No activated agent with id ${id}`);
|
||||
}
|
||||
|
||||
if (!data.agent.provideFollowups) {
|
||||
if (!data.impl?.provideFollowups) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return data.agent.provideFollowups(request, result, token);
|
||||
return data.impl.provideFollowups(request, result, token);
|
||||
}
|
||||
}
|
||||
|
||||
export class MergedChatAgent implements IChatAgent {
|
||||
constructor(
|
||||
private readonly data: IChatAgentData,
|
||||
private readonly impl: IChatAgentImplementation
|
||||
) { }
|
||||
|
||||
get id(): string { return this.data.id; }
|
||||
get extensionId(): ExtensionIdentifier { return this.data.extensionId; }
|
||||
get isDefault(): boolean | undefined { return this.data.isDefault; }
|
||||
get metadata(): IChatAgentMetadata { return this.data.metadata; }
|
||||
get slashCommands(): IChatAgentCommand[] { return this.data.slashCommands; }
|
||||
|
||||
async invoke(request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentResult> {
|
||||
return this.impl.invoke(request, progress, history, token);
|
||||
}
|
||||
|
||||
async provideFollowups(request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> {
|
||||
if (this.impl.provideFollowups) {
|
||||
return this.impl.provideFollowups(request, result, token);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
provideWelcomeMessage(token: CancellationToken): ProviderResult<(string | IMarkdownString)[] | undefined> {
|
||||
if (this.impl.provideWelcomeMessage) {
|
||||
return this.impl.provideWelcomeMessage(token);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
provideSampleQuestions(token: CancellationToken): ProviderResult<IChatFollowup[] | undefined> {
|
||||
if (this.impl.provideSampleQuestions) {
|
||||
return this.impl.provideSampleQuestions(token);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export interface IChatProviderContribution {
|
||||
|
@ -18,6 +19,10 @@ export interface IChatContributionService {
|
|||
registerChatProvider(provider: IChatProviderContribution): void;
|
||||
deregisterChatProvider(providerId: string): void;
|
||||
getViewIdForProvider(providerId: string): string;
|
||||
|
||||
readonly registeredParticipants: IChatParticipantContribution[];
|
||||
registerChatParticipant(participant: IChatParticipantContribution): void;
|
||||
deregisterChatParticipant(participant: IChatParticipantContribution): void;
|
||||
}
|
||||
|
||||
export interface IRawChatProviderContribution {
|
||||
|
@ -26,3 +31,23 @@ export interface IRawChatProviderContribution {
|
|||
icon?: string;
|
||||
when?: string;
|
||||
}
|
||||
|
||||
export interface IRawChatCommandContribution {
|
||||
name: string;
|
||||
description: string;
|
||||
sampleRequest?: string;
|
||||
isSticky?: boolean;
|
||||
when?: string;
|
||||
}
|
||||
|
||||
export interface IRawChatParticipantContribution {
|
||||
name: string;
|
||||
description?: string;
|
||||
isDefault?: boolean;
|
||||
commands?: IRawChatCommandContribution[];
|
||||
}
|
||||
|
||||
export interface IChatParticipantContribution extends IRawChatParticipantContribution {
|
||||
// Participant id is extensionId + name
|
||||
extensionId: ExtensionIdentifier;
|
||||
}
|
||||
|
|
|
@ -683,7 +683,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
|||
} else if (progress.kind === 'usedContext' || progress.kind === 'reference') {
|
||||
request.response.applyReference(progress);
|
||||
} else if (progress.kind === 'agentDetection') {
|
||||
const agent = this.chatAgentService.getAgent(progress.agentName);
|
||||
const agent = this.chatAgentService.getRegisteredAgent(progress.agentName);
|
||||
if (agent) {
|
||||
request.response.setAgent(agent, progress.command);
|
||||
}
|
||||
|
@ -780,7 +780,10 @@ export class ChatModel extends Disposable implements IChatModel {
|
|||
followups: r.response?.followups,
|
||||
isCanceled: r.response?.isCanceled,
|
||||
vote: r.response?.vote,
|
||||
agent: r.response?.agent ? { id: r.response.agent.id, extensionId: r.response.agent.extensionId, metadata: r.response.agent.metadata } : undefined, // May actually be the full IChatAgent instance, just take the data props
|
||||
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, extensionId: r.response.agent.extensionId, metadata: r.response.agent.metadata, slashCommands: [] }
|
||||
: undefined,
|
||||
slashCommand: r.response?.slashCommand,
|
||||
usedContext: r.response?.usedContext,
|
||||
contentReferences: r.response?.contentReferences
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { IOffsetRange, OffsetRange } from 'vs/editor/common/core/offsetRange';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { IChatAgent, IChatAgentCommand } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatAgentCommand, IChatAgentData } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatSlashData } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||
import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
|
||||
|
@ -72,7 +72,7 @@ export class ChatRequestVariablePart implements IParsedChatRequestPart {
|
|||
export class ChatRequestAgentPart implements IParsedChatRequestPart {
|
||||
static readonly Kind = 'agent';
|
||||
readonly kind = ChatRequestAgentPart.Kind;
|
||||
constructor(readonly range: OffsetRange, readonly editorRange: IRange, readonly agent: IChatAgent) { }
|
||||
constructor(readonly range: OffsetRange, readonly editorRange: IRange, readonly agent: IChatAgentData) { }
|
||||
|
||||
get text(): string {
|
||||
return `${chatAgentLeader}${this.agent.id}`;
|
||||
|
|
|
@ -99,7 +99,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 agent = this.agentService.getAgent(name);
|
||||
const agent = this.agentService.getRegisteredAgent(name);
|
||||
if (!agent) {
|
||||
return;
|
||||
}
|
||||
|
@ -171,8 +171,7 @@ export class ChatRequestParser {
|
|||
return;
|
||||
}
|
||||
|
||||
const subCommands = usedAgent.agent.getLastSlashCommands(model);
|
||||
const subCommand = subCommands?.find(c => c.name === command);
|
||||
const subCommand = usedAgent.agent.slashCommands.find(c => c.name === command);
|
||||
if (subCommand) {
|
||||
// Valid agent subcommand
|
||||
return new ChatRequestAgentSubcommandPart(slashRange, slashEditorRange, subCommand);
|
||||
|
|
|
@ -20,15 +20,15 @@ import { Progress } from 'vs/platform/progress/common/progress';
|
|||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IChatAgent, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { CONTEXT_PROVIDER_EXISTS } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
import { ChatModel, ChatModelInitState, ChatRequestModel, ChatWelcomeMessageModel, IChatModel, IChatRequestVariableData, ISerializableChatData, ISerializableChatsData, getHistoryEntriesFromModel, updateRanges } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart, IParsedChatRequest, getPromptText } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||
import { ChatCopyKind, IChat, IChatCompleteResponse, IChatDetail, IChatDynamicRequest, IChatFollowup, IChatProgress, IChatProvider, IChatProviderInfo, IChatSendRequestData, IChatService, IChatTransferredSessionData, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
const serializedChatKey = 'interactive.sessions';
|
||||
|
@ -193,12 +193,6 @@ export class ChatService extends Disposable implements IChatService {
|
|||
}
|
||||
|
||||
this._register(storageService.onWillSaveState(() => this.saveState()));
|
||||
|
||||
this._register(Event.debounce(this.chatAgentService.onDidChangeAgents, () => { }, 500)(() => {
|
||||
for (const model of this._sessionModels.values()) {
|
||||
this.warmSlashCommandCache(model);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private saveState(): void {
|
||||
|
@ -364,15 +358,9 @@ export class ChatService extends Disposable implements IChatService {
|
|||
this.initializeSession(model, CancellationToken.None);
|
||||
}
|
||||
|
||||
private warmSlashCommandCache(model: IChatModel, agent?: IChatAgent) {
|
||||
const agents = agent ? [agent] : this.chatAgentService.getAgents();
|
||||
agents.forEach(agent => agent.provideSlashCommands(model, [], CancellationToken.None));
|
||||
}
|
||||
|
||||
private async initializeSession(model: ChatModel, token: CancellationToken): Promise<void> {
|
||||
try {
|
||||
this.trace('initializeSession', `Initialize session ${model.sessionId}`);
|
||||
this.warmSlashCommandCache(model);
|
||||
model.startInitialize();
|
||||
await this.extensionService.activateByEvent(`onInteractiveSession:${model.providerId}`);
|
||||
|
||||
|
@ -543,6 +531,7 @@ export class ChatService extends Disposable implements IChatService {
|
|||
const defaultAgent = this.chatAgentService.getDefaultAgent();
|
||||
if (agentPart || (defaultAgent && !commandPart)) {
|
||||
const agent = (agentPart?.agent ?? defaultAgent)!;
|
||||
await this.extensionService.activateByEvent(`onChatParticipant:${agent.id}`);
|
||||
const history = getHistoryEntriesFromModel(model);
|
||||
|
||||
const initVariableData: IChatRequestVariableData = { variables: [] };
|
||||
|
|
|
@ -87,19 +87,16 @@ export class VoiceChatService extends Disposable implements IVoiceChatService {
|
|||
private createPhrases(model?: IChatModel): Map<string, IPhraseValue> {
|
||||
const phrases = new Map<string, IPhraseValue>();
|
||||
|
||||
for (const agent of this.chatAgentService.getAgents()) {
|
||||
for (const agent of this.chatAgentService.getActivatedAgents()) {
|
||||
const agentPhrase = `${VoiceChatService.PHRASES_LOWER[VoiceChatService.AGENT_PREFIX]} ${VoiceChatService.CHAT_AGENT_ALIAS.get(agent.id) ?? agent.id}`.toLowerCase();
|
||||
phrases.set(agentPhrase, { agent: agent.id });
|
||||
|
||||
const commands = model && agent.getLastSlashCommands(model);
|
||||
if (commands) {
|
||||
for (const slashCommand of commands) {
|
||||
const slashCommandPhrase = `${VoiceChatService.PHRASES_LOWER[VoiceChatService.COMMAND_PREFIX]} ${slashCommand.name}`.toLowerCase();
|
||||
phrases.set(slashCommandPhrase, { agent: agent.id, command: slashCommand.name });
|
||||
for (const slashCommand of agent.slashCommands) {
|
||||
const slashCommandPhrase = `${VoiceChatService.PHRASES_LOWER[VoiceChatService.COMMAND_PREFIX]} ${slashCommand.name}`.toLowerCase();
|
||||
phrases.set(slashCommandPhrase, { agent: agent.id, command: slashCommand.name });
|
||||
|
||||
const agentSlashCommandPhrase = `${agentPhrase} ${slashCommandPhrase}`.toLowerCase();
|
||||
phrases.set(agentSlashCommandPhrase, { agent: agent.id, command: slashCommand.name });
|
||||
}
|
||||
const agentSlashCommandPhrase = `${agentPhrase} ${slashCommandPhrase}`.toLowerCase();
|
||||
phrases.set(agentSlashCommandPhrase, { agent: agent.id, command: slashCommand.name });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -28,8 +28,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -14,8 +14,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -14,8 +14,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -14,8 +14,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -14,8 +14,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -14,8 +14,12 @@
|
|||
agent: {
|
||||
id: "agent",
|
||||
metadata: { description: "" },
|
||||
provideSlashCommands: [Function provideSlashCommands],
|
||||
getLastSlashCommands: [Function getLastSlashCommands]
|
||||
slashCommands: [
|
||||
{
|
||||
name: "subCommand",
|
||||
description: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
kind: "agent"
|
||||
},
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
agent: {
|
||||
id: "ChatProviderWithUsedContext",
|
||||
metadata: { }
|
||||
metadata: { description: undefined }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -54,7 +54,8 @@
|
|||
value: "nullExtensionDescription",
|
||||
_lower: "nullextensiondescription"
|
||||
},
|
||||
metadata: { }
|
||||
metadata: { description: undefined },
|
||||
slashCommands: [ ]
|
||||
},
|
||||
slashCommand: undefined,
|
||||
usedContext: {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
},
|
||||
agent: {
|
||||
id: "ChatProviderWithUsedContext",
|
||||
metadata: { }
|
||||
metadata: { description: undefined }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -54,7 +54,8 @@
|
|||
value: "nullExtensionDescription",
|
||||
_lower: "nullextensiondescription"
|
||||
},
|
||||
metadata: { }
|
||||
metadata: { description: undefined },
|
||||
slashCommands: [ ]
|
||||
},
|
||||
slashCommand: undefined,
|
||||
usedContext: {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/uti
|
|||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ChatAgentService, IChatAgent, IChatAgentCommand, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { ChatAgentService, IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
|
||||
|
@ -112,12 +112,12 @@ suite('ChatRequestParser', () => {
|
|||
});
|
||||
|
||||
const getAgentWithSlashCommands = (slashCommands: IChatAgentCommand[]) => {
|
||||
return <Partial<IChatAgent>>{ id: 'agent', metadata: { description: '' }, provideSlashCommands: async () => [], getLastSlashCommands: () => slashCommands };
|
||||
return <IChatAgentData>{ id: 'agent', metadata: { description: '' }, slashCommands };
|
||||
};
|
||||
|
||||
test('agent with subcommand after text', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
|
@ -127,7 +127,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agents, subCommand', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
|
@ -137,7 +137,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agent with question mark', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
|
@ -147,7 +147,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agent and subcommand with leading whitespace', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
|
@ -157,7 +157,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agent and subcommand after newline', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
|
@ -167,7 +167,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agent not first', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
parser = instantiationService.createInstance(ChatRequestParser);
|
||||
|
@ -177,7 +177,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agents and variables and multiline', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
varService.hasVariable.returns(true);
|
||||
|
@ -189,7 +189,7 @@ suite('ChatRequestParser', () => {
|
|||
|
||||
test('agents and variables and multiline, part2', async () => {
|
||||
const agentsService = mockObject<IChatAgentService>()({});
|
||||
agentsService.getAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
agentsService.getRegisteredAgent.returns(getAgentWithSlashCommands([{ name: 'subCommand', description: '' }]));
|
||||
instantiationService.stub(IChatAgentService, agentsService as any);
|
||||
|
||||
varService.hasVariable.returns(true);
|
||||
|
|
|
@ -21,7 +21,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
|
||||
import { ChatAgentService, IChatAgent, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { ChatAgentService, IChatAgent, IChatAgentImplementation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
import { ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChat, IChatFollowup, IChatProgress, IChatProvider, IChatRequest, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
|
@ -32,6 +32,7 @@ import { MockChatVariablesService } from 'vs/workbench/contrib/chat/test/common/
|
|||
import { IExtensionService, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { TestContextService, TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { MockChatService } from 'vs/workbench/contrib/chat/test/common/mockChatService';
|
||||
import { MockChatContributionService } from 'vs/workbench/contrib/chat/test/common/mockChatContributionService';
|
||||
|
||||
class SimpleTestProvider extends Disposable implements IChatProvider {
|
||||
private static sessionId = 0;
|
||||
|
@ -60,12 +61,7 @@ const chatAgentWithUsedContext: IChatAgent = {
|
|||
id: chatAgentWithUsedContextId,
|
||||
extensionId: nullExtensionDescription.identifier,
|
||||
metadata: {},
|
||||
getLastSlashCommands() {
|
||||
return undefined;
|
||||
},
|
||||
async provideSlashCommands() {
|
||||
return [];
|
||||
},
|
||||
slashCommands: [],
|
||||
async invoke(request, progress, history, token) {
|
||||
progress({
|
||||
documents: [
|
||||
|
@ -109,25 +105,21 @@ suite('Chat', () => {
|
|||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||
instantiationService.stub(IChatSlashCommandService, testDisposables.add(instantiationService.createInstance(ChatSlashCommandService)));
|
||||
instantiationService.stub(IChatService, new MockChatService());
|
||||
instantiationService.stub(IChatContributionService, new MockChatContributionService(
|
||||
[
|
||||
{ extensionId: nullExtensionDescription.identifier, name: 'testAgent', isDefault: true },
|
||||
{ extensionId: nullExtensionDescription.identifier, name: chatAgentWithUsedContextId, isDefault: true },
|
||||
]));
|
||||
|
||||
chatAgentService = testDisposables.add(instantiationService.createInstance(ChatAgentService));
|
||||
instantiationService.stub(IChatAgentService, chatAgentService);
|
||||
|
||||
const agent = {
|
||||
id: 'testAgent',
|
||||
extensionId: nullExtensionDescription.identifier,
|
||||
metadata: { isDefault: true },
|
||||
async invoke(request, progress, history, token) {
|
||||
return {};
|
||||
},
|
||||
getLastSlashCommands() {
|
||||
return undefined;
|
||||
},
|
||||
async provideSlashCommands(token) {
|
||||
return [];
|
||||
},
|
||||
} as IChatAgent;
|
||||
testDisposables.add(chatAgentService.registerAgent(agent));
|
||||
} satisfies IChatAgentImplementation;
|
||||
testDisposables.add(chatAgentService.registerAgent('testAgent', agent));
|
||||
});
|
||||
|
||||
test('retrieveSession', async () => {
|
||||
|
@ -229,7 +221,7 @@ suite('Chat', () => {
|
|||
});
|
||||
|
||||
test('can serialize', async () => {
|
||||
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContext));
|
||||
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContext.id, chatAgentWithUsedContext));
|
||||
const testService = testDisposables.add(instantiationService.createInstance(ChatService));
|
||||
testDisposables.add(testService.registerProvider(testDisposables.add(new SimpleTestProvider('testProvider'))));
|
||||
|
||||
|
@ -249,7 +241,7 @@ suite('Chat', () => {
|
|||
|
||||
test('can deserialize', async () => {
|
||||
let serializedChatData: ISerializableChatData;
|
||||
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContext));
|
||||
testDisposables.add(chatAgentService.registerAgent(chatAgentWithUsedContext.id, chatAgentWithUsedContext));
|
||||
|
||||
// create the first service, send request, get response, and serialize the state
|
||||
{ // serapate block to not leak variables in outer scope
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IChatContributionService, IChatParticipantContribution, IChatProviderContribution } from 'vs/workbench/contrib/chat/common/chatContributionService';
|
||||
|
||||
export class MockChatContributionService implements IChatContributionService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
public readonly registeredParticipants: IChatParticipantContribution[] = []
|
||||
) { }
|
||||
|
||||
registeredProviders: IChatProviderContribution[] = [];
|
||||
registerChatParticipant(participant: IChatParticipantContribution): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
deregisterChatParticipant(participant: IChatParticipantContribution): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
registerChatProvider(provider: IChatProviderContribution): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
deregisterChatProvider(providerId: string): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getViewIdForProvider(providerId: string): string {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifec
|
|||
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
|
||||
import { ProviderResult } from 'vs/editor/common/languages';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IChatAgent, IChatAgentCommand, IChatAgentHistoryEntry, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatAgent, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentImplementation, IChatAgentMetadata, IChatAgentRequest, IChatAgentResult, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
|
||||
import { IChatProgress, IChatFollowup } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IVoiceChatSessionOptions, IVoiceChatTextEvent, VoiceChatService } from 'vs/workbench/contrib/chat/common/voiceChat';
|
||||
|
@ -28,10 +28,8 @@ suite('VoiceChat', () => {
|
|||
|
||||
extensionId: ExtensionIdentifier = nullExtensionDescription.identifier;
|
||||
|
||||
constructor(readonly id: string, private readonly lastSlashCommands: IChatAgentCommand[]) { }
|
||||
getLastSlashCommands(model: IChatModel): IChatAgentCommand[] | undefined { return this.lastSlashCommands; }
|
||||
constructor(readonly id: string, readonly slashCommands: IChatAgentCommand[]) { }
|
||||
invoke(request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentResult> { throw new Error('Method not implemented.'); }
|
||||
provideSlashCommands(model: IChatModel | undefined, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentCommand[]> { throw new Error('Method not implemented.'); }
|
||||
provideWelcomeMessage?(token: CancellationToken): ProviderResult<(string | IMarkdownString)[] | undefined> { throw new Error('Method not implemented.'); }
|
||||
metadata = {};
|
||||
}
|
||||
|
@ -49,14 +47,15 @@ suite('VoiceChat', () => {
|
|||
class TestChatAgentService implements IChatAgentService {
|
||||
_serviceBrand: undefined;
|
||||
readonly onDidChangeAgents = Event.None;
|
||||
registerAgent(agent: IChatAgent): IDisposable { throw new Error(); }
|
||||
registerAgent(name: string, agent: IChatAgentImplementation): IDisposable { throw new Error(); }
|
||||
registerDynamicAgent(data: IChatAgentData, agentImpl: IChatAgentImplementation): IDisposable { throw new Error('Method not implemented.'); }
|
||||
invokeAgent(id: string, request: IChatAgentRequest, progress: (part: IChatProgress) => void, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatAgentResult> { throw new Error(); }
|
||||
getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> { throw new Error(); }
|
||||
getAgents(): Array<IChatAgent> { return agents; }
|
||||
getAgent(id: string): IChatAgent | undefined { throw new Error(); }
|
||||
getRegisteredAgents(): Array<IChatAgent> { return agents; }
|
||||
getActivatedAgents(): IChatAgent[] { return agents; }
|
||||
getRegisteredAgent(id: string): IChatAgent | undefined { throw new Error(); }
|
||||
getDefaultAgent(): IChatAgent | undefined { throw new Error(); }
|
||||
getSecondaryAgent(): IChatAgent | undefined { throw new Error(); }
|
||||
hasAgent(id: string): boolean { throw new Error(); }
|
||||
updateAgent(id: string, updateMetadata: IChatAgentMetadata): void { throw new Error(); }
|
||||
}
|
||||
|
||||
|
|
|
@ -520,8 +520,8 @@ export class InlineChatController implements IEditorContribution {
|
|||
const withoutSubCommandLeader = input.slice(1);
|
||||
const cts = new CancellationTokenSource();
|
||||
this._sessionStore.add(cts);
|
||||
for (const agent of this._chatAgentService.getAgents()) {
|
||||
const commands = await agent.provideSlashCommands(undefined, [], cts.token);
|
||||
for (const agent of this._chatAgentService.getActivatedAgents()) {
|
||||
const commands = agent.slashCommands;
|
||||
if (commands.find((command) => withoutSubCommandLeader.startsWith(command.name))) {
|
||||
massagedInput = `${chatAgentLeader}${agent.id} ${input}`;
|
||||
break;
|
||||
|
|
|
@ -143,49 +143,6 @@ declare module 'vscode' {
|
|||
readonly kind: ChatResultFeedbackKind;
|
||||
}
|
||||
|
||||
export interface ChatCommand {
|
||||
/**
|
||||
* A short name by which this command is referred to in the UI, e.g. `fix` or
|
||||
* `explain` for commands that fix an issue or explain code.
|
||||
*
|
||||
* **Note**: The name should be unique among the commands provided by this participant.
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* Human-readable description explaining what this command does.
|
||||
*/
|
||||
readonly description: string;
|
||||
|
||||
/**
|
||||
* When the user clicks this command in `/help`, this text will be submitted to this command
|
||||
*/
|
||||
readonly sampleRequest?: string;
|
||||
|
||||
/**
|
||||
* Whether executing the command puts the chat into a persistent mode, where the command is automatically added to the chat input for the next message.
|
||||
*/
|
||||
readonly isSticky?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A ChatCommandProvider returns {@link ChatCommands commands} that can be invoked on a chat participant using `/`. For example, `@participant /command`.
|
||||
* These can be used as shortcuts to let the user explicitly invoke different functionalities provided by the participant.
|
||||
*/
|
||||
export interface ChatCommandProvider {
|
||||
/**
|
||||
* Returns a list of commands that its participant is capable of handling. A command
|
||||
* can be selected by the user and will then be passed to the {@link ChatRequestHandler handler}
|
||||
* via the {@link ChatRequest.command command} property.
|
||||
*
|
||||
*
|
||||
* @param token A cancellation token.
|
||||
* @returns A list of commands. The lack of a result can be signaled by returning `undefined`, `null`, or
|
||||
* an empty array.
|
||||
*/
|
||||
provideCommands(context: ChatContext, token: CancellationToken): ProviderResult<ChatCommand[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A followup question suggested by the participant.
|
||||
*/
|
||||
|
@ -239,11 +196,6 @@ declare module 'vscode' {
|
|||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* A human-readable description explaining what this participant does.
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Icon for the participant shown in UI.
|
||||
*/
|
||||
|
@ -263,11 +215,6 @@ declare module 'vscode' {
|
|||
*/
|
||||
requestHandler: ChatRequestHandler;
|
||||
|
||||
/**
|
||||
* This provider will be called to retrieve the participant's commands.
|
||||
*/
|
||||
commandProvider?: ChatCommandProvider;
|
||||
|
||||
/**
|
||||
* This provider will be called once after each request to retrieve suggested followup questions.
|
||||
*/
|
||||
|
|
|
@ -22,9 +22,18 @@ declare module 'vscode' {
|
|||
markdownContent: MarkdownString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Now only used for the "intent detection" API below
|
||||
*/
|
||||
export interface ChatCommand {
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
}
|
||||
|
||||
// TODO@API fit this into the stream
|
||||
export interface ChatDetectedParticipant {
|
||||
participant: string;
|
||||
// TODO@API validate this against statically-declared slash commands?
|
||||
command?: ChatCommand;
|
||||
}
|
||||
|
||||
|
@ -231,20 +240,6 @@ declare module 'vscode' {
|
|||
kind?: string;
|
||||
}
|
||||
|
||||
export interface ChatCommand {
|
||||
readonly isSticky2?: {
|
||||
/**
|
||||
* Indicates that the command should be automatically repopulated.
|
||||
*/
|
||||
isSticky: true;
|
||||
|
||||
/**
|
||||
* This can be set to a string to use a different placeholder message in the input box when the command has been repopulated.
|
||||
*/
|
||||
placeholder?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ChatVariableResolverResponseStream {
|
||||
/**
|
||||
* Push a progress part to this stream. Short-hand for
|
||||
|
@ -285,4 +280,12 @@ declare module 'vscode' {
|
|||
*/
|
||||
resolve2?(name: string, context: ChatVariableContext, stream: ChatVariableResolverResponseStream, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
|
||||
}
|
||||
|
||||
export interface ChatParticipant {
|
||||
/**
|
||||
* A human-readable description explaining what this participant does.
|
||||
* Only allow a static description for normal participants. Here where dynamic participants are allowed, the description must be able to be set as well.
|
||||
*/
|
||||
description?: string;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue