Skip to content

Latest commit

 

History

History
884 lines (693 loc) · 29.3 KB

File metadata and controls

884 lines (693 loc) · 29.3 KB

Claude Code v2.1.88 - Task System and Coordinator Mode

Architecture Diagram

Task System and Coordinator Architecture

1. Overview

Task 系统是 Claude Code 的后台工作管理核心,负责管理所有异步执行单元:Shell 命令、本地 Agent、远程 Agent、进程内 Teammate 和 Dream 内存整合。Coordinator 模式则在此之上提供多 Worker 编排能力,将 Claude Code 从单线程对话转变为并行任务调度器。

核心源码分布:

模块 路径 职责
基础类型 src/Task.ts TaskType、TaskStatus、TaskStateBase 定义
任务注册表 src/tasks.ts getAllTasks()、getTaskByType()
联合类型 src/tasks/types.ts TaskState 联合类型、isBackgroundTask 判定
框架工具 src/utils/task/framework.ts registerTask、updateTaskState、pollTasks
磁盘输出 src/utils/task/diskOutput.ts 任务输出文件管理
Coordinator src/coordinator/coordinatorMode.ts 协调者模式系统提示与配置
                    +-----------------------------+
                    |       AppState.tasks        |
                    |  Record<string, TaskState>  |
                    +-------------+---------------+
                                  |
        +----------+---------+---+---+-----------+---------+
        |          |         |       |           |         |
   LocalShell  LocalAgent  Remote  InProcess   Dream   Workflow
    (bash)     (subagent)  (cloud) (teammate)  (memory) (scripts)
        |          |         |       |           |
        v          v         v       v           v
     ShellCmd   query()    poll    runAgent   forkAgent
               (local)    (API)   (in-proc)  (consolidate)

2. Task 基础类型体系

2.1 TaskType 枚举

// src/Task.ts
export type TaskType =
  | 'local_bash'           // Shell 命令执行
  | 'local_agent'          // 本地 Agent 子进程
  | 'remote_agent'         // 云端远程 Agent
  | 'in_process_teammate'  // 进程内 Teammate (Swarm)
  | 'local_workflow'       // 工作流脚本 (feature-gated)
  | 'monitor_mcp'          // MCP 监控 (feature-gated)
  | 'dream'                // 内存整合 (auto-dream)

2.2 TaskStatus 生命周期

export type TaskStatus =
  | 'pending'    // 已注册,尚未启动
  | 'running'    // 正在执行
  | 'completed'  // 成功完成
  | 'failed'     // 执行失败
  | 'killed'     // 被用户/系统终止

状态转换图:

pending ──> running ──> completed
                   ├──> failed
                   └──> killed

isTerminalTaskStatus() 判定终态 (completed/failed/killed),终态任务不会再发生状态转换。

2.3 TaskStateBase

所有任务类型共享的基础字段:

export type TaskStateBase = {
  id: string           // 任务唯一 ID (前缀编码: b=bash, a=agent, r=remote, t=teammate, d=dream)
  type: TaskType       // 任务类型
  status: TaskStatus   // 当前状态
  description: string  // 人类可读描述
  toolUseId?: string   // 关联的 tool_use block ID
  startTime: number    // 创建时间戳
  endTime?: number     // 结束时间戳
  totalPausedMs?: number // 总暂停时间
  outputFile: string   // 磁盘输出文件路径
  outputOffset: number // 已上报的输出偏移量
  notified: boolean    // 是否已发送完成通知
}

2.4 Task ID 生成

每个任务类型有独立的前缀,后跟 8 位随机字符 (36^8 约 2.8 万亿组合):

const TASK_ID_PREFIXES: Record<string, string> = {
  local_bash: 'b',
  local_agent: 'a',
  remote_agent: 'r',
  in_process_teammate: 't',
  local_workflow: 'w',
  monitor_mcp: 'm',
  dream: 'd',
}

示例: a7k2m9x3f 表示一个 local_agent 任务。

2.5 Task 接口

export type Task = {
  name: string
  type: TaskType
  kill(taskId: string, setAppState: SetAppState): Promise<void>
}

kill 是唯一的多态方法。spawn 和 render 各任务类型独立实现,不走统一调度。

3. Task 类型层级详解

3.1 LocalShellTask (local_bash)

Shell 命令后台执行,由 BashTool 的 run_in_background 参数触发。

