# Phase 10：高级编排（Advanced Orchestration）

日期：2026-04-04
状态：待开始
前置依赖：Phase 6-9（工具系统、Hook、插件、Skills）
Demo参考：claw-code-main — assistant/, cli/, structuredIO.ts, remoteIO.ts

---

## 1. 阶段目标

实现**高级 Agent 编排能力**，包括：
- Team 多 Agent 协作
- 远程/结构化传输
- 高级会话管理
- 后台任务系统

这是 claw-code 与 Jarvis 架构差距最大的地方，也是最复杂的功能。

---

## 2. Team 多 Agent 协作

### 2.1 TeamLeader

```python
# backend/app/agents/team/leader.py

@dataclass
class TeamMember:
    """团队成员"""
    agent_id: str
    role: str
    capabilities: list[str]
    status: AgentStatus
    current_task: str | None = None

@dataclass
class TeamTask:
    """团队任务"""
    task_id: str
    description: str
    parent_id: str | None = None
    assignee: str | None = None
    status: TaskStatus
    dependencies: list[str] = field(default_factory=list)
    result: Any = None

class TeamLeader:
    """
    团队领导者
    
    负责协调多个 Agent 的协作
    """
    
    def __init__(
        self,
        team_id: str,
        tool_registry: ToolRegistry,
        hook_manager: HookManager
    ):
        self.team_id = team_id
        self.tool_registry = tool_registry
        self.hook_manager = hook_manager
        
        self.members: dict[str, TeamMember] = {}
        self.tasks: dict[str, TeamTask] = {}
        self.task_queue: asyncio.Queue = asyncio.Queue()
    
    async def create_team(
        self,
        config: TeamConfig
    ) -> str:
        """创建团队"""
        self.team_id = config.team_id
        
        # 创建团队成员
        for member_config in config.members:
            member = TeamMember(
                agent_id=member_config.agent_id,
                role=member_config.role,
                capabilities=member_config.capabilities,
                status=AgentStatus.IDLE
            )
            self.members[member.agent_id] = member
        
        return self.team_id
    
    async def assign_task(
        self,
        task: TeamTask
    ) -> str:
        """分配任务"""
        self.tasks[task.task_id] = task
        
        # 找到最合适的成员
        assignee = await self._find_assignee(task)
        
        if assignee:
            task.assignee = assignee.agent_id
            assignee.current_task = task.task_id
            assignee.status = AgentStatus.WORKING
        
        return task.task_id
    
    async def _find_assignee(
        self,
        task: TeamTask
    ) -> TeamMember | None:
        """找到最适合执行任务的成员"""
        # 过滤掉忙碌的成员
        available = [
            m for m in self.members.values()
            if m.status == AgentStatus.IDLE
        ]
        
        if not available:
            return None
        
        # 按能力匹配
        for cap in task.required_capabilities:
            matches = [m for m in available if cap in m.capabilities]
            if matches:
                return matches[0]
        
        return available[0] if available else None
    
    async def broadcast_task(
        self,
        description: str,
        required_capabilities: list[str]
    ) -> list[str]:
        """广播任务给所有符合条件的成员"""
        task_ids = []
        
        for member in self.members.values():
            if member.status != AgentStatus.IDLE:
                continue
            
            # 检查能力匹配
            if not any(cap in member.capabilities for cap in required_capabilities):
                continue
            
            # 创建任务
            task = TeamTask(
                task_id=generate_id(),
                description=description,
                assignee=member.agent_id,
                status=TaskStatus.PENDING
            )
            
            await self.assign_task(task)
            task_ids.append(task.task_id)
        
        return task_ids
    
    async def collect_results(
        self,
        task_ids: list[str],
        timeout: float = 300
    ) -> dict[str, Any]:
        """收集任务结果"""
        results = {}
        start_time = time.time()
        
        while len(results) < len(task_ids):
            if time.time() - start_time > timeout:
                break
            
            for task_id in task_ids:
                if task_id in results:
                    continue
                
                task = self.tasks.get(task_id)
                if task and task.status == TaskStatus.COMPLETED:
                    results[task_id] = task.result
            
            await asyncio.sleep(0.1)
        
        return results
    
    async def get_team_status(self) -> TeamStatus:
        """获取团队状态"""
        return TeamStatus(
            team_id=self.team_id,
            members={
                agent_id: {
                    "role": m.role,
                    "status": m.status.value,
                    "current_task": m.current_task
                }
                for agent_id, m in self.members.items()
            },
            active_tasks=sum(1 for t in self.tasks.values() if t.status == TaskStatus.PENDING),
            completed_tasks=sum(1 for t in self.tasks.values() if t.status == TaskStatus.COMPLETED)
        )
```

---

## 3. 远程传输层

### 3.1 StructuredIO

