Add chat.agent.autoAccept setting to auto-accept agent changes#307685
Add chat.agent.autoAccept setting to auto-accept agent changes#307685pierceboggan wants to merge 7 commits intomainfrom
chat.agent.autoAccept setting to auto-accept agent changes#307685Conversation
When enabled, this setting: - Immediately auto-accepts all agent changes when the request completes - Disables review mode so the editor Keep/Undo overlay buttons are hidden - Hides Keep/Undo buttons in the chat panel (both per-file and Accept/Undo All) The setting works alongside the existing chat.editing.autoAcceptDelay (which provides a countdown-based auto-accept). When autoAccept is true, it takes precedence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When autoAccept is on, include all entries (not just Modified) in the files-changed bar above the chat input. This preserves the file list and Explain button while still hiding Keep/Undo buttons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The entries observable returns readonly IModifiedFileEntry[] which isn't assignable to the mutable array type. Use spread operator to create a mutable copy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When auto-accept fires, the diff is reset (original matches modified), so linesAdded/linesRemoved go to 0. Cache the values while the entry is still Modified so the files-changed bar shows accurate counts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The cachedDiffMeta map was local to renderChatEditingSessionState, getting recreated on each call. Move it to a class-level field so cached line counts survive when the method is called again after auto-accept triggers a re-render. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of caching at the UI layer, snapshot linesAdded/linesRemoved directly on the entry in acceptDeferred() before _doAccept() resets the diff. The UI reads snapshotLinesAdded/snapshotLinesRemoved as fallback values when the live diff returns 0 after acceptance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add autoAccept guard to: - MultiDiffAcceptDiscardAction (EditorTitle toolbar) - Per-file Accept/Discard in MultiDiffEditorFileToolbar Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new chat.agent.autoAccept boolean setting to automatically accept agent-applied edits (removing the Keep/Undo review UX) and adjusts UI surfaces to remain useful after auto-accept (e.g., preserving file change counts).
Changes:
- Introduces
chat.agent.autoAcceptconfiguration and wires it into chat editing review/auto-accept behavior. - Hides Keep/Undo actions in chat editing toolbars and multi-diff editor toolbars when auto-accept is enabled.
- Preserves the files-changed bar (+/- line counts) after accept by snapshotting counts before accept resets the diff and by including accepted entries in the list.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/contrib/chat/common/editing/chatEditingService.ts | Extends IModifiedFileEntry with snapshot line-count observables for post-accept display. |
| src/vs/workbench/contrib/chat/common/constants.ts | Adds ChatConfiguration.AutoAccept key for chat.agent.autoAccept. |
| src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts | Keeps the “files changed” bar populated after auto-accept and uses snapshot counts as fallback. |
| src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedFileEntry.ts | Applies auto-accept setting to review mode/timeout and snapshots line counts on accept. |
| src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingEditorActions.ts | Hides multi-diff “Keep/Undo All” editor title actions when auto-accept is enabled. |
| src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingActions.ts | Hides Keep/Undo actions across chat editing widget and multi-diff file toolbars when auto-accept is enabled. |
| src/vs/workbench/contrib/chat/browser/chat.contribution.ts | Registers the new chat.agent.autoAccept setting in configuration. |
| const autoAcceptEnabled = this.configurationService.getValue<boolean>(ChatConfiguration.AutoAccept); | ||
|
|
||
| const modifiedEntries = derivedOpts<IModifiedFileEntry[]>({ equalsFn: arraysEqual }, r => { | ||
| // Background chat sessions render the working set based on the session files, and not the editing session | ||
| const sessionResource = chatEditingSession?.chatSessionResource ?? this._widget?.viewModel?.model.sessionResource; | ||
| if (sessionResource && getChatSessionType(sessionResource) === AgentSessionProviders.Background) { | ||
| return []; | ||
| } | ||
|
|
||
| if (autoAcceptEnabled) { | ||
| return [...(chatEditingSession?.entries.read(r) || [])]; | ||
| } | ||
| return chatEditingSession?.entries.read(r).filter(entry => entry.state.read(r) === ModifiedFileEntryState.Modified) || []; |
There was a problem hiding this comment.
autoAcceptEnabled is read once via configurationService.getValue(...) and then captured by the derived observables below. Because it isn’t an observable, toggling chat.agent.autoAccept at runtime won’t cause modifiedEntries / editSessionEntries to recompute, so the files-changed bar can get stuck showing the wrong set of entries until something else triggers a full re-render. Consider using an observable config (e.g. observableConfigValue(ChatConfiguration.AutoAccept, ...)) or wiring onDidChangeConfiguration into an observable that the derived computations read.
| const snapshotAdded = entry.snapshotLinesAdded?.read(reader); | ||
| const snapshotRemoved = entry.snapshotLinesRemoved?.read(reader); |
There was a problem hiding this comment.
snapshotLinesAdded/Removed are used as an unconditional fallback for all states. If a file is accepted (snapshots set) and then later receives additional edits (entry transitions back to Modified), the stale snapshot values will continue to override the live linesAdded/linesRemoved values, causing incorrect +/- counts until the next accept. Suggested fix: only prefer snapshot values when state === ModifiedFileEntryState.Accepted (or clear the snapshot observables when the entry returns to Modified).
| const snapshotAdded = entry.snapshotLinesAdded?.read(reader); | |
| const snapshotRemoved = entry.snapshotLinesRemoved?.read(reader); | |
| const useSnapshotDiff = state === ModifiedFileEntryState.Accepted; | |
| const snapshotAdded = useSnapshotDiff ? entry.snapshotLinesAdded?.read(reader) : undefined; | |
| const snapshotRemoved = useSnapshotDiff ? entry.snapshotLinesRemoved?.read(reader) : undefined; |
| // Snapshot line counts before accept resets the diff | ||
| const self = this as IModifiedFileEntry; | ||
| this._snapshotLinesAdded.set(self.linesAdded?.get() ?? 0, undefined); | ||
| this._snapshotLinesRemoved.set(self.linesRemoved?.get() ?? 0, undefined); | ||
|
|
There was a problem hiding this comment.
The new snapshot observables are written on accept, but they are never cleared. Entries can transition back to Modified when additional agent edits arrive (several acceptAgentEdits implementations set _stateObs back to Modified unconditionally), which risks stale snapshot values being reused for subsequent edit cycles. Consider clearing _snapshotLinesAdded/_snapshotLinesRemoved whenever the entry goes back to Modified (e.g. at the start of acceptAgentEdits in concrete entry types) or only treating snapshots as valid while in Accepted state.
| /** | ||
| * Snapshot of lines added, captured before accept resets the diff. | ||
| */ | ||
| readonly snapshotLinesAdded?: IObservable<number | undefined>; | ||
|
|
||
| /** | ||
| * Snapshot of lines removed, captured before accept resets the diff. | ||
| */ | ||
| readonly snapshotLinesRemoved?: IObservable<number | undefined>; | ||
|
|
There was a problem hiding this comment.
linesAdded/linesRemoved are derived from the current diff and become 0 after accept() resets the models (e.g. keep() makes original === modified). With auto-accept enabled, this means any code that computes session stats after acceptance (e.g. awaitStatsForSession in chat/common/chat.ts) will likely report 0/undefined changes. If these snapshot observables are the new source of truth post-accept, consider updating the stats aggregation (and any other summaries) to use snapshotLinesAdded/Removed when available and the entry is Accepted.
|
it would be nice if we could just modify |
Summary
Adds a new boolean setting
chat.agent.autoAccept(default:false) that, when enabled, removes the Keep/Undo review UX and immediately auto-accepts all agent changes when a request completes.Experience before/after shown here:
Auto-Accept.mov
Motivation
Users who trust agent changes and don't want to manually review each edit can enable this setting to streamline their workflow — changes are applied and accepted automatically without requiring interaction with the Keep/Undo UI.
Approach
Auto-accept logic (
chatEditingModifiedFileEntry.ts): When the setting is enabled,reviewModeis set tofalseand the auto-accept timeout is set to0, causing changes to be accepted immediately when the agent turn completes.Hide Keep/Undo buttons across all surfaces:
chatEditingActions.ts): Keep All, Undo All, and per-file Keep/Undo buttons are hidden viaconfig.chat.agent.autoAcceptwhen-clause guardsctxReviewModeEnabled, which becomesfalseautomaticallychatEditingEditorActions.ts): Keep/Undo in the EditorTitle toolbar and per-file MultiDiffEditorFileToolbar are hiddenPreserve files-changed bar (
chatInputPart.ts): The bar above the chat input (showing changed files + Explain button) is kept visible after auto-accept by includingAcceptedentries in the file list, not justModifiedones.Snapshot line counts (
chatEditingModifiedFileEntry.ts,chatEditingService.ts): Whenaccept()fires,_doAccept()resets the diff (original = modified), zeroing outlinesAdded/linesRemoved. To preserve accurate counts in the UI, line counts are snapshotted on the entry inacceptDeferred()before the diff reset. The UI readssnapshotLinesAdded/snapshotLinesRemovedas fallback values.How to test
chat.agent.autoAccept, enable it+N -Mline counts