mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-26 04:54:25 -07:00
feat(agents): Add remote agents to agent registry (#15711)
This commit is contained in:
@@ -11,6 +11,7 @@ import type { AgentDefinition } from './types.js';
|
||||
import { loadAgentsFromDirectory } from './toml-loader.js';
|
||||
import { CodebaseInvestigatorAgent } from './codebase-investigator.js';
|
||||
import { IntrospectionAgent } from './introspection-agent.js';
|
||||
import { A2AClientManager } from './a2a-client-manager.js';
|
||||
import { type z } from 'zod';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import {
|
||||
@@ -47,7 +48,12 @@ export class AgentRegistry {
|
||||
this.loadBuiltInAgents();
|
||||
|
||||
coreEvents.on(CoreEvent.ModelChanged, () => {
|
||||
this.refreshAgents();
|
||||
this.refreshAgents().catch((e) => {
|
||||
debugLogger.error(
|
||||
'[AgentRegistry] Failed to refresh agents on model change:',
|
||||
e,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
if (!this.config.isAgentsEnabled()) {
|
||||
@@ -63,9 +69,9 @@ export class AgentRegistry {
|
||||
);
|
||||
coreEvents.emitFeedback('error', `Agent loading error: ${error.message}`);
|
||||
}
|
||||
for (const agent of userAgents.agents) {
|
||||
this.registerAgent(agent);
|
||||
}
|
||||
await Promise.allSettled(
|
||||
userAgents.agents.map((agent) => this.registerAgent(agent)),
|
||||
);
|
||||
|
||||
// Load project-level agents: .gemini/agents/ (relative to Project Root)
|
||||
const folderTrustEnabled = this.config.getFolderTrust();
|
||||
@@ -80,9 +86,9 @@ export class AgentRegistry {
|
||||
`Agent loading error: ${error.message}`,
|
||||
);
|
||||
}
|
||||
for (const agent of projectAgents.agents) {
|
||||
this.registerAgent(agent);
|
||||
}
|
||||
await Promise.allSettled(
|
||||
projectAgents.agents.map((agent) => this.registerAgent(agent)),
|
||||
);
|
||||
} else {
|
||||
coreEvents.emitFeedback(
|
||||
'info',
|
||||
@@ -135,20 +141,22 @@ export class AgentRegistry {
|
||||
CodebaseInvestigatorAgent.runConfig.max_turns,
|
||||
},
|
||||
};
|
||||
this.registerAgent(agentDef);
|
||||
this.registerLocalAgent(agentDef);
|
||||
}
|
||||
|
||||
// Register the introspection agent if it's explicitly enabled.
|
||||
if (introspectionSettings.enabled) {
|
||||
this.registerAgent(IntrospectionAgent);
|
||||
this.registerLocalAgent(IntrospectionAgent);
|
||||
}
|
||||
}
|
||||
|
||||
private refreshAgents(): void {
|
||||
private async refreshAgents(): Promise<void> {
|
||||
this.loadBuiltInAgents();
|
||||
for (const agent of this.agents.values()) {
|
||||
this.registerAgent(agent);
|
||||
}
|
||||
await Promise.allSettled(
|
||||
Array.from(this.agents.values()).map((agent) =>
|
||||
this.registerAgent(agent),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,9 +164,26 @@ export class AgentRegistry {
|
||||
* it will be overwritten, respecting the precedence established by the
|
||||
* initialization order.
|
||||
*/
|
||||
protected registerAgent<TOutput extends z.ZodTypeAny>(
|
||||
protected async registerAgent<TOutput extends z.ZodTypeAny>(
|
||||
definition: AgentDefinition<TOutput>,
|
||||
): Promise<void> {
|
||||
if (definition.kind === 'local') {
|
||||
this.registerLocalAgent(definition);
|
||||
} else if (definition.kind === 'remote') {
|
||||
await this.registerRemoteAgent(definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a local agent definition synchronously.
|
||||
*/
|
||||
protected registerLocalAgent<TOutput extends z.ZodTypeAny>(
|
||||
definition: AgentDefinition<TOutput>,
|
||||
): void {
|
||||
if (definition.kind !== 'local') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
if (!definition.name || !definition.description) {
|
||||
debugLogger.warn(
|
||||
@@ -175,37 +200,79 @@ export class AgentRegistry {
|
||||
|
||||
// Register model config.
|
||||
// TODO(12916): Migrate sub-agents where possible to static configs.
|
||||
if (definition.kind === 'local') {
|
||||
const modelConfig = definition.modelConfig;
|
||||
let model = modelConfig.model;
|
||||
if (model === 'inherit') {
|
||||
model = this.config.getModel();
|
||||
}
|
||||
const modelConfig = definition.modelConfig;
|
||||
let model = modelConfig.model;
|
||||
if (model === 'inherit') {
|
||||
model = this.config.getModel();
|
||||
}
|
||||
|
||||
const runtimeAlias: ModelConfigAlias = {
|
||||
modelConfig: {
|
||||
model,
|
||||
generateContentConfig: {
|
||||
temperature: modelConfig.temp,
|
||||
topP: modelConfig.top_p,
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingBudget: modelConfig.thinkingBudget ?? -1,
|
||||
},
|
||||
const runtimeAlias: ModelConfigAlias = {
|
||||
modelConfig: {
|
||||
model,
|
||||
generateContentConfig: {
|
||||
temperature: modelConfig.temp,
|
||||
topP: modelConfig.top_p,
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingBudget: modelConfig.thinkingBudget ?? -1,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
this.config.modelConfigService.registerRuntimeModelConfig(
|
||||
getModelConfigAlias(definition),
|
||||
runtimeAlias,
|
||||
this.config.modelConfigService.registerRuntimeModelConfig(
|
||||
getModelConfigAlias(definition),
|
||||
runtimeAlias,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a remote agent definition asynchronously.
|
||||
*/
|
||||
protected async registerRemoteAgent<TOutput extends z.ZodTypeAny>(
|
||||
definition: AgentDefinition<TOutput>,
|
||||
): Promise<void> {
|
||||
if (definition.kind !== 'remote') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
if (!definition.name || !definition.description) {
|
||||
debugLogger.warn(
|
||||
`[AgentRegistry] Skipping invalid agent definition. Missing name or description.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.agents.has(definition.name) && this.config.getDebugMode()) {
|
||||
debugLogger.log(`[AgentRegistry] Overriding agent '${definition.name}'`);
|
||||
}
|
||||
|
||||
// Log remote A2A agent registration for visibility.
|
||||
if (definition.kind === 'remote' && this.config.getDebugMode()) {
|
||||
debugLogger.log(
|
||||
`[AgentRegistry] Registered remote agent '${definition.name}' with card: ${definition.agentCardUrl}`,
|
||||
try {
|
||||
const clientManager = A2AClientManager.getInstance();
|
||||
const agentCard = await clientManager.loadAgent(
|
||||
definition.name,
|
||||
definition.agentCardUrl,
|
||||
);
|
||||
if (agentCard.skills && agentCard.skills.length > 0) {
|
||||
definition.description = agentCard.skills
|
||||
.map(
|
||||
(skill: { name: string; description: string }) =>
|
||||
`${skill.name}: ${skill.description}`,
|
||||
)
|
||||
.join('\n');
|
||||
}
|
||||
if (this.config.getDebugMode()) {
|
||||
debugLogger.log(
|
||||
`[AgentRegistry] Registered remote agent '${definition.name}' with card: ${definition.agentCardUrl}`,
|
||||
);
|
||||
}
|
||||
this.agents.set(definition.name, definition);
|
||||
} catch (e) {
|
||||
debugLogger.warn(
|
||||
`[AgentRegistry] Error loading A2A agent "${definition.name}":`,
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user