ad5d30b262
- 新增 AgentManager 管理后台 Agent 生命周期 - Task 工具支持 run_in_background 参数实现后台执行 - Task 工具支持 model 参数选择 sonnet/opus/haiku 模型 - 新增 agent_output 工具查询后台 Agent 执行状态和结果 - 添加 AgentManager 和 AgentOutput 工具单元测试
161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||
import { agentOutputTool } from '../../../../src/tools/task/agent_output.js';
|
||
import { getAgentManager, resetAgentManager } from '../../../../src/agent/manager.js';
|
||
|
||
// Mock AgentExecutor - 使用延迟执行让测试更可控
|
||
vi.mock('../../../../src/agent/executor.js', () => ({
|
||
AgentExecutor: vi.fn().mockImplementation(() => ({
|
||
execute: vi.fn().mockImplementation(async () => {
|
||
await new Promise((r) => setTimeout(r, 50));
|
||
return {
|
||
success: true,
|
||
text: '任务完成结果',
|
||
steps: 3,
|
||
sessionId: 'test-session',
|
||
};
|
||
}),
|
||
})),
|
||
}));
|
||
|
||
describe('agentOutputTool - Agent 输出工具', () => {
|
||
beforeEach(() => {
|
||
vi.clearAllMocks();
|
||
resetAgentManager();
|
||
});
|
||
|
||
describe('工具定义', () => {
|
||
it('有正确的名称', () => {
|
||
expect(agentOutputTool.name).toBe('agent_output');
|
||
});
|
||
|
||
it('有正确的元数据', () => {
|
||
expect(agentOutputTool.metadata.category).toBe('agent');
|
||
expect(agentOutputTool.metadata.keywords).toContain('agent');
|
||
expect(agentOutputTool.metadata.keywords).toContain('output');
|
||
expect(agentOutputTool.metadata.keywords).toContain('background');
|
||
});
|
||
|
||
it('agent_id 参数是必须的', () => {
|
||
expect(agentOutputTool.parameters.agent_id.required).toBe(true);
|
||
});
|
||
|
||
it('block 和 timeout 参数是可选的', () => {
|
||
expect(agentOutputTool.parameters.block.required).toBe(false);
|
||
expect(agentOutputTool.parameters.timeout.required).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('execute - 执行', () => {
|
||
it('Agent 不存在时返回错误', async () => {
|
||
const result = await agentOutputTool.execute({
|
||
agent_id: 'non-existent-id',
|
||
});
|
||
|
||
expect(result.success).toBe(false);
|
||
expect(result.error).toContain('不存在');
|
||
});
|
||
|
||
it('返回 Agent 的状态', async () => {
|
||
const manager = getAgentManager();
|
||
const agentId = await manager.runInBackground(
|
||
{
|
||
name: 'test-agent',
|
||
description: '测试',
|
||
mode: 'subagent',
|
||
},
|
||
'测试任务',
|
||
'执行测试',
|
||
{
|
||
provider: 'anthropic',
|
||
apiKey: 'test',
|
||
model: 'test',
|
||
maxTokens: 1000,
|
||
systemPrompt: 'test',
|
||
},
|
||
{} as any,
|
||
{ parentSessionId: 'parent', workdir: '/test' }
|
||
);
|
||
|
||
// 立即查询(不阻塞)
|
||
const result = await agentOutputTool.execute({
|
||
agent_id: agentId,
|
||
block: false,
|
||
});
|
||
|
||
// 应该成功返回状态(可能是 running 或 completed)
|
||
expect(result.output).toBeDefined();
|
||
expect(result.metadata?.agentId).toBe(agentId);
|
||
});
|
||
|
||
it('阻塞等待后返回结果', async () => {
|
||
const manager = getAgentManager();
|
||
const agentId = await manager.runInBackground(
|
||
{
|
||
name: 'test-agent',
|
||
description: '测试',
|
||
mode: 'subagent',
|
||
},
|
||
'测试任务',
|
||
'执行测试',
|
||
{
|
||
provider: 'anthropic',
|
||
apiKey: 'test',
|
||
model: 'test',
|
||
maxTokens: 1000,
|
||
systemPrompt: 'test',
|
||
},
|
||
{} as any,
|
||
{ parentSessionId: 'parent', workdir: '/test' }
|
||
);
|
||
|
||
// 使用阻塞模式等待
|
||
const result = await agentOutputTool.execute({
|
||
agent_id: agentId,
|
||
block: true,
|
||
timeout: 5,
|
||
});
|
||
|
||
// 等待后应该有确定的状态
|
||
expect(result.metadata?.status).toBeDefined();
|
||
expect(['running', 'completed', 'failed']).toContain(result.metadata?.status);
|
||
});
|
||
|
||
it('返回包含正确字段的输出', async () => {
|
||
const manager = getAgentManager();
|
||
const agentId = await manager.runInBackground(
|
||
{
|
||
name: 'test-agent',
|
||
description: '测试',
|
||
mode: 'subagent',
|
||
},
|
||
'测试任务',
|
||
'执行测试',
|
||
{
|
||
provider: 'anthropic',
|
||
apiKey: 'test',
|
||
model: 'test',
|
||
maxTokens: 1000,
|
||
systemPrompt: 'test',
|
||
},
|
||
{} as any,
|
||
{ parentSessionId: 'parent', workdir: '/test' }
|
||
);
|
||
|
||
// 等待完成
|
||
await new Promise((r) => setTimeout(r, 200));
|
||
|
||
const result = await agentOutputTool.execute({
|
||
agent_id: agentId,
|
||
block: false,
|
||
});
|
||
|
||
// 检查返回了有效结果
|
||
expect(result.output).toBeDefined();
|
||
expect(result.metadata?.agentId).toBe(agentId);
|
||
expect(result.metadata?.agentName).toBe('test-agent');
|
||
// 状态应该是完成或失败(由于 mock,可能会失败)
|
||
expect(['completed', 'failed']).toContain(result.metadata?.status);
|
||
});
|
||
});
|
||
});
|