Refactor subagent delegation to be one tool per agent (#17346)

This commit is contained in:
Christian Gunderman
2026-01-23 02:18:31 +00:00
committed by GitHub
parent 07bd89399d
commit 2c6781d134
18 changed files with 247 additions and 720 deletions
@@ -61,6 +61,7 @@ import type {
ModelConfigKey,
ResolvedModelConfig,
} from '../services/modelConfigService.js';
import type { AgentRegistry } from './registry.js';
import { getModelConfigAlias } from './registry.js';
import type { ModelRouterService } from '../routing/modelRouterService.js';
@@ -298,6 +299,9 @@ describe('LocalAgentExecutor', () => {
parentToolRegistry.registerTool(MOCK_TOOL_NOT_ALLOWED);
vi.spyOn(mockConfig, 'getToolRegistry').mockReturnValue(parentToolRegistry);
vi.spyOn(mockConfig, 'getAgentRegistry').mockReturnValue({
getAllAgentNames: () => [],
} as unknown as AgentRegistry);
mockedGetDirectoryContextString.mockResolvedValue(
'Mocked Environment Context',
@@ -411,6 +415,32 @@ describe('LocalAgentExecutor', () => {
const secondPart = startHistory?.[1]?.parts?.[0];
expect(secondPart?.text).toBe('OK, starting on TestGoal.');
});
it('should filter out subagent tools to prevent recursion', async () => {
const subAgentName = 'recursive-agent';
// Register a mock tool that simulates a subagent
parentToolRegistry.registerTool(new MockTool({ name: subAgentName }));
// Mock the agent registry to return the subagent name
vi.spyOn(
mockConfig.getAgentRegistry(),
'getAllAgentNames',
).mockReturnValue([subAgentName]);
const definition = createTestDefinition([LS_TOOL_NAME, subAgentName]);
const executor = await LocalAgentExecutor.create(
definition,
mockConfig,
onActivity,
);
const agentRegistry = executor['toolRegistry'];
// LS should be present
expect(agentRegistry.getTool(LS_TOOL_NAME)).toBeDefined();
// Subagent should be filtered out
expect(agentRegistry.getTool(subAgentName)).toBeUndefined();
});
});
describe('run (Execution Loop and Logic)', () => {