From 54821ee1f14beca4866abd7de86175b4794b030d Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Tue, 14 Nov 2023 12:51:10 +0100 Subject: [PATCH] Revert "Make the chat progress types nicer (#198175)" (#198198) This reverts commit 94959e85502687ec77e23eb0d4d4b1a827b919af. --- .../api/browser/mainThreadChatAgents2.ts | 37 ++++++---- .../workbench/api/common/extHost.protocol.ts | 32 +++------ .../api/common/extHostChatAgents2.ts | 3 +- .../api/common/extHostTypeConverters.ts | 23 +++--- .../contrib/chat/browser/chat.contribution.ts | 10 +-- .../contrib/chat/common/chatModel.ts | 70 +++++++++++-------- .../contrib/chat/common/chatService.ts | 40 +++-------- .../contrib/chat/common/chatServiceImpl.ts | 27 +++++-- .../__snapshots__/Chat_can_deserialize.0.snap | 7 +- .../__snapshots__/Chat_can_serialize.1.snap | 7 +- .../chat/test/common/chatService.test.ts | 3 +- 11 files changed, 128 insertions(+), 131 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index 318dd3ee83f..35908757eda 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -7,9 +7,11 @@ import { DeferredPromise } from 'vs/base/common/async'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { Disposable, DisposableMap } from 'vs/base/common/lifecycle'; import { revive } from 'vs/base/common/marshalling'; -import { ExtHostChatAgentsShape2, ExtHostContext, IChatProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; +import { UriComponents } from 'vs/base/common/uri'; +import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IChatResponseProgressFileTreeData, IExtensionChatAgentMetadata, ILocationDto, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol'; import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; -import { IChatFollowup, IChatProgress, IChatService, IChatTreeData } from 'vs/workbench/contrib/chat/common/chatService'; +import { isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel'; +import { IChatFollowup, IChatProgress, IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers'; type AgentData = { @@ -27,7 +29,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA private readonly _proxy: ExtHostChatAgentsShape2; private _responsePartHandlePool = 0; - private readonly _activeResponsePartPromises = new Map>(); + private readonly _activeResponsePartPromises = new Map>(); constructor( extHostContext: IExtHostContext, @@ -104,11 +106,11 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA this._chatAgentService.updateAgent(data.name, revive(metadataUpdate)); } - async $handleProgressChunk(requestId: string, progress: IChatProgressDto, responsePartHandle?: number): Promise { - if (progress.kind === 'asyncContent') { + async $handleProgressChunk(requestId: string, progress: IChatResponseProgressDto, responsePartHandle?: number): Promise { + if ('placeholder' in progress) { const handle = ++this._responsePartHandlePool; const responsePartId = `${requestId}_${handle}`; - const deferredContentPromise = new DeferredPromise(); + const deferredContentPromise = new DeferredPromise(); this._activeResponsePartPromises.set(responsePartId, deferredContentPromise); this._pendingProgress.get(requestId)?.({ ...progress, resolvedContent: deferredContentPromise.p }); return handle; @@ -116,11 +118,11 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA // Complete an existing deferred promise with resolved content const responsePartId = `${requestId}_${responsePartHandle}`; const deferredContentPromise = this._activeResponsePartPromises.get(responsePartId); - if (deferredContentPromise && progress.kind === 'treeData') { - const withRevivedUris = revive(progress); + if (deferredContentPromise && isCompleteInteractiveProgressTreeData(progress)) { + const withRevivedUris = revive<{ treeData: IChatResponseProgressFileTreeData }>(progress); deferredContentPromise.complete(withRevivedUris); this._activeResponsePartPromises.delete(responsePartId); - } else if (deferredContentPromise && progress.kind === 'content') { + } else if (deferredContentPromise && 'content' in progress) { deferredContentPromise.complete(progress.content); this._activeResponsePartPromises.delete(responsePartId); } @@ -128,11 +130,22 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA } // No need to support standalone tree data that's not attached to a placeholder in API - if (progress.kind === 'treeData') { + if (isCompleteInteractiveProgressTreeData(progress)) { return; } - const revivedProgress = revive(progress); - this._pendingProgress.get(requestId)?.(revivedProgress as IChatProgress); + // TS won't let us change the type of `progress` + let revivedProgress: IChatProgress; + if ('documents' in progress) { + revivedProgress = { documents: revive(progress.documents) }; + } else if ('reference' in progress) { + revivedProgress = revive<{ reference: UriComponents | ILocationDto }>(progress); + } else if ('inlineReference' in progress) { + revivedProgress = revive<{ inlineReference: UriComponents | ILocationDto; name?: string }>(progress); + } else { + revivedProgress = progress; + } + + this._pendingProgress.get(requestId)?.(revivedProgress); } } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index c322e4f4505..a01697db5a6 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -52,7 +52,7 @@ 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 { IChatMessage, IChatResponseFragment, IChatResponseProviderMetadata } from 'vs/workbench/contrib/chat/common/chatProvider'; -import { IChatAgentDetection, IChatAsyncContent, IChatContent, IChatContentInlineReference, IChatContentReference, IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatTreeData, IChatUsedContext, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatAgentDetection, IChatDynamicRequest, IChatFollowup, IChatReplyFollowup, IChatResponseErrorDetails, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatRequestVariableValue, IChatVariableData } from 'vs/workbench/contrib/chat/common/chatVariables'; import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug'; import { IInlineChatBulkEditResponse, IInlineChatEditResponse, IInlineChatMessageResponse, IInlineChatProgressItem, IInlineChatRequest, IInlineChatSession, InlineChatResponseFeedbackKind } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; @@ -1174,7 +1174,7 @@ export interface MainThreadChatAgentsShape2 extends IDisposable { $registerAgent(handle: number, name: string, metadata: IExtensionChatAgentMetadata): void; $updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void; $unregisterAgent(handle: number): void; - $handleProgressChunk(requestId: string, chunk: IChatProgressDto, responsePartHandle?: number): Promise; + $handleProgressChunk(requestId: string, chunk: IChatResponseProgressDto, responsePartHandle?: number): Promise; } export interface ExtHostChatAgentsShape2 { @@ -1250,26 +1250,14 @@ export type IDocumentContextDto = { ranges: IRange[]; }; -export type IChatAsyncContentDto = Dto>; - -// TODO@some type ninja who can do this without the duplication (the async content case throws me off) -export type IChatProgressDto = - | Dto - | Dto - | Dto - | Dto - | Dto - | Dto - | Dto - | IChatAsyncContentDto; - -// | { content: string | IMarkdownString } -// | { placeholder: string } -// | { treeData: IChatResponseProgressFileTreeData } -// | { documents: IDocumentContextDto[] } -// | { reference: UriComponents | ILocationDto } -// | { inlineReference: UriComponents | ILocationDto; title?: string } -// | IChatAgentDetection; +export type IChatResponseProgressDto = + | { content: string | IMarkdownString } + | { placeholder: string } + | { treeData: IChatResponseProgressFileTreeData } + | { documents: IDocumentContextDto[] } + | { reference: UriComponents | ILocationDto } + | { inlineReference: UriComponents | ILocationDto; title?: string } + | IChatAgentDetection; export interface MainThreadChatShape extends IDisposable { $registerChatProvider(handle: number, id: string): Promise; diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 314de7e2b22..f35ee2d995f 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -103,8 +103,7 @@ export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { return; /* Cancelled */ } const [progressHandle, progressContent] = res; - const convertedContent = typeConvert.ChatResponseProgress.from(agent.extension, progressContent); - this._proxy.$handleProgressChunk(requestId, convertedContent, progressHandle ?? undefined); + this._proxy.$handleProgressChunk(requestId, progressContent, progressHandle ?? undefined); }); } else { this._proxy.$handleProgressChunk(requestId, convertedProgress); diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 76565868b9e..8ae2479fd2f 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2293,27 +2293,26 @@ export namespace InteractiveEditorResponseFeedbackKind { } export namespace ChatResponseProgress { - export function from(extension: IExtensionDescription, progress: vscode.ChatAgentExtendedProgress): extHostProtocol.IChatProgressDto { + export function from(extension: IExtensionDescription, progress: vscode.ChatAgentExtendedProgress): extHostProtocol.IChatResponseProgressDto { if ('placeholder' in progress && 'resolvedContent' in progress) { - return { placeholder: progress.placeholder, kind: 'asyncContent' } satisfies extHostProtocol.IChatAsyncContentDto; + return { placeholder: progress.placeholder }; } else if ('markdownContent' in progress) { checkProposedApiEnabled(extension, 'chatAgents2Additions'); - return { content: MarkdownString.from(progress.markdownContent), kind: 'content' }; + return { content: MarkdownString.from(progress.markdownContent) }; } else if ('content' in progress) { if (typeof progress.content === 'string') { - return { content: progress.content, kind: 'content' }; + return progress; } checkProposedApiEnabled(extension, 'chatAgents2Additions'); - return { content: MarkdownString.from(progress.content), kind: 'content' }; + return { content: MarkdownString.from(progress.content) }; } else if ('documents' in progress) { return { documents: progress.documents.map(d => ({ uri: d.uri, version: d.version, ranges: d.ranges.map(r => Range.from(r)) - })), - kind: 'usedContext' + })) }; } else if ('reference' in progress) { return { @@ -2321,8 +2320,7 @@ export namespace ChatResponseProgress { { uri: progress.reference.uri, range: Range.from(progress.reference.range) - } : progress.reference, - kind: 'reference' + } : progress.reference }; } else if ('inlineReference' in progress) { return { @@ -2331,14 +2329,13 @@ export namespace ChatResponseProgress { uri: progress.inlineReference.uri, range: Range.from(progress.inlineReference.range) } : progress.inlineReference, - name: progress.title, - kind: 'inlineReference' + title: progress.title, }; } else if ('agentName' in progress) { checkProposedApiEnabled(extension, 'chatAgents2Additions'); - return { agentName: progress.agentName, command: progress.command, kind: 'agentDetection' }; + return progress; } else { - return { treeData: progress.treeData, kind: 'treeData' }; + return progress; } } } diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 91810918bd3..e990302b9ff 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -243,8 +243,8 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable { const defaultAgent = chatAgentService.getDefaultAgent(); const agents = chatAgentService.getAgents(); if (defaultAgent?.metadata.helpTextPrefix) { - progress.report({ content: defaultAgent.metadata.helpTextPrefix, kind: 'content' }); - progress.report({ content: '\n\n', kind: 'content' }); + progress.report({ content: defaultAgent.metadata.helpTextPrefix }); + progress.report({ content: '\n\n' }); } const agentText = (await Promise.all(agents @@ -263,10 +263,10 @@ class ChatSlashStaticSlashCommandsContribution extends Disposable { return agentLine + '\n' + commandText; }))).join('\n'); - progress.report({ content: new MarkdownString(agentText, { isTrusted: { enabledCommands: [SubmitAction.ID] } }), kind: 'content' }); + progress.report({ content: new MarkdownString(agentText, { isTrusted: { enabledCommands: [SubmitAction.ID] } }) }); if (defaultAgent?.metadata.helpTextPostfix) { - progress.report({ content: '\n\n', kind: 'content' }); - progress.report({ content: defaultAgent.metadata.helpTextPostfix, kind: 'content' }); + progress.report({ content: '\n\n' }); + progress.report({ content: defaultAgent.metadata.helpTextPostfix }); } })); } diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 7f9900d1fcc..b743e6915fe 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -16,7 +16,7 @@ import { OffsetRange } from 'vs/editor/common/core/offsetRange'; import { ILogService } from 'vs/platform/log/common/log'; import { IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; -import { IChat, IChatAgentDetection, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatProgress, IChatReplyFollowup, IChatResponse, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, IChatUsedContext, InteractiveSessionVoteDirection, isIUsedContext } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChat, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatProgress, IChatReplyFollowup, IChatResponse, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, IUsedContext, InteractiveSessionVoteDirection, isIUsedContext } from 'vs/workbench/contrib/chat/common/chatService'; export interface IChatRequestModel { readonly id: string; @@ -27,11 +27,23 @@ export interface IChatRequestModel { readonly response: IChatResponseModel | undefined; } -export type IChatProgressResponseContent = Exclude; +export type ResponsePart = + | string + | IMarkdownString + | { treeData: IChatResponseProgressFileTreeData } + | { + placeholder: string; + resolvedContent?: Promise< + string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData } + >; + } + | IUsedContext + | IChatContentReference + | IChatContentInlineReference; export interface IResponse { readonly value: ReadonlyArray; - readonly usedContext: IChatUsedContext | undefined; + readonly usedContext: IUsedContext | undefined; readonly contentReferences: ReadonlyArray; asString(): string; } @@ -100,8 +112,8 @@ export class Response implements IResponse { return this._contentReferences; } - private _usedContext: IChatUsedContext | undefined; - public get usedContext(): IChatUsedContext | undefined { + private _usedContext: IUsedContext | undefined; + public get usedContext(): IUsedContext | undefined { return this._usedContext; } @@ -135,36 +147,36 @@ export class Response implements IResponse { return this._responseRepr; } - updateContent(progress: IChatProgressResponseContent, quiet?: boolean): void { - if (progress.kind === 'content') { + updateContent(responsePart: ResponsePart, quiet?: boolean): void { + if (typeof responsePart === 'string' || isMarkdownString(responsePart)) { const responsePartLength = this._responseParts.length - 1; const lastResponsePart = this._responseParts[responsePartLength]; if (lastResponsePart && ('inlineReference' in lastResponsePart || lastResponsePart.isPlaceholder === true || isCompleteInteractiveProgressTreeData(lastResponsePart))) { // The last part is resolving or a tree data item, start a new part - this._responseParts.push({ string: typeof progress.content === 'string' ? new MarkdownString(progress.content) : progress.content }); + this._responseParts.push({ string: typeof responsePart === 'string' ? new MarkdownString(responsePart) : responsePart }); } else if (lastResponsePart) { // Combine this part with the last, non-resolving string part - if (isMarkdownString(progress.content)) { + if (isMarkdownString(responsePart)) { // Merge all enabled commands const lastPartEnabledCommands = typeof lastResponsePart.string.isTrusted === 'object' ? lastResponsePart.string.isTrusted.enabledCommands : []; - const thisPartEnabledCommands = typeof progress.content.isTrusted === 'object' ? progress.content.isTrusted.enabledCommands : []; + const thisPartEnabledCommands = typeof responsePart.isTrusted === 'object' ? responsePart.isTrusted.enabledCommands : []; const enabledCommands = [...lastPartEnabledCommands, ...thisPartEnabledCommands]; - this._responseParts[responsePartLength] = { string: new MarkdownString(lastResponsePart.string.value + progress.content.value, { isTrusted: { enabledCommands } }) }; + this._responseParts[responsePartLength] = { string: new MarkdownString(lastResponsePart.string.value + responsePart.value, { isTrusted: { enabledCommands } }) }; } else { - this._responseParts[responsePartLength] = { string: new MarkdownString(lastResponsePart.string.value + progress, lastResponsePart.string) }; + this._responseParts[responsePartLength] = { string: new MarkdownString(lastResponsePart.string.value + responsePart, lastResponsePart.string) }; } } else { - this._responseParts.push({ string: isMarkdownString(progress.content) ? progress.content : new MarkdownString(progress.content) }); + this._responseParts.push({ string: isMarkdownString(responsePart) ? responsePart : new MarkdownString(responsePart) }); } this._updateRepr(quiet); - } else if ('placeholder' in progress) { + } else if ('placeholder' in responsePart) { // Add a new resolving part - const responsePosition = this._responseParts.push({ string: new MarkdownString(progress.placeholder), isPlaceholder: true }) - 1; + const responsePosition = this._responseParts.push({ string: new MarkdownString(responsePart.placeholder), isPlaceholder: true }) - 1; this._updateRepr(quiet); - progress.resolvedContent?.then((content) => { + responsePart.resolvedContent?.then((content) => { // Replace the resolving part's content with the resolved response if (typeof content === 'string') { this._responseParts[responsePosition] = { string: new MarkdownString(content), isPlaceholder: true }; @@ -177,17 +189,19 @@ export class Response implements IResponse { this._updateRepr(quiet); } }); - } else if (isCompleteInteractiveProgressTreeData(progress)) { - this._responseParts.push(progress); + } else if (isCompleteInteractiveProgressTreeData(responsePart)) { + this._responseParts.push(responsePart); this._updateRepr(quiet); - } else if ('documents' in progress) { - this._usedContext = progress; - } else if ('reference' in progress) { - this._contentReferences.push(progress); + } else if ('documents' in responsePart) { + this._usedContext = responsePart; + } else if ('reference' in responsePart) { + this._contentReferences.push(responsePart); this._onDidChangeValue.fire(); - } else if ('inlineReference' in progress) { - this._responseParts.push(progress); + } else if ('inlineReference' in responsePart) { + this._responseParts.push(responsePart); this._updateRepr(quiet); + } else if ('agentName' in responsePart) { + } } @@ -299,7 +313,7 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel this._id = 'response_' + ChatResponseModel.nextId++; } - updateContent(responsePart: IChatProgressResponseContent, quiet?: boolean) { + updateContent(responsePart: ResponsePart, quiet?: boolean) { this._response.updateContent(responsePart, quiet); } @@ -367,7 +381,7 @@ export interface ISerializableChatRequestData { isCanceled: boolean | undefined; vote: InteractiveSessionVoteDirection | undefined; /** For backward compat: should be optional */ - usedContext?: IChatUsedContext; + usedContext?: IUsedContext; contentReferences?: ReadonlyArray; } @@ -647,8 +661,8 @@ export class ChatModel extends Disposable implements IChatModel { throw new Error('acceptResponseProgress: Adding progress to a completed response'); } - if (progress.kind === 'content') { - request.response.updateContent(progress, quiet); + if ('content' in progress) { + request.response.updateContent(progress.content, quiet); } else if ('placeholder' in progress || isCompleteInteractiveProgressTreeData(progress)) { request.response.updateContent(progress, quiet); } else if ('documents' in progress || 'reference' in progress || 'inlineReference' in progress) { diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 67a37babec9..8f5d6054790 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -8,11 +8,11 @@ import { Event } from 'vs/base/common/event'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { IRange, Range } from 'vs/editor/common/core/range'; -import { Location, ProviderResult } from 'vs/editor/common/languages'; +import { Range, IRange } from 'vs/editor/common/core/range'; +import { ProviderResult, Location } from 'vs/editor/common/languages'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IChatAgentCommand, IChatAgentData } from 'vs/workbench/contrib/chat/common/chatAgents'; -import { ChatModel, IChatModel, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel'; +import { IChatModel, ChatModel, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel'; import { IParsedChatRequest } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { IChatRequestVariableValue } from 'vs/workbench/contrib/chat/common/chatVariables'; @@ -69,12 +69,11 @@ export function isIDocumentContext(obj: unknown): obj is IDocumentContext { ); } -export interface IChatUsedContext { +export type IUsedContext = { documents: IDocumentContext[]; - kind: 'usedContext'; -} +}; -export function isIUsedContext(obj: unknown): obj is IChatUsedContext { +export function isIUsedContext(obj: unknown): obj is IUsedContext { return ( !!obj && typeof obj === 'object' && @@ -86,42 +85,23 @@ export function isIUsedContext(obj: unknown): obj is IChatUsedContext { export interface IChatContentReference { reference: URI | Location; - kind: 'reference'; } export interface IChatContentInlineReference { inlineReference: URI | Location; name?: string; - kind: 'inlineReference'; } export interface IChatAgentDetection { agentName: string; command?: IChatAgentCommand; - kind: 'agentDetection'; -} - -export interface IChatContent { - content: string | IMarkdownString; - kind: 'content'; -} - -export interface IChatTreeData { - treeData: IChatResponseProgressFileTreeData; - kind: 'treeData'; -} - -export interface IChatAsyncContent { - placeholder: string; - resolvedContent: Promise; - kind: 'asyncContent'; } export type IChatProgress = - | IChatContent - | IChatTreeData - | IChatAsyncContent - | IChatUsedContext + | { content: string | IMarkdownString } + | { treeData: IChatResponseProgressFileTreeData } + | { placeholder: string; resolvedContent: Promise } + | IUsedContext | IChatContentReference | IChatContentInlineReference | IChatAgentDetection; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index 1e3ef878ce7..f1c3f8454ee 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -23,7 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IChatAgentCommand, IChatAgentData, IChatAgentRequest, 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, ISerializableChatData, ISerializableChatsData } from 'vs/workbench/contrib/chat/common/chatModel'; +import { ChatModel, ChatModelInitState, ChatRequestModel, ChatWelcomeMessageModel, IChatModel, ISerializableChatData, ISerializableChatsData, isCompleteInteractiveProgressTreeData } from 'vs/workbench/contrib/chat/common/chatModel'; import { ChatRequestAgentPart, ChatRequestAgentSubcommandPart, ChatRequestSlashCommandPart } from 'vs/workbench/contrib/chat/common/chatParserTypes'; import { ChatMessageRole, IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser'; @@ -469,10 +469,23 @@ export class ChatService extends Disposable implements IChatService { gotProgress = true; - if (progress.kind === 'content') { + if ('content' in progress) { this.trace('sendRequest', `Provider returned progress for session ${model.sessionId}, ${typeof progress.content === 'string' ? progress.content.length : progress.content.value.length} chars`); + } else if ('placeholder' in progress) { + this.trace('sendRequest', `Provider returned placeholder for session ${model.sessionId}, ${progress.placeholder}`); + } else if (isCompleteInteractiveProgressTreeData(progress)) { + // This isn't exposed in API + this.trace('sendRequest', `Provider returned tree data for session ${model.sessionId}, ${progress.treeData.label}`); + } else if ('documents' in progress) { + this.trace('sendRequest', `Provider returned documents for session ${model.sessionId}:\n ${JSON.stringify(progress.documents, null, '\t')}`); + } else if ('reference' in progress) { + this.trace('sendRequest', `Provider returned a reference for session ${model.sessionId}:\n ${JSON.stringify(progress.reference, null, '\t')}`); + } else if ('inlineReference' in progress) { + this.trace('sendRequest', `Provider returned an inline reference for session ${model.sessionId}:\n ${JSON.stringify(progress.inlineReference, null, '\t')}`); + } else if ('agentName' in progress) { + this.trace('sendRequest', `Provider returned an agent detection for session ${model.sessionId}:\n ${JSON.stringify(progress, null, '\t')}`); } else { - this.trace('sendRequest', `Provider returned progress: ${JSON.stringify(progress)}`); + this.trace('sendRequest', `Provider returned unknown progress for session ${model.sessionId}:\n ${JSON.stringify(progress, null, '\t')}`); } model.acceptResponseProgress(request, progress); @@ -643,12 +656,12 @@ export class ChatService extends Disposable implements IChatService { const parsedRequest = await this.instantiationService.createInstance(ChatRequestParser).parseChatRequest(sessionId, message); const request = model.addRequest(parsedRequest); if (typeof response.message === 'string') { - model.acceptResponseProgress(request, { content: response.message, kind: 'content' }); + model.acceptResponseProgress(request, { content: response.message }); } else { for (const part of response.message) { - const progress: IChatProgress = 'inlineReference' in part ? part : - isMarkdownString(part) ? { content: part.value, kind: 'content' } : - { treeData: part, kind: 'treeData' }; + const progress = 'inlineReference' in part ? part : + isMarkdownString(part) ? { content: part.value } : + { treeData: part }; model.acceptResponseProgress(request, progress, true); } } diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap index 223b9763bfe..e5e02c302c8 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_deserialize.0.snap @@ -54,8 +54,7 @@ metadata: { } }, slashCommand: undefined, - usedContext: { - documents: [ + usedContext: { documents: [ { uri: { scheme: "file", @@ -76,9 +75,7 @@ } ] } - ], - kind: "usedContext" - }, + ] }, contentReferences: [ ] } ], diff --git a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap index fbeb0fa885f..178b1177890 100644 --- a/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap +++ b/src/vs/workbench/contrib/chat/test/common/__snapshots__/Chat_can_serialize.1.snap @@ -54,8 +54,7 @@ metadata: { } }, slashCommand: undefined, - usedContext: { - documents: [ + usedContext: { documents: [ { uri: { scheme: "file", @@ -76,9 +75,7 @@ } ] } - ], - kind: "usedContext" - }, + ] }, contentReferences: [ ] } ], diff --git a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts index aa805cbe725..e2ae43a90e1 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts @@ -71,8 +71,7 @@ const chatAgentWithUsedContext: IChatAgent = { new Range(1, 1, 2, 2) ] } - ], - kind: 'usedContext' + ] }); return {};