Change FollowupProvider to take a ChatContext. (#206611)

* Change FollowupProvider to take a ChatContext.
Also fix #205761

* Update test
This commit is contained in:
Rob Lourens 2024-03-01 11:32:52 -03:00 committed by GitHub
parent be59ec51ee
commit bd79cb3a46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 21 additions and 18 deletions

View file

@ -98,7 +98,7 @@ suite('chat', () => {
});
participant.isDefault = true;
participant.followupProvider = {
provideFollowups(result, _token) {
provideFollowups(result, _context, _token) {
deferred.complete(result);
return [];
},

View file

@ -91,12 +91,12 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
this._pendingProgress.delete(request.requestId);
}
},
provideFollowups: async (request, result, token): Promise<IChatFollowup[]> => {
provideFollowups: async (request, result, history, token): Promise<IChatFollowup[]> => {
if (!this._agents.get(handle)?.hasFollowups) {
return [];
}
return this._proxy.$provideFollowups(request, handle, result, token);
return this._proxy.$provideFollowups(request, handle, result, { history }, token);
},
provideWelcomeMessage: (token: CancellationToken) => {
return this._proxy.$provideWelcomeMessage(handle, token);

View file

@ -1227,7 +1227,7 @@ export type IChatAgentHistoryEntryDto = {
export interface ExtHostChatAgentsShape2 {
$invokeAgent(handle: number, request: IChatAgentRequest, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatAgentResult | undefined>;
$provideFollowups(request: IChatAgentRequest, handle: number, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]>;
$provideFollowups(request: IChatAgentRequest, handle: number, result: IChatAgentResult, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatFollowup[]>;
$acceptFeedback(handle: number, result: IChatAgentResult, vote: InteractiveSessionVoteDirection, reportIssue?: boolean): void;
$acceptAction(handle: number, result: IChatAgentResult, action: IChatUserActionEvent): void;
$invokeCompletionProvider(handle: number, query: string, token: CancellationToken): Promise<IChatAgentCompletionItem[]>;

View file

@ -245,14 +245,16 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 {
this._sessionDisposables.deleteAndDispose(sessionId);
}
async $provideFollowups(request: IChatAgentRequest, handle: number, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> {
async $provideFollowups(request: IChatAgentRequest, handle: number, result: IChatAgentResult, context: { history: IChatAgentHistoryEntryDto[] }, token: CancellationToken): Promise<IChatFollowup[]> {
const agent = this._agents.get(handle);
if (!agent) {
return Promise.resolve([]);
}
const convertedHistory = await this.prepareHistoryTurns(agent.id, context);
const ehResult = typeConvert.ChatAgentResult.to(result);
return (await agent.provideFollowups(ehResult, token))
return (await agent.provideFollowups(ehResult, { history: convertedHistory }, token))
.filter(f => {
// The followup must refer to a participant that exists from the same extension
const isValid = !f.participant || Iterable.some(
@ -376,11 +378,12 @@ class ExtHostChatAgent {
return await this._agentVariableProvider.provider.provideCompletionItems(query, token) ?? [];
}
async provideFollowups(result: vscode.ChatResult, token: CancellationToken): Promise<vscode.ChatFollowup[]> {
async provideFollowups(result: vscode.ChatResult, context: vscode.ChatContext, token: CancellationToken): Promise<vscode.ChatFollowup[]> {
if (!this._followupProvider) {
return [];
}
const followups = await this._followupProvider.provideFollowups(result, token);
const followups = await this._followupProvider.provideFollowups(result, context, token);
if (!followups) {
return [];
}

View file

@ -37,7 +37,7 @@ export interface 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[]>;
provideFollowups?(request: IChatAgentRequest, result: IChatAgentResult, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatFollowup[]>;
provideWelcomeMessage?(token: CancellationToken): ProviderResult<(string | IMarkdownString)[] | undefined>;
provideSampleQuestions?(token: CancellationToken): ProviderResult<IChatFollowup[] | undefined>;
}
@ -118,7 +118,7 @@ export interface IChatAgentService {
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[]>;
getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatFollowup[]>;
getRegisteredAgents(): Array<IChatAgentData>;
getActivatedAgents(): Array<IChatAgent>;
getRegisteredAgent(id: string): IChatAgentData | undefined;
@ -236,7 +236,7 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
return await data.impl.invoke(request, progress, history, token);
}
async getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> {
async getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatFollowup[]> {
const data = this._agents.get(id);
if (!data?.impl) {
throw new Error(`No activated agent with id ${id}`);
@ -246,7 +246,7 @@ export class ChatAgentService extends Disposable implements IChatAgentService {
return [];
}
return data.impl.provideFollowups(request, result, token);
return data.impl.provideFollowups(request, result, history, token);
}
}
@ -266,9 +266,9 @@ export class MergedChatAgent implements IChatAgent {
return this.impl.invoke(request, progress, history, token);
}
async provideFollowups(request: IChatAgentRequest, result: IChatAgentResult, token: CancellationToken): Promise<IChatFollowup[]> {
async provideFollowups(request: IChatAgentRequest, result: IChatAgentResult, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatFollowup[]> {
if (this.impl.provideFollowups) {
return this.impl.provideFollowups(request, result, token);
return this.impl.provideFollowups(request, result, history, token);
}
return [];

View file

@ -551,7 +551,7 @@ export class ChatService extends Disposable implements IChatService {
const agentResult = await this.chatAgentService.invokeAgent(agent.id, requestProps, progressCallback, history, token);
rawResult = agentResult;
agentOrCommandFollowups = this.chatAgentService.getFollowups(agent.id, requestProps, agentResult, followupsCancelToken);
agentOrCommandFollowups = this.chatAgentService.getFollowups(agent.id, requestProps, agentResult, history, followupsCancelToken);
} else if (commandPart && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) {
request = model.addRequest(parsedRequest, { variables: [] });
// contributed slash commands

View file

@ -50,7 +50,7 @@ suite('VoiceChat', () => {
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(); }
getFollowups(id: string, request: IChatAgentRequest, result: IChatAgentResult, history: IChatAgentHistoryEntry[], token: CancellationToken): Promise<IChatFollowup[]> { throw new Error(); }
getRegisteredAgents(): Array<IChatAgent> { return agents; }
getActivatedAgents(): IChatAgent[] { return agents; }
getRegisteredAgent(id: string): IChatAgent | undefined { throw new Error(); }

View file

@ -178,7 +178,7 @@ declare module 'vscode' {
* @param result This instance has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance.
* @param token A cancellation token.
*/
provideFollowups(result: ChatResult, token: CancellationToken): ProviderResult<ChatFollowup[]>;
provideFollowups(result: ChatResult, context: ChatContext, token: CancellationToken): ProviderResult<ChatFollowup[]>;
}
/**
@ -273,7 +273,7 @@ declare module 'vscode' {
/**
* The prompt as entered by the user.
*
* Information about variables used in this request are is stored in {@link ChatRequest.variables}.
* Information about variables used in this request is stored in {@link ChatRequest.variables}.
*
* *Note* that the {@link ChatParticipant.name name} of the participant and the {@link ChatCommand.name command}
* are not part of the prompt.