```python
# backend/app/agents/transport/structured_io.py

class StructuredIO:
    """
    结构化 IO
    
    支持结构化的输入输出格式
    """
    
    async def send_response(
        self,
        channel: str,
        data: dict
    ):
        """发送结构化响应"""
        message = {
            "channel": channel,
            "type": "structured",
            "data": data,
            "timestamp": datetime.now().isoformat()
        }
        await self.transport.send(message)
    
    async def send_event(
        self,
        event_type: str,
        payload: dict
    ):
        """发送事件"""
        message = {
            "type": "event",
            "event": event_type,
            "payload": payload,
            "timestamp": datetime.now().isoformat()
        }
        await self.transport.send(message)
    
    async def send_tool_call(
        self,
        tool_name: str,
        arguments: dict,
        call_id: str
    ):
        """发送工具调用"""
        message = {
            "type": "tool_call",
            "tool": tool_name,
            "args": arguments,
            "call_id": call_id,
            "timestamp": datetime.now().isoformat()
        }
        await self.transport.send(message)
    
    async def receive(self) -> dict:
        """接收消息"""
        raw = await self.transport.receive()
        return self._parse(raw)
    
    def _parse(self, raw: bytes) -> dict:
        """解析消息"""
        # 支持 JSON 和流式格式
        pass
```

### 3.2 RemoteTransport

```python
# backend/app/agents/transport/remote.py

class RemoteTransport:
    """
    远程传输
    
    支持远程 Agent 通信
    """
    
    def __init__(
        self,
        endpoint: str,
        auth_token: str
    ):
        self.endpoint = endpoint
        self.auth_token = auth_token
        self.websocket: WebSocket | None = None
    
    async def connect(self):
        """建立连接"""
        self.websocket = await websockets.connect(
            self.endpoint,
            extra_headers={"Authorization": f"Bearer {self.auth_token}"}
        )
    
    async def send(self, message: dict):
        """发送消息"""
        if not self.websocket:
            await self.connect()
        
        await self.websocket.send(json.dumps(message))
    
    async def receive(self) -> dict:
        """接收消息"""
        if not self.websocket:
            await self.connect()
        
        raw = await self.websocket.recv()
        return json.loads(raw)
    
    async def close(self):
        """关闭连接"""
        if self.websocket:
            await self.websocket.close()
```

---

## 4. 高级会话管理

### 4.1 AgentSession

```python
# backend/app/agents/session/manager.py

@dataclass
class SessionConfig:
    """会话配置"""
    session_id: str
    user_id: str
    parent_session_id: str | None = None
    
    max_rounds: int = 50
    max_tokens: int = 100000
    timeout: float = 3600
    
    isolation_mode: IsolationMode = IsolationMode.NONE
    
    capabilities: list[str] = field(default_factory=list)
    permissions: list[str] = field(default_factory=list)

class AgentSession:
    """
    Agent 会话
    
    管理会话的生命周期和状态
    """
    
    def __init__(
        self,
        config: SessionConfig,
        agent_runtime: AgentRuntime
    ):
        self.config = config
        self.agent_runtime = agent_runtime
        
        self.state: SessionState = SessionState.INITIALIZING
        self.round_count: int = 0
        self.token_count: int = 0
        
        self.messages: list[Message] = []
        self.tool_calls: list[ToolCall] = []
        self.events: list[SessionEvent] = []
    
    async def initialize(self) -> str:
        """初始化会话"""
        # 创建会话记录
        await self._create_session_record()
        
        # 初始化隔离环境
        if self.config.isolation_mode != IsolationMode.NONE:
            await self._initialize_isolation()
        
        self.state = SessionState.ACTIVE
        return self.config.session_id
    
    async def process_message(
        self,
        message: str
    ) -> Response:
        """处理消息"""
        if self.state != SessionState.ACTIVE:
            raise SessionStateError(f"Session not active: {self.state}")
        
        # 检查轮次限制
        self.round_count += 1
        if self.round_count > self.config.max_rounds:
            raise SessionLimitError("Max rounds exceeded")
        
        # 处理消息
        response = await self.agent_runtime.process(
            message,
            context=self._get_context()
        )
        
        # 记录
        self.messages.append(Message(role="user", content=message))
        self.messages.append(Message(role="assistant", content=response.content))
        
        # 更新 token 计数
        self.token_count += response.usage.total_tokens
        
        return response
    
    async def spawn_child_session(
        self,
        config: SessionConfig
    ) -> "AgentSession":
        """创建子会话"""
        child_config = SessionConfig(
            **{
                **asdict(config),
                "parent_session_id": self.config.session_id
            }
        )
        
        child_session = AgentSession(
            config=child_config,
            agent_runtime=self.agent_runtime
        )
        
        await child_session.initialize()
        
        return child_session
    
    async def get_session_summary(self) -> SessionSummary:
        """获取会话摘要"""
        return SessionSummary(
            session_id=self.config.session_id,
            user_id=self.config.user_id,
            round_count=self.round_count,
            token_count=self.token_count,
            message_count=len(self.messages),
            tool_call_count=len(self.tool_calls),
            duration_seconds=(datetime.now() - self.start_time).total_seconds(),
            state=self.state.value
        )
    
    async def persist(self):
        """持久化会话"""
        await self.session_service.save(SessionRecord(
            session_id=self.config.session_id,
            user_id=self.config.user_id,
            state=self.state.value,
            round_count=self.round_count,
            token_count=self.token_count,
            messages=self.messages,
            tool_calls=self.tool_calls,
            events=self.events
        ))
```

