Harness 集成与 ACP 分层

说明具名 dock 集成层与 ACPX 的职责,并分别列出 Codex、dsh 的原生接入和能力边界。

设备内部有两种不同职责的适配:dock 集成层把设备执行契约接到 ACPX,codex-acp 则实现 ACP 的 Agent 端并接入原生 Codex。本文把仓库内 Driver 明确称为 dock 集成层,把依赖 @agentclientprotocol/codex-acp 称为 ACP 协议适配器。

应用只通过 client SDK 使用设备;这些集成代码属于独立 Daemon。Codex 的固定调用链与下图为:

DeviceHost → ProviderAdapter → CodexHost → CodexExecutor → ACPX → codex-acp → Codex

执行分层与协议边界#

Codex 集成与 ACP 分层DeviceHost 经 dock 集成层调用 ACPX 客户端运行库,由 codex-acp 实现 ACP 的 Agent 端并接入原生 Codex。ACP 协议边界DeviceHost执行准入、去重、持久化与生命周期dock 集成层ProviderAdapter → CodexHost → CodexExecutor选择原生环境,处理回调、事件差异与结果证据ACPX · ACP 客户端运行库由 dock 调用;管理 ACP 会话与后端进程codex-acp · ACP Agent 端协议适配器实现 ACP 接口,向下接入所选本机 Codex原生 Codex Harness模型循环 · 原生工具 · 会话 · 权限规则
窄屏可横向滚动查看全图。箭头表示向下调用关系,事件与交互响应沿原路返回。ACPX 在 codex-acp 上层;dock 集成层在 ACPX 上层。dock 集成层与 ACPX 库运行在 Daemon 内,codex-acp 是 ACPX 管理的后端进程。
名称职责所在位置
DeviceHost准入、runId 去重、并发互斥、持久化与资源生命周期Daemon 内
dock 集成层选择本机安装与环境,映射配置、回调、事件和恢复证据packages/drivers
ACPAgent Client Protocol,客户端与 Agent 端之间的通信协议ACPX 与 codex-acp 之间
ACPXACP 客户端运行库,管理协议会话、执行请求与后端进程Daemon 内引用的依赖库
codex-acp实现 ACP 的 Agent 端,把协议请求接入 Codex由 ACPX 管理的后端进程
Codex原生模型循环、会话、工具、MCP、skills 与权限规则所选设备原生环境

ACPX 位于 codex-acp 上层,dock 集成层位于 ACPX 上层。 packages/drivers 是源码模块的名称,不能据此把 ACPX 和 codex-acp 合成同一层。跨机器的 dock JSON-RPC/WSS 协议与这里的 ACP 协议分开;前者连接 SDK、Server 和 Daemon,后者连接设备内部的 ACP 客户端与 Agent 端。

接口与所有权#

ProviderAdapter 提供 inspect、validate、environment、execute、close 和 forgetSession。ProviderAdapters 创建具名适配器并提供只读 reconcile。

  • DeviceHost 拥有设备准入、runId 去重、容量、审批归属、持久化与资源管理。
  • dock 集成层选择原生环境、声明能力,处理安装依赖及协议、会话、模式、事件和结果差异。
  • environment 是设备端私有的不透明持久化上下文,不是远程指定原生路径的入口。
  • reconcile 按原 runId 只读查回;不支持或无完成证据时返回 null,不派发 prompt 或建立替代会话。

公共 wire 类型位于 protocol,并由 client 导出。dock 集成层不依赖调用方业务类型。原生交互类型与公共类型的兼容性由编译 fixture 校验。

Codex 环境与执行#

使用所选本机安装及 home,dock 状态独立放在 stateDir。保留原生配置、认证、工具、插件、skills 和 memory;调用方内容只使用明确支持的增量入口。

本机 Provider 环境只接受具名代理/证书变量,不继承整个父进程环境,不接受远程命令、home 或权限变量。原生宿主不可用时报告实际限制,不绕过身份、签名或进程链检查。

Codex 执行后端固定走 ACPX → codex-acp → Codex 路径,版本见 依赖清单。不添加异常时自动切换的并行执行后端。

从代码读起#

入口实现位置读什么
DeviceHost.executeapps/daemon/src/device-host.ts准入、持久化、审批归属与执行结果
ProviderAdapter / CodexHostpackages/drivers/src/provider-adapter.ts、codex-host.ts原生环境、配置校验、MCP Bridge 与会话生命周期
CodexExecutorpackages/drivers/src/codex.tsensureSession、配置、startTurn、事件解码与只读 read_turn
createCodexRuntimepackages/drivers/src/codex.ts调用 ACPX createAcpRuntime,并在 agentRegistry 指定 codex-acp 启动入口

ACPX 与 codex-acp 是固定依赖;dock 集成层不重写 Codex 的模型循环。过程回调与结果保存顺序见 执行时序。

能力、交互和结果#

独立声明 sessionResume、resultQuery、exactFinalAnswer、callerSkills、permissionInteractions、desktopTools 和 browser。协议 ready 不代表模型或所有原生工具已执行。

原生审批从 Codex 经 codex-acp、ACPX 和 dock 集成层回到 Daemon,再经 Server 回调应用;有效决定沿原路径返回。应用声明的工具由本机 MCP Bridge 暴露给 Codex,执行时回调应用;原生工具仍由 Codex 管理。审批保留精确 optionId、form/url、作用域与有效期。投递确认只报告原生协议 ACK。工具结果保留调用方 deliveryContext,未确认投递为 unknown。

