dsh-council — DeepSeek Harness「小组」插件
把会话变成群聊:你说一句需求,指挥拆解 → 成员在各自的 agent 框架里并发干活 → 审校初审 → 指挥终审 → 不合格自动返工一次。所有过程在「群聊」页实时可见。
与官方子代理的区别:官方只回最终答案;本插件把每一步(谁、什么阶段、多久)暴露出来,并且每个成员可以挂不同框架/模型,各跑各的原生 agent(Codex CLI / Claude Code CLI / DSH 内建 agent / 图像接口 / 任意 OpenAI·Anthropic 兼容中转)。
仓库标签:dsh · deepseek-harness · cordis · plugin · multi-agent · agent-orchestration · codex · claude · ai-agents
安装
# 从 GitHub 克隆后安装(推荐)
git clone https://github.com/ZelyStaric/dsh-council
plugin_manager install_bundle --target ./dsh-council
# 或直接用目录路径
plugin_manager install_bundle --target /path/to/dsh-council
# 或 npm 安装(如已发布)
plugin_manager install_bundle --target @zelystaric/dsh-council
安装后在任意会话顶部点 小组模式,进「小组」页配置成员。
首次配置
- 名册:岗位 → 成员 → 每个成员选框架与模型;
- API:在「小组」页填中转站地址与 key(同时支持两种通用格式):
| 用途 | 协议 | 填在哪 |
|---|
codex 成员(GPT 系) | OpenAI | ① 卡片的 gpt key(base 来自 ~/.codex) |
image 成员(出图) | OpenAI /v1/images/generations | ① 卡片的 gpt-image key |
claude 成员(Anthropic 系) | Anthropic /v1/messages | ① 卡片的 claude key + claude base URL |
-
首次使用的顺序(全新安装时很重要):
① 先发一条消息,建立一个会话
② 点顶部「小组模式」(Hero 草稿态点它会提示先建会话)
③ 进「小组」页填密钥、确认名册
④ 再派活
-
也可以不填页面,改 profile 的 cordis.patch.yml:
- insert:
- id: council
name: '@zelystaric/dsh-council'
config:
claudeBaseUrl: https://your-relay # claude 成员用
defaultWorkspace: /your/workspace # 成员的工作目录
strictDelegate: true # 小组模式硬拦截父会话自己写文件(默认 true)
memberIdleMinutes: 10 # 成员连续多久没有任何输出才算死(看门狗,默认 10 分钟)
memberHardLimitMinutes: 360 # 极大兵底(默认 6 小时;0 = 完全不限制总时长)
imageTimeoutSeconds: 240 # 出图 HTTP 请求超时(无流式输出,默认 240s)
页面里的 base 留空 = 用 profile 里的;页面填了会覆盖它。
成员没有总时长超时:只要还在输出就一直跑,静默超过 memberIdleMinutes 才终止;
旧的 memberTimeoutMinutes 仍可读但已废弃、不再生效。
硬拦截:小组模式下父会话不许自己动手
光靠提示词拦不住(实测有会话自己跑了 120 次 bash / 12 次 edit 却不派活),所以 Host 半在
agent.ctx.tools.guard() 上加了一道守卫:写类工具直接拒绝,理由会回到父会话。
-
拒绝名单:edit、write、apply_patch、blender_python、blender_import、blender_export、
blender_render、blender_render_frames;
-
不拦 bash(只计审计数)与只读工具(read / read_image / grep / glob / blender_status /
blender_scene_info / blender_object_info / blender_validate_* / blender_helper_catalog);
-
两条逃生口:本轮最后一条用户消息里说「你自己做 / 你直接改 / 你亲自动手 / 放行」;或把
strictDelegate 设为 false(默认 true,改 profile 的 config.strictDelegate,见上)。
-
被拦次数会累加,council_delegate 回执末尾出现 ## 越权拦截(如「edit×3、blender_render×2」),
GET /council/api/progress 的 entry 里也有 selfWorkBlocked;GET/POST /council/api/config
读写 strictDelegate。
官方 key 与中转站都能直接用
三个框架的凭据都从插件配置里取(页面 ① 或 profile 的 cordis.patch.yml),填官方 key 就是官方通道,填中转 key 就是中转通道:
| 成员 | 填什么 | 官方 | 中转站 |
|---|
claude | claudeBase + claudeKey | 地址 https://api.anthropic.com,模型如 claude-sonnet-4-5 | 地址如 https://your-relay |
image | codexBase + imageKey | 地址 https://api.openai.com,模型 gpt-image-1 | 地址如 https://your-relay,模型按中转提供的写 |
codex | codexBase + codexToken(或 codex 成员的 ~/.codex 配置) | 地址 https://api.openai.com,codexWireApi 默认 responses | 地址如 https://your-relay |
实现细节(排障时有用):
- base 会被归一成根地址(自动去掉尾部
/ 与 /v1),各调用点再拼 /v1/models、/v1/images/generations、/v1/usage;
claude 通过 ANTHROPIC_BASE_URL / ANTHROPIC_API_KEY 传给 CLI,所以官方与中转走的是同一条路;
codex 会用它自己生成的 ~/.dsh/storages/council-codex/config.toml(内含 model_providers.council 与 bearer token),不改你 ~/.codex 里的配置;没配 base/key 时才回退到你自己的 ~/.codex。
用官方 key 需要代理时
只填官方 key、base 留空会自动走官方端点(api.openai.com / api.anthropic.com)。如果本机直连官方不通,在 ① 卡片最右的输入框填本机代理地址(Clash 混合端口):
http://127.0.0.1:7897
- 只影响插件自己发起的请求(模型列表、出图、用量)以及 claude / codex CLI 子进程的环境变量;
- 代理没起来时会自动回退直连并打日志,不会把整个插件拖死;
- 用中转站时不需要填(填了会多一跳)。
升级到新版本
dsh plugin add 不会覆盖已安装的同名依赖,换 tarball / 目录升级时要先移除:
dsh plugin --profile web remove @zelystaric/dsh-council
dsh plugin --profile web add -w file:/path/to/zelystaric-dsh-council-0.2.4.tgz
systemctl --user restart dsh-web # 或重启你起的 dsh web
从 npm 安装时同理:remove 之后 add @zelystaric/dsh-council@<version>。
成员框架
| kind | 跑什么 | 说明 |
|---|
codex | Codex CLI(codex exec) | GPT 系,原生 app-server,工具链最全 |
claude | Claude Code CLI | Anthropic 系,长上下文,能读图 |
deepseek | DSH 内建 agent(subagent seam) | 用完即弃 + 摘要回灌;可复用同一条子会话 |
image | 图像接口(OpenAI 兼容 /v1/images/generations) | 出图、序列帧 |
岗位(角色)
内置 8 个:指挥 / 代码 / 全栈 / 审校 / 画师 / 配乐 / 3D建模 / 动画。都只是预设——岗位名、提示词、成员、模型、风格都可以自己改。指挥负责拆解与终审,审校负责初审,其余按任务分派。
外部依赖(可选,按岗位)
codex、claude 两个 CLI(对应成员才需要)
- 配乐:
fluidsynth + GM SoundFont + ffmpeg + python3-midiutil/mido
- 3D:
blender(无头)、openscad、python3 -m pip install trimesh pygltflib
- 动画:
ffmpeg、Pillow
自定义外观(头像、名字、气泡)
头像:默认是内置的三张 SVG 占位图。想换成自己的角色,只要把 192×192 的 PNG 放进
~/.dsh/storages/council-images/
├── avatar-codex-small.png # codex / GPT 成员
├── avatar-claude-small.png # claude 成员
└── avatar-deepseek-small.png # deepseek 成员
画师(image)默认复用 avatar-codex-small.png。文件不存在时自动回退到内置 SVG,
所以想换哪个换哪个、删掉也安全。文件名不对或不想要这套命名,改 client.js 里的 AVATAR_FILE 映射即可:
const AVATAR_FILE = {
codex: 'avatar-codex-small.png',
claude: 'avatar-claude-small.png',
deepseek: 'avatar-deepseek-small.png',
image: 'avatar-codex-small.png',
}
// 也可以指向任意经 /council/api/image/ 提供的文件名
注意:头像是按框架取的,不是按成员——同一个框架的所有成员共用一张图
(比如 claude 既当指挥又当审校,仍是同一张)。想让不同成员不同图,需要在 Avatar 组件里
改成按 member.id 映射(当前不做,避免状态里存图片路径)。
没配的框架继续用内置 SVG 占位。
名字与气泡:成员名、岗位名、岗位提示词、组级统一风格都在「小组」页和「名册」浮层里改,
不涉及代码。气泡里的框架标签(claude · 模型名)跟随成员选择的框架与模型自动变化。
按钮文案 / 页面标题:locale/{zh,en}.json 的 meta.title、meta.description 改了就生效(刷新页面)。
外部 CLI 的路径
codex 与 claude 默认从 PATH 找;找不到时会直接报
未找到 codex CLI(codex)。安装 Codex,或用环境变量 COUNCIL_CODEX_BIN 指定绝对路径。
也可以显式指定:
export COUNCIL_CODEX_BIN=/usr/local/bin/codex
export COUNCIL_CLAUDE_BIN=/path/to/claude
claude 若装了 dsh-subagent-claude-code bundle,会自动用 bundle 自带的二进制。
兼容性
- 仅测试于
dsh 0.2.1-rc.2(用到 subagent seam、uiConversation 等内部 API);
- 中转站只要是 OpenAI 或 Anthropic 通用格式即可,不绑定具体厂商。
二次开发
- Host 半
index.js:createHandler() 暴露全部 HTTP 路由;runKind() 是所有框架的分发点,加新框架只需加一个分支;
- Client 半
client.js:CouncilChatView(群聊页)/CouncilView(编排页)/RosterPanel(名册浮层)/CouncilProgress(进度条);
- 状态文件:
~/.dsh/storages/council.json(职位/成员/组/用量/摘要);出图落在 ~/.dsh/storages/council-images/;
- 修改 Host 后需
systemctl --user restart dsh-web;只改 Client 刷新页面即可。
许可
MIT。头像为内置占位图;如需自定义,替换 client.js 里的 AVATAR_FILE 映射即可。