export type LocalShellTaskState = TaskStateBase & {
  type: 'local_bash'
  command: string                    // 执行的命令
  result?: { code: number; interrupted: boolean }
  shellCommand: ShellCommand | null  // 底层进程句柄
  isBackgrounded: boolean            // 是否已后台化
  agentId?: AgentId                  // 所属 Agent (用于孤儿清理)
  kind?: 'bash' | 'monitor'         // UI 显示变体
  lastReportedTotalLines: number     // 输出增量追踪
  completionStatusSentInAttachment: boolean
}

关键机制:

  • Stall Watchdog: 每 5 秒检查输出增长。若 45 秒无新输出且末行匹配交互式提示模式 ((y/n), Press Enter 等),自动发送 <task-notification> 通知模型
  • 孤儿清理: Agent 退出时,killShellTasksForAgent() 终止该 Agent 名下所有 Shell 任务
  • 前台/后台切换: isBackgrounded 标志控制是否显示在状态栏 pill 中

3.2 LocalAgentTask (local_agent)

本地 Agent 子进程,是最常用的并发任务类型。

export type LocalAgentTaskState = TaskStateBase & {
  type: 'local_agent'
  agentId: string                    // Agent 唯一标识
  prompt: string                     // 初始提示
  selectedAgent?: AgentDefinition    // Agent 定义
  agentType: string                  // Agent 类型名
  model?: string                     // 模型覆盖
  abortController?: AbortController  // 终止控制器
  error?: string
  result?: AgentToolResult           // 最终结果
  progress?: AgentProgress           // 实时进度
  isBackgrounded: boolean            // 后台标志
  pendingMessages: string[]          // SendMessage 队列
  retain: boolean                    // UI 持有标志 (阻止回收)
  diskLoaded: boolean                // 侧链加载状态
  evictAfter?: number                // 面板宽限期截止时间
  messages?: Message[]               // UI 显示用消息
}

进度追踪系统:

export type AgentProgress = {
  toolUseCount: number        // 工具调用计数
  tokenCount: number          // Token 消耗
  lastActivity?: ToolActivity // 最近活动
  recentActivities?: ToolActivity[] // 最近 5 条活动
  summary?: string            // 进度摘要
}

export type ProgressTracker = {
  toolUseCount: number
  latestInputTokens: number       // 最新输入 token (API 累计值)
  cumulativeOutputTokens: number  // 累计输出 token
  recentActivities: ToolActivity[]
}

消息队列机制: pendingMessages 数组在 tool-round 边界被 drainPendingMessages() 排空,实现 SendMessage 对运行中 Agent 的消息注入。

面板宽限期: 终态任务设置 evictAfter = Date.now() + 30_000 (PANEL_GRACE_MS),30 秒后才允许从 AppState 回收。

3.3 RemoteAgentTask (remote_agent)

云端远程 Agent,通过 Teleport API 执行,支持多种远程任务类型:

export type RemoteAgentTaskState = TaskStateBase & {
  type: 'remote_agent'
  remoteTaskType: RemoteTaskType     // 远程任务类型
  remoteTaskMetadata?: RemoteTaskMetadata
  sessionId: string                  // 远程会话 ID
  command: string
  title: string
  todoList: TodoList                 // 关联的待办列表
  log: SDKMessage[]                  // 消息日志
  isLongRunning?: boolean            // 长运行标志
  pollStartedAt: number              // 轮询起始时间
  isRemoteReview?: boolean           // 远程代码审查
  reviewProgress?: { ... }           // 审查进度
  isUltraplan?: boolean              // Ultraplan 标志
  ultraplanPhase?: UltraplanPhase    // Ultraplan 阶段
}

type RemoteTaskType = 'remote-agent' | 'ultraplan' | 'ultrareview' | 'autofix-pr' | 'background-pr'

关键机制:

  • 资格检查: 创建前通过 checkRemoteAgentEligibility() 验证: 已登录、有远程环境、在 Git 仓库中、有 GitHub remote、已安装 Claude GitHub App
  • 轮询恢复: pollStartedAt 记录轮询起始,--resume 恢复时从当前时刻重新计时,避免立即超时
  • 完成检查器: registerCompletionChecker() 注册按 RemoteTaskType 分发的回调,每个轮询周期执行
  • 元数据持久化: 通过 sidecar 文件持久化/删除远程 Agent 元数据,使会话恢复不会复活已完成任务
  • Ultraplan 阶段: pill 徽标根据 ultraplanPhase 显示不同状态 (running/needs_input/plan_ready)

