mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-12 07:01:09 -07:00
fix(core): propagate subagent context to policy engine (#22086)
This commit is contained in:
@@ -19,6 +19,8 @@ import type { EditorType } from '../utils/editor.js';
|
||||
export interface AgentSchedulingOptions {
|
||||
/** The unique ID for this agent's scheduler. */
|
||||
schedulerId: string;
|
||||
/** The name of the subagent. */
|
||||
subagent?: string;
|
||||
/** The ID of the tool call that invoked this agent. */
|
||||
parentCallId?: string;
|
||||
/** The tool registry specific to this agent. */
|
||||
@@ -46,6 +48,7 @@ export async function scheduleAgentTools(
|
||||
): Promise<CompletedToolCall[]> {
|
||||
const {
|
||||
schedulerId,
|
||||
subagent,
|
||||
parentCallId,
|
||||
toolRegistry,
|
||||
signal,
|
||||
@@ -69,6 +72,7 @@ export async function scheduleAgentTools(
|
||||
messageBus: toolRegistry.getMessageBus(),
|
||||
getPreferredEditor: getPreferredEditor ?? (() => undefined),
|
||||
schedulerId,
|
||||
subagent,
|
||||
parentCallId,
|
||||
onWaitingForConfirmation,
|
||||
});
|
||||
|
||||
@@ -1099,6 +1099,7 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
toolRequests,
|
||||
{
|
||||
schedulerId: this.agentId,
|
||||
subagent: this.definition.name,
|
||||
parentCallId: this.parentCallId,
|
||||
toolRegistry: this.toolRegistry,
|
||||
signal,
|
||||
|
||||
@@ -68,6 +68,7 @@ describe('policy.ts', () => {
|
||||
{ name: 'test-tool', args: {} },
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -97,6 +98,7 @@ describe('policy.ts', () => {
|
||||
{ name: 'mcp-tool', args: {} },
|
||||
'my-server',
|
||||
{ readOnlyHint: true },
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ export function getPolicyDenialError(
|
||||
export async function checkPolicy(
|
||||
toolCall: ValidatingToolCall,
|
||||
config: Config,
|
||||
subagent?: string,
|
||||
): Promise<CheckResult> {
|
||||
const serverName =
|
||||
toolCall.tool instanceof DiscoveredMCPTool
|
||||
@@ -66,6 +67,7 @@ export async function checkPolicy(
|
||||
{ name: toolCall.request.name, args: toolCall.request.args },
|
||||
serverName,
|
||||
toolAnnotations,
|
||||
subagent,
|
||||
);
|
||||
|
||||
const { decision } = result;
|
||||
@@ -115,6 +117,7 @@ export async function updatePolicy(
|
||||
toolInvocation?: AnyToolInvocation,
|
||||
): Promise<void> {
|
||||
const deps = { ...context, toolInvocation };
|
||||
|
||||
// Mode Transitions (AUTO_EDIT)
|
||||
if (isAutoEditTransition(tool, outcome)) {
|
||||
deps.config.setApprovalMode(ApprovalMode.AUTO_EDIT);
|
||||
|
||||
@@ -368,6 +368,32 @@ describe('Scheduler (Orchestrator)', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should propagate subagent name to checkPolicy', async () => {
|
||||
const { checkPolicy } = await import('./policy.js');
|
||||
const scheduler = new Scheduler({
|
||||
context: mockConfig,
|
||||
schedulerId: 'sub-scheduler',
|
||||
subagent: 'my-agent',
|
||||
getPreferredEditor: () => undefined,
|
||||
});
|
||||
|
||||
const request: ToolCallRequestInfo = {
|
||||
callId: 'call-1',
|
||||
name: 'test-tool',
|
||||
args: {},
|
||||
isClientInitiated: false,
|
||||
prompt_id: 'p1',
|
||||
};
|
||||
|
||||
await scheduler.schedule([request], new AbortController().signal);
|
||||
|
||||
expect(checkPolicy).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
'my-agent',
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly build ValidatingToolCalls for happy path', async () => {
|
||||
await scheduler.schedule(req1, signal);
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ export interface SchedulerOptions {
|
||||
messageBus?: MessageBus;
|
||||
getPreferredEditor: () => EditorType | undefined;
|
||||
schedulerId: string;
|
||||
subagent?: string;
|
||||
parentCallId?: string;
|
||||
onWaitingForConfirmation?: (waiting: boolean) => void;
|
||||
}
|
||||
@@ -102,6 +103,7 @@ export class Scheduler {
|
||||
private readonly messageBus: MessageBus;
|
||||
private readonly getPreferredEditor: () => EditorType | undefined;
|
||||
private readonly schedulerId: string;
|
||||
private readonly subagent?: string;
|
||||
private readonly parentCallId?: string;
|
||||
private readonly onWaitingForConfirmation?: (waiting: boolean) => void;
|
||||
|
||||
@@ -115,6 +117,7 @@ export class Scheduler {
|
||||
this.messageBus = options.messageBus ?? this.context.messageBus;
|
||||
this.getPreferredEditor = options.getPreferredEditor;
|
||||
this.schedulerId = options.schedulerId;
|
||||
this.subagent = options.subagent;
|
||||
this.parentCallId = options.parentCallId;
|
||||
this.onWaitingForConfirmation = options.onWaitingForConfirmation;
|
||||
this.state = new SchedulerStateManager(
|
||||
@@ -563,7 +566,11 @@ export class Scheduler {
|
||||
const callId = toolCall.request.callId;
|
||||
|
||||
// Policy & Security
|
||||
const { decision, rule } = await checkPolicy(toolCall, this.config);
|
||||
const { decision, rule } = await checkPolicy(
|
||||
toolCall,
|
||||
this.config,
|
||||
this.subagent,
|
||||
);
|
||||
|
||||
if (decision === PolicyDecision.DENY) {
|
||||
const { errorMessage, errorType } = getPolicyDenialError(
|
||||
|
||||
Reference in New Issue
Block a user