mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-17 09:30:58 -07:00
feat(plan): inject message when user manually exits Plan mode (#20203)
This commit is contained in:
@@ -39,6 +39,7 @@ import {
|
||||
coreEvents,
|
||||
CoreEvent,
|
||||
MCPDiscoveryState,
|
||||
getPlanModeExitMessage,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { Part, PartListUnion } from '@google/genai';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
@@ -2079,6 +2080,34 @@ describe('useGeminiStream', () => {
|
||||
expect.objectContaining({ correlationId: 'corr-call2' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should inject a notification message when manually exiting Plan Mode', async () => {
|
||||
// Setup mockConfig to return PLAN mode initially
|
||||
(mockConfig.getApprovalMode as Mock).mockReturnValue(ApprovalMode.PLAN);
|
||||
|
||||
// Render the hook, which will initialize the previousApprovalModeRef with PLAN
|
||||
const { result, client } = renderTestHook([]);
|
||||
|
||||
// Update mockConfig to return DEFAULT mode (new mode)
|
||||
(mockConfig.getApprovalMode as Mock).mockReturnValue(
|
||||
ApprovalMode.DEFAULT,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
// Trigger manual exit from Plan Mode
|
||||
await result.current.handleApprovalModeChange(ApprovalMode.DEFAULT);
|
||||
});
|
||||
|
||||
// Verify that addHistory was called with the notification message
|
||||
expect(client.addHistory).toHaveBeenCalledWith({
|
||||
role: 'user',
|
||||
parts: [
|
||||
{
|
||||
text: getPlanModeExitMessage(ApprovalMode.DEFAULT, true),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleFinishedEvent', () => {
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
CoreToolCallStatus,
|
||||
buildUserSteeringHintPrompt,
|
||||
generateSteeringAckMessage,
|
||||
getPlanModeExitMessage,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type {
|
||||
Config,
|
||||
@@ -203,6 +204,9 @@ export const useGeminiStream = (
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
const turnCancelledRef = useRef(false);
|
||||
const activeQueryIdRef = useRef<string | null>(null);
|
||||
const previousApprovalModeRef = useRef<ApprovalMode>(
|
||||
config.getApprovalMode(),
|
||||
);
|
||||
const [isResponding, setIsResponding] = useState<boolean>(false);
|
||||
const [thought, thoughtRef, setThought] =
|
||||
useStateAndRef<ThoughtSummary | null>(null);
|
||||
@@ -1435,6 +1439,34 @@ export const useGeminiStream = (
|
||||
|
||||
const handleApprovalModeChange = useCallback(
|
||||
async (newApprovalMode: ApprovalMode) => {
|
||||
if (
|
||||
previousApprovalModeRef.current === ApprovalMode.PLAN &&
|
||||
newApprovalMode !== ApprovalMode.PLAN &&
|
||||
streamingState === StreamingState.Idle
|
||||
) {
|
||||
if (geminiClient) {
|
||||
try {
|
||||
await geminiClient.addHistory({
|
||||
role: 'user',
|
||||
parts: [
|
||||
{
|
||||
text: getPlanModeExitMessage(newApprovalMode, true),
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch (error) {
|
||||
onDebugMessage(
|
||||
`Failed to notify model of Plan Mode exit: ${getErrorMessage(error)}`,
|
||||
);
|
||||
addItem({
|
||||
type: MessageType.ERROR,
|
||||
text: 'Failed to update the model about exiting Plan Mode. The model might be out of sync. Please consider restarting the session if you see unexpected behavior.',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
previousApprovalModeRef.current = newApprovalMode;
|
||||
|
||||
// Auto-approve pending tool calls when switching to auto-approval modes
|
||||
if (
|
||||
newApprovalMode === ApprovalMode.YOLO ||
|
||||
@@ -1473,7 +1505,7 @@ export const useGeminiStream = (
|
||||
}
|
||||
}
|
||||
},
|
||||
[config, toolCalls],
|
||||
[config, toolCalls, geminiClient, streamingState, addItem, onDebugMessage],
|
||||
);
|
||||
|
||||
const handleCompletedTools = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user