3.4 InProcessTeammateTask (in_process_teammate)

进程内 Teammate,是 Swarm 系统的核心执行单元。与 LocalAgentTask 的关键区别:

export type InProcessTeammateTaskState = TaskStateBase & {
  type: 'in_process_teammate'
  identity: TeammateIdentity         // 团队身份
  prompt: string
  model?: string
  abortController?: AbortController  // 终止整个 Teammate
  currentWorkAbortController?: AbortController // 仅终止当前回合
  awaitingPlanApproval: boolean      // Plan 模式审批中
  permissionMode: PermissionMode     // 独立权限模式
  progress?: AgentProgress
  messages?: Message[]               // UI 显示用 (上限 50 条)
  pendingUserMessages: string[]      // 用户消息注入队列
  isIdle: boolean                    // 空闲状态 (等待工作)
  shutdownRequested: boolean         // 关闭请求标志
  onIdleCallbacks?: Array<() => void> // 空闲回调 (避免轮询)
}

export type TeammateIdentity = {
  agentId: string       // "researcher@my-team"
  agentName: string     // "researcher"
  teamName: string
  color?: string
  planModeRequired: boolean
  parentSessionId: string
}

内存管理:

// 消息 UI 缓冲上限 50 条 -- 鲸鱼会话 9a990de8 在 2 分钟内启动 292 个 agent 达到 36.8GB
export const TEAMMATE_MESSAGES_UI_CAP = 50

生命周期特点:

  • 双层 AbortController: abortController 杀死整个 Teammate, currentWorkAbortController 仅终止当前回合
  • 空闲/活跃切换: isIdle 标志配合 onIdleCallbacks 实现高效等待,无需轮询
  • Plan 模式: awaitingPlanApproval + planModeRequired 实现写代码前的审批流程

3.5 DreamTask (dream)

内存整合任务,对应 auto-dream 功能。纯 UI 展示层,让隐形的 fork agent 在状态栏可见。

export type DreamTaskState = TaskStateBase & {
  type: 'dream'
  phase: 'starting' | 'updating'     // 简单两阶段
  sessionsReviewing: number           // 审查的会话数
  filesTouched: string[]              // 已触及的文件路径
  turns: DreamTurn[]                  // 最近 30 个回合
  abortController?: AbortController
  priorMtime: number                  // 整合锁回滚用
}

export type DreamTurn = {
  text: string
  toolUseCount: number
}

杀死 DreamTask 时,通过 rollbackConsolidationLock(priorMtime) 回滚锁的 mtime,使下次会话可以重试。

3.6 LocalMainSessionTask (main-session)

主会话后台化任务,复用 LocalAgentTaskState 结构,以 agentType: 'main-session' 标记区分。

当用户按 Ctrl+B 两次时,当前会话被后台化:

  • 查询继续在后台运行
  • UI 清空为新提示符
  • 完成时发送 <task-notification>
export type LocalMainSessionTaskState = LocalAgentTaskState & {
  agentType: 'main-session'
}

isPanelAgentTask() 过滤器排除 main-session 任务,使其不出现在 Coordinator 面板中。

4. Task 框架核心

4.1 注册与状态更新

// src/utils/task/framework.ts

// 注册新任务到 AppState
function registerTask(task: TaskState, setAppState: SetAppState): void

// 类型安全的状态更新
function updateTaskState<T extends TaskState>(
  taskId: string,
  setAppState: SetAppState,
  updater: (task: T) => T,  // 返回同一引用则跳过更新
): void

registerTask 的智能合并: 若任务已存在 (resume 场景),保留 retainstartTimemessagesdiskLoadedpendingMessages 等 UI 状态。

4.2 轮询与回收

// 主轮询循环,由框架每秒调用
async function pollTasks(
  getAppState: () => AppState,
  setAppState: SetAppState,
): Promise<void>

// 生成任务附件 (增量输出 + 终态回收)
async function generateTaskAttachments(state: AppState): Promise<{
  attachments: TaskAttachment[]
  updatedTaskOffsets: Record<string, number>
  evictedTaskIds: string[]
}>

回收策略:

  1. 延迟回收: 终态 + notified 的任务在下一轮 generateTaskAttachments 时被标记为可回收
  2. 主动回收: evictTerminalTask() 允许立即回收,但受面板宽限期约束
  3. TOCTOU 防护: applyTaskOffsetsAndEvictions() 在 FRESH prev.tasks 上操作,避免并发状态转换被覆盖

