Bundle
dsh-agent-lead
DSH 带队模式插件:主 Agent 只规划派活监工,改动交给 subagent,每次派活弹窗选子模型
- Source
- JunguangJiang
- stars
- 2 stars
- License
- MIT
- Updated
- Updated 11 days ago
Readme
# agent-lead — `/lead` 带队模式
主 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` 查看地盘地图,按四步决策链路由。
### 第一步:要不要新建(六条规则,按优先序,前面的一票否决后面的)
1. **R1 单一写者**:要改的文件与在编 subagent 地盘重叠 → 必须派给它,绝不新建第二个写者。
2. **R2 返工归原主**:验收不合格发回原主;同一问题返工 2 次仍不合格 → 止损换人,prompt 写明失败史。
3. **R3 独立评审必须新人**:审查/验收某产出永远不派给原作者或同域老 subagent。
4. **R4 同域延续优先复用**:建立在已完成工作之上且未跑偏 → 复用,交底只写增量。
5. **R5 独立新域必新建**:无文件、无知识重叠或需真并行 → `assign` 新建,声明不重叠的 scope。
6. **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 必须自己补全后再下发。
**增量交底模板(复用时):**
1. 承接:「你之前完成了 X/正在做 X」
2. 变化:什么变了、为什么(用户新决定、其他 subagent 的相关产出、验收结论等它不知道的信息)
3. 新目标:做什么、不做什么
4. 涉及路径(超出原 scope 时 `redirect` 顺带更新 scope)
5. 验收标准
**增量原则:**老 subagent 已有的上下文不重复,但它不知道的信息必须写全——它看不到主会话。
> **注意**:`send_message` 是宿主全局工具,其使用规范由带队策略文本约束(宿主工具描述不可改),不在本插件代码层面做参数校验。
## 工作流程
带队模式采用「简版派工单」流程——给人看的简明扼要,给 subagent 的完整自足:
1. **规划阶段**:Agent 勘察现状后,输出简版派工单(每个子任务一行:任务名 + 一句话说清干什么),等用户确认。如果方案已在本会话定案(计划模式或用户直接给出),不复述方案,直接给拆解映射。
2. **执行阶段**:用户确认后(ok/go/执行/没问题等),Agent 按决策链路由——新建用 `assign`,复用用 `send_message`/`redirect`——立即并行派活。下发给 subagent 的指令包含完整背景、目标、路径、验收标准——subagent 看不到对话。
3. **验收阶段**:子任务完成后,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 次数(`职责=数据预处理[src/preprocess] redirect×2`)
- 最近一次操作摘要
- 在线时的队列积压条数
无子 agent 时返回空列表不报错。派活(`assign`)前必须先调本工具查看地盘地图,决定复用还是新建。
## 模型只能弹窗选
`assign` 只有 `description` 和 `prompt` 两个参数,**没有 `model` 参数**:模型花多少钱、值不值得,是你的决定,不是模型的决定。所以这里既没有自然语言识别,也没有别名、默认值和「记住上次选择」。
弹窗候选按三段组装,按 `provider|model` 去重(先出现者保留):
1. **当前主模型** —— 该会话此刻真正在用的路由,标注「(当前主模型)」。读取顺序:`request/header` 的 config → `request/context` → `agent.options`;首轮请求之前读不到,这一段就省略。
2. **最近最常用的 N 个** —— 来自本插件自己的派活历史,标注「(常用)」。按出现次数降序,同次数看最近一次使用时间。
3. **配置里固定列出的模型** —— 原序展示,保证弹窗永远非空。
显示名优先用配置里的 `label`,其次是 provider 目录(`ctx.llm.listModels`)里的名字,最后退回 model id。标签重复时自动追加 ` · <provider>` 消歧。
## 配置
写在 `~/.dsh/cordis.patch.yml` 的这一行里:
```yaml
- 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 唤醒。
Install
dsh plugin --profile web add github:JunguangJiang/dsh-agent-lead
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-agent-lead from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.