Skip to content

Commit 59260b3

Browse files
authored
fix: automatically undo and show retry action for failed editing requests (microsoft#232201)
fix: automatically undo and show retry action for failed requests
1 parent 5adea64 commit 59260b3

File tree

5 files changed

+35
-16
lines changed

5 files changed

+35
-16
lines changed

src/vs/workbench/contrib/chat/browser/actions/chatTitleActions.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { CellEditType, CellKind, NOTEBOOK_EDITOR_ID } from '../../../notebook/co
2828
import { NOTEBOOK_IS_ACTIVE_EDITOR } from '../../../notebook/common/notebookContextKeys.js';
2929
import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js';
3030
import { CONTEXT_CHAT_EDITING_PARTICIPANT_REGISTERED, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_RESPONSE_SUPPORT_ISSUE_REPORTING, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_ITEM_ID, CONTEXT_LAST_ITEM_ID, CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_ERROR, CONTEXT_RESPONSE_FILTERED, CONTEXT_RESPONSE_VOTE } from '../../common/chatContextKeys.js';
31-
import { IChatEditingService, WorkingSetEntryState } from '../../common/chatEditingService.js';
31+
import { applyingChatEditsFailedContextKey, IChatEditingService, WorkingSetEntryState } from '../../common/chatEditingService.js';
3232
import { IParsedChatRequest } from '../../common/chatParserTypes.js';
3333
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatProgress, IChatService } from '../../common/chatService.js';
3434
import { isRequestVM, isResponseVM } from '../../common/chatViewModel.js';
@@ -189,13 +189,21 @@ export function registerChatTitleActions() {
189189
f1: false,
190190
category: CHAT_CATEGORY,
191191
icon: Codicon.refresh,
192-
menu: [{
193-
id: MenuId.ChatMessageFooter,
194-
group: 'navigation',
195-
when: ContextKeyExpr.and(
196-
CONTEXT_RESPONSE,
197-
ContextKeyExpr.in(CONTEXT_ITEM_ID.key, CONTEXT_LAST_ITEM_ID.key))
198-
}]
192+
menu: [
193+
{
194+
id: MenuId.ChatMessageFooter,
195+
group: 'navigation',
196+
when: ContextKeyExpr.and(
197+
CONTEXT_RESPONSE,
198+
ContextKeyExpr.in(CONTEXT_ITEM_ID.key, CONTEXT_LAST_ITEM_ID.key))
199+
},
200+
{
201+
id: MenuId.ChatEditingWidgetToolbar,
202+
group: 'navigation',
203+
when: applyingChatEditsFailedContextKey,
204+
order: 0
205+
}
206+
]
199207
});
200208
}
201209

