mirror of
https://github.com/Microsoft/vscode
synced 2024-10-01 08:50:48 +00:00
feat: associate chat references and warnings with chat progress (#212391)
feat: associate chat references and warnings with chat progress
This commit is contained in:
parent
351fa19d43
commit
bbc0159f43
|
@ -5,6 +5,8 @@
|
|||
|
||||
import { DeferredPromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { Disposable, DisposableMap, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
|
@ -25,7 +27,7 @@ import { AddDynamicVariableAction, IAddDynamicVariableContext } from 'vs/workben
|
|||
import { ChatAgentLocation, IChatAgentImplementation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { ChatRequestAgentPart } from 'vs/workbench/contrib/chat/common/chatParserTypes';
|
||||
import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestParser';
|
||||
import { IChatFollowup, IChatProgress, IChatService } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatContentReference, IChatFollowup, IChatProgress, IChatService, IChatTask, IChatWarningMessage } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
|
@ -36,6 +38,36 @@ interface AgentData {
|
|||
hasFollowups?: boolean;
|
||||
}
|
||||
|
||||
class MainThreadChatTask implements IChatTask {
|
||||
public readonly kind = 'progressTask';
|
||||
|
||||
public readonly deferred = new DeferredPromise<string | void>();
|
||||
|
||||
private readonly _onDidAddProgress = new Emitter<IChatWarningMessage | IChatContentReference>();
|
||||
public get onDidAddProgress(): Event<IChatWarningMessage | IChatContentReference> { return this._onDidAddProgress.event; }
|
||||
|
||||
public readonly progress: (IChatWarningMessage | IChatContentReference)[] = [];
|
||||
|
||||
constructor(public content: IMarkdownString) { }
|
||||
|
||||
task() {
|
||||
return this.deferred.p;
|
||||
}
|
||||
|
||||
isSettled() {
|
||||
return this.deferred.isSettled;
|
||||
}
|
||||
|
||||
complete(v: string | void) {
|
||||
this.deferred.complete(v);
|
||||
}
|
||||
|
||||
add(progress: IChatWarningMessage | IChatContentReference): void {
|
||||
this.progress.push(progress);
|
||||
this._onDidAddProgress.fire(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadChatAgents2)
|
||||
export class MainThreadChatAgents2 extends Disposable implements MainThreadChatAgentsShape2 {
|
||||
|
||||
|
@ -46,7 +78,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
private readonly _proxy: ExtHostChatAgentsShape2;
|
||||
|
||||
private _responsePartHandlePool = 0;
|
||||
private readonly _activeResponsePartPromises = new Map<string, DeferredPromise<string | void>>();
|
||||
private readonly _activeTasks = new Map<string, IChatTask>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
|
@ -172,26 +204,33 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
|||
}
|
||||
|
||||
async $handleProgressChunk(requestId: string, progress: IChatProgressDto, responsePartHandle?: number): Promise<number | void> {
|
||||
if (progress.kind === 'progressTask') {
|
||||
const revivedProgress = revive(progress) as IChatProgress;
|
||||
if (revivedProgress.kind === 'progressTask') {
|
||||
const handle = ++this._responsePartHandlePool;
|
||||
const responsePartId = `${requestId}_${handle}`;
|
||||
const deferredContentPromise = new DeferredPromise<string | void>();
|
||||
this._activeResponsePartPromises.set(responsePartId, deferredContentPromise);
|
||||
this._pendingProgress.get(requestId)?.({ ...progress, task: () => deferredContentPromise.p, isSettled: () => deferredContentPromise.isSettled });
|
||||
const task = new MainThreadChatTask(revivedProgress.content);
|
||||
this._activeTasks.set(responsePartId, task);
|
||||
this._pendingProgress.get(requestId)?.(task);
|
||||
return handle;
|
||||
} else if (progress.kind === 'progressTaskResult' && responsePartHandle !== undefined) {
|
||||
} else if (responsePartHandle !== undefined) {
|
||||
const responsePartId = `${requestId}_${responsePartHandle}`;
|
||||
const deferredContentPromise = this._activeResponsePartPromises.get(responsePartId);
|
||||
if (deferredContentPromise && progress.content) {
|
||||
deferredContentPromise.complete(progress.content.value);
|
||||
this._activeResponsePartPromises.delete(responsePartId);
|
||||
} else {
|
||||
deferredContentPromise?.complete(undefined);
|
||||
const task = this._activeTasks.get(responsePartId);
|
||||
switch (revivedProgress.kind) {
|
||||
case 'progressTaskResult':
|
||||
if (task && revivedProgress.content) {
|
||||
task.complete(revivedProgress.content.value);
|
||||
this._activeTasks.delete(responsePartId);
|
||||
} else {
|
||||
task?.complete(undefined);
|
||||
}
|
||||
return responsePartHandle;
|
||||
case 'warning':
|
||||
case 'reference':
|
||||
task?.add(revivedProgress);
|
||||
return;
|
||||
}
|
||||
return responsePartHandle;
|
||||
}
|
||||
const revivedProgress = revive(progress);
|
||||
this._pendingProgress.get(requestId)?.(revivedProgress as IChatProgress);
|
||||
this._pendingProgress.get(requestId)?.(revivedProgress);
|
||||
}
|
||||
|
||||
$registerAgentCompletionsProvider(handle: number, triggerCharacters: string[]): void {
|
||||
|
|
|
@ -68,17 +68,31 @@ class ChatAgentResponseStream {
|
|||
}
|
||||
}
|
||||
|
||||
const _report = (progress: IChatProgressDto, task?: () => Thenable<string | void>) => {
|
||||
const _report = (progress: IChatProgressDto, task?: (progress: vscode.Progress<vscode.ChatResponseWarningPart | vscode.ChatResponseReferencePart>) => Thenable<string | void>) => {
|
||||
// Measure the time to the first progress update with real markdown content
|
||||
if (typeof this._firstProgress === 'undefined' && 'content' in progress) {
|
||||
this._firstProgress = this._stopWatch.elapsed();
|
||||
}
|
||||
|
||||
Promise.all([this._proxy.$handleProgressChunk(this._request.requestId, progress), task ? task() : undefined]).then(([handle, res]) => {
|
||||
if (typeof handle === 'number' && task) {
|
||||
this._proxy.$handleProgressChunk(this._request.requestId, typeConvert.ChatTaskResult.from(res), handle);
|
||||
}
|
||||
});
|
||||
this._proxy.$handleProgressChunk(this._request.requestId, progress)
|
||||
.then((handle) => {
|
||||
if (handle) {
|
||||
task?.({
|
||||
report: (p) => {
|
||||
if (extHostTypes.MarkdownString.isMarkdownString(p.value)) {
|
||||
this._proxy.$handleProgressChunk(this._request.requestId, typeConvert.ChatResponseWarningPart.from(<vscode.ChatResponseWarningPart>p), handle);
|
||||
return;
|
||||
} else {
|
||||
this._proxy.$handleProgressChunk(this._request.requestId, typeConvert.ChatResponseReferencePart.from(<vscode.ChatResponseReferencePart>p), handle);
|
||||
}
|
||||
}
|
||||
}).then((res) => {
|
||||
if (typeof handle === 'number') {
|
||||
this._proxy.$handleProgressChunk(this._request.requestId, typeConvert.ChatTaskResult.from(res), handle);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this._apiObject = {
|
||||
|
@ -121,7 +135,7 @@ class ChatAgentResponseStream {
|
|||
_report(dto);
|
||||
return this;
|
||||
},
|
||||
progress(value, task?: (() => Thenable<string | void>)) {
|
||||
progress(value, task?: ((progress: vscode.Progress<vscode.ChatResponseWarningPart>) => Thenable<string | void>)) {
|
||||
throwIfDone(this.progress);
|
||||
const part = new extHostTypes.ChatResponseProgressPart2(value, task);
|
||||
const dto = task ? typeConvert.ChatTask.from(part) : typeConvert.ChatResponseProgressPart.from(part);
|
||||
|
|
|
@ -4376,8 +4376,8 @@ export class ChatResponseProgressPart {
|
|||
|
||||
export class ChatResponseProgressPart2 {
|
||||
value: string;
|
||||
task?: () => Thenable<string | void>;
|
||||
constructor(value: string, task?: () => Thenable<string | void>) {
|
||||
task?: (progress: vscode.Progress<vscode.ChatResponseWarningPart>) => Thenable<string | void>;
|
||||
constructor(value: string, task?: (progress: vscode.Progress<vscode.ChatResponseWarningPart>) => Thenable<string | void>) {
|
||||
this.value = value;
|
||||
this.task = task;
|
||||
}
|
||||
|
|
|
@ -456,7 +456,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
: data.kind === 'markdownContent'
|
||||
? this.renderMarkdown(data.content, element, templateData, fillInIncompleteTokens)
|
||||
: data.kind === 'progressMessage' && onlyProgressMessagesAfterI(value, index) ? this.renderProgressMessage(data, false) // TODO render command
|
||||
: data.kind === 'progressTask' && onlyProgressMessagesAfterI(value, index) ? this.renderProgressMessage(data, data.isSettled ? !data.isSettled() : false)
|
||||
: data.kind === 'progressTask' ? this.renderProgressTask(data, !data.deferred.isSettled, element, templateData)
|
||||
: data.kind === 'command' ? this.renderCommandButton(element, data)
|
||||
: data.kind === 'textEditGroup' ? this.renderTextEdit(element, data, templateData)
|
||||
: data.kind === 'warning' ? this.renderNotification('warning', data.content)
|
||||
|
@ -579,7 +579,8 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
} else if (part.kind === 'progressTask') {
|
||||
partsToRender[index] = {
|
||||
task: part,
|
||||
isSettled: part.isSettled?.() ?? true
|
||||
isSettled: part.isSettled?.() ?? true,
|
||||
progressLength: part.progress.length,
|
||||
};
|
||||
} else {
|
||||
const wordCountResult = this.getDataForProgressiveRender(element, contentToMarkdown(part.content), { renderedWordCount: 0, lastRenderTime: 0 });
|
||||
|
@ -626,15 +627,15 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
} satisfies IChatProgressMessageRenderData;
|
||||
}
|
||||
|
||||
else if (part.kind === 'progressTask' && isProgressTaskRenderData(renderedPart) && renderedPart.isSettled !== part.isSettled?.()) {
|
||||
else if (part.kind === 'progressTask' && isProgressTaskRenderData(renderedPart)) {
|
||||
const isSettled = part.isSettled?.() ?? true;
|
||||
if (renderedPart.isSettled !== isSettled) {
|
||||
partsToRender[index] = { task: part, isSettled };
|
||||
if (renderedPart.isSettled !== isSettled || part.progress.length !== renderedPart.progressLength || isSettled) {
|
||||
partsToRender[index] = { task: part, isSettled, progressLength: part.progress.length };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
isFullyRendered = partsToRender.length === 0 && !somePartIsNotFullyRendered;
|
||||
isFullyRendered = partsToRender.filter((p) => !('isSettled' in p) || !p.isSettled).length === 0 && !somePartIsNotFullyRendered;
|
||||
|
||||
if (isFullyRendered && element.isComplete) {
|
||||
// Response is done and content is rendered, so do a normal render
|
||||
|
@ -662,7 +663,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
result = null;
|
||||
}
|
||||
} else if (isProgressTaskRenderData(partToRender)) {
|
||||
result = this.renderProgressMessage(partToRender.task, !partToRender.isSettled);
|
||||
result = this.renderProgressTask(partToRender.task, !partToRender.isSettled, element, templateData);
|
||||
} else if (isCommandButtonRenderData(partToRender)) {
|
||||
result = this.renderCommandButton(element, partToRender);
|
||||
} else if (isTextEditRenderData(partToRender)) {
|
||||
|
@ -775,7 +776,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
private renderContentReferencesIfNeeded(element: ChatTreeItem, templateData: IChatListItemTemplate, disposables: DisposableStore): void {
|
||||
if (isResponseVM(element) && this._usedReferencesEnabled && element.contentReferences.length) {
|
||||
dom.show(templateData.referencesListContainer);
|
||||
const contentReferencesListResult = this.renderContentReferencesListData(element.contentReferences, element, templateData);
|
||||
const contentReferencesListResult = this.renderContentReferencesListData(null, element.contentReferences, element, templateData);
|
||||
if (templateData.referencesListContainer.firstChild) {
|
||||
templateData.referencesListContainer.replaceChild(contentReferencesListResult.element, templateData.referencesListContainer.firstChild!);
|
||||
} else {
|
||||
|
@ -787,11 +788,11 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
}
|
||||
}
|
||||
|
||||
private renderContentReferencesListData(data: ReadonlyArray<IChatContentReference>, element: IChatResponseViewModel, templateData: IChatListItemTemplate): { element: HTMLElement; dispose: () => void } {
|
||||
private renderContentReferencesListData(task: IChatTask | null, data: ReadonlyArray<IChatContentReference | IChatWarningMessage>, element: IChatResponseViewModel, templateData: IChatListItemTemplate): { element: HTMLElement; dispose: () => void } {
|
||||
const listDisposables = new DisposableStore();
|
||||
const referencesLabel = data.length > 1 ?
|
||||
const referencesLabel = task?.content.value ?? (data.length > 1 ?
|
||||
localize('usedReferencesPlural', "Used {0} references", data.length) :
|
||||
localize('usedReferencesSingular', "Used {0} reference", 1);
|
||||
localize('usedReferencesSingular', "Used {0} reference", 1));
|
||||
const iconElement = $('.chat-used-context-icon');
|
||||
const icon = (element: IChatResponseViewModel) => element.usedReferencesExpanded ? Codicon.chevronDown : Codicon.chevronRight;
|
||||
iconElement.classList.add(...ThemeIcon.asClassNameArray(icon(element)));
|
||||
|
@ -826,7 +827,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
container.appendChild(list.getHTMLElement().parentElement!);
|
||||
|
||||
listDisposables.add(list.onDidOpen((e) => {
|
||||
if (e.element) {
|
||||
if (e.element && 'reference' in e.element) {
|
||||
const uriOrLocation = 'variableName' in e.element.reference ? e.element.reference.value : e.element.reference;
|
||||
const uri = URI.isUri(uriOrLocation) ? uriOrLocation :
|
||||
uriOrLocation?.uri;
|
||||
|
@ -869,6 +870,21 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
|
|||
element.ariaLabel = expanded ? localize('usedReferencesExpanded', "{0}, expanded", label) : localize('usedReferencesCollapsed', "{0}, collapsed", label);
|
||||
}
|
||||
|
||||
private renderProgressTask(task: IChatTask, showSpinner: boolean, element: ChatTreeItem, templateData: IChatListItemTemplate): IMarkdownRenderResult | undefined {
|
||||
if (!isResponseVM(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (task.progress.length) {
|
||||
const refs = this.renderContentReferencesListData(task, task.progress, element, templateData);
|
||||
const node = dom.$('.chat-progress-task');
|
||||
node.appendChild(refs.element);
|
||||
return { element: node, dispose: refs.dispose };
|
||||
}
|
||||
|
||||
return this.renderProgressMessage(task, showSpinner);
|
||||
}
|
||||
|
||||
private renderProgressMessage(progress: IChatProgressMessage | IChatTask, showSpinner: boolean): IMarkdownRenderResult {
|
||||
if (showSpinner) {
|
||||
// this step is in progress, communicate it to SR users
|
||||
|
@ -1338,9 +1354,9 @@ class TreePool extends Disposable {
|
|||
}
|
||||
|
||||
class ContentReferencesListPool extends Disposable {
|
||||
private _pool: ResourcePool<WorkbenchList<IChatContentReference>>;
|
||||
private _pool: ResourcePool<WorkbenchList<IChatContentReference | IChatWarningMessage>>;
|
||||
|
||||
public get inUse(): ReadonlySet<WorkbenchList<IChatContentReference>> {
|
||||
public get inUse(): ReadonlySet<WorkbenchList<IChatContentReference | IChatWarningMessage>> {
|
||||
return this._pool.inUse;
|
||||
}
|
||||
|
||||
|
@ -1353,14 +1369,14 @@ class ContentReferencesListPool extends Disposable {
|
|||
this._pool = this._register(new ResourcePool(() => this.listFactory()));
|
||||
}
|
||||
|
||||
private listFactory(): WorkbenchList<IChatContentReference> {
|
||||
private listFactory(): WorkbenchList<IChatContentReference | IChatWarningMessage> {
|
||||
const resourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this._onDidChangeVisibility }));
|
||||
|
||||
const container = $('.chat-used-context-list');
|
||||
this._register(createFileIconThemableTreeContainerScope(container, this.themeService));
|
||||
|
||||
const list = this.instantiationService.createInstance(
|
||||
WorkbenchList<IChatContentReference>,
|
||||
WorkbenchList<IChatContentReference | IChatWarningMessage>,
|
||||
'ChatListRenderer',
|
||||
container,
|
||||
new ContentReferencesListDelegate(),
|
||||
|
@ -1368,7 +1384,10 @@ class ContentReferencesListPool extends Disposable {
|
|||
{
|
||||
alwaysConsumeMouseWheel: false,
|
||||
accessibilityProvider: {
|
||||
getAriaLabel: (element: IChatContentReference) => {
|
||||
getAriaLabel: (element: IChatContentReference | IChatWarningMessage) => {
|
||||
if (element.kind === 'warning') {
|
||||
return element.content.value;
|
||||
}
|
||||
const reference = element.reference;
|
||||
if ('variableName' in reference) {
|
||||
return reference.variableName;
|
||||
|
@ -1382,7 +1401,11 @@ class ContentReferencesListPool extends Disposable {
|
|||
getWidgetAriaLabel: () => localize('usedReferences', "Used References")
|
||||
},
|
||||
dnd: {
|
||||
getDragURI: ({ reference }: IChatContentReference) => {
|
||||
getDragURI: (element: IChatContentReference | IChatWarningMessage) => {
|
||||
if (element.kind === 'warning') {
|
||||
return null;
|
||||
}
|
||||
const { reference } = element;
|
||||
if ('variableName' in reference) {
|
||||
return null;
|
||||
} else if (URI.isUri(reference)) {
|
||||
|
@ -1400,7 +1423,7 @@ class ContentReferencesListPool extends Disposable {
|
|||
return list;
|
||||
}
|
||||
|
||||
get(): IDisposableReference<WorkbenchList<IChatContentReference>> {
|
||||
get(): IDisposableReference<WorkbenchList<IChatContentReference | IChatWarningMessage>> {
|
||||
const object = this._pool.get();
|
||||
let stale = false;
|
||||
return {
|
||||
|
@ -1414,7 +1437,7 @@ class ContentReferencesListPool extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
class ContentReferencesListDelegate implements IListVirtualDelegate<IChatContentReference> {
|
||||
class ContentReferencesListDelegate implements IListVirtualDelegate<IChatContentReference | IChatWarningMessage> {
|
||||
getHeight(element: IChatContentReference): number {
|
||||
return 22;
|
||||
}
|
||||
|
@ -1429,7 +1452,7 @@ interface IChatContentReferenceListTemplate {
|
|||
templateDisposables: IDisposable;
|
||||
}
|
||||
|
||||
class ContentReferencesListRenderer implements IListRenderer<IChatContentReference, IChatContentReferenceListTemplate> {
|
||||
class ContentReferencesListRenderer implements IListRenderer<IChatContentReference | IChatWarningMessage, IChatContentReferenceListTemplate> {
|
||||
static TEMPLATE_ID = 'contentReferencesListRenderer';
|
||||
readonly templateId: string = ContentReferencesListRenderer.TEMPLATE_ID;
|
||||
|
||||
|
@ -1450,12 +1473,18 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
|
|||
if (ThemeIcon.isThemeIcon(data.iconPath)) {
|
||||
return data.iconPath;
|
||||
} else {
|
||||
return this.themeService.getColorTheme().type === ColorScheme.DARK && data.iconPath?.dark ? data.iconPath?.dark :
|
||||
data.iconPath?.light;
|
||||
return this.themeService.getColorTheme().type === ColorScheme.DARK && data.iconPath?.dark
|
||||
? data.iconPath?.dark
|
||||
: data.iconPath?.light;
|
||||
}
|
||||
}
|
||||
|
||||
renderElement(data: IChatContentReference, index: number, templateData: IChatContentReferenceListTemplate, height: number | undefined): void {
|
||||
renderElement(data: IChatContentReference | IChatWarningMessage, index: number, templateData: IChatContentReferenceListTemplate, height: number | undefined): void {
|
||||
if (data.kind === 'warning') {
|
||||
templateData.label.setResource({ name: data.content.value }, { icon: Codicon.warning });
|
||||
return;
|
||||
}
|
||||
|
||||
const reference = data.reference;
|
||||
const icon = this.getReferenceIcon(data);
|
||||
templateData.label.element.style.display = 'flex';
|
||||
|
|
|
@ -165,6 +165,10 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.interactive-item-container .chat-progress-task {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.interactive-item-container .value .rendered-markdown table {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
|
@ -431,6 +435,14 @@
|
|||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.chat-used-context-list .codicon-warning {
|
||||
color: var(--vscode-notificationsWarningIcon-foreground); /* Have to override default styles which apply to all lists */
|
||||
}
|
||||
|
||||
.chat-used-context-list .monaco-icon-label-container {
|
||||
color: var(--vscode-interactive-session-foreground);
|
||||
}
|
||||
|
||||
.chat-notification-widget .chat-warning-codicon .codicon-warning {
|
||||
color: var(--vscode-notificationsWarningIcon-foreground) !important; /* Have to override default styles which apply to all lists */
|
||||
}
|
||||
|
|
|
@ -214,13 +214,21 @@ export class Response implements IResponse {
|
|||
const responsePosition = this._responseParts.push(progress) - 1;
|
||||
this._updateRepr(quiet);
|
||||
|
||||
const disp = progress.onDidAddProgress(() => {
|
||||
this._updateRepr(false);
|
||||
});
|
||||
|
||||
progress.task?.().then((content) => {
|
||||
// Stop listening for progress updates once the task settles
|
||||
disp.dispose();
|
||||
|
||||
// Replace the resolving part's content with the resolved response
|
||||
if (typeof content === 'string') {
|
||||
this._responseParts[responsePosition] = { ...progress, content: new MarkdownString(content) };
|
||||
}
|
||||
this._updateRepr(false);
|
||||
});
|
||||
|
||||
} else {
|
||||
this._responseParts.push(progress);
|
||||
this._updateRepr(quiet);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DeferredPromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
@ -107,6 +108,12 @@ export interface IChatProgressMessage {
|
|||
}
|
||||
|
||||
export interface IChatTask extends IChatTaskDto {
|
||||
deferred: DeferredPromise<string | void>;
|
||||
progress: (IChatWarningMessage | IChatContentReference)[];
|
||||
onDidAddProgress: Event<IChatWarningMessage | IChatContentReference>;
|
||||
add(progress: IChatWarningMessage | IChatContentReference): void;
|
||||
|
||||
complete: (result: string | void) => void;
|
||||
task: () => Promise<string | void>;
|
||||
isSettled: () => boolean;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ export interface IChatProgressMessageRenderData {
|
|||
export interface IChatTaskRenderData {
|
||||
task: IChatTask;
|
||||
isSettled: boolean;
|
||||
progressLength: number;
|
||||
}
|
||||
|
||||
export type IChatRenderData = IChatResponseProgressFileTreeData | IChatResponseMarkdownRenderData | IChatProgressMessageRenderData | IChatCommandButton | IChatTextEditGroup | IChatConfirmation | IChatTaskRenderData | IChatWarningMessage;
|
||||
|
|
|
@ -118,8 +118,8 @@ declare module 'vscode' {
|
|||
|
||||
export class ChatResponseProgressPart2 extends ChatResponseProgressPart {
|
||||
value: string;
|
||||
task?: () => Thenable<string | void>;
|
||||
constructor(value: string, task?: () => Thenable<string | void>);
|
||||
task?: (progress: Progress<ChatResponseWarningPart | ChatResponseReferencePart>) => Thenable<string | void>;
|
||||
constructor(value: string, task?: (progress: Progress<ChatResponseWarningPart | ChatResponseReferencePart>) => Thenable<string | void>);
|
||||
}
|
||||
|
||||
export interface ChatResponseStream {
|
||||
|
@ -132,7 +132,7 @@ declare module 'vscode' {
|
|||
* @param task If provided, a task to run while the progress is displayed. When the Thenable resolves, the progress will be marked complete in the UI, and the progress message will be updated to the resolved string if one is specified.
|
||||
* @returns This stream.
|
||||
*/
|
||||
progress(value: string, task?: () => Thenable<string | void>): ChatResponseStream;
|
||||
progress(value: string, task?: (progress: Progress<ChatResponseWarningPart | ChatResponseReferencePart>) => Thenable<string | void>): ChatResponseStream;
|
||||
|
||||
textEdit(target: Uri, edits: TextEdit | TextEdit[]): ChatResponseStream;
|
||||
markdownWithVulnerabilities(value: string | MarkdownString, vulnerabilities: ChatVulnerability[]): ChatResponseStream;
|
||||
|
|
Loading…
Reference in a new issue