mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-31 06:02:47 -07:00
feat(core): implement configuration-based tool isolation for subagents
This commit is contained in:
@@ -160,13 +160,15 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
|
||||
// registry and register it with the agent's isolated registry.
|
||||
const tool = parentToolRegistry.getTool(toolName);
|
||||
if (tool) {
|
||||
if (tool instanceof DiscoveredMCPTool) {
|
||||
// Clone the tool, so it gets its own state and subagent messageBus
|
||||
const clonedTool = tool.clone(subagentMessageBus);
|
||||
if (clonedTool instanceof DiscoveredMCPTool) {
|
||||
// Subagents MUST use fully qualified names for MCP tools to ensure
|
||||
// unambiguous tool calls and to comply with policy requirements.
|
||||
// We automatically "upgrade" any MCP tool to its qualified version.
|
||||
agentToolRegistry.registerTool(tool.asFullyQualifiedTool());
|
||||
agentToolRegistry.registerTool(clonedTool.asFullyQualifiedTool());
|
||||
} else {
|
||||
agentToolRegistry.registerTool(tool);
|
||||
agentToolRegistry.registerTool(clonedTool);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -235,6 +235,7 @@ export interface AgentOverride {
|
||||
modelConfig?: ModelConfig;
|
||||
runConfig?: AgentRunConfig;
|
||||
enabled?: boolean;
|
||||
tools?: string[];
|
||||
}
|
||||
|
||||
export interface AgentSettings {
|
||||
@@ -484,6 +485,7 @@ export interface ConfigParameters {
|
||||
question?: string;
|
||||
|
||||
coreTools?: string[];
|
||||
mainAgentTools?: string[];
|
||||
/** @deprecated Use Policy Engine instead */
|
||||
allowedTools?: string[];
|
||||
/** @deprecated Use Policy Engine instead */
|
||||
@@ -635,6 +637,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
readonly enableConseca: boolean;
|
||||
|
||||
private readonly coreTools: string[] | undefined;
|
||||
private readonly mainAgentTools: string[] | undefined;
|
||||
/** @deprecated Use Policy Engine instead */
|
||||
private readonly allowedTools: string[] | undefined;
|
||||
/** @deprecated Use Policy Engine instead */
|
||||
@@ -831,6 +834,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
this.question = params.question;
|
||||
|
||||
this.coreTools = params.coreTools;
|
||||
this.mainAgentTools = params.mainAgentTools;
|
||||
this.allowedTools = params.allowedTools;
|
||||
this.excludeTools = params.excludeTools;
|
||||
this.toolDiscoveryCommand = params.toolDiscoveryCommand;
|
||||
@@ -1778,6 +1782,10 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
return this.coreTools;
|
||||
}
|
||||
|
||||
getMainAgentTools(): string[] | undefined {
|
||||
return this.mainAgentTools;
|
||||
}
|
||||
|
||||
getAllowedTools(): string[] | undefined {
|
||||
return this.allowedTools;
|
||||
}
|
||||
@@ -2823,7 +2831,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
}
|
||||
|
||||
async createToolRegistry(): Promise<ToolRegistry> {
|
||||
const registry = new ToolRegistry(this, this.messageBus);
|
||||
const registry = new ToolRegistry(this, this.messageBus, true);
|
||||
|
||||
// helper to create & register core tools that are enabled
|
||||
const maybeRegister = (
|
||||
|
||||
@@ -202,10 +202,16 @@ export class ToolRegistry {
|
||||
private allKnownTools: Map<string, AnyDeclarativeTool> = new Map();
|
||||
private config: Config;
|
||||
private messageBus: MessageBus;
|
||||
private isMainRegistry: boolean;
|
||||
|
||||
constructor(config: Config, messageBus: MessageBus) {
|
||||
constructor(
|
||||
config: Config,
|
||||
messageBus: MessageBus,
|
||||
isMainRegistry: boolean = false,
|
||||
) {
|
||||
this.config = config;
|
||||
this.messageBus = messageBus;
|
||||
this.isMainRegistry = isMainRegistry;
|
||||
}
|
||||
|
||||
getMessageBus(): MessageBus {
|
||||
@@ -545,6 +551,10 @@ export class ToolRegistry {
|
||||
const declarations: FunctionDeclaration[] = [];
|
||||
const seenNames = new Set<string>();
|
||||
|
||||
const mainAgentTools = this.isMainRegistry
|
||||
? this.config.getMainAgentTools()
|
||||
: undefined;
|
||||
|
||||
this.getActiveTools().forEach((tool) => {
|
||||
const toolName =
|
||||
tool instanceof DiscoveredMCPTool
|
||||
@@ -554,6 +564,16 @@ export class ToolRegistry {
|
||||
if (seenNames.has(toolName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
mainAgentTools &&
|
||||
!mainAgentTools.includes(toolName) &&
|
||||
!mainAgentTools.includes(tool.constructor.name) &&
|
||||
!mainAgentTools.some((t) => t.startsWith(`${tool.constructor.name}(`))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
seenNames.add(toolName);
|
||||
|
||||
let schema = tool.getSchema(modelId);
|
||||
|
||||
@@ -380,6 +380,22 @@ export abstract class DeclarativeTool<
|
||||
readonly extensionId?: string,
|
||||
) {}
|
||||
|
||||
clone(messageBus?: MessageBus): this {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const cloned = Object.assign(
|
||||
Object.create(Object.getPrototypeOf(this)),
|
||||
this,
|
||||
) as this;
|
||||
if (messageBus) {
|
||||
Object.defineProperty(cloned, 'messageBus', {
|
||||
value: messageBus,
|
||||
writable: false,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
get isReadOnly(): boolean {
|
||||
return READ_ONLY_KINDS.includes(this.kind);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user