工具事实优先复用标准 ACP 事件;dock 集成层提供有界展示投影,权威消息完成和终态不依赖展示截断。原生 thread/turn 身份、完整消息完成和只读查询采用具名协议接缝,见 补丁说明。

验证要求#

确定性测试覆盖身份、审批、取消、迟到回答、状态未知、恢复及进程清理边界;真实 Provider 验证使用隔离身份和合成内容,分别记录结果。

原生安装、配置、登录和用户文件不是清理对象。模拟后端只证明控制边界,不能据此新增对外 Provider 支持。验证方法见 验证与验收。

dsh(DeepSeek Harness)实验接入#

DeviceHost → ProviderAdapter → DshHost → ACPX → dsh --profile acp。已发布开发者 SDK sdk-v0.1.2 的配套 macOS arm64 Daemon/CLI 与 App v0.1.3 均包含此实验路径,dsh 保持实验性。

Daemon 经 ACPX 的具名 dsh registry 启动已选安装的 dsh --profile acp,无需 ACPX 内置快捷命令。设备仍限 macOS arm64,首个适配版本为 @deepseek-ai/dsh 0.1.2-rc.1。不安装另一套 dsh,不修改用户登录或 patch;原生 CLI 自己管理 profile 的初始化。

Daemon 发现 PATH / nvm 中的 dsh,home 使用 DSH_HOME 或默认 ~/.dsh。有多个安装时,设备所有者在私有本地配置中设置 providers.dsh.executable 和 providers.dsh.home;可用 providers.dsh.disabled 禁用。显式代理和证书仍放该 Provider 的本地 environment 配置。

应用仍只使用连接 SDK:从 inventory 选择 key 为 dsh 且 ready 的 Provider,模型标识从其 models 数组原样传入 execute;模型值为原生不透明值,不能自行拼接裸模型名。配置仅接收已报告的 effort。调用方 skills 通过独立命名 root 叠加,保留原生默认目录与配置。

审批转发原生 options,应用返回其中一个 { optionId };笼统 allow 不会升级为原生许可。支持 session/resume,不依赖 dsh 未实现的 session/load。dsh 的 ACP 文本为已提交消息,但没有 Codex 的 final_answer phase,因此 exactFinalAnswer: false;无只读原生结果查询,因此 resultQuery: unsupported。completed 只表示原生 prompt 正常结束,业务验收仍由调用方负责。连接恢复和 Daemon 重启不会重派;缺终止证据仍为 unknown。

App v0.1.3 首页展示已检测到的 Harness 数量和安装列表、服务连接及“设置与维护”入口,不常驻展示任务统计;点击 Harness 条目查看安装信息、固定回显、诊断与分环境历史,正常回到调用方应用。日志和版本信息收纳在可返回首页的“设置与维护”独立页面。安装发现不等于模型就绪。Codex 使用原生确认的只读模式;dsh 实验测试仅核对固定回显,沿用原生权限配置,不提供只读保证,出现工具活动或额外审批不会判定通过。App 与 SDK 的 dsh 适配均保持实验性,具体工具与业务用途需分别验收。维护者运行 pnpm accept:dsh 可通过本机隔离的 SDK、Server、DeviceHost 与原生 dsh 验收 MCP 成功/错误、送达、调用方和原生项目 skills 共存、审批允许/拒绝/取消后旧决定失效及一次性授权作用域。脚本使用模型额度,实际输入、回调、原生结果及源码摘要留在 ignored .local/dsh-acceptance-*。MCP 错误响应在原生投影为 failed 时,送达状态保守保持 unknown。

审批 fixture 只为其原生子进程选择 read-only,以验证最窄的一次性 workspace-write 授权;不修改用户 settings 或已安装 Daemon。必须实际观察原生只读拒绝与审批回调,未触发审批不能计通过。本机合成验收不替代独立 Daemon 进程、独立设备、发行包或业务验收。App、SDK 发行物与源码 fixture 的验收范围分别记录,不能相互替代。

本地配置与 SDK 示例

自动发现不明确时,设备所有者可在私有设备配置中加入以下片段,替换示例路径;不传给远端 execute,也不修改原生认证:

json
{"providers":{"dsh":{"executable":"/absolute/path/to/dsh","home":"/absolute/path/to/native-dsh-home"}}}

SDK 延续本页 SDK 接入契约;以下示例仅发送合成回显。真实审批 UI 应展示原生 options,并返回用户选定的 optionId。

示例
import { connectDock } from '@harness-dock/client';
import { randomUUID } from 'node:crypto';

const dock = await connectDock('.local/client.json');
try {
  // 唯一设备可自动选择;多设备时显式选取,不默认调用列表第一台。
  const nodes = dock.listNodes();
  const nodeId = nodes.length === 1 ? nodes[0].nodeId : undefined;
  const peer = nodeId ? dock.client.node(nodeId) : undefined;
  if (!peer?.connected) throw new Error('select_one_connected_device');
  const inventory = await peer.request('inventory');
  const dsh = inventory.providers.find(p => p.key === 'dsh' && p.status === 'ready');
  if (!dsh?.models.length) throw new Error('dsh_unavailable');
  const response = await dock.run({
    nodeId, provider: 'dsh', model: dsh.models[0],
    receipt: '.local/dsh-' + randomUUID() + '.json',
    prompt: 'Reply exactly DOCK_DSH_OK. Do not call tools or perform other actions.',
  });
  console.log(response.runId, response.result);
  // run 在 prepare/execute 前保存原身份,默认拒绝原生审批。
  // 业务结果由应用验收;按原 receipt 查询,不通过新建任务恢复。
} finally { await dock.close(); }
界舟 · Harness Dock · 原生 Harness 接入与执行管理更新于 2026-11-11