fix: allow ask_user tool in yolo mode (#18541)

This commit is contained in:
Jack Wotherspoon
2026-02-10 13:56:51 -05:00
committed by GitHub
parent b37e67451a
commit 740f0e4c3d
7 changed files with 146 additions and 6 deletions
+4 -4
View File
@@ -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(
+13 -2
View File
@@ -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);
});
});
});