From 49c26b48018258a9329f0fdee3d3d7b34fa511e6 Mon Sep 17 00:00:00 2001 From: Jerop Kipruto Date: Mon, 26 Jan 2026 18:45:24 -0500 Subject: [PATCH] feat(plan): refresh system prompt when approval mode changes (Shift+Tab) (#17585) --- packages/core/src/commands/memory.ts | 2 +- packages/core/src/config/config.test.ts | 33 +++++++++++++++++++++++++ packages/core/src/config/config.ts | 17 +++++++++---- packages/core/src/core/client.test.ts | 4 +-- packages/core/src/core/client.ts | 2 +- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/packages/core/src/commands/memory.ts b/packages/core/src/commands/memory.ts index 6065cf0dab..a1c6573b4f 100644 --- a/packages/core/src/commands/memory.ts +++ b/packages/core/src/commands/memory.ts @@ -59,7 +59,7 @@ export async function refreshMemory( fileCount = result.fileCount; } - await config.updateSystemInstructionIfInitialized(); + config.updateSystemInstructionIfInitialized(); let content: string; if (memoryContent.length > 0) { diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index 97b2ab67bb..c5062c6d64 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -1269,6 +1269,39 @@ describe('setApprovalMode with folder trust', () => { expect(() => config.setApprovalMode(ApprovalMode.DEFAULT)).not.toThrow(); }); + it('should update system instruction when entering Plan mode', () => { + const config = new Config(baseParams); + vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true); + const updateSpy = vi.spyOn(config, 'updateSystemInstructionIfInitialized'); + + config.setApprovalMode(ApprovalMode.PLAN); + + expect(updateSpy).toHaveBeenCalled(); + }); + + it('should update system instruction when leaving Plan mode', () => { + const config = new Config({ + ...baseParams, + approvalMode: ApprovalMode.PLAN, + }); + vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true); + const updateSpy = vi.spyOn(config, 'updateSystemInstructionIfInitialized'); + + config.setApprovalMode(ApprovalMode.DEFAULT); + + expect(updateSpy).toHaveBeenCalled(); + }); + + it('should not update system instruction when switching between non-Plan modes', () => { + const config = new Config(baseParams); + vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true); + const updateSpy = vi.spyOn(config, 'updateSystemInstructionIfInitialized'); + + config.setApprovalMode(ApprovalMode.AUTO_EDIT); + + expect(updateSpy).not.toHaveBeenCalled(); + }); + describe('registerCoreTools', () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 6da474cbcf..b4be2cbdfc 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -1341,7 +1341,7 @@ export class Config { } if (this.geminiClient?.isInitialized()) { await this.geminiClient.setTools(); - await this.geminiClient.updateSystemInstruction(); + this.geminiClient.updateSystemInstruction(); } } @@ -1409,6 +1409,13 @@ export class Config { } this.policyEngine.setApprovalMode(mode); + + const isPlanModeTransition = + currentMode !== mode && + (currentMode === ApprovalMode.PLAN || mode === ApprovalMode.PLAN); + if (isPlanModeTransition) { + this.updateSystemInstructionIfInitialized(); + } } /** @@ -1491,10 +1498,10 @@ export class Config { * Updates the system instruction with the latest user memory. * Whenever the user memory (GEMINI.md files) is updated. */ - async updateSystemInstructionIfInitialized(): Promise { + updateSystemInstructionIfInitialized(): void { const geminiClient = this.getGeminiClient(); if (geminiClient?.isInitialized()) { - await geminiClient.updateSystemInstruction(); + geminiClient.updateSystemInstruction(); } } @@ -1803,7 +1810,7 @@ export class Config { } // Notify the client that system instructions might need updating - await this.updateSystemInstructionIfInitialized(); + this.updateSystemInstructionIfInitialized(); } /** @@ -2142,7 +2149,7 @@ export class Config { const client = this.getGeminiClient(); if (client?.isInitialized()) { await client.setTools(); - await client.updateSystemInstruction(); + client.updateSystemInstruction(); } else { debugLogger.debug( '[Config] GeminiClient not initialized; skipping live prompt/tool refresh.', diff --git a/packages/core/src/core/client.test.ts b/packages/core/src/core/client.test.ts index 49d71ce1a9..ba30a63327 100644 --- a/packages/core/src/core/client.test.ts +++ b/packages/core/src/core/client.test.ts @@ -1842,7 +1842,7 @@ ${JSON.stringify( const { getCoreSystemPrompt } = await import('./prompts.js'); const mockGetCoreSystemPrompt = vi.mocked(getCoreSystemPrompt); - await client.updateSystemInstruction(); + client.updateSystemInstruction(); expect(mockGetCoreSystemPrompt).toHaveBeenCalledWith( mockConfig, @@ -1857,7 +1857,7 @@ ${JSON.stringify( const { getCoreSystemPrompt } = await import('./prompts.js'); const mockGetCoreSystemPrompt = vi.mocked(getCoreSystemPrompt); - await client.updateSystemInstruction(); + client.updateSystemInstruction(); expect(mockGetCoreSystemPrompt).toHaveBeenCalledWith( mockConfig, diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index 2adb5d8bad..d80b8b4002 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -300,7 +300,7 @@ export class GeminiClient { }); } - async updateSystemInstruction(): Promise { + updateSystemInstruction(): void { if (!this.isInitialized()) { return; }