@flg1217/dsh-subagent-codebuddy
Manifest validCodeBuddy CLI (Tencent) as a dsh LLM provider via ACP: selectable as a main-agent model (the ACP CLI owns the turn and its tools) and as a subagent backend through the generic subagent tool; exposes the CLI model catalog via listModels().
dsh-subagent-codebuddy
CodeBuddy Code CLI 模型提供方 — DeepSeek Harness (dsh) 插件 把腾讯 CodeBuddy CLI 以 ACP (Agent Client Protocol) 接入 dsh,注册为
codebuddyLLM provider: 主代理可直接在模型选择器选用 CodeBuddy 模型,通用subagent工具也可委派 CodeBuddy 子代理。 完全遵循 dsh 官方扩展机制,零源码改动。
一、这是什么
codebuddy 是一位完整的模型供应商:
| 能力 | 说明 |
|---|---|
| 主代理模型 | 模型选择器出现 CodeBuddy 分组(模型目录 = codebuddy --help 解析 ∪ 配置默认模型),选中后该轮由 CodeBuddy CLI 全权驱动 |
| 子代理 provider | 通用 dsh subagent 工具可传 provider: codebuddy 委派(配合 subagent-model-selection 设置);进程内 child agent、可并行、send_message 续聊 |
| 模型目录 | adapter 实现 listModels()(带缓存、永不抛错),主选择器与 list_subagent_models 共用 |
| 推理强度 | CLI --effort 档位(low / medium / high / xhigh / max / ultracode)暴露到 dsh 模型选择器;子代理可用 reasoning_effort 参数指定 |
| 图片输入/读取 | 输入:图片块读字节后以 ACP 原生 image 内容块(base64)随 prompt 发送(promptCapabilities.image,不落盘);读取:模型用 dsh 的 read_image,图片以 MCP image 内容块回到 CLI 侧模型、同时进 dsh 会话出图片卡片;历史种子与子代理转录里的图片经 CodeBuddy blob(内容寻址)双向原生转换,两侧均可预览 |
| 子代理可视化 | codebuddy 轮里的 Agent 委派镜像为 dsh 子会话(parentSession 血缘 + subagent/descriptor),侧边栏可点开完整转录(消息/工具/思考/任务),运行中近实时跟随 |
| 任务/todo | 走 dsh 原生 todo_write(工具桥一等公民,主轮与子代理会话都复用 dsh 的 TodoPanel 渲染);CLI 侧 TaskCreate/TaskUpdate 已随内置工具禁用,todo-bridge 保留作旧会话重放兼容 |
| 工具桥(MCP / delegate) | 把本会话可见的 dsh 工具暴露给 CodeBuddy,使它的文件/命令类能力走 dsh 管线(审批/沙箱/审计/后台面板)。默认 mcp:dsh 起 HTTP MCP server,工具以 mcp__dsh__<名> 一等公民呈现(完整 JSON Schema 强约束);delegate 为旧通道(dsh_<名> 合成 DelegateTool),保留作回退 |
| opt-in 工具 | subagent_codebuddy + list_codebuddy_models(registerSubagentTools: true 开启;默认关闭,推荐通用工具) |
| 压缩归属 | codebuddy 会话的压缩由 CLI 负责(dsh 的自动压缩被插件接管,不压镜像);CLI 压完之后镜像成 dsh 的标准压缩卡,零 token(见 §三「压缩归属」) |
语义说明(主代理轮,重要):ACP CLI 自带 agent 循环,但它的内置工具已全部禁用
(spawn 传 --tools "";delegate 模式只放行委托工具合成器 DelegateTool,见 §三「工具桥」)。
因此:
- 模型的全部工具面 = dsh 侧工具(MCP 模式下是
mcp__dsh__bash/mcp__dsh__edit/mcp__dsh__read_image…,delegate 模式下是dsh_bash/dsh_edit…)。这些调用 在 dsh 侧执行,受 dsh 的沙箱与审批约束,并进会话日志、审计与后台任务面板。 - 读图片走 dsh 的
read_image:图片既作为图片进入 CLI 侧模型的上下文(MCP image 内容块), 也进 dsh 会话出图片卡片(read_image是 dsh 原生工具名,UI 按名字渲染图片卡)。 - 文本/思考/工具卡片仍以会话事件实时回传 dsh 界面。
为什么全禁而不是白名单(2026-09-18):CLI 原生工具要进 dsh 会话,必须在会话 scope 注册 「回放镜像」承接;镜像注册一旦丢失,该会话的原生调用就永久报
unknown tool "cli_read"(偶发、不可复现)。全禁后这条路径不再被触发。 逃生口:extraArgs排在--tools之后,可用extraArgs: ['--tools', 'Read']覆盖本策略。 历史注记:更早的版本让 CLI 用自己的工具链、dsh 沙箱不参与——安全模型以本节为准。
二、快速开始
系统要求
- dsh
>= 0.1.3-alpha.2(验证于 0.1.3-alpha.2) - CodeBuddy CLI 已安装并登录(子进程继承登录态)
- 需运行在带
webServer服务的 profile(如web):bridgeMode: mcp依赖它挂 MCP 端点;拿不到该服务时端点不注册,--mcp-config不注入(不会报错,但工具桥不可用)
安装插件
node scripts/link-profile.mjs # 默认装配进 web profile
# 或等价于:dsh plugin --profile web add <本仓库目录>
插件行由插件自带的 cordis.patch.yml(bundle patch)自动注入,默认配置开箱即用。
需要覆盖默认值时,在 profile 的 cordis.patch.yml 用同 id 覆盖:
- id: subagent-codebuddy
config:
model: <其他模型> # 默认 deepseek-v4-flash
registerSubagentTools: true # 需要 opt-in 工具时开启
bridgeMode: delegate # 工具桥回退到旧通道(默认 mcp)
设置面板(设置 → 插件 → CodeBuddy)也可改模型与工具桥开关,表单值优先于本文件。
重启 dsh web 后:模型选择器出现 CodeBuddy 分组。
主代理使用
新会话 → 模型选择器 → 选中 CodeBuddy 的某个模型(如 deepseek-v4-flash)→ 正常对话。
该轮由 CodeBuddy 驱动;它的文件/命令类工具经工具桥回到 dsh 执行(见 §一「语义说明」),
步骤/文本实时回传 dsh 界面。
子代理委派(通用工具)
- 设置 → 子代理模型选择,把 codebuddy 路由加入允许列表(新顶层会话生效):
subagent-model-selection: enabled: true allowedModels: - provider: codebuddy model: deepseek-v4-flash - 主代理调
subagent工具,传provider: codebuddy、model: <id>(model 为精确 id, 目录见list_subagent_models或主模型选择器)。
动态模型选择
- adapter
listModels():从codebuddy --help实时解析支持列表(成功缓存 10 分钟), 配置默认模型始终并入目录,CLI 不可用时回退配置模型、provider 仍可选择。 - opt-in 的
list_codebuddy_models工具提供同样数据的文本视图。
配置项
| 键 | 默认 | 含义 |
|---|---|---|
command | codebuddy | 可执行文件(Windows 自动解析 npm cmd-shim → node <真实CLI>) |
model | deepseek-v4-flash | 默认 CodeBuddy 模型 ID(子代理委派缺省值;主代理选择器另选) |
permissionMode | bypassPermissions | --permission-mode:CodeBuddy 工具调用自动放行 |
extraArgs | [] | 追加的 CodeBuddy 参数 |
providerName | codebuddy | LLM provider 路由名 |
toolName | subagent_codebuddy | opt-in 工具名 |
registerSubagentTools | false | 是否注册 opt-in 委派工具(推荐用通用 subagent) |
bridgeMode | mcp | 工具桥模式:mcp = dsh 起 HTTP MCP server、工具以 mcp__dsh__<名> 呈现(完整 schema,推荐);delegate = 旧 DelegateTool 通道(dsh_<名>,回退用)。设置面板有同名开关,切换对新回合生效 |
longToolCapMinutes | 30 | 静默长工具硬顶(分钟,0 = 关闭):只影响发起后零事件的工具段(任何中间进展都会重置计时);超顶中止本次调用并自动续跑——防止 CLI 卡死时进程泄漏、子会话回合悬空 |
tailQuietSeconds | 5 | 尾巴窗口静默阈值(秒,0 = 关闭):干净收尾后继续抽流,等 CLI 后台任务完成后的自发续跑 |
tailBgQuietMinutes | 10 | 起了后台任务的回合的静默阈值(分钟) |
tailCapMinutes | 30 | 尾巴窗口硬顶(分钟):后台任务最长可拖着回合不闭合的时长 |
三、工作原理
主代理轮: 会话模型选择器 → codebuddy/<id> → CodebuddyLlmAdapter
└─ spawn codebuddy --acp --tools "" [--mcp-config <会话专属配置>]
→ initialize → session/new|load → session/prompt
└─ session/update(思考/文本/工具)→ 写入调用方已打开的 step
└─ 工具调用回流:CLI 调 mcp__dsh__<名> ──HTTP JSON-RPC──▶ dsh MCP 端点
└─ 伪装成工具调用块灌进 dsh loop → 原生执行(审批/沙箱/事件/UI 卡片)
└─ tool/result 回填 MCP 响应 ──▶ CLI 拿到结果继续
子代理轮: 通用 subagent(provider: spawn) → child agent → 同一 adapter
工具桥(MCP / delegate)
CLI 内置工具已全部禁用(--tools "",见 §一「语义说明」),模型的一切能力必须由 dsh 提供。
插件把当前会话可见的 dsh 工具暴露给 CLI,两条通道:
mcp(默认) | delegate(回退) | |
|---|---|---|
| 呈现 | mcp__dsh__bash / mcp__dsh__edit … | dsh_bash / dsh_edit …(合成 DelegateTool) |
| 参数约束 | 各工具完整 JSON Schema(协议下发,强约束) | 无结构 input: object(模型端几乎零约束) |
| 传输 | dsh 起 HTTP MCP server,CLI 每回合以 --mcp-config 连接 | ACP session/request 反向调用 |
| 工具集 | tools/list 每次现取会话可见工具(不缓存) | 回合开始前批量注册 |
MCP 端点的安全约束:仅 loopback 来源 + URL 携带每进程随机 key(双重校验),挂在 dsh
自带 webserver 上(与 Web UI 同端口),不额外开监听;tools/call 另按 tools/list 的同一份
工具面校验可见性。会话专属配置写在系统临时目录,权限 0600,超龄自动清扫。
客户端放弃后的结果补投(交互式工具的关键路径):CLI 侧一旦按超时/断连放弃一次
tools/call,它的模型就永远看不到结果,而 dsh 侧不会因此中止已经注入 loop 的调用。
对交互式工具这是致命的:用户在 ask_user_question /
exit_plan_mode 上作答之后,回答送达的是一个已经消失的调用——界面上"提问结束就完了",
不会有任何后续。所以端点把这类结果补投进会话:客户端确实断连过(响应未写完就
close)且调用最终完成时,把结果作为一条 notice 投进会话;会话空闲就唤起一轮(CLI 被
重新 prompt,模型据此继续),忙则排队等下一步。只在客户端确实断连时才投递——那时 CLI
一定没收到响应,所以这不是重复上报。同理,转发兜底超时那句"不要盲目重跑同一命令"
也会补投:它正是防止同一副作用跑两遍的关键,丢在一个已经消失的响应里等于没说。
诊断落盘:桥的关键诊断(客户端等待时长、兜底超时、回落直执、补投失败)除
console.error 外还会追加到 ~/.dsh/codebuddy/mcp-bridge.log。控制台日志会随终端滚掉,
而"CLI 到底有没有放弃这次调用"必须可事后核对——其中打印的客户端等待时长就是
CLI 侧工具超时 T_client。pump.ts 的 MCP_CALL_TIMEOUT_MS 若要收紧必须以这个值为据,
不要拿尾注里那句未经验证的 30s 反推(曾这样推成 25s 并造成回归,有回归用例钉住)。
- 事件写入:adapter 检测调用方(agent-loop)已打开的 turn/step,把 ACP 的
思考/文本/工具事件直写进该 step(tool/call 前先以 assistant/message 广告,
严格满足 dsh 会话格式 v2 关系校验);辅助调用(压缩/标题,带
purpose) 或没有打开 step 时退化为纯 chunk 流,不写会话。 - 历史原生转换:已有对话切换到 codebuddy 时,折叠后的 dsh 历史由转换器写成
CodeBuddy 原生会话文件(
~/.codebuddy/projects/<slug>/<sessionId>.jsonl: user/assistant 消息 + function_call/result 记录),再session/load载入—— 历史以原生消息进入 CodeBuddy,而不是压成一段提示词文本。载入失败自动回退 "新会话 + 全量提示词"。单条消息的新会话(如子代理首次委派)直接走session/new。 - 会话续跑:同一 dsh 会话映射到同一 ACP sessionId(
session/load回放复用, 映射持久化在~/.dsh/codebuddy/conversations.json,服务重启可恢复); 可重试失败(静默空跑/进程退出/超时)自动恢复续跑,用尽才显式报错; 切换其他模型期间的缺失轮次在续聊时自动补发。 - 假死防御:进展性 update 重置动态空闲阈值;工具在途期间暂停计时
(ACP 工具无心跳,完成即重新起算);静默超阈值先
session/cancel、5s 后 kill。 - CodeBuddy 的模型、网络与配额由 CodeBuddy 侧负责,插件只做桥接。
压缩归属(重要)
codebuddy 会话的压缩由 CLI 负责,dsh 不参与。 这不是可选项,是架构约束:dsh 只是渲染层,
真实上下文在 CLI 自己的会话文件里;而 dsh 的压力测量以 CLI 上报的 usage 为基线,它唯一能压的
却是 dsh 侧的镜像消息面 —— 压完压力不降 → 下一个 step 再触发;compaction-basic 的收缩闸门
(summary is not smaller than the shadowed content)在镜像面只剩旧摘要时必然拒绝,于是变成
压缩风暴(短时间内连打 20+ 次 compaction/start → compaction/end(error)),
偶发成功的那几次还会把镜像面替换成摘要、把模型带偏。
实现方式(零 dsh 源码改动):
| 路径 | 行为 |
|---|---|
自动压缩(agent/pre-step 的 pressure / agent/request-error 的 context-overflow) | 插件在 ctx.compaction 服务实例上接管 compactIfNeeded;codebuddy 路由的会话一律返回 null |
手动 /compact | per-agent 命令覆盖 → 转发给 CLI(跑在 runMaintenance 相位里,压缩期间消息按原生行为排队) |
compactNow 兜底 | per-agent 覆盖没挂上时全局命令会走到它 → 同样接管,不压镜像 |
| CLI 自己压完之后 | compact-mirror 把这次压缩镜像成 dsh 的一次压缩事务 → 界面出现标准压缩卡。零 token:照抄 CLI 的摘要原文,不调用任何模型,只有本地文件读取 + 日志写入 |
镜像的两个时机与一条去重规则:
- 时机:挂在
agent/pre-step(CLI 在 step 之间压的)和agent/turn-stopping(CLI 在 回合收尾压的,最常见)。只挂前者的话,回合收尾那一次本轮再没有下一个 step,压缩卡与 上下文容量都要等到下一个大轮才出现。两个时机都在turn/end之前,turn归属天然正确。 - 去重:dsh 自己发起的那次压缩(手动
/compact转发)不再镜像——命令回执已经报过它, 再补一张压缩卡就是同一次压缩的两条消息。判定按时间线而不是"第几条摘要":CLI 的摘要是 惰性落盘的(手动压缩的摘要可能十几分钟后才写出),期间镜像层会先看到一条更早的、与本次 无关的摘要,而它恰恰会落在手动压缩回执的旁边——用户看到的两条正是这一对。30 分钟 TTL 兜底, 转发没有产出时不会永久静音镜像。
判据是会话最新一次请求的路由 provider(不是持久化的会话映射)——把 codebuddy 会话切回别的 provider 后,dsh 会恢复正常压缩。
已知限制:镜像时机与容量刷新
- 压缩卡必然出现在一轮对话的尾部。ACP 协议不报压缩事件(
session/update只有agent_message_chunk/agent_thought_chunk/tool_call/usage_update等类型, 没有compact或summary)。CLI 的压缩发生在 ACP run 内部(收到 prompt → 检查压力 → 压缩 → 落盘 → 处理 → 流式返回),对 dsh 完全不可见。镜像层只能 tail CLI 的会话文件 (~/.codebuddy/projects/<slug>/<acpId>.jsonl里的{"type":"summary","providerData":{"source":"periodic"}}记录),而该记录的落盘是惰性的。所以卡片最早只能在turn-stopping(turn 收尾)弹出—— 这是 dsh 能读到新摘要的最早时机。除非 CLI 在 ACP 协议里增加压缩通知,否则无法更早。 - 上下文容量环(ContextMeter)不会在压缩时立即下降。容量环显示的是
contextPressure投影的projectedTokens,而pressureTokens只在 CLI 上报usagechunk 时更新。压缩镜像是纯逻辑写(零模型调用、零 usage 事件),不产生usage→ 容量环停在 最后一次请求的值,直到下一轮请求上报 usage 才降到新值。这是设计后果,不是 bug。
压缩卡不会隐藏或删除任何历史消息:被遮蔽的消息照常渲染,dsh 的历史接口不做过滤。 压缩改的是 dsh 的 surface(上下文压力表,以及插件需要重建 CLI 上下文时的素材
buildPrompt/ 原生 seed)。
启动自检与告警(不会再静默失效):插件装载时自检接管是否真的落到实例上,dsh 升级若改了
压缩入口,控制台会出现 [subagent-codebuddy/compact] …未生效/未安装 的 warn;正常接管时每个
codebuddy 会话播报一次 已接管 <sessionId> 的 dsh 压缩;镜像成功时播报
[subagent-codebuddy/mirror] 已把 CodeBuddy CLI 的压缩镜像到 dsh 会话 <id>…。
四、参与开发
pnpm install # 安装 typescript + vitest(PowerShell)
pnpm build # tsc 编译 → lib/(产物随仓库提交,免构建安装)
pnpm test # vitest 单元测试
pnpm typecheck # tsc --noEmit
本仓库的
pnpm install只在开发机上可用:package.json的devDependencies用了link:<绝对路径>形式指向 dsh 源码树(本地联调需要)。 换机器前需把它们改成正常的版本号(如>=0.1.3-alpha.2)或workspace:*。 仅使用插件(不构建)的人不受影响——运行时lib/只依赖相对路径与 peerDependencies。
分发与发布
分发走 git(不做 npm publish):使用者把本仓库目录加进 profile 即可,lib/ 已随仓库提交。
发布前检查:
pnpm typecheck && pnpm test全绿;pnpm build且lib/与src/同步(git status里lib/的改动应与src/一致—— 否则使用者拿到的是旧产物);- README 的配置项表/能力表与实际
Config一致; git status无遗留文件;git add -A && git commit -m "..." && git push origin master。
五、许可证
MIT
Comments
Loading…
From the same category
by zhu1090093659
DeepSeek Harness (DSH) Web Plugin Aggregation Ecosystem · Everything is a plugin, distributed via the Creative Workshop
★ 8.2k
↓ 134/wk
Apache-2.0
TypeScript
Oct 1, 2026
dsh plugin --profile web add dsh-webby ccch1mneyyy
DSH 官方公众号收录的 TUI 补位插件:Claude Code 风,鲸鱼顶栏/实时状态/流式思考/双击 Esc 回滚/上下文进度+TPS。npm 一键装。 DSH official WeChat featured TUI plugin — Claude Code style: whale bar, live status, streaming thoughts, double-Esc rol
★ 3.9k
↓ 11.6k/wk
MIT
TypeScript
Oct 1, 2026
dsh plugin --profile terminal add @deepseek-harness-tui/dsh-tuiby YuJunZhiXue
DeepSeek Harness 破甲:让所有模型都能破甲,不同模型可换不同提示词;默认提示词面向国模「小码酱」。Jailbreak for every model — swap prompts per model. 求 Star 收藏 ⭐
★ 2.9k
MIT
JavaScript
Oct 1, 2026
dsh plugin --profile web add dsh-purgeby bowenliang123
The best DeepSeek Harness plugin for context insight and management, with context dashboard / browser / sidebar and context command, for context statistics, composition, breakdown, evolution details,
★ 1.8k
↓ 32k/wk
Apache-2.0
TypeScript
Sep 30, 2026
dsh plugin --profile web add dsh-contextby agentrq
AgentRQ: Human-in-loop realtime conversational task manager for AI Agents. Self-hosted! Control your own agents from wherever you want Mobile, Web, Desktop. Designed to work well with your own Claude
★ 1.1k
↓ 56/wk
Apache-2.0
JavaScript
Oct 1, 2026
dsh plugin --profile web add @agentrq/dsh-plugin-agentrqby vshulcz
One memory shared by Claude Code, Codex, Cursor, Copilot CLI, OpenClaw and 20 more coding agents, built from the session history already on disk. A fix found in one agent comes back in any of them, in
★ 1.1k
↓ 1.2k/wk
MIT
Go
Oct 1, 2026
dsh plugin --profile web add dsh-deja