deepseek-harness-desktop/packages/dsh-desktop-compat

156Star5Fork6Issue0Watching

为 DeepSeek Harness 桌面端修补若干兼容问题:取消后队列消息不发送、停止提示显示 [object Object]、部分模型的工具调用多一层 arguments 包装。

机审证据安装命令仓库已核验dsh-plugin Topic许可证READMEAI 百科

此插件是大仓库 ningbainb/deepseek-harness-desktop 的子包,星数与活跃度统计的是整个仓库。

语言
TypeScript
License
BSD-3-Clause
分支
main
ai-agentai-coding-assistantcodexdeepseekdeepseek-harnessdesktop-appdshdsh-plugin

安装

$ dsh plugin --profile web add github:ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat

在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程

对话式安装

帮我安装 DeepSeek Harness 插件 ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat:先查看仓库 https://github.com/ningbainb/deepseek-harness-desktop.git 确认安全性,然后执行安装命令并验证插件加载成功。

把这段指令粘贴给 DSH Web GUI 里的助手,由它代你完成安装与验证。

一句话定位

为 DeepSeek Harness 桌面端修补 0.1.0-rc.7 上几处特定兼容问题——取消后排队消息不再被发送、停止提示显示成 [object Object]、部分模型给工具调用多套一层参数包装。它通过公开 SDK 钩子工作,不修改 DSH 源码,上游修好后即可移除。

核心能力

  • 取消当前回复后自动续推普通排队消息:监听 agent 状态进入空闲且 inbox 仍有排队项时,通过公开的 followup 钩子重新叫醒官方 agent 驱动,保留先进先出顺序,不会复制消息
  • 把工具执行的 [object Object] 取消展示替换成中文友好提示:当 code run failed (abort)tools/post-execute 钩子时,将其替换为「当前执行已停止,排队消息将继续发送」
  • 修复模型工具调用的多余 arguments 包装:部分适配器会把工具实参再套一层 {"arguments":{...}},插件在 agent loop 解析之前按 schema 严格匹配,只在外层被拒绝、内层被接受时剥掉一层
  • 在桌面端隔离 profile 里维护主题/皮肤的启用与禁用状态:自动迁移旧条目、按标记段安全写入,避免与官方皮肤中心的持久化状态互相覆盖
  • 在桌面端后台自动化模式下提供任务板 Host 调度器:仅当 DSH_DESKTOP_BACKGROUND_AUTOMATION=1 时挂载,使用官方 agent / session / workspace 接口跑调度任务,支持崩溃后恢复会话
  • 通过本地回环路由控制工作区文件本地打开:限制只能打开白名单扩展名的非脚本文件,路径必须落在已注册工作区根目录下,并用 Token 验证只接受 Electron 主进程请求