src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { GroupsOrder, IEditorGroupsService } from '../../../../services/editor/c
2222
import { IEditorService } from '../../../../services/editor/common/editorService.js';
2323
import { ChatAgentLocation } from '../../common/chatAgents.js';
2424
import { CONTEXT_CHAT_INPUT_HAS_TEXT, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_INPUT, CONTEXT_IN_CHAT_SESSION, CONTEXT_ITEM_ID, CONTEXT_LAST_ITEM_ID, CONTEXT_REQUEST, CONTEXT_RESPONSE } from '../../common/chatContextKeys.js';
25-
import { applyingChatEditsContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingResourceContextKey, chatEditingWidgetFileStateContextKey, decidedChatEditingResourceContextKey, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, isChatRequestCheckpointed, WorkingSetEntryState } from '../../common/chatEditingService.js';
25+
import { applyingChatEditsContextKey, applyingChatEditsFailedContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingResourceContextKey, chatEditingWidgetFileStateContextKey, decidedChatEditingResourceContextKey, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, isChatRequestCheckpointed, WorkingSetEntryState } from '../../common/chatEditingService.js';
2626
import { IChatService } from '../../common/chatService.js';
2727
import { isRequestVM, isResponseVM } from '../../common/chatViewModel.js';
2828
import { CHAT_CATEGORY } from '../actions/chatActions.js';
@@ -197,7 +197,7 @@ export class ChatEditingAcceptAllAction extends Action2 {
197197
id: MenuId.ChatEditingWidgetToolbar,
198198
group: 'navigation',
199199
order: 0,
200-
when: ContextKeyExpr.or(hasAppliedChatEditsContextKey.negate(), ContextKeyExpr.and(hasUndecidedChatEditingResourceContextKey, ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession))))
200+
when: ContextKeyExpr.and(applyingChatEditsFailedContextKey.negate(), ContextKeyExpr.or(hasAppliedChatEditsContextKey.negate(), ContextKeyExpr.and(hasUndecidedChatEditingResourceContextKey, ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession)))))
201201
}
202202
]
203203
});
@@ -234,7 +234,7 @@ export class ChatEditingDiscardAllAction extends Action2 {
234234
id: MenuId.ChatEditingWidgetToolbar,
235235
group: 'navigation',
236236
order: 1,
237-
when: ContextKeyExpr.or(hasAppliedChatEditsContextKey.negate(), ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession), hasUndecidedChatEditingResourceContextKey))
237+
when: ContextKeyExpr.and(applyingChatEditsFailedContextKey.negate(), ContextKeyExpr.or(hasAppliedChatEditsContextKey.negate(), ContextKeyExpr.and(CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession), hasUndecidedChatEditingResourceContextKey)))
238238
}
239239
],
240240
keybinding: {
@@ -273,7 +273,7 @@ export class ChatEditingShowChangesAction extends Action2 {
273273
id: MenuId.ChatEditingWidgetToolbar,
274274
group: 'navigation',
275275
order: 4,
276-
when: ContextKeyExpr.or(hasAppliedChatEditsContextKey.negate(), ContextKeyExpr.and(hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession)))
276+
when: ContextKeyExpr.and(applyingChatEditsFailedContextKey.negate(), ContextKeyExpr.or(hasAppliedChatEditsContextKey.negate(), ContextKeyExpr.and(hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession))))
277277
}
278278
],
279279
});

src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingService.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { URI } from '../../../../../base/common/uri.js';
1818
import { TextEdit } from '../../../../../editor/common/languages.js';
1919
import { ITextModelService } from '../../../../../editor/common/services/resolverService.js';
2020
import { localize, localize2 } from '../../../../../nls.js';
21-
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
21+
import { IContextKey, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
2222
import { EditorActivation } from '../../../../../platform/editor/common/editor.js';
2323
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
2424
import { bindContextKey } from '../../../../../platform/observable/common/platformObservableUtils.js';
@@ -33,7 +33,7 @@ import { MultiDiffEditorInput } from '../../../multiDiffEditor/browser/multiDiff
3333
import { IMultiDiffSourceResolver, IMultiDiffSourceResolverService, IResolvedMultiDiffSource, MultiDiffEditorItem } from '../../../multiDiffEditor/browser/multiDiffSourceResolverService.js';
3434
import { ICodeMapperResponse, ICodeMapperService } from '../../common/chatCodeMapperService.js';
3535
import { CONTEXT_CHAT_EDITING_CAN_REDO, CONTEXT_CHAT_EDITING_CAN_UNDO } from '../../common/chatContextKeys.js';
36-
import { applyingChatEditsContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingMaxFileAssignmentName, chatEditingResourceContextKey, ChatEditingSessionState, decidedChatEditingResourceContextKey, defaultChatEditingMaxFileLimit, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, IChatEditingSessionStream, inChatEditingSessionContextKey, WorkingSetEntryState } from '../../common/chatEditingService.js';
36+
import { applyingChatEditsContextKey, applyingChatEditsFailedContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, chatEditingMaxFileAssignmentName, chatEditingResourceContextKey, ChatEditingSessionState, decidedChatEditingResourceContextKey, defaultChatEditingMaxFileLimit, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, IChatEditingSessionStream, inChatEditingSessionContextKey, WorkingSetEntryState } from '../../common/chatEditingService.js';
3737
import { IChatResponseModel, IChatTextEditGroup } from '../../common/chatModel.js';
3838
import { IChatService } from '../../common/chatService.js';
3939
import { ChatEditingSession } from './chatEditingSession.js';
@@ -73,6 +73,8 @@ export class ChatEditingService extends Disposable implements IChatEditingServic
7373
return this._editingSessionFileLimit ?? defaultChatEditingMaxFileLimit;
7474
}
7575

