Files
beaver_project/app-instance/frontend/lib/office.test.ts
steven_li 29dfd14aa6 ```
feat(agent): 添加对持久化子智能体的支持并增强委派管理

添加了持久化子智能体的完整生命周期管理功能,包括创建、更新、删除和查询API接口。
新增了子智能体的JSON-RPC通信协议支持,实现了远程调用和任务管理功能。

同时增强了委派管理器的功能:
- 添加了对本地委派、插件委派和本地回退的开关控制
- 实现了持久化子智能体任务的自动检测和本地执行保护
- 增加了对不同委派类型的权限验证机制

修改了智能体注册表以支持插件智能体的条件性包含,并更新了工具注册逻辑以支持可选工具。

BREAKING CHANGE: 委派管理器的构造函数签名已更改,添加了新的控制参数。
```
2026-03-27 10:15:35 +08:00

228 lines
6.6 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { buildOfficeTaskList, buildOfficeView } from '@/lib/office';
import type { ProcessArtifact, ProcessEvent, ProcessRun, Session } from '@/types';
describe('office view builders', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-03-24T12:00:00.000Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('builds an office view from a root run tree', () => {
const sessions: Session[] = [
{
key: 'web:default',
path: '需求讨论',
created_at: '2026-03-24T09:55:00.000Z',
updated_at: '2026-03-24T10:10:00.000Z',
},
];
const processRuns: ProcessRun[] = [
{
run_id: 'run-root',
parent_run_id: null,
session_id: 'web:default',
actor_type: 'agent',
actor_id: 'main-agent',
actor_name: '主 Agent',
title: '整理竞品研究并给出结论',
status: 'running',
started_at: '2026-03-24T10:00:00.000Z',
metadata: {
stage_label: '分析结果',
},
},
{
run_id: 'run-sub-agent',
parent_run_id: 'run-root',
session_id: 'web:default',
actor_type: 'agent',
actor_id: 'research-agent',
actor_name: 'Research Agent',
title: '收集竞品资料',
status: 'done',
started_at: '2026-03-24T10:01:00.000Z',
finished_at: '2026-03-24T10:04:00.000Z',
summary: '已完成资料收集',
},
{
run_id: 'run-sub-mcp',
parent_run_id: 'run-root',
session_id: 'web:default',
actor_type: 'mcp',
actor_id: 'search-mcp',
actor_name: 'Search MCP',
title: '抓取公开资料',
status: 'running',
started_at: '2026-03-24T10:02:00.000Z',
},
];
const processEvents: ProcessEvent[] = [
{
event_id: 'evt-1',
run_id: 'run-root',
parent_run_id: null,
kind: 'run_progress',
actor_type: 'agent',
actor_id: 'main-agent',
actor_name: '主 Agent',
text: '开始归纳公开信息',
created_at: '2026-03-24T10:03:00.000Z',
metadata: {
stage_label: '分析结果',
},
},
{
event_id: 'evt-2',
run_id: 'run-sub-agent',
parent_run_id: 'run-root',
kind: 'run_finished',
actor_type: 'agent',
actor_id: 'research-agent',
actor_name: 'Research Agent',
text: '资料整理完成',
status: 'done',
created_at: '2026-03-24T10:04:00.000Z',
},
{
event_id: 'evt-3',
run_id: 'run-sub-mcp',
parent_run_id: 'run-root',
kind: 'run_progress',
actor_type: 'mcp',
actor_id: 'search-mcp',
actor_name: 'Search MCP',
text: '正在搜索公开网页',
created_at: '2026-03-24T10:05:00.000Z',
},
];
const processArtifacts: ProcessArtifact[] = [
{
artifact_id: 'artifact-1',
run_id: 'run-sub-agent',
actor_type: 'agent',
actor_id: 'research-agent',
actor_name: 'Research Agent',
title: '竞品清单',
artifact_type: 'markdown',
content: '- A\n- B',
created_at: '2026-03-24T10:04:30.000Z',
},
];
const office = buildOfficeView('run-root', {
sessions,
processRuns,
processEvents,
processArtifacts,
});
expect(office).not.toBeNull();
expect(office?.taskId).toBe('run-root');
expect(office?.title).toBe('整理竞品研究并给出结论');
expect(office?.sourceSessionLabel).toBe('需求讨论');
expect(office?.members).toHaveLength(3);
expect(office?.tasks).toHaveLength(3);
expect(office?.assignments).toHaveLength(1);
expect(office?.progress.label).toBe('已完成子任务 1 / 3');
expect(office?.currentStageLabel).toBe('分析结果');
expect(office?.stats.artifactCount).toBe(1);
expect(office?.zones.find((zone) => zone.id === 'workspace')?.memberIds).toContain('main-agent');
expect(office?.zones.find((zone) => zone.id === 'collab')?.memberIds).toContain('research-agent');
expect(office?.zones.find((zone) => zone.id === 'research')?.memberIds).toContain('search-mcp');
});
it('marks stale waiting tasks as blocked and emits alerts', () => {
const processRuns: ProcessRun[] = [
{
run_id: 'run-blocked',
parent_run_id: null,
session_id: 'web:default',
actor_type: 'agent',
actor_id: 'main-agent',
actor_name: '主 Agent',
title: '等待下游结果',
status: 'waiting',
started_at: '2026-03-24T09:00:00.000Z',
},
];
const office = buildOfficeView('run-blocked', {
sessions: [],
processRuns,
processEvents: [],
processArtifacts: [],
});
expect(office?.status).toBe('blocked');
expect(office?.alerts).toHaveLength(1);
expect(office?.alerts[0].level).toBe('warn');
expect(office?.members[0].zoneId).toBe('collab');
});
it('builds a filtered task list and sorts active tasks ahead of finished ones', () => {
const sessions: Session[] = [
{ key: 'web:alpha', path: 'Alpha Session' },
{ key: 'web:beta', path: 'Beta Session' },
];
const processRuns: ProcessRun[] = [
{
run_id: 'run-active',
parent_run_id: null,
session_id: 'web:alpha',
actor_type: 'agent',
actor_id: 'agent-a',
actor_name: 'Agent A',
title: '执行活跃任务',
status: 'running',
started_at: '2026-03-24T11:20:00.000Z',
},
{
run_id: 'run-done',
parent_run_id: null,
session_id: 'web:alpha',
actor_type: 'agent',
actor_id: 'agent-b',
actor_name: 'Agent B',
title: '已结束任务',
status: 'done',
started_at: '2026-03-24T10:00:00.000Z',
finished_at: '2026-03-24T10:08:00.000Z',
},
{
run_id: 'run-other-session',
parent_run_id: null,
session_id: 'web:beta',
actor_type: 'agent',
actor_id: 'agent-c',
actor_name: 'Agent C',
title: '其他会话任务',
status: 'running',
started_at: '2026-03-24T11:00:00.000Z',
},
];
const tasks = buildOfficeTaskList({
sessionId: 'web:alpha',
sessions,
processRuns,
processEvents: [],
processArtifacts: [],
});
expect(tasks).toHaveLength(2);
expect(tasks[0].taskId).toBe('run-active');
expect(tasks[1].taskId).toBe('run-done');
expect(tasks[0].sessionLabel).toBe('Alpha Session');
});
});