mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -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(),
|
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) => {
|
vi.mock('../utils/promptIdContext.js', async (importOriginal) => {
|
||||||
const actual =
|
const actual =
|
||||||
await importOriginal<typeof import('../utils/promptIdContext.js')>();
|
await importOriginal<typeof import('../utils/promptIdContext.js')>();
|
||||||
@@ -441,6 +458,40 @@ describe('LocalAgentExecutor', () => {
|
|||||||
// Subagent should be filtered out
|
// Subagent should be filtered out
|
||||||
expect(agentRegistry.getTool(subAgentName)).toBeUndefined();
|
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)', () => {
|
describe('run (Execution Loop and Logic)', () => {
|
||||||
|
|||||||
@@ -114,24 +114,28 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
|||||||
runtimeContext.getAgentRegistry().getAllAgentNames(),
|
runtimeContext.getAgentRegistry().getAllAgentNames(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (definition.toolConfig) {
|
const registerToolByName = (toolName: string) => {
|
||||||
for (const toolRef of definition.toolConfig.tools) {
|
|
||||||
if (typeof toolRef === 'string') {
|
|
||||||
// Check if the tool is a subagent to prevent recursion.
|
// Check if the tool is a subagent to prevent recursion.
|
||||||
// We do not allow agents to call other agents.
|
// We do not allow agents to call other agents.
|
||||||
if (allAgentNames.has(toolRef)) {
|
if (allAgentNames.has(toolName)) {
|
||||||
debugLogger.warn(
|
debugLogger.warn(
|
||||||
`[LocalAgentExecutor] Skipping subagent tool '${toolRef}' for agent '${definition.name}' to prevent recursion.`,
|
`[LocalAgentExecutor] Skipping subagent tool '${toolName}' for agent '${definition.name}' to prevent recursion.`,
|
||||||
);
|
);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the tool is referenced by name, retrieve it from the parent
|
// If the tool is referenced by name, retrieve it from the parent
|
||||||
// registry and register it with the agent's isolated registry.
|
// registry and register it with the agent's isolated registry.
|
||||||
const toolFromParent = parentToolRegistry.getTool(toolRef);
|
const tool = parentToolRegistry.getTool(toolName);
|
||||||
if (toolFromParent) {
|
if (tool) {
|
||||||
agentToolRegistry.registerTool(toolFromParent);
|
agentToolRegistry.registerTool(tool);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (definition.toolConfig) {
|
||||||
|
for (const toolRef of definition.toolConfig.tools) {
|
||||||
|
if (typeof toolRef === 'string') {
|
||||||
|
registerToolByName(toolRef);
|
||||||
} else if (
|
} else if (
|
||||||
typeof toolRef === 'object' &&
|
typeof toolRef === 'object' &&
|
||||||
'name' in toolRef &&
|
'name' in toolRef &&
|
||||||
@@ -142,9 +146,14 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
|||||||
// Note: Raw `FunctionDeclaration` objects in the config don't need to be
|
// Note: Raw `FunctionDeclaration` objects in the config don't need to be
|
||||||
// registered; their schemas are passed directly to the model later.
|
// registered; their schemas are passed directly to the model later.
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If no tools are explicitly configured, default to all available tools.
|
||||||
|
for (const toolName of parentToolRegistry.getAllToolNames()) {
|
||||||
|
registerToolByName(toolName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
agentToolRegistry.sortTools();
|
agentToolRegistry.sortTools();
|
||||||
}
|
|
||||||
|
|
||||||
// Get the parent prompt ID from context
|
// Get the parent prompt ID from context
|
||||||
const parentPromptId = promptIdContext.getStore();
|
const parentPromptId = promptIdContext.getStore();
|
||||||
|
|||||||
Reference in New Issue
Block a user