Files
ai-terminal-assistant/tests/unit/tools/task/task-extended.test.ts
T
kurihada f8b0cd4bec test: 补充 task、copy_file、skill_search 工具测试
- task-extended.test.ts: 覆盖 Vision Agent、模型选择、后台运行
- copy_file-extended.test.ts: 覆盖递归复制、权限检查边界情况
- skill_search-extended.test.ts: 覆盖来源标记、未分类分组、参数显示

覆盖率提升:
- task.ts: 97.91%
- copy_file.ts: 100%
- skill_search.ts: 98.61%
2025-12-11 20:33:14 +08:00

381 lines
10 KiB
TypeScript

import { describe, it, expect, beforeEach, vi } from 'vitest';
// 可变状态
let mockExecuteResult = {
success: true,
text: '任务完成',
steps: 3,
};
let mockVisionConfig: { provider: string; apiKey: string; model: string; baseUrl?: string } | null = null;
let mockRunInBackgroundResult = 'agent-123';
// Mock loadVisionConfig
vi.mock('../../../../src/utils/config.js', () => ({
loadVisionConfig: () => mockVisionConfig,
}));
// Mock agent manager
vi.mock('../../../../src/agent/manager.js', () => ({
getAgentManager: () => ({
runInBackground: vi.fn(async () => mockRunInBackgroundResult),
}),
}));
// Mock agent registry 和 AgentExecutor
vi.mock('../../../../src/agent/index.js', () => ({
agentRegistry: {
listSubagents: vi.fn(() => [
{ name: 'explore', description: '代码探索', mode: 'subagent' },
{ name: 'vision', description: '图片分析', mode: 'subagent' },
]),
get: vi.fn(),
},
AgentExecutor: class {
execute() {
return Promise.resolve(mockExecuteResult);
}
},
}));
// Mock tool registry
vi.mock('../../../../src/tools/registry.js', () => ({
toolRegistry: {},
}));
// Mock session manager
vi.mock('../../../../src/session/index.js', () => ({
SessionManager: vi.fn(),
}));
import { taskTool, initTaskContext, getTaskContext } from '../../../../src/tools/task/task.js';
import { agentRegistry } from '../../../../src/agent/index.js';
describe('taskTool - 扩展测试', () => {
const createMockSession = () => ({
getSessionId: vi.fn(() => 'parent-session'),
createChildSession: vi.fn(() => ({
id: 'child-session',
messages: [],
})),
saveChildSession: vi.fn(),
});
beforeEach(() => {
vi.clearAllMocks();
initTaskContext(null as any, null as any);
mockExecuteResult = {
success: true,
text: '任务完成',
steps: 3,
};
mockVisionConfig = null;
mockRunInBackgroundResult = 'agent-123';
});
describe('getTaskContext', () => {
it('返回上下文', () => {
initTaskContext({ model: 'test' } as any, { sessionManager: true } as any);
expect(getTaskContext()).not.toBeNull();
});
it('初始化 null 时返回包含 null 的对象', () => {
initTaskContext(null as any, null as any);
const ctx = getTaskContext();
expect(ctx?.baseConfig).toBeNull();
expect(ctx?.sessionManager).toBeNull();
});
});
describe('Vision Agent 处理', () => {
it('Vision Agent 无配置时返回错误', async () => {
mockVisionConfig = null;
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'vision',
description: '图片分析 Agent',
mode: 'subagent',
prompt: '你是视觉助手',
});
const result = await taskTool.execute({
description: 'analyze image',
prompt: '分析图片',
subagent_type: 'vision',
});
expect(result.success).toBe(false);
expect(result.error).toContain('Vision Agent 需要配置');
});
it('Vision Agent 有配置时成功执行', async () => {
mockVisionConfig = {
provider: 'openai',
apiKey: 'vision-key',
model: 'gpt-4o',
};
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'vision',
description: '图片分析 Agent',
mode: 'subagent',
prompt: '你是视觉助手',
});
const result = await taskTool.execute({
description: 'analyze image',
prompt: '分析图片',
subagent_type: 'vision',
});
expect(result.success).toBe(true);
});
});
describe('模型选择', () => {
it('无效模型选择返回错误', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
model: 'invalid-model',
});
expect(result.success).toBe(false);
expect(result.error).toContain('无效的模型选择');
expect(result.error).toContain('sonnet, opus, haiku');
});
it('sonnet 模型选择有效', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'original-model' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
model: 'sonnet',
});
expect(result.success).toBe(true);
});
it('opus 模型选择有效', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'original-model' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
model: 'opus',
});
expect(result.success).toBe(true);
});
it('haiku 模型选择有效', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'original-model' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
model: 'haiku',
});
expect(result.success).toBe(true);
});
});
describe('后台运行模式', () => {
it('后台运行返回 agentId', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'background task',
prompt: 'do something',
subagent_type: 'explore',
run_in_background: true,
});
expect(result.success).toBe(true);
expect(result.output).toContain('agent-123');
expect(result.output).toContain('后台启动');
expect(result.metadata?.mode).toBe('background');
});
it('sessionId 不存在时使用 standalone', async () => {
const mockSession = {
getSessionId: vi.fn(() => null),
createChildSession: vi.fn(() => ({
id: 'child-session',
messages: [],
})),
saveChildSession: vi.fn(),
};
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'background task',
prompt: 'do something',
subagent_type: 'explore',
run_in_background: true,
});
expect(result.success).toBe(true);
});
});
describe('同步执行模式元数据', () => {
it('同步模式返回正确 metadata', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
});
expect(result.metadata?.mode).toBe('sync');
});
it('失败时也返回 metadata', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
mockExecuteResult = {
success: false,
text: '',
steps: 1,
};
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
});
expect(result.success).toBe(false);
expect(result.metadata).toBeDefined();
expect(result.metadata?.mode).toBe('sync');
});
it('失败时没有 error 消息时使用默认消息', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
mockExecuteResult = {
success: false,
text: '',
steps: 1,
// 没有 error 字段
} as any;
const result = await taskTool.execute({
description: 'test',
prompt: 'test',
subagent_type: 'explore',
});
expect(result.success).toBe(false);
expect(result.error).toBe('子任务执行失败');
});
});
describe('图片传递', () => {
it('同步模式传递图片', async () => {
const mockSession = createMockSession();
initTaskContext({ model: 'test' } as any, mockSession as any);
vi.mocked(agentRegistry.get).mockReturnValue({
name: 'explore',
description: '探索 Agent',
mode: 'subagent',
prompt: '你是探索助手',
});
const result = await taskTool.execute({
description: 'analyze images',
prompt: 'describe these',
subagent_type: 'explore',
images: [{ data: 'base64data', mimeType: 'image/png' }],
});
expect(result.success).toBe(true);
});
});
});