diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 36df48dc744..d40b954580b 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -593,7 +593,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer void } { + private renderContentReferencesListData(data: ReadonlyArray, element: IChatResponseViewModel, templateData: IChatListItemTemplate): { element: HTMLElement; dispose: () => void } { const listDisposables = new DisposableStore(); const referencesLabel = data.length > 1 ? localize('usedReferencesPlural', "Used {0} references", data.length) : diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index adf86861a1a..77f4de7c133 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -39,9 +39,9 @@ export type ResponsePart = | IChatContentReference; export interface IResponse { - readonly value: (IMarkdownString | IPlaceholderMarkdownString | IChatResponseProgressFileTreeData)[]; + readonly value: ReadonlyArray; readonly usedContext: IUsedContext | undefined; - readonly contentReferences: IChatContentReference[]; + readonly contentReferences: ReadonlyArray; onDidChangeValue: Event; updateContent(responsePart: ResponsePart, quiet?: boolean): void; asString(): string; @@ -133,7 +133,7 @@ export class Response implements IResponse { return this._responseData; } - constructor(value: IMarkdownString | (IMarkdownString | IChatResponseProgressFileTreeData)[]) { + constructor(value: IMarkdownString | ReadonlyArray) { this._responseData = Array.isArray(value) ? value : [value]; this._responseParts = Array.isArray(value) ? value.map((v) => ('value' in v ? { string: v } : { treeData: v })) : [{ string: value }]; this._responseRepr = this._responseParts.map((part) => { @@ -269,8 +269,10 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel return this.agent?.metadata.icon ?? this.session.responderAvatarIconUri; } + private _followups?: IChatFollowup[]; + constructor( - _response: IMarkdownString | (IMarkdownString | IChatResponseProgressFileTreeData)[], + _response: IMarkdownString | ReadonlyArray, public readonly session: ChatModel, public readonly agent: IChatAgentData | undefined, private _isComplete: boolean = false, @@ -278,9 +280,10 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel private _vote?: InteractiveSessionVoteDirection, private _providerResponseId?: string, private _errorDetails?: IChatResponseErrorDetails, - private _followups?: IChatFollowup[] + followups?: ReadonlyArray ) { super(); + this._followups = followups ? [...followups] : undefined; this._response = new Response(_response); this._register(this._response.onDidChangeValue(() => this._onDidChange.fire())); this._id = 'response_' + ChatResponseModel.nextId++; @@ -350,15 +353,15 @@ export interface ISerializableChatAgentData { export interface ISerializableChatRequestData { providerRequestId: string | undefined; message: string | IParsedChatRequest; - response: (IMarkdownString | IChatResponseProgressFileTreeData)[] | undefined; + response: ReadonlyArray | undefined; agent?: ISerializableChatAgentData; responseErrorDetails: IChatResponseErrorDetails | undefined; - followups: IChatFollowup[] | undefined; + followups: ReadonlyArray | undefined; isCanceled: boolean | undefined; vote: InteractiveSessionVoteDirection | undefined; /** For backward compat: should be optional */ usedContext?: IUsedContext; - contentReferences?: IChatContentReference[]; + contentReferences?: ReadonlyArray; } export interface IExportableChatData { @@ -540,6 +543,10 @@ export class ChatModel extends Disposable implements IChatModel { if (raw.usedContext) { // @ulugbekna: if this's a new vscode sessions, doc versions are incorrect anyway? request.response.updateContent(raw.usedContext); } + + if (raw.contentReferences) { + raw.contentReferences.forEach(r => request.response!.updateContent(r)); + } } return request; }); @@ -720,6 +727,7 @@ export class ChatModel extends Disposable implements IChatModel { icon: r.response.agent.metadata.icon } : undefined, usedContext: r.response?.response.usedContext, + contentReferences: r.response?.response.contentReferences }; }), providerId: this.providerId, diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 3dc49274cef..f98758ec2f5 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -223,7 +223,7 @@ export interface IChatDynamicRequest { } export interface IChatCompleteResponse { - message: string | (IMarkdownString | IChatResponseProgressFileTreeData)[]; + message: string | ReadonlyArray; errorDetails?: IChatResponseErrorDetails; followups?: IChatFollowup[]; } 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 8a055fa5157..bd85fe7d442 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 @@ -60,7 +60,8 @@ } ] } - ] } + ] }, + contentReferences: [ ] } ], providerId: "ChatProviderWithUsedContext", 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 4abd4c09014..cc7309c9489 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 @@ -60,7 +60,8 @@ } ] } - ] } + ] }, + contentReferences: [ ] } ], providerId: "ChatProviderWithUsedContext",