mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-28 12:33:35 +01:00
Add errorDetails to interactive session responses. (#176457)
* Add errorDetails to interactive session responses. Also avoid calling updateElementHeight during a renderElement * Fix hygiene
This commit is contained in:
@@ -51,7 +51,7 @@ import { SaveReason } from 'vs/workbench/common/editor';
|
|||||||
import { IRevealOptions, ITreeItem, IViewBadge } from 'vs/workbench/common/views';
|
import { IRevealOptions, ITreeItem, IViewBadge } from 'vs/workbench/common/views';
|
||||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||||
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
||||||
import { IInteractiveSessionResponseCommandFollowup } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
|
import { IInteractiveResponseErrorDetails, IInteractiveSessionResponseCommandFollowup } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
|
||||||
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||||
import { ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
import { ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||||
@@ -1102,6 +1102,7 @@ export interface IInteractiveRequestDto {
|
|||||||
export interface IInteractiveResponseDto {
|
export interface IInteractiveResponseDto {
|
||||||
followups?: string[];
|
followups?: string[];
|
||||||
commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
||||||
|
errorDetails?: IInteractiveResponseErrorDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInteractiveResponseProgressDto {
|
export interface IInteractiveResponseProgressDto {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { ExtHostInteractiveSessionShape, IInteractiveRequestDto, IInteractiveResponseDto, IInteractiveSessionDto, IMainContext, MainContext, MainThreadInteractiveSessionShape } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostInteractiveSessionShape, IInteractiveRequestDto, IInteractiveResponseDto, IInteractiveSessionDto, IMainContext, MainContext, MainThreadInteractiveSessionShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
@@ -33,7 +34,7 @@ export class ExtHostInteractiveSession implements ExtHostInteractiveSessionShape
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
mainContext: IMainContext,
|
mainContext: IMainContext,
|
||||||
_logService: ILogService
|
private readonly logService: ILogService
|
||||||
) {
|
) {
|
||||||
this._proxy = mainContext.getProxy(MainContext.MainThreadInteractiveSession);
|
this._proxy = mainContext.getProxy(MainContext.MainThreadInteractiveSession);
|
||||||
}
|
}
|
||||||
@@ -147,20 +148,30 @@ export class ExtHostInteractiveSession implements ExtHostInteractiveSessionShape
|
|||||||
const progressObj: vscode.Progress<vscode.InteractiveProgress> = {
|
const progressObj: vscode.Progress<vscode.InteractiveProgress> = {
|
||||||
report: (progress: vscode.InteractiveProgress) => this._proxy.$acceptInteractiveResponseProgress(handle, sessionId, { responsePart: progress.content })
|
report: (progress: vscode.InteractiveProgress) => this._proxy.$acceptInteractiveResponseProgress(handle, sessionId, { responsePart: progress.content })
|
||||||
};
|
};
|
||||||
const res = await entry.provider.provideResponseWithProgress(requestObj, progressObj, token);
|
let result: vscode.InteractiveResponseForProgress | undefined | null;
|
||||||
if (realSession.saveState) {
|
try {
|
||||||
const newState = realSession.saveState();
|
result = await entry.provider.provideResponseWithProgress(requestObj, progressObj, token);
|
||||||
this._proxy.$acceptInteractiveSessionState(sessionId, newState);
|
if (!result) {
|
||||||
|
result = { errorDetails: { message: localize('emptyResponse', "Provider returned null response") } };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
result = { errorDetails: { message: localize('errorResponse', "Error from provider: {0}", err.message) } };
|
||||||
|
this.logService.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
try {
|
||||||
return;
|
if (realSession.saveState) {
|
||||||
|
const newState = realSession.saveState();
|
||||||
|
this._proxy.$acceptInteractiveSessionState(sessionId, newState);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.logService.warn(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { followups: res.followups, commandFollowups: res.commands };
|
return { followups: result.followups, commandFollowups: result.commands, errorDetails: result.errorDetails };
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('provider must implement either provideResponse or provideResponseWithProgress');
|
throw new Error('Provider must implement either provideResponse or provideResponseWithProgress');
|
||||||
}
|
}
|
||||||
|
|
||||||
$releaseSession(sessionId: number) {
|
$releaseSession(sessionId: number) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { Button } from 'vs/base/browser/ui/button/button';
|
import { Button } from 'vs/base/browser/ui/button/button';
|
||||||
|
import { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';
|
||||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||||
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||||
import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
|
import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
|
||||||
@@ -60,7 +61,7 @@ interface IItemHeightChangeParams {
|
|||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const forceVerboseLayoutTracing = true;
|
const forceVerboseLayoutTracing = false;
|
||||||
|
|
||||||
export class InteractiveListItemRenderer extends Disposable implements ITreeRenderer<InteractiveTreeItem, FuzzyScore, IInteractiveListItemTemplate> {
|
export class InteractiveListItemRenderer extends Disposable implements ITreeRenderer<InteractiveTreeItem, FuzzyScore, IInteractiveListItemTemplate> {
|
||||||
static readonly cursorCharacter = '\u258c';
|
static readonly cursorCharacter = '\u258c';
|
||||||
@@ -176,12 +177,12 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
|
|||||||
this.traceLayout('renderElement', `start progressive render ${kind}, index=${index}`);
|
this.traceLayout('renderElement', `start progressive render ${kind}, index=${index}`);
|
||||||
const progressiveRenderingDisposables = templateData.elementDisposables.add(new DisposableStore());
|
const progressiveRenderingDisposables = templateData.elementDisposables.add(new DisposableStore());
|
||||||
const timer = templateData.elementDisposables.add(new IntervalTimer());
|
const timer = templateData.elementDisposables.add(new IntervalTimer());
|
||||||
const runProgressiveRender = () => {
|
const runProgressiveRender = (initial?: boolean) => {
|
||||||
if (this.doNextProgressiveRender(element, index, templateData, progressiveRenderingDisposables)) {
|
if (this.doNextProgressiveRender(element, index, templateData, !!initial, progressiveRenderingDisposables)) {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
runProgressiveRender();
|
runProgressiveRender(true);
|
||||||
timer.cancelAndSet(runProgressiveRender, 100);
|
timer.cancelAndSet(runProgressiveRender, 100);
|
||||||
} else if (isResponseVM(element)) {
|
} else if (isResponseVM(element)) {
|
||||||
this.basicRenderElement(element.response.value, element, index, templateData);
|
this.basicRenderElement(element.response.value, element, index, templateData);
|
||||||
@@ -196,6 +197,11 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
|
|||||||
templateData.value.appendChild(result.element);
|
templateData.value.appendChild(result.element);
|
||||||
templateData.elementDisposables.add(result);
|
templateData.elementDisposables.add(result);
|
||||||
|
|
||||||
|
if (isResponseVM(element) && element.errorDetails) {
|
||||||
|
const errorDetails = dom.append(templateData.value, $('.interactive-response-error-details', undefined, renderIcon(Codicon.error)));
|
||||||
|
errorDetails.appendChild($('span', undefined, element.errorDetails.message));
|
||||||
|
}
|
||||||
|
|
||||||
if (isResponseVM(element) && index === this.delegate.getListLength() - 1) {
|
if (isResponseVM(element) && index === this.delegate.getListLength() - 1) {
|
||||||
const followupsContainer = dom.append(templateData.value, $('.interactive-response-followups'));
|
const followupsContainer = dom.append(templateData.value, $('.interactive-response-followups'));
|
||||||
const followups = element.commandFollowups ?? element.followups ?? [];
|
const followups = element.commandFollowups ?? element.followups ?? [];
|
||||||
@@ -217,36 +223,43 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private doNextProgressiveRender(element: IInteractiveResponseViewModel, index: number, templateData: IInteractiveListItemTemplate, disposables: DisposableStore): boolean {
|
private doNextProgressiveRender(element: IInteractiveResponseViewModel, index: number, templateData: IInteractiveListItemTemplate, isInRenderElement: boolean, disposables: DisposableStore): boolean {
|
||||||
disposables.clear();
|
disposables.clear();
|
||||||
const toRender = this.getProgressiveMarkdownToRender(element);
|
|
||||||
if (toRender) {
|
|
||||||
const isFullyRendered = element.renderData?.isFullyRendered;
|
|
||||||
if (isFullyRendered) {
|
|
||||||
this.traceLayout('runProgressiveRender', `end progressive render, index=${index}`);
|
|
||||||
if (element.isComplete) {
|
|
||||||
this.traceLayout('runProgressiveRender', `and disposing renderData, response is complete, index=${index}`);
|
|
||||||
element.renderData = undefined;
|
|
||||||
} else {
|
|
||||||
this.traceLayout('runProgressiveRender', `Rendered all available words, but model is not complete.`);
|
|
||||||
}
|
|
||||||
disposables.clear();
|
|
||||||
this.basicRenderElement(element.response.value, element, index, templateData);
|
|
||||||
} else {
|
|
||||||
const plusCursor = toRender.match(/```.*$/) ? toRender + `\n${InteractiveListItemRenderer.cursorCharacter}` : toRender + ` ${InteractiveListItemRenderer.cursorCharacter}`;
|
|
||||||
const result = this.renderMarkdown(element, index, new MarkdownString(plusCursor), disposables, templateData, true);
|
|
||||||
dom.clearNode(templateData.value);
|
|
||||||
templateData.value.appendChild(result.element);
|
|
||||||
disposables.add(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
const height = templateData.rowContainer.offsetHeight;
|
// TODO- this method has the side effect of updating element.renderData
|
||||||
element.currentRenderedHeight = height;
|
const toRender = this.getProgressiveMarkdownToRender(element);
|
||||||
this._onDidChangeItemHeight.fire({ element, height: templateData.rowContainer.offsetHeight });
|
const isFullyRendered = element.renderData?.isFullyRendered;
|
||||||
return !!isFullyRendered;
|
if (isFullyRendered) {
|
||||||
|
// We've reached the end of the available content, so do a normal render
|
||||||
|
this.traceLayout('runProgressiveRender', `end progressive render, index=${index}`);
|
||||||
|
if (element.isComplete) {
|
||||||
|
this.traceLayout('runProgressiveRender', `and disposing renderData, response is complete, index=${index}`);
|
||||||
|
element.renderData = undefined;
|
||||||
|
} else {
|
||||||
|
this.traceLayout('runProgressiveRender', `Rendered all available words, but model is not complete.`);
|
||||||
|
}
|
||||||
|
disposables.clear();
|
||||||
|
this.basicRenderElement(element.response.value, element, index, templateData);
|
||||||
|
} else if (toRender) {
|
||||||
|
// Doing the progressive render
|
||||||
|
const plusCursor = toRender.match(/```.*$/) ? toRender + `\n${InteractiveListItemRenderer.cursorCharacter}` : toRender + ` ${InteractiveListItemRenderer.cursorCharacter}`;
|
||||||
|
const result = this.renderMarkdown(element, index, new MarkdownString(plusCursor), disposables, templateData, true);
|
||||||
|
dom.clearNode(templateData.value);
|
||||||
|
templateData.value.appendChild(result.element);
|
||||||
|
disposables.add(result);
|
||||||
|
} else {
|
||||||
|
// Nothing new to render, not done, keep waiting
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// Some render happened - update the height
|
||||||
|
const height = templateData.rowContainer.offsetHeight;
|
||||||
|
element.currentRenderedHeight = height;
|
||||||
|
if (!isInRenderElement) {
|
||||||
|
this._onDidChangeItemHeight.fire({ element, height: templateData.rowContainer.offsetHeight });
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!isFullyRendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderMarkdown(element: InteractiveTreeItem, index: number, markdown: IMarkdownString, disposables: DisposableStore, templateData: IInteractiveListItemTemplate, fillInIncompleteTokens = false): IMarkdownRenderResult {
|
private renderMarkdown(element: InteractiveTreeItem, index: number, markdown: IMarkdownString, disposables: DisposableStore, templateData: IInteractiveListItemTemplate, fillInIncompleteTokens = false): IMarkdownRenderResult {
|
||||||
|
|||||||
@@ -184,3 +184,13 @@
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.interactive-session .interactive-response .interactive-response-error-details {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.interactive-session .interactive-response .interactive-response-error-details .codicon {
|
||||||
|
color: var(--vscode-errorForeground);
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
|
|||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IInteractiveSession } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
|
import { IInteractiveResponse, IInteractiveSession } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
|
||||||
|
|
||||||
export interface IInteractiveRequestModel {
|
export interface IInteractiveRequestModel {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
@@ -24,6 +24,11 @@ export interface IInteractiveSessionResponseCommandFollowup {
|
|||||||
title: string; // supports codicon strings
|
title: string; // supports codicon strings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IInteractiveResponseErrorDetails {
|
||||||
|
message: string;
|
||||||
|
responseIsIncomplete?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IInteractiveResponseModel {
|
export interface IInteractiveResponseModel {
|
||||||
readonly onDidChange: Event<void>;
|
readonly onDidChange: Event<void>;
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
@@ -33,6 +38,7 @@ export interface IInteractiveResponseModel {
|
|||||||
readonly isComplete: boolean;
|
readonly isComplete: boolean;
|
||||||
readonly followups?: string[];
|
readonly followups?: string[];
|
||||||
readonly commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
readonly commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
||||||
|
readonly errorDetails?: IInteractiveResponseErrorDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRequest(item: unknown): item is IInteractiveRequestModel {
|
export function isRequest(item: unknown): item is IInteractiveRequestModel {
|
||||||
@@ -89,11 +95,17 @@ export class InteractiveResponseModel extends Disposable implements IInteractive
|
|||||||
return this._response;
|
return this._response;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(response: IMarkdownString, public readonly username: string, public readonly avatarIconUri?: URI, isComplete: boolean = false, followups?: string[]) {
|
private _errorDetails: IInteractiveResponseErrorDetails | undefined;
|
||||||
|
public get errorDetails(): IInteractiveResponseErrorDetails | undefined {
|
||||||
|
return this._errorDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(response: IMarkdownString, public readonly username: string, public readonly avatarIconUri?: URI, isComplete: boolean = false, errorDetails?: IInteractiveResponseErrorDetails, followups?: string[]) {
|
||||||
super();
|
super();
|
||||||
this._response = response;
|
this._response = response;
|
||||||
this._isComplete = isComplete;
|
this._isComplete = isComplete;
|
||||||
this._followups = followups;
|
this._followups = followups;
|
||||||
|
this._errorDetails = errorDetails;
|
||||||
this._id = 'response_' + InteractiveResponseModel.nextId++;
|
this._id = 'response_' + InteractiveResponseModel.nextId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,10 +114,11 @@ export class InteractiveResponseModel extends Disposable implements IInteractive
|
|||||||
this._onDidChange.fire();
|
this._onDidChange.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
complete(followups: string[] | undefined, commandFollowups: IInteractiveSessionResponseCommandFollowup[] | undefined): void {
|
complete(followups: string[] | undefined, commandFollowups: IInteractiveSessionResponseCommandFollowup[] | undefined, errorDetails?: IInteractiveResponseErrorDetails): void {
|
||||||
this._isComplete = true;
|
this._isComplete = true;
|
||||||
this._followups = followups;
|
this._followups = followups;
|
||||||
this._commandFollowups = commandFollowups;
|
this._commandFollowups = commandFollowups;
|
||||||
|
this._errorDetails = errorDetails;
|
||||||
this._onDidChange.fire();
|
this._onDidChange.fire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,6 +138,7 @@ export interface ISerializableInteractiveSessionsData {
|
|||||||
export interface ISerializableInteractiveSessionRequestData {
|
export interface ISerializableInteractiveSessionRequestData {
|
||||||
message: string;
|
message: string;
|
||||||
response: string | undefined;
|
response: string | undefined;
|
||||||
|
responseErrorDetails: IInteractiveResponseErrorDetails | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISerializableInteractiveSessionData {
|
export interface ISerializableInteractiveSessionData {
|
||||||
@@ -181,10 +195,10 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return requests.map((r: ISerializableInteractiveSessionRequestData) => {
|
return requests.map((raw: ISerializableInteractiveSessionRequestData) => {
|
||||||
const request = new InteractiveRequestModel(r.message, this.session.requesterUsername, this.session.requesterAvatarIconUri);
|
const request = new InteractiveRequestModel(raw.message, this.session.requesterUsername, this.session.requesterAvatarIconUri);
|
||||||
if (r.response) {
|
if (raw.response || raw.responseErrorDetails) {
|
||||||
request.response = new InteractiveResponseModel(new MarkdownString(r.response), this.session.responderUsername, this.session.responderAvatarIconUri, true);
|
request.response = new InteractiveResponseModel(new MarkdownString(raw.response), this.session.responderUsername, this.session.responderAvatarIconUri, true, raw.responseErrorDetails);
|
||||||
}
|
}
|
||||||
return request;
|
return request;
|
||||||
});
|
});
|
||||||
@@ -224,8 +238,8 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completeResponse(request: InteractiveRequestModel, followups?: string[], commandFollowups?: IInteractiveSessionResponseCommandFollowup[]): void {
|
completeResponse(request: InteractiveRequestModel, response: IInteractiveResponse): void {
|
||||||
request.response!.complete(followups, commandFollowups);
|
request.response!.complete(response.followups, response.commandFollowups, response.errorDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
setResponse(request: InteractiveRequestModel, response: InteractiveResponseModel): void {
|
setResponse(request: InteractiveRequestModel, response: InteractiveResponseModel): void {
|
||||||
@@ -239,6 +253,7 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS
|
|||||||
return {
|
return {
|
||||||
message: r.message,
|
message: r.message,
|
||||||
response: r.response ? r.response.response.value : undefined,
|
response: r.response ? r.response.response.value : undefined,
|
||||||
|
responseErrorDetails: r.response?.errorDetails
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
providerId: this.providerId,
|
providerId: this.providerId,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ProviderResult } from 'vs/editor/common/languages';
|
import { ProviderResult } from 'vs/editor/common/languages';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IInteractiveSessionResponseCommandFollowup, InteractiveSessionModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
|
import { IInteractiveResponseErrorDetails, IInteractiveSessionResponseCommandFollowup, InteractiveSessionModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
|
||||||
|
|
||||||
export interface IInteractiveSession {
|
export interface IInteractiveSession {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -28,6 +28,7 @@ export interface IInteractiveResponse {
|
|||||||
session: IInteractiveSession;
|
session: IInteractiveSession;
|
||||||
followups?: string[];
|
followups?: string[];
|
||||||
commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
||||||
|
errorDetails?: IInteractiveResponseErrorDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInteractiveProgress {
|
export interface IInteractiveProgress {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { groupBy } from 'vs/base/common/collections';
|
|||||||
import { Iterable } from 'vs/base/common/iterator';
|
import { Iterable } from 'vs/base/common/iterator';
|
||||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||||
@@ -125,7 +126,6 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO log failures, add dummy response with error message
|
|
||||||
const _sendRequest = async (): Promise<void> => {
|
const _sendRequest = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
this._pendingRequestSessions.add(sessionId);
|
this._pendingRequestSessions.add(sessionId);
|
||||||
@@ -134,13 +134,13 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
|
|||||||
this.trace('sendRequest', `Provider returned progress for session ${sessionId}, ${progress.responsePart.length} chars`);
|
this.trace('sendRequest', `Provider returned progress for session ${sessionId}, ${progress.responsePart.length} chars`);
|
||||||
model.mergeResponseContent(request, progress.responsePart);
|
model.mergeResponseContent(request, progress.responsePart);
|
||||||
};
|
};
|
||||||
const rawResponse = await provider.provideReply({ session: model.session, message }, progressCallback, token);
|
let rawResponse = await provider.provideReply({ session: model.session, message }, progressCallback, token);
|
||||||
if (!rawResponse) {
|
if (!rawResponse) {
|
||||||
this.trace('sendRequest', `Provider returned no response for session ${sessionId}`);
|
this.trace('sendRequest', `Provider returned no response for session ${sessionId}`);
|
||||||
return;
|
rawResponse = { session: model.session, errorDetails: { message: localize('emptyResponse', "Provider returned null response") } };
|
||||||
}
|
}
|
||||||
|
|
||||||
model.completeResponse(request, rawResponse.followups, rawResponse.commandFollowups);
|
model.completeResponse(request, rawResponse);
|
||||||
this.trace('sendRequest', `Provider returned response for session ${sessionId} with ${rawResponse.followups} followups`);
|
this.trace('sendRequest', `Provider returned response for session ${sessionId} with ${rawResponse.followups} followups`);
|
||||||
} finally {
|
} finally {
|
||||||
this._pendingRequestSessions.delete(sessionId);
|
this._pendingRequestSessions.delete(sessionId);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { IInteractiveRequestModel, IInteractiveResponseModel, IInteractiveSessionModel, IInteractiveSessionResponseCommandFollowup } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
|
import { IInteractiveRequestModel, IInteractiveResponseErrorDetails, IInteractiveResponseModel, IInteractiveSessionModel, IInteractiveSessionResponseCommandFollowup } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
|
||||||
import { IInteractiveSessionService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
|
import { IInteractiveSessionService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
|
||||||
import { countWords } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionWordCounter';
|
import { countWords } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionWordCounter';
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ export interface IInteractiveResponseViewModel {
|
|||||||
readonly isComplete: boolean;
|
readonly isComplete: boolean;
|
||||||
readonly followups?: string[];
|
readonly followups?: string[];
|
||||||
readonly commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
readonly commandFollowups?: IInteractiveSessionResponseCommandFollowup[];
|
||||||
|
readonly errorDetails?: IInteractiveResponseErrorDetails;
|
||||||
readonly progressiveResponseRenderingEnabled: boolean;
|
readonly progressiveResponseRenderingEnabled: boolean;
|
||||||
readonly contentUpdateTimings?: IInteractiveSessionLiveUpdateData;
|
readonly contentUpdateTimings?: IInteractiveSessionLiveUpdateData;
|
||||||
renderData?: IInteractiveResponseRenderData;
|
renderData?: IInteractiveResponseRenderData;
|
||||||
@@ -196,6 +197,10 @@ export class InteractiveResponseViewModel extends Disposable implements IInterac
|
|||||||
return this._model.commandFollowups;
|
return this._model.commandFollowups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get errorDetails() {
|
||||||
|
return this._model.errorDetails;
|
||||||
|
}
|
||||||
|
|
||||||
renderData: IInteractiveResponseRenderData | undefined = undefined;
|
renderData: IInteractiveResponseRenderData | undefined = undefined;
|
||||||
|
|
||||||
currentRenderedHeight: number | undefined;
|
currentRenderedHeight: number | undefined;
|
||||||
@@ -224,7 +229,7 @@ export class InteractiveResponseViewModel extends Disposable implements IInterac
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._register(_model.onDidChange(() => {
|
this._register(_model.onDidChange(() => {
|
||||||
if (this._isPlaceholder && _model.response.value) {
|
if (this._isPlaceholder && (_model.response.value || this.isComplete)) {
|
||||||
this._isPlaceholder = false;
|
this._isPlaceholder = false;
|
||||||
if (this.renderData) {
|
if (this.renderData) {
|
||||||
this.renderData.renderedWordCount = 0;
|
this.renderData.renderedWordCount = 0;
|
||||||
|
|||||||
@@ -76,9 +76,15 @@ declare module 'vscode' {
|
|||||||
followups?: string[];
|
followups?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InteractiveResponseErrorDetails {
|
||||||
|
message: string;
|
||||||
|
responseIsIncomplete?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface InteractiveResponseForProgress {
|
export interface InteractiveResponseForProgress {
|
||||||
followups?: string[];
|
followups?: string[];
|
||||||
commands?: InteractiveResponseCommand[];
|
commands?: InteractiveResponseCommand[];
|
||||||
|
errorDetails?: InteractiveResponseErrorDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InteractiveProgress {
|
export interface InteractiveProgress {
|
||||||
|
|||||||
Reference in New Issue
Block a user