agent-lead
August 28, 2026 · View on GitHub
主 Agent 只负责理解、拆解、分发、验收与监工;改动类工作一律通过 assign 派给后台 subagent。每次派活都弹窗,由你选这个 subagent 用哪个模型。
装在 ~/.dsh/plugins/agent-lead/,通过 ~/.dsh/cordis.patch.yml 的 insert 行挂到宿主,对所有 agent 预设生效。
怎么用
| 输入 | 行为 |
|---|---|
/lead | 切换带队模式开关(再次输入退出) |
/lead off | 强制退出带队模式(CLI 等适配器的显式写法) |
/lead auto | 开启全自动派活(assign 不弹窗,自动采用上次选择的模型) |
/lead manual | 恢复手动选模型(assign 每次弹窗) |
/lead auto <任务> | 开启全自动派活 + 同时提交任务 |
/lead manual <任务> | 恢复手动选模型 + 同时提交任务 |
/lead <任务描述> | 进入带队模式并提交任务(auto 状态不变) |
进入后:
- 系统提示里出现带队策略(只在开启时出现,关闭时该区段为空、不进请求)。
- 主 Agent 调
write/edit/str_replace_editor会被拒绝,并被告知改用assign派活。 read/grep/glob/bash保留——勘察和验收要用。- 主 Agent 每次调
assign,你都会收到一个模型选择框。
工具概览
| 工具 | 用途 |
|---|---|
assign | 派活给后台 subagent(唯一的创建子 agent 途径),必须声明职责范围(scope) |
redirect | 推翻性指令:一步完成打断 + 清队列 + 发新指令,可顺带更新 scope |
manage_queue | 查看/操作子 agent 的待执行消息队列 |
lead_status | 查看所有子 agent 实时状态与派活台账(含地盘地图),派活前必查 |
scope — 职责范围契约
每次 assign 必须传 scope: { summary, paths }:summary 是一句话职责范围(如「负责数据预处理流水线」),paths 是负责的文件/目录清单(相对或绝对路径,目录按内容前缀匹配理解,至少 1 项)。scope 是该 subagent 的地盘契约,写入台账并在 lead_status 中展示。
重叠预警:派活时对照台账中本会话所有子 agent 的 scope.paths 做路径重叠检测——一方路径与另一方相等或互为目录前缀(按 / 边界,尾斜杠归一化)即算重叠。有重叠且未传 force: true 时 assign 报错,列出重叠的子 agent、其职责与重叠路径,并提示改用 send_message/redirect 派给地盘主人;确认确需新建(如原 subagent 已退役)时带 force: true 重试。
scope 更新:走 redirect 的可选参数 scope(结构同 assign)——推翻指令时如新工作超出原职责范围,传入新 scope 覆盖台账记录,同样做与其他子 agent 的重叠检测(排除目标自己)+ force 逃生门。
派活决策链(四步)
带队策略要求派活前先调 lead_status 查看地盘地图,按四步决策链路由。
第一步:要不要新建(六条规则,按优先序,前面的一票否决后面的)
- R1 单一写者:要改的文件与在编 subagent 地盘重叠 → 必须派给它,绝不新建第二个写者。
- R2 返工归原主:验收不合格发回原主;同一问题返工 2 次仍不合格 → 止损换人,prompt 写明失败史。
- R3 独立评审必须新人:审查/验收某产出永远不派给原作者或同域老 subagent。
- R4 同域延续优先复用:建立在已完成工作之上且未跑偏 → 复用,交底只写增量。
- R5 独立新域必新建:无文件、无知识重叠或需真并行 →
assign新建,声明不重叠的 scope。 - R6 污染即退役:被 redirect 2 次以上、跑偏或自相矛盾 → 不再派新活,新建接班人。
第二步:复用哪个
由 R1/R2/R4 指向的唯一对象;有歧义时以 lead_status 的 scope.paths 重叠度为准。
第三步:选投递方式(三选一判定梯)
| 情形 | 投递方式 |
|---|---|
| 新指令推翻/取代目标 subagent 正在跑或已排队的工作 | redirect(打断+清队+新指令一步完成) |
| 新指令是追加/后续、不与在跑工作冲突 | send_message 排队为下一轮 |
| 不需要新指令、只修正已排队还没执行的指令 | manage_queue(replace/remove/push_front),不发新消息 |
| 拿不准冲不冲突 | 先 manage_queue list 看队列 + lead_status 看在跑什么,再决定 |
第四步:撰写指令(复用与新建同一标准)
给老 subagent 的 send_message/redirect 消息和给新 subagent 的 assign prompt 是同一种东西——完整任务书,不是传话。用户的原话只是素材,主 Agent 必须自己补全后再下发。
增量交底模板(复用时):
- 承接:「你之前完成了 X/正在做 X」
- 变化:什么变了、为什么(用户新决定、其他 subagent 的相关产出、验收结论等它不知道的信息)
- 新目标:做什么、不做什么
- 涉及路径(超出原 scope 时
redirect顺带更新 scope) - 验收标准
**增量原则:**老 subagent 已有的上下文不重复,但它不知道的信息必须写全——它看不到主会话。
注意:
send_message是宿主全局工具,其使用规范由带队策略文本约束(宿主工具描述不可改),不在本插件代码层面做参数校验。
工作流程
带队模式采用「简版派工单」流程——给人看的简明扼要,给 subagent 的完整自足:
- 规划阶段:Agent 勘察现状后,输出简版派工单(每个子任务一行:任务名 + 一句话说清干什么),等用户确认。如果方案已在本会话定案(计划模式或用户直接给出),不复述方案,直接给拆解映射。
- 执行阶段:用户确认后(ok/go/执行/没问题等),Agent 按决策链路由——新建用
assign,复用用send_message/redirect——立即并行派活。下发给 subagent 的指令包含完整背景、目标、路径、验收标准——subagent 看不到对话。 - 验收阶段:子任务完成后,Agent 按下发指令里的验收标准读文件、看 diff、跑检查,向用户汇报结论和问题,不复述过程细节。
redirect — 推翻性指令
当你需要彻底推翻子 agent 当前的工作方向时,必须用 redirect(一步完成),不要 interrupt_agent + send_message 两步走(两步走存在中间状态竞态)。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
subagentId | string | ✅ | 目标子 agent 的 session id |
message | string | ✅ | 新指令(完整自足,取代一切旧指令) |
clearQueue | boolean | - | 是否清空待执行队列(默认 true) |
scope | object | - | 新职责范围契约(覆盖台账记录,做重叠检测) |
force | boolean | - | 新 scope 与他人重叠仍要覆盖时传 true |
执行链路:后代校验 → interrupt → clear inbox → followup(带「指令更替」前缀)→ 写台账。
manage_queue — 队列管理
查看或操作子 agent 的待执行消息队列。支持六种 action:
| action | 需要 | 说明 |
|---|---|---|
list | — | 查看 next-turn / next-step 两个列表(离线时返回空) |
clear | — | 清空全部排队消息 |
remove | messageId | 按 id 删除一条排队消息 |
replace | messageId + message | 替换一条排队消息的内容 |
push | message | 追加一条消息到 next-turn 队尾 |
push_front | message | 插入一条消息到 next-turn 队首 |
注意:队列操作只对在线子 agent 生效。子 agent 不在线时,list 返回空并注明离线,其余操作报错要求先用 send_message 唤醒。
lead_status — 状态概览
无参数调用列出所有子 agent;传 subagentId 过滤单个。返回每个子 agent 的:
- id、标题(label)
- 活动状态(running / inactive / unknown)
- 模式(continuable / one-shot)
- 模型、provider
- 派活时间、已运行时长
- 职责范围 scope(summary + paths,旧条目可能缺席)与 redirect 次数()
- 最近一次操作摘要
- 在线时的队列积压条数
无子 agent 时返回空列表不报错。派活(assign)前必须先调本工具查看地盘地图,决定复用还是新建。
模型只能弹窗选
assign 只有 description 和 prompt 两个参数,没有 model 参数:模型花多少钱、值不值得,是你的决定,不是模型的决定。所以这里既没有自然语言识别,也没有别名、默认值和「记住上次选择」。
弹窗候选按三段组装,按 provider|model 去重(先出现者保留):
- 当前主模型 —— 该会话此刻真正在用的路由,标注「(当前主模型)」。读取顺序:
request/header的 config →request/context→agent.options;首轮请求之前读不到,这一段就省略。 - 最近最常用的 N 个 —— 来自本插件自己的派活历史,标注「(常用)」。按出现次数降序,同次数看最近一次使用时间。
- 配置里固定列出的模型 —— 原序展示,保证弹窗永远非空。
显示名优先用配置里的 label,其次是 provider 目录(ctx.llm.listModels)里的名字,最后退回 model id。标签重复时自动追加 · <provider> 消歧。
配置
写在 ~/.dsh/cordis.patch.yml 的这一行里:
- id: agent-lead
name: '/home/jiangjunguang/.dsh/plugins/agent-lead/index.mjs'
config:
llmProvider: hfai
rulesFile: /home/jiangjunguang/.dsh/captain-rules.md
models:
- id: anthropic/claude-opus-4.6
label: Opus 4.6
description: 强,贵,适合复杂实现与重构
- id: deepseek-v4-flash
label: DeepSeek-V4-Flash
description: 快,便宜,适合批量与机械改动
| key | 含义 | 默认 |
|---|---|---|
llmProvider | 子 agent 默认 LLM 路由 | 必填 |
models[] | { id, label?, provider?, description? },固定候选段 | 必填非空 |
includeCurrentModel | 是否把当前主模型置顶为一项 | true |
recentCount | 「常用」段条数 | 3 |
recentWindow | 统计频次时只看最近多少条派活记录 | 50 |
usageFile | 派活历史文件(绝对路径) | $DSH_HOME/agent-lead-usage.json |
rulesFile | 全局 captain 规矩文件(绝对路径,Markdown) | $DSH_HOME/captain-rules.md |
subagentProvider | ctx.subagents 提供者 | spawn |
toolName | 派活工具名 | assign |
commandName | 命令名 | lead |
maxDepth | 子 agent 深度上限 | 3 |
lockedTools[] | 开启时禁止主 Agent 自己调用的工具(空数组=不锁) | ['write','edit','str_replace_editor'] |
section | 带队策略提示文本({{tool}} 会替换成工具名) | 内置中文文本 |
配置非法(models 为空、label 重复、recentCount 不是正整数、usageFile 非绝对路径、rulesFile 非绝对路径、commandName 不合法…)会在加载期抛错,而不是等到第一次派活才失败。
rulesFile — 全局带队规范
rulesFile 指定一个 Markdown 文件路径(默认 ~/.dsh/captain-rules.md)。文件存在时,其内容附加到带队策略区段末尾,标题「## 全局带队规范(来自 captain-rules.md)」;不存在静默跳过;读失败 warn 不致命。
用途:把跨项目通用的 captain 规矩(代码风格约束、review 标准、禁止事项等)写在这个文件里,所有带队会话都能看到,不用每个项目的 AGENTS.md 重复写。
assign.taskId
assign 工具的可选参数 taskId(string)保留:对应已发布计划中的子任务 id,派活时带上。不填也不影响派活本身的功能。
状态与数据
- 模式状态不写新的 session 事件类型:
Session.append无法给事件打ignorable,而KNOWN_SESSION_EVENT_TYPES之外的类型会让日志加载直接拒绝。状态由 commands 注册表本来就会写的command/run(name === commandName)折叠得出——空 args toggle 取反、off强制退出、auto/manual精确匹配切模式、auto <任务>前缀开启 auto + 提交任务、manual <任务>前缀关闭 auto + 提交任务、其他 args 开启 active(auto 不变)——因此 resume / fork / compaction 之后都能恢复,也满足「模型可见 ⟺ 已记录」。 - 派活历史存在
usageFile:{ schema: 1, entries: [{ provider, model, time }] },只保留最近 200 条,写入串行化并原子替换(*.tmp+rename),文件权限0600。只在派活成功启动后才记一条,失败的派活不进「常用」排序。 - 派活台账(内存态):每会话维护
childId → { description, promptHead, provider, model, startedAt, scope, redirectCount, actions }的 Map。assign、redirect、manage_queue成功后记录;redirect自增redirectCount。进程重启后台账丢失(只影响lead_status的历史展示与重叠预警,不影响功能);旧会话内没有 scope/redirectCount 字段的条目按缺席/0 处理,不崩。
已知限制
- 每次派活都要人点一次。 这是设计目标,不是待优化项;不想点就
/lead off。 - 只派后台可续 subagent。 结算通知 +
send_message/interrupt_agent正是监工闭环需要的;本工具没有前台等待路径。 - 子 agent 不能用
assign再往下派活。 提问通道只认活着的根 agent(DELEGATED_CALLER),此时工具会报错并要求它把待定决定写进最终结果交回主 Agent。 - 没有提问通道就直接失败。 没有
model参数可兜底,headless / ACP 会话里assign会报错而不是偷偷挑一个模型。 - 历史是本机单文件。 多个 dsh 进程并发写为最后写入者赢;读失败只影响候选排序,不影响派活。
- 台账为内存态。 进程重启后丢失。只影响
lead_status历史展示,不影响工具功能。 - 切换模式会让系统提示前缀变化,因此那一次请求的 KV cache 命中会失效一次。
- 「梁神模式」phase-1 锚定期看不到
assign(tool-bootstrap会把工具裁到两件),晋升后出现——符合该预设的设计。 - 结算误报 — DSH 核心侧的结算通知有时把正常完成的 subagent 标记为 failed/stopped,属已知核心侧问题,后续跟进。带队策略已要求 captain 先查产物再定性。
- 消息无 read-ack — 目前无法确认子 agent 实际读到了某条消息(只能确认入队),read-ack 属 DSH 核心侧后续跟进。
- 队列操作只对在线子 agent 生效 — 不在线的子 agent 无法操作其 inbox(inbox 随 Agent 生命周期),需先 send_message 唤醒。