4.3 通知系统

任务完成通知通过 XML 格式的 <task-notification> 发送:

<task-notification>
  <task-id>{taskId}</task-id>
  <tool-use-id>{toolUseId}</tool-use-id>
  <task-type>{taskType}</task-type>
  <output-file>{outputPath}</output-file>
  <status>completed|failed|killed</status>
  <summary>Task "description" completed successfully</summary>
</task-notification>

每个任务类型自行管理通知发送,通过 enqueuePendingNotification() 入队。notified 标志的原子性 check-and-set 防止重复通知。

4.4 停止任务

// src/tasks/stopTask.ts
async function stopTask(
  taskId: string,
  context: { getAppState, setAppState },
): Promise<{ taskId: string; taskType: string; command: string | undefined }>

流程: 查找任务 -> 验证运行中 -> 调用 taskImpl.kill() -> 标记已通知 (Shell 特殊处理: 抑制 exit code 137 噪音通知)

4.5 磁盘输出

任务输出文件存储在会话隔离的临时目录中:

{projectTempDir}/{sessionId}/tasks/{taskId}

安全措施: 使用 O_NOFOLLOW 防止 symlink 攻击。输出上限 5GB (MAX_TASK_OUTPUT_BYTES)。

5. Agent 生成模式 (AgentTool)

5.1 工具过滤

Agent 可用工具通过多层过滤:

function filterToolsForAgent({
  tools,
  isBuiltIn,       // 内置 Agent 有更宽松的工具限制
  isAsync,         // 异步 Agent 仅允许 ASYNC_AGENT_ALLOWED_TOOLS
  permissionMode,  // plan 模式允许 ExitPlanMode
}): Tools

过滤层级:

  1. MCP 工具 (mcp__ 前缀) 始终允许
  2. ALL_AGENT_DISALLOWED_TOOLS 全局黑名单
  3. CUSTOM_AGENT_DISALLOWED_TOOLS 自定义 Agent 额外黑名单
  4. ASYNC_AGENT_ALLOWED_TOOLS 异步 Agent 白名单
  5. Swarm Teammate 特殊例外: 允许 AgentTool (同步子 Agent) 和 IN_PROCESS_TEAMMATE_ALLOWED_TOOLS

5.2 Fork 子 Agent

FORK_SUBAGENT feature flag 启用时,省略 subagent_type 会触发 fork:

export const FORK_AGENT = {
  agentType: 'fork',
  tools: ['*'],           // 继承父级全部工具
  model: 'inherit',       // 继承父级模型 (保持 cache)
  permissionMode: 'bubble', // 权限冒泡到父终端
  source: 'built-in',
}

Fork 与 Coordinator 互斥: isForkSubagentEnabled() 在 Coordinator 模式下返回 false。

防递归: isInForkChild() 检测对话历史中的 fork boilerplate tag,阻止 fork 子进程再次 fork。

5.3 Agent 运行生命周期

AgentTool.call()
  |
  +--> resolveAgentTools()       # 解析工具集
  +--> runAgent()                # 创建子 Agent 上下文
       |
       +--> createSubagentContext()  # 隔离上下文
       +--> registerTask()           # 注册到 AppState
       +--> query()                  # 执行 API 调用循环
       |    |
       |    +--> (stream events) --> updateProgressFromMessage()
       |    +--> recordSidechainTranscript()  # 侧链持久化
       |
       +--> enqueueAgentNotification()  # 完成通知
       +--> evictTaskOutput()           # 清理输出文件

5.4 SendMessage 续接

通过 SendMessageTool,可以向运行中的 Agent 发送后续消息:

// SendMessageTool 对 local_agent 的处理:
// 1. 通过 queuePendingMessage() 入队
// 2. 在 tool-round 边界由 drainPendingMessages() 排空
// 3. Agent 将排空的消息作为新用户消息处理

// 也可通过 resumeAgentBackground() 恢复已完成的 Agent

6. Coordinator 模式

6.1 启用条件

// src/coordinator/coordinatorMode.ts
export function isCoordinatorMode(): boolean {
  // 需要 COORDINATOR_MODE build feature + 环境变量
  return feature('COORDINATOR_MODE') &&
         isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
}

会话恢复时通过 matchSessionMode() 自动切换:

