From 4eb07edec2fde1a1de1886086a947e737ff3d8e4 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 12 Feb 2024 15:20:58 +0100 Subject: [PATCH] api - change history into turns (#204992) https://github.com/microsoft/vscode/issues/199908 --- .../workbench/api/common/extHost.api.impl.ts | 2 + .../api/common/extHostChatAgents2.ts | 24 ++++++- .../api/common/extHostTypeConverters.ts | 4 +- src/vs/workbench/api/common/extHostTypes.ts | 17 +++++ .../vscode.proposed.chatAgents2.d.ts | 72 ++++++++++++++----- 5 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index a820c667796..071e935c051 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1663,6 +1663,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ChatResponseProgressPart: extHostTypes.ChatResponseProgressPart, ChatResponseReferencePart: extHostTypes.ChatResponseReferencePart, ChatResponseCommandButtonPart: extHostTypes.ChatResponseCommandButtonPart, + ChatAgentRequestTurn: extHostTypes.ChatAgentRequestTurn, + ChatAgentResponseTurn: extHostTypes.ChatAgentResponseTurn, }; }; } diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 558061ddbe8..65a95d5374e 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -198,9 +198,10 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { const stream = new ChatAgentResponseStream(agent.extension, request, this._proxy, this._logService, this.commands.converter, sessionDisposables); try { const convertedHistory = await this.prepareHistory(request, context); + const convertedHistory2 = await this.prepareHistoryTurns(request, context); const task = agent.invoke( typeConvert.ChatAgentRequest.to(request), - { history: convertedHistory }, + { history: convertedHistory, history2: convertedHistory2 }, stream.apiObject, token ); @@ -243,6 +244,27 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { }))); } + private async prepareHistoryTurns(request: IChatAgentRequest, context: { history: IChatAgentHistoryEntryDto[] }): Promise<(vscode.ChatAgentRequestTurn | vscode.ChatAgentResponseTurn)[]> { + + const res: (vscode.ChatAgentRequestTurn | vscode.ChatAgentResponseTurn)[] = []; + + for (const h of context.history) { + const ehResult = typeConvert.ChatAgentResult.to(h.result); + const result: vscode.ChatAgentResult2 = request.agentId === h.request.agentId ? + ehResult : + { ...ehResult, metadata: undefined }; + + // REQUEST turn + res.push(new extHostTypes.ChatAgentRequestTurn(h.request.message, h.request.agentId, h.request.command, h.request.variables2.variables.map(typeConvert.ChatAgentResolvedVariable.to))); + + // RESPONSE turn + const parts = coalesce(h.response.map(r => typeConvert.ChatResponsePart.from(r, this.commands.converter))); + res.push(new extHostTypes.ChatAgentResponseTurn(parts, result, h.request.agentId)); + } + + return res; + } + $releaseSession(sessionId: string): void { this._sessionDisposables.deleteAndDispose(sessionId); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 0b639e933b5..588ab94a8de 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2479,7 +2479,7 @@ export namespace ChatResponsePart { } - export function from(part: extHostProtocol.IChatProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponsePart { + export function from(part: extHostProtocol.IChatProgressDto, commandsConverter: CommandsConverter): vscode.ChatResponsePart | undefined { switch (part.kind) { case 'markdownContent': return ChatResponseMarkdownPart.from(part); case 'inlineReference': return ChatResponseAnchorPart.from(part); @@ -2488,7 +2488,7 @@ export namespace ChatResponsePart { case 'treeData': return ChatResponseFilesPart.from(part); case 'command': return ChatResponseCommandButtonPart.from(part, commandsConverter); } - return new types.ChatResponseTextPart(''); + return undefined; } } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 9a392ffc2e3..492cf921558 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4257,6 +4257,23 @@ export class ChatResponseReferencePart { } +export class ChatAgentRequestTurn implements vscode.ChatAgentRequestTurn { + constructor( + readonly prompt: string, + readonly agentId: string, + readonly command: string | undefined, + readonly variables: vscode.ChatAgentResolvedVariable[], + ) { } +} + +export class ChatAgentResponseTurn implements vscode.ChatAgentResponseTurn { + constructor( + readonly response: ReadonlyArray, + readonly result: vscode.ChatAgentResult2, + readonly agentId: string, + ) { } +} + //#endregion //#region ai diff --git a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts index 403265ad3f2..9f0f46769f1 100644 --- a/src/vscode-dts/vscode.proposed.chatAgents2.d.ts +++ b/src/vscode-dts/vscode.proposed.chatAgents2.d.ts @@ -12,13 +12,12 @@ declare module 'vscode' { /** * The request that was sent to the chat agent. */ - // TODO@API make this optional? Allow for response without request? request: ChatAgentRequest; /** * The content that was received from the chat agent. Only the progress parts that represent actual content (not metadata) are represented. */ - response: (ChatResponseTextPart | ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart)[]; + response: ReadonlyArray; /** * The result that was received from the chat agent. @@ -26,31 +25,69 @@ declare module 'vscode' { result: ChatAgentResult2; } - // TODO@API class - // export interface ChatAgentResponse { - // /** - // * The content that was received from the chat agent. Only the progress parts that represent actual content (not metadata) are represented. - // */ - // response: (ChatAgentContentProgress | ChatResponseTextPart | ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart)[]; + // TODO@API name: Turn? + export class ChatAgentRequestTurn { - // agentId: string + /** + * The prompt as entered by the user. + * + * Information about variables used in this request are is stored in {@link ChatAgentRequest.variables2}. + * + * *Note* that the {@link ChatAgent2.name name} of the agent and the {@link ChatAgentCommand.name command} + * are not part of the prompt. + */ + readonly prompt: string; - // /** - // * The result that was received from the chat agent. - // */ - // result: ChatAgentResult2; - // } + /** + * The ID of the chat agent to which this request was directed. + */ + readonly agentId: string; + + /** + * The name of the {@link ChatAgentCommand command} that was selected for this request. + */ + readonly command: string | undefined; + + /** + * + */ + // TODO@API is this needed? + readonly variables: ChatAgentResolvedVariable[]; + + private constructor(prompt: string, agentId: string, command: string | undefined, variables: ChatAgentResolvedVariable[],); + } + + // TODO@API name: Turn? + export class ChatAgentResponseTurn { + + /** + * The content that was received from the chat agent. Only the progress parts that represent actual content (not metadata) are represented. + */ + readonly response: ReadonlyArray; + + /** + * The result that was received from the chat agent. + */ + readonly result: ChatAgentResult2; + + readonly agentId: string; + + private constructor(response: ReadonlyArray, result: ChatAgentResult2, agentId: string); + } export interface ChatAgentContext { /** - * All of the chat messages so far in the current chat session. + * @deprecated */ history: ChatAgentHistoryEntry[]; // location: - // TODO@API have "turns" - // history2: (ChatAgentRequest | ChatAgentResponse)[]; + /** + * All of the chat messages so far in the current chat session. + */ + // TODO@API name: histroy + readonly history2: ReadonlyArray; } /** @@ -479,6 +516,7 @@ declare module 'vscode' { * @param description A description of the variable for the chat input suggest widget. * @param resolver Will be called to provide the chat variable's value when it is used. */ + // TODO@API NAME: registerChatVariable, registerChatVariableResolver export function registerVariable(name: string, description: string, resolver: ChatVariableResolver): Disposable; }