mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-22 07:41:23 -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.
|
// registry and register it with the agent's isolated registry.
|
||||||
const tool = parentToolRegistry.getTool(toolName);
|
const tool = parentToolRegistry.getTool(toolName);
|
||||||
if (tool) {
|
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
|
// Subagents MUST use fully qualified names for MCP tools to ensure
|
||||||
// unambiguous tool calls and to comply with policy requirements.
|
// unambiguous tool calls and to comply with policy requirements.
|
||||||
// We automatically "upgrade" any MCP tool to its qualified version.
|
// We automatically "upgrade" any MCP tool to its qualified version.
|
||||||
agentToolRegistry.registerTool(tool.asFullyQualifiedTool());
|
agentToolRegistry.registerTool(clonedTool.asFullyQualifiedTool());
|
||||||
} else {
|
} else {
|
||||||
agentToolRegistry.registerTool(tool);
|
agentToolRegistry.registerTool(clonedTool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ export interface AgentOverride {
|
|||||||
modelConfig?: ModelConfig;
|
modelConfig?: ModelConfig;
|
||||||
runConfig?: AgentRunConfig;
|
runConfig?: AgentRunConfig;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
tools?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentSettings {
|
export interface AgentSettings {
|
||||||
@@ -484,6 +485,7 @@ export interface ConfigParameters {
|
|||||||
question?: string;
|
question?: string;
|
||||||
|
|
||||||
coreTools?: string[];
|
coreTools?: string[];
|
||||||
|
mainAgentTools?: string[];
|
||||||
/** @deprecated Use Policy Engine instead */
|
/** @deprecated Use Policy Engine instead */
|
||||||
allowedTools?: string[];
|
allowedTools?: string[];
|
||||||
/** @deprecated Use Policy Engine instead */
|
/** @deprecated Use Policy Engine instead */
|
||||||
@@ -635,6 +637,7 @@ export class Config implements McpContext, AgentLoopContext {
|
|||||||
readonly enableConseca: boolean;
|
readonly enableConseca: boolean;
|
||||||
|
|
||||||
private readonly coreTools: string[] | undefined;
|
private readonly coreTools: string[] | undefined;
|
||||||
|
private readonly mainAgentTools: string[] | undefined;
|
||||||
/** @deprecated Use Policy Engine instead */
|
/** @deprecated Use Policy Engine instead */
|
||||||
private readonly allowedTools: string[] | undefined;
|
private readonly allowedTools: string[] | undefined;
|
||||||
/** @deprecated Use Policy Engine instead */
|
/** @deprecated Use Policy Engine instead */
|
||||||
@@ -831,6 +834,7 @@ export class Config implements McpContext, AgentLoopContext {
|
|||||||
this.question = params.question;
|
this.question = params.question;
|
||||||
|
|
||||||
this.coreTools = params.coreTools;
|
this.coreTools = params.coreTools;
|
||||||
|
this.mainAgentTools = params.mainAgentTools;
|
||||||
this.allowedTools = params.allowedTools;
|
this.allowedTools = params.allowedTools;
|
||||||
this.excludeTools = params.excludeTools;
|
this.excludeTools = params.excludeTools;
|
||||||
this.toolDiscoveryCommand = params.toolDiscoveryCommand;
|
this.toolDiscoveryCommand = params.toolDiscoveryCommand;
|
||||||
@@ -1778,6 +1782,10 @@ export class Config implements McpContext, AgentLoopContext {
|
|||||||
return this.coreTools;
|
return this.coreTools;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMainAgentTools(): string[] | undefined {
|
||||||
|
return this.mainAgentTools;
|
||||||
|
}
|
||||||
|
|
||||||
getAllowedTools(): string[] | undefined {
|
getAllowedTools(): string[] | undefined {
|
||||||
return this.allowedTools;
|
return this.allowedTools;
|
||||||
}
|
}
|
||||||
@@ -2823,7 +2831,7 @@ export class Config implements McpContext, AgentLoopContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createToolRegistry(): Promise<ToolRegistry> {
|
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
|
// helper to create & register core tools that are enabled
|
||||||
const maybeRegister = (
|
const maybeRegister = (
|
||||||
|
|||||||
@@ -202,10 +202,16 @@ export class ToolRegistry {
|
|||||||
private allKnownTools: Map<string, AnyDeclarativeTool> = new Map();
|
private allKnownTools: Map<string, AnyDeclarativeTool> = new Map();
|
||||||
private config: Config;
|
private config: Config;
|
||||||
private messageBus: MessageBus;
|
private messageBus: MessageBus;
|
||||||
|
private isMainRegistry: boolean;
|
||||||
|
|
||||||
constructor(config: Config, messageBus: MessageBus) {
|
constructor(
|
||||||
|
config: Config,
|
||||||
|
messageBus: MessageBus,
|
||||||
|
isMainRegistry: boolean = false,
|
||||||
|
) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.messageBus = messageBus;
|
this.messageBus = messageBus;
|
||||||
|
this.isMainRegistry = isMainRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageBus(): MessageBus {
|
getMessageBus(): MessageBus {
|
||||||
@@ -545,6 +551,10 @@ export class ToolRegistry {
|
|||||||
const declarations: FunctionDeclaration[] = [];
|
const declarations: FunctionDeclaration[] = [];
|
||||||
const seenNames = new Set<string>();
|
const seenNames = new Set<string>();
|
||||||
|
|
||||||
|
const mainAgentTools = this.isMainRegistry
|
||||||
|
? this.config.getMainAgentTools()
|
||||||
|
: undefined;
|
||||||
|
|
||||||
this.getActiveTools().forEach((tool) => {
|
this.getActiveTools().forEach((tool) => {
|
||||||
const toolName =
|
const toolName =
|
||||||
tool instanceof DiscoveredMCPTool
|
tool instanceof DiscoveredMCPTool
|
||||||
@@ -554,6 +564,16 @@ export class ToolRegistry {
|
|||||||
if (seenNames.has(toolName)) {
|
if (seenNames.has(toolName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
mainAgentTools &&
|
||||||
|
!mainAgentTools.includes(toolName) &&
|
||||||
|
!mainAgentTools.includes(tool.constructor.name) &&
|
||||||
|
!mainAgentTools.some((t) => t.startsWith(`${tool.constructor.name}(`))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
seenNames.add(toolName);
|
seenNames.add(toolName);
|
||||||
|
|
||||||
let schema = tool.getSchema(modelId);
|
let schema = tool.getSchema(modelId);
|
||||||
|
|||||||
@@ -380,6 +380,22 @@ export abstract class DeclarativeTool<
|
|||||||
readonly extensionId?: string,
|
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 {
|
get isReadOnly(): boolean {
|
||||||
return READ_ONLY_KINDS.includes(this.kind);
|
return READ_ONLY_KINDS.includes(this.kind);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user