diff --git a/packages/core/src/agents/agent-scheduler.ts b/packages/core/src/agents/agent-scheduler.ts index 088cd9bda7..38804bf01a 100644 --- a/packages/core/src/agents/agent-scheduler.ts +++ b/packages/core/src/agents/agent-scheduler.ts @@ -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 { const { schedulerId, + subagent, parentCallId, toolRegistry, signal, @@ -69,6 +72,7 @@ export async function scheduleAgentTools( messageBus: toolRegistry.getMessageBus(), getPreferredEditor: getPreferredEditor ?? (() => undefined), schedulerId, + subagent, parentCallId, onWaitingForConfirmation, }); diff --git a/packages/core/src/agents/local-executor.ts b/packages/core/src/agents/local-executor.ts index 4ec9ea3eb3..cbc6260304 100644 --- a/packages/core/src/agents/local-executor.ts +++ b/packages/core/src/agents/local-executor.ts @@ -1099,6 +1099,7 @@ export class LocalAgentExecutor { toolRequests, { schedulerId: this.agentId, + subagent: this.definition.name, parentCallId: this.parentCallId, toolRegistry: this.toolRegistry, signal, diff --git a/packages/core/src/scheduler/policy.test.ts b/packages/core/src/scheduler/policy.test.ts index b459955d2b..796b9f2803 100644 --- a/packages/core/src/scheduler/policy.test.ts +++ b/packages/core/src/scheduler/policy.test.ts @@ -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, ); }); diff --git a/packages/core/src/scheduler/policy.ts b/packages/core/src/scheduler/policy.ts index 9a5a43735d..039eea7e1d 100644 --- a/packages/core/src/scheduler/policy.ts +++ b/packages/core/src/scheduler/policy.ts @@ -52,6 +52,7 @@ export function getPolicyDenialError( export async function checkPolicy( toolCall: ValidatingToolCall, config: Config, + subagent?: string, ): Promise { 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 { const deps = { ...context, toolInvocation }; + // Mode Transitions (AUTO_EDIT) if (isAutoEditTransition(tool, outcome)) { deps.config.setApprovalMode(ApprovalMode.AUTO_EDIT); diff --git a/packages/core/src/scheduler/scheduler.test.ts b/packages/core/src/scheduler/scheduler.test.ts index 3e5e6877cf..76d5e50382 100644 --- a/packages/core/src/scheduler/scheduler.test.ts +++ b/packages/core/src/scheduler/scheduler.test.ts @@ -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); diff --git a/packages/core/src/scheduler/scheduler.ts b/packages/core/src/scheduler/scheduler.ts index 6cc7367609..ee8e9371e2 100644 --- a/packages/core/src/scheduler/scheduler.ts +++ b/packages/core/src/scheduler/scheduler.ts @@ -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(