---

## 5. 后台任务系统

### 5.1 BackgroundTaskManager

```python
# backend/app/agents/background/manager.py

@dataclass
class BackgroundTask:
    """后台任务"""
    task_id: str
    description: str
    agent_config: dict
    schedule: str | None = None  # cron expression
    
    status: BackgroundTaskStatus
    created_at: datetime
    started_at: datetime | None = None
    completed_at: datetime | None = None
    
    result: Any = None
    error: str | None = None

class BackgroundTaskManager:
    """
    后台任务管理器
    
    管理长期运行的 Agent 任务
    """
    
    def __init__(
        self,
        task_store: TaskStore,
        agent_factory: AgentFactory
    ):
        self.task_store = task_store
        self.agent_factory = agent_factory
        
        self._running_tasks: dict[str, asyncio.Task] = {}
        self._scheduler = AsyncIOScheduler()
    
    async def submit_task(
        self,
        task: BackgroundTask
    ) -> str:
        """提交后台任务"""
        # 保存任务记录
        await self.task_store.save(task)
        
        # 如果有定时计划，调度任务
        if task.schedule:
            self._scheduler.add_job(
                self._execute_task,
                CronTrigger.from_crontab(task.schedule),
                args=[task.task_id]
            )
        else:
            # 立即执行
            asyncio.create_task(self._execute_task(task.task_id))
        
        return task.task_id
    
    async def _execute_task(self, task_id: str):
        """执行任务"""
        task = await self.task_store.get(task_id)
        if not task:
            return
        
        self._running_tasks[task_id] = asyncio.current_task()
        
        task.status = BackgroundTaskStatus.RUNNING
        task.started_at = datetime.now()
        await self.task_store.save(task)
        
        try:
            # 创建 Agent
            agent = await self.agent_factory.create(task.agent_config)
            
            # 执行
            result = await agent.run()
            
            task.status = BackgroundTaskStatus.COMPLETED
            task.result = result
            
        except Exception as e:
            task.status = BackgroundTaskStatus.FAILED
            task.error = str(e)
        
        finally:
            task.completed_at = datetime.now()
            await self.task_store.save(task)
            
            if task_id in self._running_tasks:
                del self._running_tasks[task_id]
    
    async def cancel_task(self, task_id: str) -> bool:
        """取消任务"""
        if task_id in self._running_tasks:
            self._running_tasks[task_id].cancel()
            del self._running_tasks[task_id]
        
        task = await self.task_store.get(task_id)
        if task:
            task.status = BackgroundTaskStatus.CANCELLED
            await self.task_store.save(task)
        
        return True
    
    async def get_task_status(self, task_id: str) -> BackgroundTask | None:
        """获取任务状态"""
        return await self.task_store.get(task_id)
    
    async def list_tasks(
        self,
        user_id: str,
        status: BackgroundTaskStatus | None = None
    ) -> list[BackgroundTask]:
        """列出任务"""
        return await self.task_store.list(user_id, status)
```

---

## 6. 文件结构

```
backend/app/agents/
├── team/                  # Team 协作
│   ├── __init__.py
│   ├── leader.py          # 团队领导
│   ├── member.py         # 团队成员
│   └── task.py            # 团队任务
│
├── transport/             # 传输层
│   ├── __init__.py
│   ├── structured_io.py  # 结构化 IO
│   ├── remote.py         # 远程传输
│   └── websocket.py      # WebSocket 传输
│
├── session/              # 会话管理
│   ├── __init__.py
│   ├── manager.py        # 会话管理器
│   ├── context.py        # 会话上下文
│   └── persistence.py    # 会话持久化
│
├── background/          # 后台任务
│   ├── __init__.py
│   ├── manager.py       # 后台任务管理器
│   ├── scheduler.py     # 任务调度
│   └── executor.py      # 任务执行器
│
└── coordinator.py       # 协调整合（现有）
```

---

## 7. 验收标准

| 检查点 | 标准 |
|--------|------|
| Team 创建 | 可以创建和管理 Agent 团队 |
| Team 任务分配 | 任务能正确分配给合适的成员 |
| Team 结果收集 | 能收集和聚合多成员的结果 |
| 结构化 IO | 支持结构化的输入输出格式 |
| 远程传输 | 支持远程 Agent 通信 |
| 会话管理 | 支持复杂的会话层级和状态管理 |
| 后台任务 | 支持定时和异步后台任务 |
| 子会话 | 支持从父会话创建子会话 |

---

## 8. Demo 借鉴

| claw-code | Jarvis 对应 |
|-----------|------------|
| `src/assistant/sessionHistory.ts` | `session/manager.py` |
| `src/cli/structuredIO.ts` | `transport/structured_io.py` |
| `src/cli/remoteIO.ts` | `transport/remote.py` |
| `src/cli/transports/*` | `transport/` |
| Team/* tools | `team/leader.py` |
| Background tasks | `background/manager.py` |