function matchSessionMode(
  sessionMode: 'coordinator' | 'normal' | undefined,
): string | undefined
// 若当前模式与存储模式不匹配,翻转环境变量

6.2 Coordinator 系统提示

Coordinator 模式完全替换标准系统提示,定义了一套独立的交互模型:

角色定位: 编排器,不是执行器。直接回答简单问题,复杂任务交给 Worker。

可用工具:

工具 用途
Agent 创建新 Worker
SendMessage 续接现有 Worker
TaskStop 终止运行中的 Worker
subscribe/unsubscribe_pr_activity GitHub PR 事件订阅

Worker 工具集上下文:

function getCoordinatorUserContext(
  mcpClients: ReadonlyArray<{ name: string }>,
  scratchpadDir?: string,
): { [k: string]: string }

注入内容包括:

  • Worker 可用工具列表 (普通模式: ASYNC_AGENT_ALLOWED_TOOLS; simple 模式: Bash+Read+Edit)
  • MCP 服务器列表
  • Scratchpad 目录路径 (跨 Worker 持久化知识)

6.3 任务工作流

Coordinator 系统提示定义了标准四阶段工作流:

+-------------------+     +-------------------+     +-------------------+     +-------------------+
|     Research      | --> |    Synthesis       | --> |  Implementation   | --> |   Verification    |
|  (Workers 并行)   |     |  (Coordinator)     |     |  (Workers)        |     |  (Workers)        |
|                   |     |  读取发现,理解问题, |     |  按规格执行变更    |     |  运行测试,检查类型  |
|  调查代码库       |     |  编写实施规格       |     |                   |     |                   |
+-------------------+     +-------------------+     +-------------------+     +-------------------+

并发规则:

  • 只读任务 (研究): 自由并行
  • 写入任务 (实现): 每组文件同时只有一个 Worker
  • 验证任务: 可与不同文件区域的实现并行

6.4 Worker 结果交付

Worker 结果以 <task-notification> XML 作为 user-role 消息交付:

