mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-26 13:04:49 -07:00
Implement support for subagents as extensions. (#16473)
This commit is contained in:
committed by
GitHub
parent
0f7a136612
commit
aa52462550
@@ -8,7 +8,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { AgentRegistry, getModelConfigAlias } from './registry.js';
|
||||
import { makeFakeConfig } from '../test-utils/config.js';
|
||||
import type { AgentDefinition, LocalAgentDefinition } from './types.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import type { Config, GeminiCLIExtension } from '../config/config.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import { coreEvents, CoreEvent } from '../utils/events.js';
|
||||
import { A2AClientManager } from './a2a-client-manager.js';
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
PREVIEW_GEMINI_MODEL_AUTO,
|
||||
} from '../config/models.js';
|
||||
import * as tomlLoader from './agentLoader.js';
|
||||
import { SimpleExtensionLoader } from '../utils/extensionLoader.js';
|
||||
|
||||
vi.mock('./agentLoader.js', () => ({
|
||||
loadAgentsFromDirectory: vi
|
||||
@@ -230,7 +231,7 @@ describe('AgentRegistry', () => {
|
||||
expect(registry.getDefinition('cli_help')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should NOT register CLI help agent if disabled', async () => {
|
||||
it('should register CLI help agent if disabled', async () => {
|
||||
const config = makeFakeConfig({
|
||||
cliHelpAgentSettings: { enabled: false },
|
||||
});
|
||||
@@ -240,6 +241,59 @@ describe('AgentRegistry', () => {
|
||||
|
||||
expect(registry.getDefinition('cli_help')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should load agents from active extensions', async () => {
|
||||
const extensionAgent = {
|
||||
...MOCK_AGENT_V1,
|
||||
name: 'extension-agent',
|
||||
};
|
||||
const extensions: GeminiCLIExtension[] = [
|
||||
{
|
||||
name: 'test-extension',
|
||||
isActive: true,
|
||||
agents: [extensionAgent],
|
||||
version: '1.0.0',
|
||||
path: '/path/to/extension',
|
||||
contextFiles: [],
|
||||
id: 'test-extension-id',
|
||||
},
|
||||
];
|
||||
const mockConfig = makeFakeConfig({
|
||||
extensionLoader: new SimpleExtensionLoader(extensions),
|
||||
enableAgents: true,
|
||||
});
|
||||
const registry = new TestableAgentRegistry(mockConfig);
|
||||
|
||||
await registry.initialize();
|
||||
|
||||
expect(registry.getDefinition('extension-agent')).toEqual(extensionAgent);
|
||||
});
|
||||
|
||||
it('should NOT load agents from inactive extensions', async () => {
|
||||
const extensionAgent = {
|
||||
...MOCK_AGENT_V1,
|
||||
name: 'extension-agent',
|
||||
};
|
||||
const extensions: GeminiCLIExtension[] = [
|
||||
{
|
||||
name: 'test-extension',
|
||||
isActive: false,
|
||||
agents: [extensionAgent],
|
||||
version: '1.0.0',
|
||||
path: '/path/to/extension',
|
||||
contextFiles: [],
|
||||
id: 'test-extension-id',
|
||||
},
|
||||
];
|
||||
const mockConfig = makeFakeConfig({
|
||||
extensionLoader: new SimpleExtensionLoader(extensions),
|
||||
});
|
||||
const registry = new TestableAgentRegistry(mockConfig);
|
||||
|
||||
await registry.initialize();
|
||||
|
||||
expect(registry.getDefinition('extension-agent')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('registration logic', () => {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { CliHelpAgent } from './cli-help-agent.js';
|
||||
import { A2AClientManager } from './a2a-client-manager.js';
|
||||
import { ADCHandler } from './remote-invocation.js';
|
||||
import { type z } from 'zod';
|
||||
import type { GenerateContentConfig } from '@google/genai';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import {
|
||||
DEFAULT_GEMINI_MODEL,
|
||||
@@ -120,6 +121,15 @@ export class AgentRegistry {
|
||||
);
|
||||
}
|
||||
|
||||
// Load agents from extensions
|
||||
for (const extension of this.config.getExtensions()) {
|
||||
if (extension.isActive && extension.agents) {
|
||||
await Promise.allSettled(
|
||||
extension.agents.map((agent) => this.registerAgent(agent)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.config.getDebugMode()) {
|
||||
debugLogger.log(
|
||||
`[AgentRegistry] Loaded with ${this.agents.size} agents.`,
|
||||
@@ -233,7 +243,7 @@ export class AgentRegistry {
|
||||
model = this.config.getModel();
|
||||
}
|
||||
|
||||
const generateContentConfig = {
|
||||
const generateContentConfig: GenerateContentConfig = {
|
||||
temperature: modelConfig.temp,
|
||||
topP: modelConfig.top_p,
|
||||
thinkingConfig: {
|
||||
|
||||
@@ -101,6 +101,7 @@ import { ExperimentFlags } from '../code_assist/experiments/flagNames.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import { SkillManager, type SkillDefinition } from '../skills/skillManager.js';
|
||||
import { startupProfiler } from '../telemetry/startupProfiler.js';
|
||||
import type { AgentDefinition } from '../agents/types.js';
|
||||
|
||||
export interface AccessibilitySettings {
|
||||
disableLoadingPhrases?: boolean;
|
||||
@@ -178,6 +179,7 @@ export interface GeminiCLIExtension {
|
||||
settings?: ExtensionSetting[];
|
||||
resolvedSettings?: ResolvedExtensionSetting[];
|
||||
skills?: SkillDefinition[];
|
||||
agents?: AgentDefinition[];
|
||||
}
|
||||
|
||||
export interface ExtensionInstallMetadata {
|
||||
|
||||
@@ -126,6 +126,7 @@ export * from './prompts/mcp-prompts.js';
|
||||
|
||||
// Export agent definitions
|
||||
export * from './agents/types.js';
|
||||
export * from './agents/agentLoader.js';
|
||||
|
||||
// Export specific tool logic
|
||||
export * from './tools/read-file.js';
|
||||
|
||||
Reference in New Issue
Block a user