autopilot mode + secondary chat input toolbar#296691
autopilot mode + secondary chat input toolbar#296691
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an “Autopilot” chat mode and a /yolo slash command path to enable auto-approval of tool calls, wiring the new mode through chat mode selection, telemetry, and tool-confirmation logic.
Changes:
- Introduces
ChatModeKind.Autopilotand surfaces it in mode lists/context keys/UI (mode picker icons, MCP command enablement, command detection exclusions). - Adds
autoApproveplumbing for modes/agents (prompt headerauto-approve,ICustomAgent.autoApprove,IChatRequestModeInfo.autoApprove). - Implements session-scoped and next-request YOLO behavior in
LanguageModelToolsServiceand adds a/yoloslash command + a command palette action to toggle global auto-approve.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/contrib/mcp/browser/mcpCommands.ts | Allows MCP server listing command in Autopilot mode via context key expression. |
| src/vs/workbench/contrib/editTelemetry/browser/telemetry/aiEditTelemetry/aiEditTelemetryServiceImpl.ts | Extends telemetry modeId union to include autopilot. |
| src/vs/workbench/contrib/editTelemetry/browser/telemetry/aiEditTelemetry/aiEditTelemetryService.ts | Documents and adds autopilot to EditTelemetryModeId. |
| src/vs/workbench/contrib/chat/test/common/tools/mockLanguageModelToolsService.ts | Updates mock to satisfy new YOLO methods on ILanguageModelToolsService. |
| src/vs/workbench/contrib/chat/common/tools/languageModelToolsService.ts | Extends tools service interface with session/next-request YOLO APIs. |
| src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsServiceImpl.ts | Adds autoApprove to loaded custom agent data from prompt AST header. |
| src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts | Adds ICustomAgent.autoApprove contract. |
| src/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser.ts | Adds auto-approve header attribute + parsed accessor. |
| src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.ts | Allows auto-approve in agent headers (attribute list). |
| src/vs/workbench/contrib/chat/common/participants/chatAgents.ts | Treats Autopilot as Agent when resolving default agent selection. |
| src/vs/workbench/contrib/chat/common/model/chatModel.ts | Extends request mode info to include autopilot and autoApprove. |
| src/vs/workbench/contrib/chat/common/editing/chatEditingService.ts | Updates telemetry modeId union for chat editing telemetry. |
| src/vs/workbench/contrib/chat/common/constants.ts | Adds ChatModeKind.Autopilot and validates it. |
| src/vs/workbench/contrib/chat/common/chatService/chatServiceImpl.ts | Excludes Autopilot from command detection logic (alongside Agent/Edit). |
| src/vs/workbench/contrib/chat/common/chatModes.ts | Adds built-in Autopilot mode and autoApprove observable support. |
| src/vs/workbench/contrib/chat/common/actions/chatContextKeys.ts | Treats Autopilot as “editing mode” for relevant context expressions. |
| src/vs/workbench/contrib/chat/browser/widget/input/modePickerActionItem.ts | Provides a rocket icon for Autopilot in the mode picker. |
| src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts | Propagates modeId + autoApprove into currentModeInfo. |
| src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts | Implements YOLO state + uses mode/session YOLO in auto-confirm decisions. |
| src/vs/workbench/contrib/chat/browser/chatSlashCommands.ts | Adds /yolo command to toggle session YOLO or enable next-request YOLO. |
| src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSessionStorage.ts | Extends stored telemetry DTO union to include autopilot. |
| src/vs/workbench/contrib/chat/browser/actions/chatActions.ts | Adds command palette action to toggle global auto-approve (“YOLO Mode”). |
Comments suppressed due to low confidence (3)
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts:1107
- Mode-level
autoApproveis determined by looking atmodel.getRequests().at(-1). In sessions with queued requests, the last request may not be the request that is currently invoking the tool, so tool confirmations could be auto-approved (or not) based on the wrong request/mode. SinceIToolInvocationalready carrieschatRequestId, consider threading that through and resolving the request by id (falling back to last request only when needed).
// Mode-level auto-approve (e.g. autopilot agent with auto-approve: true)
const model = this._chatService.getSession(chatSessionResource);
const request = model?.getRequests().at(-1);
if (request?.modeInfo?.autoApprove) {
return { type: ToolConfirmKind.Setting, id: 'chat.mode.autoApprove' };
}
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts:1158
- Same issue as pre-execution: post-execution auto-confirm checks
model.getRequests().at(-1)to decide whether the current request hasmodeInfo.autoApprove. With queued requests, this can consult the wrong request. Consider using thechatRequestIdassociated with the tool invocation to locate the correct request when deciding mode-level auto-approve.
// Mode-level auto-approve
const model = this._chatService.getSession(chatSessionResource);
const request = model?.getRequests().at(-1);
if (request?.modeInfo?.autoApprove) {
return { type: ToolConfirmKind.Setting, id: 'chat.mode.autoApprove' };
}
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts:1158
- Post-execution YOLO/mode auto-approve returns
ToolConfirmKind.Settingwith ids that aren’t actual settings ('chat.yolo.session','chat.mode.autoApprove'). This will surface as a broken “Auto approved by …” settings link in the tool invocation UI. Consider usingLmServicePerTool/ConfirmationNotNeeded(or a real setting key) instead ofToolConfirmKind.Settinghere.
// Session-scoped YOLO mode bypasses all post-execution confirmations
if (chatSessionResource) {
const key = chatSessionResource.toString();
if (this._yoloSessions.has(key) || this._yoloNextRequestSessions.has(key)) {
return { type: ToolConfirmKind.Setting, id: 'chat.yolo.session' };
}
// Mode-level auto-approve
const model = this._chatService.getSession(chatSessionResource);
const request = model?.getRequests().at(-1);
if (request?.modeInfo?.autoApprove) {
return { type: ToolConfirmKind.Setting, id: 'chat.mode.autoApprove' };
}
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts
Outdated
Show resolved
Hide resolved
src/vs/workbench/contrib/chat/common/promptSyntax/languageProviders/promptValidator.ts
Outdated
Show resolved
Hide resolved
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts
Outdated
Show resolved
Hide resolved
- Move context usage widget to secondary toolbar with percentage label on hover - Adjust secondary toolbar padding/gap and input part bottom padding - Lower icon-only threshold to 300px - Darken input placeholder foreground in 2026 dark theme - Update agent mode description
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 21 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (4)
src/vs/workbench/contrib/chat/common/chatService/chatServiceImpl.ts:1278
- The new auto-retry behavior should be covered by tests in the existing chat service test suite (e.g. verify no retry occurs after cancellation, max retry cap is honored, and rate-limited/quota errors are not retried).
private static readonly MAX_AUTO_RETRIES = 5;
private _shouldAutoRetry(options: IChatSendRequestOptions | undefined, attempt: number, errorDetails?: IChatResponseErrorDetails): boolean {
if (!isAutoApproveLevel(options?.modeInfo?.permissionLevel)) {
return false;
}
if (attempt >= ChatService.MAX_AUTO_RETRIES) {
return false;
}
// Don't retry rate-limited or quota-exceeded errors
if (errorDetails?.isRateLimited || errorDetails?.isQuotaExceeded) {
return false;
}
return true;
}
private _scheduleAutoRetry(request: IChatRequestModel, options: IChatSendRequestOptions | undefined, attempt: number): void {
const nextAttempt = attempt + 1;
this.logService.info(`[ChatService] Auto-retrying request (attempt ${nextAttempt}/${ChatService.MAX_AUTO_RETRIES}) due to auto-approve-all permission level`);
timeout(1000).then(() => {
this.resendRequest(request, { ...options, attempt: nextAttempt });
});
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts:1092
- Same issue as pre-exec auto-confirm: this uses
model.getRequests().at(-1)to decide whether to bypass post-execution confirmations. Please resolve the correct request (bychatRequestId) so permission level is applied to the right interaction.
if (chatSessionResource) {
const model = this._chatService.getSession(chatSessionResource);
const request = model?.getRequests().at(-1);
if (isAutoApproveLevel(request?.modeInfo?.permissionLevel)) {
return { type: ToolConfirmKind.ConfirmationNotNeeded, reason: 'auto-approve-all' };
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts:1172
cancelToolCallsForRequestnow removes pending streaming invocations from_pendingToolCallswithout cancelling them (cancelFromStreaming(...)was removed). If the invocation was already appended to the request as progress, it will remain stuck inStreamingstate in the UI. Consider cancelling the invocation (e.g.Skipped) before deleting so the transcript state is consistent.
// Clean up any pending tool calls that belong to this request
for (const [toolCallId, invocation] of this._pendingToolCalls) {
if (invocation.chatRequestId === requestId) {
this._pendingToolCalls.delete(toolCallId);
}
}
src/vs/workbench/contrib/chat/browser/tools/languageModelToolsService.ts:1092
- New permission-level auto-confirm behavior (and request selection by
chatRequestId) should be covered by unit tests in the existinglanguageModelToolsService.test.tssuite, including: (1) bypass confirmation only for the matching request, and (2) cancellation marks streaming invocations as cancelled/skipped rather than leaving them inStreaming.
if (chatSessionResource) {
const model = this._chatService.getSession(chatSessionResource);
const request = model?.getRequests().at(-1);
if (isAutoApproveLevel(request?.modeInfo?.permissionLevel)) {
return { type: ToolConfirmKind.ConfirmationNotNeeded, reason: 'auto-approve-all' };
}
}
if (!this.isToolEligibleForAutoApproval(tool.data)) {
return undefined;
}
const reason = this._confirmationService.getPreConfirmAction({ toolId, source, parameters, chatSessionResource });
if (reason) {
return reason;
}
const config = this._configurationService.inspect<boolean | Record<string, boolean>>(ChatConfiguration.GlobalAutoApprove);
// If we know the tool runs at a global level, only consider the global config.
// If we know the tool runs at a workspace level, use those specific settings when appropriate.
let value = config.value ?? config.defaultValue;
if (typeof runsInWorkspace === 'boolean') {
value = config.userLocalValue ?? config.applicationValue;
if (runsInWorkspace) {
value = config.workspaceValue ?? config.workspaceFolderValue ?? config.userRemoteValue ?? value;
}
}
const autoConfirm = value === true || (typeof value === 'object' && value.hasOwnProperty(toolId) && value[toolId] === true);
if (autoConfirm) {
if (await this._checkGlobalAutoApprove()) {
return { type: ToolConfirmKind.Setting, id: ChatConfiguration.GlobalAutoApprove };
}
}
return undefined;
}
private async shouldAutoConfirmPostExecution(toolId: string, runsInWorkspace: boolean | undefined, source: ToolDataSource, parameters: unknown, chatSessionResource: URI | undefined): Promise<ConfirmedReason | undefined> {
// Auto-Approve All permission level bypasses all post-execution confirmations
if (chatSessionResource) {
const model = this._chatService.getSession(chatSessionResource);
const request = model?.getRequests().at(-1);
if (isAutoApproveLevel(request?.modeInfo?.permissionLevel)) {
return { type: ToolConfirmKind.ConfirmationNotNeeded, reason: 'auto-approve-all' };
fix #296662 and #297815
/yolo and /autoApprove moved to #297158.