<task-notification>
  <task-id>{agentId}</task-id>
  <status>completed|failed|killed</status>
  <summary>{human-readable status summary}</summary>
  <result>{agent's final text response}</result>
  <usage>
    <total_tokens>N</total_tokens>
    <tool_uses>N</tool_uses>
    <duration_ms>N</duration_ms>
  </usage>
</task-notification>

Coordinator 必须区分用户消息和 task-notification (通过 <task-notification> 开头标签判定)。

6.5 内部 Worker 工具隔离

const INTERNAL_WORKER_TOOLS = new Set([
  'TeamCreate',
  'TeamDelete',
  'SendMessage',
  'SyntheticOutput',
])
// 这些工具从 Worker 可见工具列表中过滤掉

6.6 Synthesis 核心原则

Coordinator 系统提示强调最重要的设计原则: 永远不要委托理解

反模式:

"Based on your findings, fix the auth bug"  // 把理解推给 Worker

正确模式:

"Fix the null pointer in src/auth/validate.ts:42. The user field
on Session is undefined when sessions expire but the token remains
cached. Add a null check before user.id access."  // 具体到文件、行号、原因

续接 vs 新建的决策矩阵:

场景 机制 原因
研究刚好覆盖需编辑的文件 SendMessage 续接 Worker 已有文件上下文
研究范围广但实现范围窄 新建 Agent 避免探索噪音
修正失败或扩展近期工作 续接 Worker 有错误上下文
验证其他 Worker 的代码 新建 Agent 独立审视
首次实现方向完全错误 新建 Agent 错误上下文会锚定重试

7. Swarm 系统

7.1 Team 数据模型

// src/utils/swarm/teamHelpers.ts
export type TeamFile = {
  name: string
  description?: string
  createdAt: number
  leadAgentId: string
  leadSessionId?: string       // Leader 的真实 session UUID
  teamAllowedPaths?: TeamAllowedPath[]
  members: Array<{
    agentId: string            // "researcher@my-team"
    name: string
    agentType?: string
    model?: string
    prompt?: string
    color?: string
    planModeRequired?: boolean
    joinedAt: number
    tmuxPaneId: string
    cwd: string
    subscriptions: string[]
    isActive?: boolean
  }>
}

团队文件存储在磁盘,通过 readTeamFile() / writeTeamFileAsync() 读写。会话清理时由 registerTeamForSessionCleanup() 注册的钩子自动删除。

7.2 Teammate 后端

三种执行后端,通过 TeammateExecutor 接口抽象:

// src/utils/swarm/backends/types.ts
export type BackendType = 'tmux' | 'iterm2' | 'in-process'
后端 隔离方式 通信方式 适用场景
tmux 独立 tmux pane 文件邮箱 终端环境,可视化多 Agent
iterm2 iTerm2 split pane 文件邮箱 macOS iTerm2 用户
in-process AsyncLocalStorage 文件邮箱 + AppState 无外部依赖,资源共享

后端检测与降级:

iTerm2 检测 -> iTerm2 可用? -> 使用 iTerm2 Backend
                    |
                    v (否)
              tmux 检测 -> tmux 可用? -> 使用 tmux Backend
                              |
                              v (否)
                        in-process Fallback

7.3 InProcess Teammate 生命周期

spawnInProcessTeammate()
  |
  +--> createTeammateContext()     # AsyncLocalStorage 隔离
  +--> generateTaskId('t')         # t 前缀 ID
  +--> registerTask()              # 注册到 AppState
  +--> startInProcessTeammate()    # 启动执行循环
       |
       +--> inProcessRunner.ts     # 主循环
            |
            +-- 读取 pending messages / mailbox
            +-- 调用 query() API
            +-- 更新 progress
            +-- 检查 shutdownRequested
            +-- 转 idle 等待新消息

7.4 消息传递

Swarm 中的消息类型:

// SendMessageTool 的消息格式
const StructuredMessage = z.discriminatedUnion('type', [
  z.object({ type: z.literal('shutdown_request'), reason: z.string().optional() }),
  z.object({ type: z.literal('shutdown_response'), request_id, approve, reason }),
  z.object({ type: z.literal('plan_approval_response'), request_id, approve, feedback }),
])

消息路由:

  • 定向消息: to: "researcher" -> 发送到指定 Teammate
  • 广播消息: to: "*" -> 发送到所有 Teammate
  • Agent 续接: to: "{agentId}" -> 如果 target 是 local_agent,用 resumeAgentBackground() 恢复
  • UDS 对等: to: "uds:<socket-path>" -> 本地 Unix socket 对等通信
  • Bridge 对等: to: "bridge:<session-id>" -> Remote Control 对等通信

7.5 TeamCreate / TeamDelete

// TeamCreateTool 创建流程:
// 1. 检查是否已在团队中 (一个 leader 只能管理一个团队)
// 2. 生成唯一团队名 (冲突时用 word slug)
// 3. 创建 team-lead agent ID: "team-lead@{teamName}"
// 4. 写入 TeamFile 到磁盘
// 5. 注册清理钩子
// 6. 重置任务列表 (Team = Project = TaskList)
// 7. 更新 AppState.teamContext

// TeamDeleteTool 清理流程:
// 1. 检查是否有活跃非 leader 成员
// 2. 如有活跃成员,拒绝删除 (需先 requestShutdown)
// 3. 清理团队目录和 worktree
// 4. 清除颜色分配
// 5. 清除 AppState.teamContext

8. Task 工具集

8.1 TaskCreateTool

创建结构化任务项 (非后台任务,而是任务列表中的项目):

// 输入
{ subject: string, description: string, activeForm?: string, metadata?: Record }

// 输出
{ task: { id: string, subject: string } }

与 TodoWrite 是不同系统: TaskCreate 管理的是 Swarm 团队共享的任务列表 (tasks/ 目录),TodoWrite 管理的是 Claude 自身的待办列表。

8.2 TaskStopTool

统一的任务终止工具:

// 输入 (兼容旧版 KillShell)
{ task_id?: string, shell_id?: string }

// 流程: validateInput -> stopTask() -> kill + markNotified

8.3 TaskOutputTool / TaskGetTool / TaskListTool / TaskUpdateTool

这些工具用于 Swarm 团队内部的任务协调:

  • TaskOutput: 读取任务输出 (大文件,65KB)
  • TaskGet: 获取单个任务详情
  • TaskList: 列出所有任务
  • TaskUpdate: 更新任务状态 (status, notes 等)

9. UI 组件

9.1 后台任务状态栏 Pill

// src/tasks/pillLabel.ts
function getPillLabel(tasks: BackgroundTaskState[]): string

Pill 文本根据任务类型和数量动态生成:

类型 单个 多个
local_bash "1 shell" "3 shells"
local_bash (monitor) "1 monitor" "2 monitors"
local_agent "1 local agent" "3 local agents"
remote_agent "diamond 1 cloud session" "diamond 3 cloud sessions"
remote_agent (ultraplan) "diamond ultraplan" / "diamond ultraplan ready" / "diamond ultraplan needs your input" -
in_process_teammate "1 team" (按团队计数) "2 teams"
dream "dreaming" -
混合 "N background tasks" -

9.2 BackgroundTaskStatus 组件

底部状态栏组件,显示 Teammate 圆点和任务状态:

  • 过滤 isBackgroundTask() 为 true 的任务
  • 排除 isPanelAgentTask() 为 true 的 Coordinator 面板任务
  • Teammate 入口按 startTime 排序
  • 支持水平滚动 (终端宽度不够时)

9.3 详情对话框

每种任务类型有独立的详情对话框:

文件 对应任务
ShellDetailDialog.tsx LocalShellTask
AsyncAgentDetailDialog.tsx LocalAgentTask
RemoteSessionDetailDialog.tsx RemoteAgentTask
InProcessTeammateDetailDialog.tsx InProcessTeammateTask
DreamDetailDialog.tsx DreamTask
BackgroundTasksDialog.tsx 总览对话框 (Shift+Down)

9.4 任务状态工具函数

// src/components/tasks/taskStatusUtils.tsx

function getTaskStatusIcon(status, options?): string
// running: play, completed: tick, failed/killed: cross
// idle: ellipsis, awaitingApproval: questionMark, shutdownRequested: warning

function getTaskStatusColor(status, options?): 'success'|'error'|'warning'|'background'

function describeTeammateActivity(t): string
// shutdownRequested -> 'stopping'
// awaitingPlanApproval -> 'awaiting approval'
// isIdle -> 'idle'
// 否则 -> 最近活动摘要 / 'working'

10. 后台任务管理

10.1 前台/后台切换

// isBackgroundTask 判定条件:
// 1. status === 'running' || status === 'pending'
// 2. isBackgrounded !== false (默认视为后台)
function isBackgroundTask(task: TaskState): task is BackgroundTaskState

主会话通过 foregroundMainSessionTask() 实现前台化: 将目标任务的 isBackgrounded 设为 false,之前的前台任务恢复为 true。

10.2 清理注册

所有任务通过 registerCleanup() 注册进程退出清理回调。Agent 任务额外注册 perfetto tracing 代理。

10.3 SDK 事件

任务系统通过 enqueueSdkEvent() 发射结构化事件给 SDK 消费者:

// 任务启动
{ type: 'system', subtype: 'task_started', task_id, tool_use_id, description, task_type }

// 任务终止 (通过 emitTaskTerminatedSdk)
{ type: 'system', subtype: 'task_terminated', task_id, status, summary }

10.4 Scratchpad

Coordinator 模式可选启用 Scratchpad 目录:

// Worker 可以在此目录无需权限提示地读写
// 用于跨 Worker 的持久化知识共享
`Scratchpad directory: ${scratchpadDir}`

11. 架构总结

+----------------------------------------------------------+
|                    用户交互层                              |
|  BackgroundTaskStatus | DetailDialogs | PillLabel         |
+------+---------------------+-----------------------------+
       |                     |
       v                     v
+------+--------+   +--------+--------+
|   AppState    |   | Coordinator     |
|  .tasks{}     |   | System Prompt   |
|  .teamContext |   | Worker dispatch  |
+------+--------+   | Synthesis        |
       |            +--------+--------+
       |                     |
+------+---------------------+-----------------------------+
|                 Task Framework Layer                       |
|  registerTask | updateTaskState | pollTasks | evict       |
+------+-----+-----+-----+-----+-----+-----+--------------+
       |     |     |     |     |     |     |
       v     v     v     v     v     v     v
     Shell Agent Remote Teammate Dream Workflow Monitor
       |     |     |      |      |
       v     v     v      v      v
    Process query  API  In-proc forkAgent
    spawn   loop   poll  runner consolidate

核心设计特点:

  1. 不可变状态更新: 所有 updateTaskState 返回新对象,=== 相等时跳过更新
  2. 原子通知: notified 标志的 check-and-set 防止重复通知
  3. TOCTOU 防护: offset/eviction 在 fresh state 上操作
  4. 内存安全: Teammate 消息上限 50 条,面板宽限期 30 秒后回收
  5. 安全隔离: 输出文件 O_NOFOLLOW 防 symlink 攻击,session ID 隔离目录