feat(a2a): switch from callback-based to event-driven tool scheduler (#21467)

Co-authored-by: Abhi <abhipatel@google.com>
Co-authored-by: Adam Weidman <adamfweidman@google.com>
This commit is contained in:
Coco Sheng
2026-03-10 15:36:17 -04:00
committed by GitHub
parent e5615f47c4
commit 1b69637032
10 changed files with 1323 additions and 59 deletions
@@ -333,6 +333,48 @@ describe('PolicyEngine', () => {
PolicyDecision.ASK_USER,
);
});
it('should return ALLOW by default in YOLO mode when no rules match', async () => {
engine = new PolicyEngine({ approvalMode: ApprovalMode.YOLO });
// No rules defined, should return ALLOW in YOLO mode
const { decision } = await engine.check({ name: 'any-tool' }, undefined);
expect(decision).toBe(PolicyDecision.ALLOW);
});
it('should NOT override explicit DENY rules in YOLO mode', async () => {
const rules: PolicyRule[] = [
{ toolName: 'dangerous-tool', decision: PolicyDecision.DENY },
];
engine = new PolicyEngine({ rules, approvalMode: ApprovalMode.YOLO });
const { decision } = await engine.check(
{ name: 'dangerous-tool' },
undefined,
);
expect(decision).toBe(PolicyDecision.DENY);
// But other tools still allowed
expect(
(await engine.check({ name: 'safe-tool' }, undefined)).decision,
).toBe(PolicyDecision.ALLOW);
});
it('should respect rule priority in YOLO mode when a match exists', async () => {
const rules: PolicyRule[] = [
{
toolName: 'test-tool',
decision: PolicyDecision.ASK_USER,
priority: 10,
},
{ toolName: 'test-tool', decision: PolicyDecision.DENY, priority: 20 },
];
engine = new PolicyEngine({ rules, approvalMode: ApprovalMode.YOLO });
// Priority 20 (DENY) should win over priority 10 (ASK_USER)
const { decision } = await engine.check({ name: 'test-tool' }, undefined);
expect(decision).toBe(PolicyDecision.DENY);
});
});
describe('addRule', () => {
@@ -466,6 +466,15 @@ export class PolicyEngine {
// Default if no rule matched
if (decision === undefined) {
if (this.approvalMode === ApprovalMode.YOLO) {
debugLogger.debug(
`[PolicyEngine.check] NO MATCH in YOLO mode - using ALLOW`,
);
return {
decision: PolicyDecision.ALLOW,
};
}
debugLogger.debug(
`[PolicyEngine.check] NO MATCH - using default decision: ${this.defaultDecision}`,
);