mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-14 08:01:02 -07:00
fix(agents): default to all tools when tool list is omitted in subagents (#17422)
This commit is contained in:
committed by
GitHub
parent
0c134079cc
commit
77aef861fe
@@ -117,6 +117,23 @@ vi.mock('../telemetry/loggers.js', () => ({
|
||||
logRecoveryAttempt: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../utils/schemaValidator.js', () => ({
|
||||
SchemaValidator: {
|
||||
validate: vi.fn().mockReturnValue(null),
|
||||
validateSchema: vi.fn().mockReturnValue(null),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../utils/filesearch/crawler.js', () => ({
|
||||
crawl: vi.fn().mockResolvedValue([]),
|
||||
}));
|
||||
|
||||
vi.mock('../telemetry/clearcut-logger/clearcut-logger.js', () => ({
|
||||
ClearcutLogger: class {
|
||||
log() {}
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../utils/promptIdContext.js', async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import('../utils/promptIdContext.js')>();
|
||||
@@ -441,6 +458,40 @@ describe('LocalAgentExecutor', () => {
|
||||
// Subagent should be filtered out
|
||||
expect(agentRegistry.getTool(subAgentName)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should default to ALL tools (except subagents) when toolConfig is undefined', async () => {
|
||||
const subAgentName = 'recursive-agent';
|
||||
// Register tools in parent registry
|
||||
// LS_TOOL_NAME is already registered in beforeEach
|
||||
const otherTool = new MockTool({ name: 'other-tool' });
|
||||
parentToolRegistry.registerTool(otherTool);
|
||||
parentToolRegistry.registerTool(new MockTool({ name: subAgentName }));
|
||||
|
||||
// Mock the agent registry to return the subagent name
|
||||
vi.spyOn(
|
||||
mockConfig.getAgentRegistry(),
|
||||
'getAllAgentNames',
|
||||
).mockReturnValue([subAgentName]);
|
||||
|
||||
// Create definition and force toolConfig to be undefined
|
||||
const definition = createTestDefinition();
|
||||
definition.toolConfig = undefined;
|
||||
|
||||
const executor = await LocalAgentExecutor.create(
|
||||
definition,
|
||||
mockConfig,
|
||||
onActivity,
|
||||
);
|
||||
|
||||
const agentRegistry = executor['toolRegistry'];
|
||||
|
||||
// Should include standard tools
|
||||
expect(agentRegistry.getTool(LS_TOOL_NAME)).toBeDefined();
|
||||
expect(agentRegistry.getTool('other-tool')).toBeDefined();
|
||||
|
||||
// Should exclude subagent
|
||||
expect(agentRegistry.getTool(subAgentName)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('run (Execution Loop and Logic)', () => {
|
||||
|
||||
@@ -114,24 +114,28 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
runtimeContext.getAgentRegistry().getAllAgentNames(),
|
||||
);
|
||||
|
||||
const registerToolByName = (toolName: string) => {
|
||||
// Check if the tool is a subagent to prevent recursion.
|
||||
// We do not allow agents to call other agents.
|
||||
if (allAgentNames.has(toolName)) {
|
||||
debugLogger.warn(
|
||||
`[LocalAgentExecutor] Skipping subagent tool '${toolName}' for agent '${definition.name}' to prevent recursion.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the tool is referenced by name, retrieve it from the parent
|
||||
// registry and register it with the agent's isolated registry.
|
||||
const tool = parentToolRegistry.getTool(toolName);
|
||||
if (tool) {
|
||||
agentToolRegistry.registerTool(tool);
|
||||
}
|
||||
};
|
||||
|
||||
if (definition.toolConfig) {
|
||||
for (const toolRef of definition.toolConfig.tools) {
|
||||
if (typeof toolRef === 'string') {
|
||||
// Check if the tool is a subagent to prevent recursion.
|
||||
// We do not allow agents to call other agents.
|
||||
if (allAgentNames.has(toolRef)) {
|
||||
debugLogger.warn(
|
||||
`[LocalAgentExecutor] Skipping subagent tool '${toolRef}' for agent '${definition.name}' to prevent recursion.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the tool is referenced by name, retrieve it from the parent
|
||||
// registry and register it with the agent's isolated registry.
|
||||
const toolFromParent = parentToolRegistry.getTool(toolRef);
|
||||
if (toolFromParent) {
|
||||
agentToolRegistry.registerTool(toolFromParent);
|
||||
}
|
||||
registerToolByName(toolRef);
|
||||
} else if (
|
||||
typeof toolRef === 'object' &&
|
||||
'name' in toolRef &&
|
||||
@@ -142,10 +146,15 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
// Note: Raw `FunctionDeclaration` objects in the config don't need to be
|
||||
// registered; their schemas are passed directly to the model later.
|
||||
}
|
||||
|
||||
agentToolRegistry.sortTools();
|
||||
} else {
|
||||
// If no tools are explicitly configured, default to all available tools.
|
||||
for (const toolName of parentToolRegistry.getAllToolNames()) {
|
||||
registerToolByName(toolName);
|
||||
}
|
||||
}
|
||||
|
||||
agentToolRegistry.sortTools();
|
||||
|
||||
// Get the parent prompt ID from context
|
||||
const parentPromptId = promptIdContext.getStore();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user