mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
fix: allow ask_user tool in yolo mode (#18541)
This commit is contained in:
@@ -483,6 +483,29 @@ describe('Core System Prompt (prompts.ts)', () => {
|
||||
expect(prompt).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('should include YOLO mode instructions in interactive mode', () => {
|
||||
vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.YOLO);
|
||||
vi.mocked(mockConfig.isInteractive).mockReturnValue(true);
|
||||
const prompt = getCoreSystemPrompt(mockConfig);
|
||||
expect(prompt).toContain('# Autonomous Mode (YOLO)');
|
||||
expect(prompt).toContain('Only use the `ask_user` tool if');
|
||||
});
|
||||
|
||||
it('should NOT include YOLO mode instructions in non-interactive mode', () => {
|
||||
vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.YOLO);
|
||||
vi.mocked(mockConfig.isInteractive).mockReturnValue(false);
|
||||
const prompt = getCoreSystemPrompt(mockConfig);
|
||||
expect(prompt).not.toContain('# Autonomous Mode (YOLO)');
|
||||
});
|
||||
|
||||
it('should NOT include YOLO mode instructions for DEFAULT mode', () => {
|
||||
vi.mocked(mockConfig.getApprovalMode).mockReturnValue(
|
||||
ApprovalMode.DEFAULT,
|
||||
);
|
||||
const prompt = getCoreSystemPrompt(mockConfig);
|
||||
expect(prompt).not.toContain('# Autonomous Mode (YOLO)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Platform-specific and Background Process instructions', () => {
|
||||
|
||||
@@ -317,8 +317,8 @@ describe('createPolicyEngineConfig', () => {
|
||||
(r) => r.decision === PolicyDecision.ALLOW && !r.toolName,
|
||||
);
|
||||
expect(rule).toBeDefined();
|
||||
// Priority 999 in default tier → 1.999
|
||||
expect(rule?.priority).toBeCloseTo(1.999, 5);
|
||||
// Priority 998 in default tier → 1.998 (999 reserved for ask_user exception)
|
||||
expect(rule?.priority).toBeCloseTo(1.998, 5);
|
||||
});
|
||||
|
||||
it('should allow edit tool in AUTO_EDIT mode', async () => {
|
||||
@@ -582,8 +582,8 @@ describe('createPolicyEngineConfig', () => {
|
||||
(r) => !r.toolName && r.decision === PolicyDecision.ALLOW,
|
||||
);
|
||||
expect(wildcardRule).toBeDefined();
|
||||
// Priority 999 in default tier → 1.999
|
||||
expect(wildcardRule?.priority).toBeCloseTo(1.999, 5);
|
||||
// Priority 998 in default tier → 1.998 (999 reserved for ask_user exception)
|
||||
expect(wildcardRule?.priority).toBeCloseTo(1.998, 5);
|
||||
|
||||
// Write tool ASK_USER rules are present (from write.toml)
|
||||
const writeToolRules = config.rules?.filter(
|
||||
|
||||
@@ -23,10 +23,21 @@
|
||||
# 10: Write tools default to ASK_USER (becomes 1.010 in default tier)
|
||||
# 15: Auto-edit tool override (becomes 1.015 in default tier)
|
||||
# 50: Read-only tools (becomes 1.050 in default tier)
|
||||
# 999: YOLO mode allow-all (becomes 1.999 in default tier)
|
||||
# 998: YOLO mode allow-all (becomes 1.998 in default tier)
|
||||
# 999: Ask-user tool (becomes 1.999 in default tier)
|
||||
|
||||
# Ask-user tool always requires user interaction, even in YOLO mode.
|
||||
# This ensures the model can gather user preferences/decisions when needed.
|
||||
# Note: In non-interactive mode, this decision is converted to DENY by the policy engine.
|
||||
[[rule]]
|
||||
decision = "allow"
|
||||
toolName = "ask_user"
|
||||
decision = "ask_user"
|
||||
priority = 999
|
||||
modes = ["yolo"]
|
||||
|
||||
# Allow everything else in YOLO mode
|
||||
[[rule]]
|
||||
decision = "allow"
|
||||
priority = 998
|
||||
modes = ["yolo"]
|
||||
allow_redirection = true
|
||||
|
||||
@@ -2030,4 +2030,60 @@ describe('PolicyEngine', () => {
|
||||
expect(result.decision).toBe(PolicyDecision.DENY);
|
||||
});
|
||||
});
|
||||
|
||||
describe('YOLO mode with ask_user tool', () => {
|
||||
it('should return ASK_USER for ask_user tool even in YOLO mode', async () => {
|
||||
const rules: PolicyRule[] = [
|
||||
{
|
||||
toolName: 'ask_user',
|
||||
decision: PolicyDecision.ASK_USER,
|
||||
priority: 999,
|
||||
modes: [ApprovalMode.YOLO],
|
||||
},
|
||||
{
|
||||
decision: PolicyDecision.ALLOW,
|
||||
priority: 998,
|
||||
modes: [ApprovalMode.YOLO],
|
||||
},
|
||||
];
|
||||
|
||||
engine = new PolicyEngine({
|
||||
rules,
|
||||
approvalMode: ApprovalMode.YOLO,
|
||||
});
|
||||
|
||||
const result = await engine.check(
|
||||
{ name: 'ask_user', args: {} },
|
||||
undefined,
|
||||
);
|
||||
expect(result.decision).toBe(PolicyDecision.ASK_USER);
|
||||
});
|
||||
|
||||
it('should return ALLOW for other tools in YOLO mode', async () => {
|
||||
const rules: PolicyRule[] = [
|
||||
{
|
||||
toolName: 'ask_user',
|
||||
decision: PolicyDecision.ASK_USER,
|
||||
priority: 999,
|
||||
modes: [ApprovalMode.YOLO],
|
||||
},
|
||||
{
|
||||
decision: PolicyDecision.ALLOW,
|
||||
priority: 998,
|
||||
modes: [ApprovalMode.YOLO],
|
||||
},
|
||||
];
|
||||
|
||||
engine = new PolicyEngine({
|
||||
rules,
|
||||
approvalMode: ApprovalMode.YOLO,
|
||||
});
|
||||
|
||||
const result = await engine.check(
|
||||
{ name: 'run_shell_command', args: { command: 'ls' } },
|
||||
undefined,
|
||||
);
|
||||
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,6 +50,7 @@ export class PromptProvider {
|
||||
const interactiveMode = interactiveOverride ?? config.isInteractive();
|
||||
const approvalMode = config.getApprovalMode?.() ?? ApprovalMode.DEFAULT;
|
||||
const isPlanMode = approvalMode === ApprovalMode.PLAN;
|
||||
const isYoloMode = approvalMode === ApprovalMode.YOLO;
|
||||
const skills = config.getSkillManager().getSkills();
|
||||
const toolNames = config.getToolRegistry().getAllToolNames();
|
||||
const enabledToolNames = new Set(toolNames);
|
||||
@@ -183,6 +184,11 @@ export class PromptProvider {
|
||||
}),
|
||||
),
|
||||
sandbox: this.withSection('sandbox', () => getSandboxMode()),
|
||||
interactiveYoloMode: this.withSection(
|
||||
'interactiveYoloMode',
|
||||
() => true,
|
||||
isYoloMode && interactiveMode,
|
||||
),
|
||||
gitRepo: this.withSection(
|
||||
'git',
|
||||
() => ({ interactive: interactiveMode }),
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface SystemPromptOptions {
|
||||
planningWorkflow?: PlanningWorkflowOptions;
|
||||
operationalGuidelines?: OperationalGuidelinesOptions;
|
||||
sandbox?: SandboxMode;
|
||||
interactiveYoloMode?: boolean;
|
||||
gitRepo?: GitRepoOptions;
|
||||
finalReminder?: FinalReminderOptions;
|
||||
}
|
||||
@@ -114,6 +115,8 @@ ${
|
||||
|
||||
${renderOperationalGuidelines(options.operationalGuidelines)}
|
||||
|
||||
${renderInteractiveYoloMode(options.interactiveYoloMode)}
|
||||
|
||||
${renderSandbox(options.sandbox)}
|
||||
|
||||
${renderGitRepo(options.gitRepo)}
|
||||
@@ -293,6 +296,25 @@ You are running outside of a sandbox container, directly on the user's system. F
|
||||
}
|
||||
}
|
||||
|
||||
export function renderInteractiveYoloMode(enabled?: boolean): string {
|
||||
if (!enabled) return '';
|
||||
return `
|
||||
# Autonomous Mode (YOLO)
|
||||
|
||||
You are operating in **autonomous mode**. The user has requested minimal interruption.
|
||||
|
||||
**Only use the \`${ASK_USER_TOOL_NAME}\` tool if:**
|
||||
- A wrong decision would cause significant re-work
|
||||
- The request is fundamentally ambiguous with no reasonable default
|
||||
- The user explicitly asks you to confirm or ask questions
|
||||
|
||||
**Otherwise, work autonomously:**
|
||||
- Make reasonable decisions based on context and existing code patterns
|
||||
- Follow established project conventions
|
||||
- If multiple valid approaches exist, choose the most robust option
|
||||
`.trim();
|
||||
}
|
||||
|
||||
export function renderGitRepo(options?: GitRepoOptions): string {
|
||||
if (!options) return '';
|
||||
return `
|
||||
|
||||
@@ -33,6 +33,7 @@ export interface SystemPromptOptions {
|
||||
planningWorkflow?: PlanningWorkflowOptions;
|
||||
operationalGuidelines?: OperationalGuidelinesOptions;
|
||||
sandbox?: SandboxMode;
|
||||
interactiveYoloMode?: boolean;
|
||||
gitRepo?: GitRepoOptions;
|
||||
}
|
||||
|
||||
@@ -111,6 +112,8 @@ ${
|
||||
|
||||
${renderOperationalGuidelines(options.operationalGuidelines)}
|
||||
|
||||
${renderInteractiveYoloMode(options.interactiveYoloMode)}
|
||||
|
||||
${renderSandbox(options.sandbox)}
|
||||
|
||||
${renderGitRepo(options.gitRepo)}
|
||||
@@ -312,6 +315,25 @@ export function renderSandbox(mode?: SandboxMode): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
export function renderInteractiveYoloMode(enabled?: boolean): string {
|
||||
if (!enabled) return '';
|
||||
return `
|
||||
# Autonomous Mode (YOLO)
|
||||
|
||||
You are operating in **autonomous mode**. The user has requested minimal interruption.
|
||||
|
||||
**Only use the \`${ASK_USER_TOOL_NAME}\` tool if:**
|
||||
- A wrong decision would cause significant re-work
|
||||
- The request is fundamentally ambiguous with no reasonable default
|
||||
- The user explicitly asks you to confirm or ask questions
|
||||
|
||||
**Otherwise, work autonomously:**
|
||||
- Make reasonable decisions based on context and existing code patterns
|
||||
- Follow established project conventions
|
||||
- If multiple valid approaches exist, choose the most robust option
|
||||
`.trim();
|
||||
}
|
||||
|
||||
export function renderGitRepo(options?: GitRepoOptions): string {
|
||||
if (!options) return '';
|
||||
return `
|
||||
|
||||
Reference in New Issue
Block a user