mapped edits: implement support for getting doc ranges from InteractiveSessionProvider's

This commit is contained in:
Ulugbek Abdullaev
2023-09-21 11:58:53 +02:00
parent 95f79a91e4
commit 49dadc018d
7 changed files with 82 additions and 6 deletions

View File

@@ -159,6 +159,18 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape {
return;
}
if ('documents' in progress) {
const usedContext = {
documents: progress.documents.map(({ uri, version, ranges }) => ({
uri: URI.revive(uri),
version,
ranges,
})),
};
this._activeRequestProgressCallbacks.get(id)?.(usedContext); // FIXME@ulugbekna: is this a correct thing to do?
return;
}
this._activeRequestProgressCallbacks.get(id)?.(progress);
}

View File

@@ -1223,7 +1223,18 @@ export interface IChatResponseProgressFileTreeData {
children?: IChatResponseProgressFileTreeData[];
}
export type IChatResponseProgressDto = { content: string | IMarkdownString } | { requestId: string } | { placeholder: string } | { treeData: IChatResponseProgressFileTreeData };
export type IDocumentContextDto = {
uri: UriComponents;
version: number;
ranges: IRange[];
};
export type IChatResponseProgressDto =
| { content: string | IMarkdownString }
| { requestId: string }
| { placeholder: string }
| { treeData: IChatResponseProgressFileTreeData }
| { documents: IDocumentContextDto[] };
export interface MainThreadChatShape extends IDisposable {
$registerChatProvider(handle: number, id: string): Promise<void>;

View File

@@ -236,6 +236,14 @@ export class ExtHostChat implements ExtHostChatShape {
this._proxy.$acceptResponseProgress(handle, sessionId, {
content: typeof progress.content === 'string' ? progress.content : typeConvert.MarkdownString.from(progress.content)
});
} else if ('documents' in progress) {
this._proxy.$acceptResponseProgress(handle, sessionId, {
documents: progress.documents.map(d => ({
uri: d.uri,
version: d.version,
ranges: d.ranges.map(r => typeConvert.Range.from(r))
}))
});
} else {
this._proxy.$acceptResponseProgress(handle, sessionId, progress);
}

View File

@@ -11,7 +11,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { ILogService } from 'vs/platform/log/common/log';
import { IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { IChat, IChatFollowup, IChatProgress, IChatReplyFollowup, IChatResponse, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
import { IChat, IChatFollowup, IChatProgress, IChatReplyFollowup, IChatResponse, IChatResponseErrorDetails, IChatResponseProgressFileTreeData, IUsedContext, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
export interface IChatRequestModel {
readonly id: string;
@@ -32,11 +32,13 @@ export type ResponsePart =
resolvedContent?: Promise<
string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }
>;
};
}
| IUsedContext;
export interface IResponse {
readonly value: (IMarkdownString | IPlaceholderMarkdownString | IChatResponseProgressFileTreeData)[];
onDidChangeValue: Event<void>;
usedContext: IUsedContext | undefined;
updateContent(responsePart: ResponsePart, quiet?: boolean): void;
asString(): string;
}
@@ -114,6 +116,11 @@ export class Response implements IResponse {
return this._onDidChangeValue.event;
}
private _usedContext: IUsedContext | undefined;
public get usedContext(): IUsedContext | undefined {
return this._usedContext;
}
// responseParts internally tracks all the response parts, including strings which are currently resolving, so that they can be updated when they do resolve
private _responseParts: InternalResponsePart[];
// responseData externally presents the response parts with consolidated contiguous strings (including strings which were previously resolving)
@@ -179,6 +186,8 @@ export class Response implements IResponse {
} else if (isCompleteInteractiveProgressTreeData(responsePart)) {
this._responseParts.push(responsePart);
this._updateRepr(quiet);
} else if ('documents' in responsePart) {
this._usedContext = responsePart;
}
}
@@ -590,6 +599,8 @@ export class ChatModel extends Disposable implements IChatModel {
request.response.updateContent(progress.content, quiet);
} else if ('placeholder' in progress || isCompleteInteractiveProgressTreeData(progress)) {
request.response.updateContent(progress, quiet);
} else if ('documents' in progress) {
request.response.updateContent(progress);
} else {
request.setProviderRequestId(progress.requestId);
request.response.setProviderResponseId(progress.requestId);

View File

@@ -8,6 +8,7 @@ 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 } from 'vs/editor/common/core/range';
import { ProviderResult } from 'vs/editor/common/languages';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IChatModel, ChatModel, ISerializableChatData } from 'vs/workbench/contrib/chat/common/chatModel';
@@ -51,8 +52,22 @@ export interface IChatResponseProgressFileTreeData {
children?: IChatResponseProgressFileTreeData[];
}
export type IDocumentContext = {
uri: URI;
version: number;
ranges: IRange[];
};
export type IUsedContext = {
documents: IDocumentContext[];
};
export type IChatProgress =
{ content: string | IMarkdownString } | { requestId: string } | { treeData: IChatResponseProgressFileTreeData } | { placeholder: string; resolvedContent: Promise<string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }> };
| { content: string | IMarkdownString }
| { requestId: string }
| { treeData: IChatResponseProgressFileTreeData }
| { placeholder: string; resolvedContent: Promise<string | IMarkdownString | { treeData: IChatResponseProgressFileTreeData }> }
| IUsedContext;
export interface IPersistedChatState { }
export interface IChatProvider {

View File

@@ -440,7 +440,6 @@ export class ChatService extends Disposable implements IChatService {
const resolvedCommand = typeof message === 'string' && message.startsWith('/') ? await this.handleSlashCommand(model.sessionId, message) : message;
let gotProgress = false;
const requestType = typeof message === 'string' ?
(message.startsWith('/') ? 'slashCommand' : 'string') :
@@ -453,6 +452,7 @@ export class ChatService extends Disposable implements IChatService {
}
gotProgress = true;
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) {
@@ -460,6 +460,8 @@ export class ChatService extends Disposable implements IChatService {
} 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 {
this.trace('sendRequest', `Provider returned id for session ${model.sessionId}, ${progress.requestId}`);
}

View File

@@ -138,7 +138,24 @@ declare module 'vscode' {
treeData: FileTreeData;
}
export type InteractiveProgress = InteractiveProgressContent | InteractiveProgressId | InteractiveProgressTask | InteractiveProgressFileTree;
// FIXME@ulugbekna: my reservation with this type is that
// we already have a type called `TextDocumentContext` above passed to inline chat providers
export interface DocumentContext {
uri: Uri;
version: number;
ranges: Range[]; // @ulugbekna: we're making this an array of ranges rather than array of `DocumentContext`s, which should be less costly
}
export interface InteractiveProgressUsedContext {
documents: DocumentContext[];
}
export type InteractiveProgress =
| InteractiveProgressContent
| InteractiveProgressId
| InteractiveProgressTask
| InteractiveProgressFileTree
| InteractiveProgressUsedContext;
export interface InteractiveResponseCommand {
commandId: string;