技术实现

  • 语言: TypeScript(target ES2022, module NodeNext, type module)
  • 关键依赖: @deepseek-ai/dsh-agent@deepseek-ai/dsh-tools@deepseek-ai/dsh-llm@deepseek-ai/dsh-workspace(皆 0.1.0-rc.7,来自 package.json:38-44)
  • 架构模式: Cordis function plugin + cordis bundle patch;apply(ctx) 一次性挂 4 个补丁点(agent/status 事件、tools/post-execute 中间件、llm/stream 全局钩子、桌面文件打开路由),并按 process.env.DSH_DESKTOP_BACKGROUND_AUTOMATION 条件挂 Host 调度器。声明 inject = ['llm','tools','webServer','workspaceRegistry'] 保证依赖服务先就绪
  • 入口文件: packages/dsh-desktop-compat/src/index.ts(apply 入口;副作用按模块分布在 recovery.tstool-call-normalization.tsskin-state.tsbackground-scheduler-runner.tsworkspace-file-open-route.ts

适用场景

当你使用 DeepSeek Harness Desktop 桌面客户端 0.1.0-rc.7,遇到以下任一情况时这个插件能直接修复:取消一轮对话后排在后面的消息再也没有被自动发出、取消后工具结果框里出现 code run failed (abort): [object Object] 这种含糊信息、或者某些模型返回的工具调用一直因为多一层 arguments 包装而失败。它不引入新功能,纯做缺漏修补,所以只在你看到上述症状时才有意义。

前置依赖与兼容性

依赖最低版本说明
DeepSeek Harness 桌面端宿主0.1.0-rc.7dependencies 全部锁到 0.1.0-rc.7(package.json:38-44);补丁清单的 applicableVersions 也只列此版本
Node.js^22.19.0 || >=24.0.0package.json:7-9 engines.node
桌面端隔离 profile必需README 写明「DeepSeek Harness Desktop 2.0 会在隔离的 desktop profile 中自动挂载这个 bundle」,通用 Web UI profile 不会加载它
DSH_DESKTOP_WORKSPACE_FILE_OPEN_TOKEN 环境变量桌面端运行时设置仅在使用原生文件打开路由时需要;Token 长度为 43 字符 base64url,由桌面端主进程随机生成并校验(src/workspace-file-open-policy.ts:14-21)
DSH_DESKTOP_BACKGROUND_AUTOMATION=1 环境变量桌面端后台自动化模式启用仅当用户显式打开「最小化到托盘 / 后台自动化」时由桌面端设置;不设则跳过 Task Board Host 调度器,浏览器侧调度器继续工作
平台macOS / Windows / Linux跨平台,无原生模块依赖(Node 自带 fscryptonode:http

安装方式

dsh plugin --profile web add github:ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat

配置项

本插件无需额外配置。所有行为都是「缺漏即补」,不开放用户级 schema。

配置类型说明默认值
DSH_DESKTOP_BACKGROUND_AUTOMATION环境变量(可选)设为 1 时启用 Task Board 的桌面端 Host 调度器(仅当用户在桌面端主动打开「最小化到托盘 / 后台自动化」时才设);不设则使用浏览器侧调度器未设置
DSH_DESKTOP_WORKSPACE_FILE_OPEN_TOKEN环境变量(可选)桌面端主进程生成的 43 字符 base64url 随机串,用于工作区文件本地打开请求的 Token 校验;仅在桌面端使用由桌面端主进程随机生成

常见问题

Q: 安装命令显示往 web profile 里装,真的能用吗?

A: 这个包的源码确实是通过 dsh plugin ... add github:... 走通用 NPM bundle 通道分发(cordis.patch.yml:1-5),但 README.md:29 明确写「DeepSeek Harness Desktop 2.0 会在隔离的 desktop profile 中自动挂载这个 bundle。这个包不作为通用 Web UI 插件提供」——也就是说它在桌面端才会被实际加载,web profile 只是安装载具。如果你的桌面客户端没有自动加载,请确认客户端版本是 0.1.0-rc.7+ 且启用了隔离 desktop profile。

Q: 用了它之后我原来的「不排队、直接发送」选项还能用吗?

A: 能。README.md:33 明确「发送仍默认进入队列,steering 消息行为不会改变」,排队行为完全维持 DSH 原状,插件只是修补取消后那一处「不该停却停了」的问题。

Q: 工具调用多了一层包装,所有模型都能修吗?

A: 不能保证。它只针对 {"arguments":{...}} 这一种单 key 包装(src/tool-call-normalization.ts:63-66)。而且「外层通过 schema、内层也通过 schema」这种二义情况会主动放弃剥壳、保持原样(src/tool-call-normalization.ts:137-142),由 DSH 自带的 schema 校验接管。其他形状的包装层一律不处理。

Q: 它会写日志吗?日志里会泄露我的工具参数吗?

A: 会写诊断日志,但不会写原始参数。工具调用参数恢复会在日志里输出 outcome、reason、provider、model、tool 名、call id、来源(src/tool-call-normalization.ts:339-352),但故意不包含任何工具实参。queue 恢复失败也会写 warn(src/index.ts:46-49)。

Q: 怎么确认它真的在我桌面端生效了?

A: 看桌面端启动日志里有没有出现 dsh-desktop-compat: 前缀的输出(任何补丁命中都会留痕),或者在调试环境 pnpm --filter @linxin666/dsh-desktop-compat test 跑包内自带 6 份 vitest 测试(tests/ 目录下)。

Q: 上游 DSH 修了同样的问题,我需要做什么?

A: 卸载插件即可。src/patch-registry.ts:49-86 给每个补丁都注明了 removeWhen 条件(比如「The upstream agent loop natively and deterministically resumes queued turns.」),达到条件后整个包就没存在的必要了。

Q: Task Board 的后台调度具体能跑什么任务?

A: 仅支持「项目制、shared-workspace 隔离、必须有 prompt」的任务(src/background-scheduler-runner.ts:114-118、216-230)。git-worktree 隔离、空 prompt、workspace 未注册或模型未配置都会被拒,但不报错——任务交给浏览器侧调度器继续找执行路径。

上手难度

入门 — 安装由桌面端自动完成,没有用户级配置,行为都是「缺漏修补」式;普通用户不需要理解 SDK 钩子细节,只要确认桌面客户端版本匹配、症状对应即可。开发者若想理解实现,需要熟悉 Cordis function plugin、agent/status 事件流和 LLM stream chunk 协议。

已知问题与限制

  • 仅适配 DSH 0.1.0-rc.7:补丁清单里每个补丁的 applicableVersions 都只列此版本(src/patch-registry.ts:49-86);其他版本需要桌面端先用着,等补丁更新
  • 工具调用参数恢复只在「外层 schema 拒绝、内层 schema 接受」时剥壳:其他情况(双通过、双不通过、未知工具、重复工具 schema)一律不动;诊断里会带 reason 标明具体原因(src/tool-call-normalization.ts:21-28、100-152)
  • 上游一旦实现相同的取消续推 / 取消展示 / arguments 包装处理,本包就失去存在意义(README.md:35-37、src/patch-registry.ts 各个 removeWhen 字段)
  • 后台 Host 调度器只接管 shared-workspace 隔离、git-worktree 隔离会被显式拒绝并写 fallbackReason(src/background-scheduler-runner.ts:256-258)
  • 工作区文件本地打开只接受白名单扩展名,脚本类(.js、.ts、.html、.svg 等)被显式排除(src/workspace-file-open-policy.ts:28-44),路径必须在已注册工作区根目录下(src/workspace-file-open-route.ts)
  • 普通 Web UI profile 不会自动加载这个 bundle,需要桌面端的隔离 desktop profile(README.md:29)

收录徽章

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat)

把这段 markdown 粘贴到你的 GitHub README,链接回本插件详情页。徽章只声明已被本站收录,不代表安全认证。

返回插件目录