dsh-acp-door
连接本机 DSH 与 VS Code 等外部程序,共用模型、工具、记忆和会话。支持历史查看、权限切换及已注册插件的能力调用。
存在 DSH workspaceRegistry 时,历史列表默认仅包含工作区已登记或已置顶的未归档会话,archived: true 只读取已归档会话,unlisted: true 读取尚未登记的未归档持久记录;过滤先于分页与标题读取。新建和接回的 ACP 会话会登记到相应工作区。归档、恢复调用同一注册表的 archiveSession、unarchiveSession,不直接修改归档文件,也不隐式停止运行中的任务。归档与成员范围变更以 dsh-door/history-changed 通知所有已连接面板,通知只含列表版本,不含会话正文。缺少该服务时明确报告归档状态未知,并禁用写入。
旧版 v3 历史异步读取并在内存中缓存摘要,最多保留 16384 条或 8 MiB;不缓存完整对话正文。文件身份、大小或修改时间变化后重新读取,删除的记录从缓存移除。客户端通过 $/cancelRequest(id)或 ACP 的 $/cancel_request(requestId)取消查询,连接断开也会停止等待结果;v3 会同时停止后续读取,v4 内部读取仍由内核公开 sessionQuery 管理。每个连接最多同时等待 8 个历史请求。
需要已安装并运行的 DeepSeek Harness,以及支持 ACP 的外部客户端。接入点仅供本机使用;安装后需重启对应的 DSH 内核。
dsh-door/images/capabilities({sessionId})检查当前连接所属会话的模型是否声明图片输入、原生附件服务是否可用,以及初始化连接时是否启用了图片。当前验证范围为 ACP 0.2.1-rc.3,发送仍使用标准 ACP 图片内容块。模型切换后重新查询;原连接禁用图片时需要重连。相关工具清单来自当前 Agent 可见的注册名称,不能据此保证外部搜图或图片生成服务可用。
成功读取历史后,图片以不含原生附件标识的临时引用返回。客户端通过 dsh-door/images/read({token})读取该连接已取得的图片引用;未知或其他连接的引用被拒绝。历史图片按格式、内容摘要和大小校验,并受并发、超时和取消限制。
在同一内核启用 dsh-meme 和 Web 服务时,客户端可通过 dsh-door/media/catalog、dsh-door/media/read 读取表情图库及图片,两个方法均指定 provider: "dsh-meme",图片读取另传图库返回的 id。状态中的 capabilities.media 表示适配接口可用;插件是否已启用以图库请求结果为准。适配器只访问该内核回环地址上的固定插件路由,不读取图库数据库,不执行图库管理操作;每项内容限制为 8 MiB,并校验图片类型及文件签名。当前按 dsh-meme 0.1.52 的公开路由格式验证。
0.2.0 增加同一连接上的 IDE Bridge:插件主动注册能力、本机自动鉴权、可恢复运行与取消。 协议规范见仓库的 docs/bridge-v1.md。现有 ACP 会话、流式输出、历史和权限方法继续兼容。
English
dsh-acp-door opens an extra ACP (Agent Client Protocol) transport on a running DeepSeek Harness kernel — loopback only (127.0.0.1), for use on your own machine. ACP chat retains its local transport; IDE Bridge calls use a per-user endpoint credential and client lease. External clients such as the *DSH Panel* VS Code extension can then drive the very same kernel you already have open: same config, same memory, same tools, same session records.
ACP normally speaks over stdio, which can only be attached at process start; this plugin instead mounts one ACP bridge per TCP connection on top of the live kernel, and exposes a few bypass methods the core does not have over ACP (session listing, permission presets).
Install:
dsh plugin --profile <your-profile> add dsh-acp-door
Restart the kernel (or the desktop app) afterwards — plugins are loaded at startup.
For a compatible update of an installed copy, run:
dsh plugin --profile <your-profile> update dsh-acp-door
Restart the kernel afterwards.
Compatibility: DSH 0.1.5-rc.2, 0.2.0-rc.1, 0.2.0-rc.2, and previews 0.2.1-alpha.1 / 0.2.1-rc.2 / 0.2.1-rc.3. DSH 0.2.1-rc.2 requires dsh-acp-door 0.5.2 or later; 0.2.1-rc.3 requires 0.6.2 or later. Current candidate acceptance is recorded in the compatibility matrix.
安装
dsh plugin --profile <档名> add dsh-acp-door
安装完成后需要重启内核(或重启桌面端)才会生效:ACP 接入点插件(dsh-acp-door)在内核启动时加载。
该插件装入哪个档,外部程序即可连接该档的 DSH —— 桌面端所用的档由桌面端自身管理 (运行时命令行无法修改),因此通常装入用户自己的档。
若 VS Code 面板需要在桌面端未运行时自行启动 DSH,应使用可由命令行启动的网页配置集, 而不是 desktop 配置集。例如:
dsh --profile vscode-panel --from-default-profile web --dump-config
dsh plugin --profile vscode-panel add dsh-acp-door
安装后重启该配置集的内核。新会话默认使用该配置集中 DSH 当前选择的默认模型;无需把 服务商或模型名再复制到本插件配置中。若该配置集还没有选择模型,先在 DSH 的模型设置中完成选择。 不同电脑分别安装各自的 DSH 与本插件;接入点固定在 127.0.0.1,不支持远程设备连接、端口转发或隧道。
安装 VS Code 配套扩展
在提供 Connection 与界面 Slots 接口的本机 DSH 桌面端或网页版中,首次加载接入点后会检查默认 VS Code 配置集。 尚未安装时显示“VS Code 配套扩展”提示。选择编辑器和已有配置集,点击“安装配套扩展”后, 插件通过 VS Code 官方命令下载 Elk-ydy.dsh-acp-panel,并重新查询所选配置集,确认存在后才显示成功。 已经安装时不重复安装或强制更新。安装失败可重试,也可使用提示中的扩展市场入口或手动命令。
点击“稍后安装”会保存偏好,不再自动弹出。之后可从 DSH 设置 → VS Code 配套扩展继续安装或重新检测。 该偏好保存在当前 DSH_HOME 的 plugins/dsh-acp-door/companion.json 中,与插件版本无关。 不会在包管理器的安装脚本中执行安装;安装动作仅由用户点击触发。
编辑器检测覆盖常见安装目录、Windows 安装记录及 PATH 中的 VS Code / Insiders;Windows 便携版读取自身数据目录。 未检测到的自定义安装可以直接在 VS Code 扩展视图搜索 DSH ACP Panel。 安装过程中不创建 VS Code 配置集。远程访问的 DSH 页面不提供此功能;无界面或缺少上述接口的旧 DSH 继续使用原有 ACP 接入点,可按以下命令单独安装扩展:
code --install-extension Elk-ydy.dsh-acp-panel
更新
常规兼容更新使用以下命令:
dsh plugin --profile <档名> update dsh-acp-door
该命令按当前配置集中声明的版本范围更新。更新完成后重启对应内核(桌面端使用的配置集则重启桌面端)。 若版本说明标为不兼容更新,按该版本的安装说明处理,避免在未阅读变更记录的情况下跨越大版本。
配置项(写入档的 cordis.patch.yml,见本包自带的同名文件):
键 · 默认 · 说明 host · 127.0.0.1 · 固定监听地址。其它值会被忽略,接入点不会暴露到局域网。 port · 47821 · 监听端口。也可用环境变量 DSH_ACP_DOOR_PORT 覆盖(0.0.11 起)。 provider / model · 留空,跟随 DSH · 可选的成对覆盖;必须同时填写才会固定新会话的初始模型。 preset · standard · 新会话挂载的 agent preset 套件。
解决的问题
ACP 默认使用标准输入输出:该通道只能在进程启动时接入。 而 DSH Desktop 已处于运行状态时,外部程序无法接入该通道。
DSH 自带的 ACP 插件支持注入传输层(其源码中有对应实现):
const stream = config.stream ?? ndJsonStream(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
因此该插件仅执行一项操作:在每个 TCP 连接上挂载一份 ACP 桥。
DSH Desktop(运行中)
├── 内核:agents / llm / sessions / 工具 / 记忆 / 技能 ← 只有一份
├── 网页界面 (原有)
└── 该插件:127.0.0.1:47821 ── 每个连接 = 一份 ACP 桥 (新增)
会话预设补挂的必要性
这是该插件除监听端口之外唯一执行的实际操作,也是最易出错的环节,因此单独说明。
桌面端与网页端架构停用了宿主层的全部工具 —— dsh-web-app 的补丁中:
- id: tool-bash
disabled: true
- id: tool-pwsh
disabled: true
- id: tool-jobs
disabled: true
- id: tool-fs
disabled: true
- id: tool-fs-search
disabled: true
它的注释说明了理由:*"the Web surface disables them here and lets each session mount a preset instead"* —— 即工具改为 每个会话按 agent preset 挂载一套。
而 @deepseek-ai/dsh-acp 创建 agent 时只传入工作目录、从不指定预设 (dsh-acp/lib/index.js 的 AcpSession.create 中为 meta: { cwd })。 两者结合后,经 ACP 建立的会话缺少工具来源:宿主层未提供工具,预设层也未指定预设 —— 即一个无法调用工具的 agent(该 agent 会声明「我来读一下这个文件」,随后无法执行任何操作)。
内核自身的报错文案指明正确做法:
(join through AgentPresets.mount() or composeFrom() in the agent factory setup)
因此该插件监听 agent/created,使用公开的 agentPresets 补上这一步。新建会话与 恢复的会话使用两个不同的入口 —— 该结论来自实测,并非推测:
情况 · 所用入口 · 原因 新建的会话 · select(agent, id) · 该入口重新组装 agent 的作用域,并将本次选择追加进会话事件日志(agent-preset/selected)。 恢复的会话(断线重连 / 打开历史会话) · mount(agent.ctx, id) · 内核按「是否执行过回合」为 select 设置了锁(agent-preset/locked,属设计行为)。恢复时 agent 的作用域为重新组装的结果,缺少该调用时作用域为空。mount 是工厂期使用的入口,只负责组装,不检查该锁。
恢复会话与工具挂载
恢复的会话需要重新挂载工具预设。select() 适用于新建会话;恢复时遇到预设锁,改用 mount(agent.ctx, id),确保恢复后的 Agent 具有该预设提供的工具。
两项必须注意的约束(均已实测)
- `agentPresets` 必须写成声明式依赖。 cordis 的服务代理对未声明的属性
直接抛错(cannot get property "…" without inject)。该异常发生在内核 创建 agent 的同步流程中:或打断 session/new,或被 async 捕获, 使该插件静默失败。因此该服务写入 inject,缺少该服务的 profile 不会启动这个插件。 同一结论也适用于 mount():该入口需要 agent 的作用域上下文(agent.ctx), 传入错误对象会抛 refusing to compose an unscoped context。
- 存在一处竞态,必须由入站闸阻塞。 内核派发
agent/created 时不等待
监听器返回的 promise,因此「补挂预设」与「客户端发送第一个 prompt」并行执行。 客户端请求先到达时,模型尚无完整工具清单。因此传输层对该会话的 session/prompt 设置入站闸,等待预设挂载完成再发送。
预设恢复来源
对于 v3 会话格式:
- 桌面端建立的会话,第一行 header 中含
"agentPreset":"standard"; - 经该插件建立的会话,不含
agentPreset —— 建立后读取即不存在,执行完一个回合后再读仍不存在。
即内核仅在桌面端所使用的建会话方式下将预设写入记录。因此:
- 该插件无法从记录中获知原先挂载的预设 → 该插件在内核进程内保存一份
sessionId → preset 映射(跨连接共享),客户端也会在 session/resume 的 _meta 中指定所需预设,两个来源合并使用。
- 这也是上文缺陷的根源:不读取记录则无法自动还原,必须依靠
mount 补挂。
配置
字段 · 默认 · 说明 host · 127.0.0.1 · 固定监听地址。其它值会被忽略,接入点不会暴露到局域网。 port · 47821 · 监听端口;传 0 由系统分配空闲端口。 provider · — · 可选。与 model 同时填写时,固定新会话的初始模型服务商。 model · — · 可选。与 provider 同时填写时,固定新会话的初始模型名。 preset · standard · 新会话挂载的 agent preset:standard(标准)/ ptc / cordis(创造)/ minimal(极简)。 diagLog · 关 · 诊断日志文件路径;也可用环境变量 DSH_ACP_DOOR_DIAG。用于排查时序问题,未配置时不写任何文件。
初始模型的选择顺序
- 插件配置中同时填写了
provider 与 model:使用这组显式覆盖。 - 未完整填写:读取 DSH 的
agentDefaultModel.currentSelection(),即该配置集当前选择的默认模型。 - 旧版 DSH 没有该服务且也没有完整显式配置:状态接口报告“模型未就绪”,新版 VS Code 面板会在
建会话前提示先选择模型。其它客户端也可调用 dsh-door/status 自检。
只填写 provider 或 model 其中一项不会与 DSH 的值拼接;这组不完整配置会被忽略并记录诊断。 DSH 冷启动时,插件会先等待用户设置加载完成再开放端口,避免短暂读取到基础默认模型。
DSH 内核兼容性
DSH · 历史会话 · 权限预设 0.2.0-rc.1 / 0.2.0-rc.2 · 公开 sessionQuery 服务,v4 会话格式 · catalog/current/resolve/set 0.2.1-alpha.1 / 0.2.1-rc.2 / 0.2.1-rc.3 · 公开 sessionQuery 服务,v4 会话格式 · catalog/current/resolve/set 0.1.5-rc.2 · 只读解析本机 v3 会话文件 · selectFor/permissionState/current/set
两条路径对外提供相同的 dsh-door/… 方法。接入点的状态回复会用 historyKind、 sessionFormat 和 permissionKind 报告实际选中的适配器。不会在插件中私自解析 v4: 该格式由 DSH 0.2 的 sessionQuery 负责读取和迁移。
状态中的可选 protocolVersion 与 runtime.acpVersion 分别报告接入协议及实际加载的 ACP 包版本。
ACP 0.2.1-rc.2 与 0.2.1-rc.3 可通过 dsh-door/text/generate 使用所属会话的当前模型直接生成文本。该路径发送空工具集合,不进入 Agent 工具调度;工具响应、错误或截断终态均拒绝,支持请求取消。未知版本或缺少直接流接口时不报告此能力。
旧 npm 发行物的依赖使用版本范围:DSH 0.1.5-rc.2 可解析到 ACP 0.1.5-rc.3。兼容矩阵分别记录两个版本;依赖范围包含该 ACP 版本不表示已经验收同号的 DSH 发行物。 无法识别的已有历史服务会报告 history: false,不尝试以旧格式读取新数据。
版本变更