76+
private _applyingChatEditsFailedContextKey: IContextKey<boolean | undefined>;
77+
7678
constructor(
7779
@IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService,
7880
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@@ -87,6 +89,8 @@ export class ChatEditingService extends Disposable implements IChatEditingServic
8789
@IWorkbenchAssignmentService private readonly _workbenchAssignmentService: IWorkbenchAssignmentService
8890
) {
8991
super();
92+
this._applyingChatEditsFailedContextKey = applyingChatEditsFailedContextKey.bindTo(contextKeyService);
93+
this._applyingChatEditsFailedContextKey.set(false);
9094
this._register(decorationsService.registerDecorationsProvider(new ChatDecorationsProvider(this._currentSessionObs)));
9195
this._register(multiDiffSourceResolverService.registerResolver(_instantiationService.createInstance(ChatEditingMultiDiffSourceResolver, this._currentSessionObs)));
9296
textModelService.registerTextModelContentProvider(ChatEditingTextModelContentProvider.scheme, _instantiationService.createInstance(ChatEditingTextModelContentProvider, this._currentSessionObs));
@@ -241,7 +245,11 @@ export class ChatEditingService extends Disposable implements IChatEditingServic
241245
const editsSeen = new ResourceMap<{ seen: number }>();
242246

243247
const onResponseComplete = (responseModel: IChatResponseModel) => {
244-
if (responseModel.result?.metadata?.autoApplyEdits) {
248+
if (responseModel.result?.errorDetails) {
249+
// Roll back everything
250+
this.restoreSnapshot(responseModel.requestId);
251+
this._applyingChatEditsFailedContextKey.set(true);
252+
} else if (responseModel.result?.metadata?.autoApplyEdits) {
245253
this.triggerEditComputation(responseModel);
246254
}
247255

@@ -290,6 +298,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic
290298

291299
observerDisposables.add(chatModel.onDidChange(e => {
292300
if (e.kind === 'addRequest') {
301+
this._applyingChatEditsFailedContextKey.set(false);
293302
const responseModel = e.request.response;
294303
if (responseModel) {
295304
if (responseModel.isComplete) {

src/vs/workbench/contrib/chat/browser/chatEditorSaving.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { IFilesConfigurationService } from '../../../services/filesConfiguration
2626
import { ITextFileService } from '../../../services/textfile/common/textfiles.js';
2727
import { ChatAgentLocation, IChatAgentService } from '../common/chatAgents.js';
2828
import { CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_INPUT } from '../common/chatContextKeys.js';
29-
import { CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, WorkingSetEntryState } from '../common/chatEditingService.js';
29+
import { applyingChatEditsFailedContextKey, CHAT_EDITING_MULTI_DIFF_SOURCE_RESOLVER_SCHEME, hasAppliedChatEditsContextKey, hasUndecidedChatEditingResourceContextKey, IChatEditingService, IChatEditingSession, WorkingSetEntryState } from '../common/chatEditingService.js';
3030

3131
export class ChatEditorSaving extends Disposable implements IWorkbenchContribution {
3232

@@ -215,6 +215,7 @@ export class ChatEditingSaveAllAction extends Action2 {
215215
// Show the option to save without accepting if the user has autosave
216216
// and also hasn't configured the setting to always save with generated changes
217217
when: ContextKeyExpr.and(
218+
applyingChatEditsFailedContextKey.negate(),
218219
ContextKeyExpr.or(hasUndecidedChatEditingResourceContextKey, hasAppliedChatEditsContextKey.negate()),
219220
ContextKeyExpr.notEquals('config.files.autoSave', 'off'), ContextKeyExpr.equals(`config.${ChatEditorSaving._config}`, false),
220221
CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.EditingSession)

src/vs/workbench/contrib/chat/common/chatEditingService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export const applyingChatEditsContextKey = new RawContextKey<boolean | undefined
108108
export const isChatRequestCheckpointed = new RawContextKey<boolean | undefined>('isChatRequestCheckpointed', false);
109109
export const hasUndecidedChatEditingResourceContextKey = new RawContextKey<boolean | undefined>('hasUndecidedChatEditingResource', false);
110110
export const hasAppliedChatEditsContextKey = new RawContextKey<boolean | undefined>('hasAppliedChatEdits', false);
111+
export const applyingChatEditsFailedContextKey = new RawContextKey<boolean | undefined>('applyingChatEditsFailed', false);
111112

112113
export const chatEditingMaxFileAssignmentName = 'chatEditingSessionFileLimit';
113114
export const defaultChatEditingMaxFileLimit = 10;

0 commit comments

Comments
 (0)