import { describe, it, expect, beforeEach, vi } from 'vitest'; import { AgentRegistry } from '../../../src/agent/registry.js'; import type { AgentInfo, AgentConfigFile } from '../../../src/agent/types.js'; // Mock config-loader vi.mock('../../../src/agent/config-loader.js', () => ({ loadAgentConfig: vi.fn(), })); // Mock presets vi.mock('../../../src/agent/presets/index.js', () => ({ presetAgents: { explore: { description: '代码探索 Agent', mode: 'subagent' as const, prompt: '你是代码探索助手', maxSteps: 5, }, 'code-reviewer': { description: '代码审查 Agent', mode: 'subagent' as const, prompt: '你是代码审查助手', }, build: { description: '构建 Agent', mode: 'all' as const, prompt: '你是构建助手', }, }, })); import { loadAgentConfig } from '../../../src/agent/config-loader.js'; describe('AgentRegistry - Agent 注册表', () => { let registry: AgentRegistry; beforeEach(() => { registry = new AgentRegistry(); vi.clearAllMocks(); vi.mocked(loadAgentConfig).mockResolvedValue(null); }); describe('init - 初始化', () => { it('初始化后注册预设 Agent', async () => { await registry.init('/test/project'); expect(registry.has('explore')).toBe(true); expect(registry.has('code-reviewer')).toBe(true); expect(registry.has('build')).toBe(true); }); it('初始化加载用户配置', async () => { const userConfig: AgentConfigFile = { defaults: { maxSteps: 20, }, agents: { 'custom-agent': { description: '自定义 Agent', mode: 'subagent', prompt: '你是自定义助手', }, }, }; vi.mocked(loadAgentConfig).mockResolvedValue(userConfig); await registry.init('/test/project'); expect(registry.has('custom-agent')).toBe(true); }); it('重复初始化只执行一次', async () => { await registry.init('/test/project'); await registry.init('/test/project'); expect(loadAgentConfig).toHaveBeenCalledTimes(1); }); }); describe('get - 获取 Agent', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('获取存在的 Agent', () => { const agent = registry.get('explore'); expect(agent).toBeDefined(); expect(agent?.name).toBe('explore'); expect(agent?.description).toBe('代码探索 Agent'); }); it('获取不存在的 Agent 返回 undefined', () => { const agent = registry.get('non-existent'); expect(agent).toBeUndefined(); }); it('获取的 Agent 应用全局配置', async () => { vi.mocked(loadAgentConfig).mockResolvedValue({ defaults: { maxSteps: 25, }, }); const newRegistry = new AgentRegistry(); await newRegistry.init('/test/project'); const agent = newRegistry.get('code-reviewer'); // code-reviewer 没有设置 maxSteps,应该使用全局默认值 expect(agent?.maxSteps).toBe(25); }); it('Agent 自己的配置优先于全局配置', async () => { vi.mocked(loadAgentConfig).mockResolvedValue({ defaults: { maxSteps: 25, }, }); const newRegistry = new AgentRegistry(); await newRegistry.init('/test/project'); const agent = newRegistry.get('explore'); // explore 设置了 maxSteps: 5 expect(agent?.maxSteps).toBe(5); }); }); describe('list - 列出 Agent', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('列出所有 Agent', () => { const agents = registry.list(); expect(agents.length).toBeGreaterThan(0); expect(agents.some(a => a.name === 'explore')).toBe(true); expect(agents.some(a => a.name === 'code-reviewer')).toBe(true); }); it('按 mode 过滤 Agent', () => { const subagents = registry.list('subagent'); expect(subagents.every(a => a.mode === 'subagent' || a.mode === 'all')).toBe(true); }); }); describe('listSubagents - 列出子 Agent', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('排除 primary-only 的 Agent', () => { const subagents = registry.listSubagents(); expect(subagents.every(a => a.mode !== 'primary')).toBe(true); }); }); describe('listPrimaryAgents - 列出主 Agent', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('排除 subagent-only 的 Agent', () => { const primaryAgents = registry.listPrimaryAgents(); expect(primaryAgents.every(a => a.mode !== 'subagent')).toBe(true); }); }); describe('register - 动态注册', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('注册新 Agent', () => { const newAgent: AgentInfo = { name: 'dynamic-agent', description: '动态注册的 Agent', mode: 'subagent', prompt: '你是动态 Agent', }; registry.register(newAgent); expect(registry.has('dynamic-agent')).toBe(true); expect(registry.get('dynamic-agent')?.description).toBe('动态注册的 Agent'); }); it('覆盖已有 Agent', () => { const updatedAgent: AgentInfo = { name: 'explore', description: '更新后的探索 Agent', mode: 'all', prompt: '更新后的提示', }; registry.register(updatedAgent); const agent = registry.get('explore'); expect(agent?.description).toBe('更新后的探索 Agent'); }); }); describe('remove - 移除 Agent', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('移除存在的 Agent', () => { const result = registry.remove('explore'); expect(result).toBe(true); expect(registry.has('explore')).toBe(false); }); it('移除不存在的 Agent 返回 false', () => { const result = registry.remove('non-existent'); expect(result).toBe(false); }); }); describe('has - 检查 Agent 是否存在', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('存在的 Agent 返回 true', () => { expect(registry.has('explore')).toBe(true); }); it('不存在的 Agent 返回 false', () => { expect(registry.has('non-existent')).toBe(false); }); }); describe('size - 获取 Agent 数量', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('返回正确的数量', () => { expect(registry.size).toBeGreaterThan(0); }); it('添加后数量增加', () => { const initialSize = registry.size; registry.register({ name: 'new-agent', description: 'New', mode: 'subagent', prompt: 'New agent', }); expect(registry.size).toBe(initialSize + 1); }); it('移除后数量减少', () => { const initialSize = registry.size; registry.remove('explore'); expect(registry.size).toBe(initialSize - 1); }); }); describe('getNames - 获取所有 Agent 名称', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('返回所有 Agent 名称', () => { const names = registry.getNames(); expect(names).toContain('explore'); expect(names).toContain('code-reviewer'); expect(names).toContain('build'); }); }); describe('getGlobalConfig - 获取全局配置', () => { it('无用户配置时返回 null', async () => { vi.mocked(loadAgentConfig).mockResolvedValue(null); await registry.init('/test/project'); expect(registry.getGlobalConfig()).toBeNull(); }); it('有用户配置时返回 defaults', async () => { vi.mocked(loadAgentConfig).mockResolvedValue({ defaults: { maxSteps: 30, model: { temperature: 0.5, }, }, }); const newRegistry = new AgentRegistry(); await newRegistry.init('/test/project'); const globalConfig = newRegistry.getGlobalConfig(); expect(globalConfig?.maxSteps).toBe(30); expect(globalConfig?.model?.temperature).toBe(0.5); }); }); describe('generateSubagentDescription - 生成子 Agent 描述', () => { beforeEach(async () => { await registry.init('/test/project'); }); it('生成包含所有子 Agent 的描述', () => { const description = registry.generateSubagentDescription(); expect(description).toContain('explore'); expect(description).toContain('代码探索'); }); it('无子 Agent 时返回提示信息', async () => { // 移除所有 Agent for (const name of registry.getNames()) { registry.remove(name); } const description = registry.generateSubagentDescription(); expect(description).toContain('没有可用'); }); }); }); describe('agentRegistry 单例', () => { it('导出单例实例', async () => { const { agentRegistry } = await import('../../../src/agent/registry.js'); expect(agentRegistry).toBeDefined(); expect(agentRegistry).toBeInstanceOf(AgentRegistry); }); });