7.2 KiB
@deepseek-ai/dsh-subagent-acp
English | 中文
ACP(Agent Client Protocol)提供方会在全新的子进程中运行每个 subagent,并作为 Agent Client Protocol 客户端驱动它。这是 spawn 与 fork 的进程外替代方案:子 agent(智能体)拥有自己的运行时、会话、模型配置和工具。
启动与所有权
start(request) 先解析子 agent 的工作目录,再依次执行 spawn → ACP initialize → newSession,然后才兑现。因此,兑现表示远程会话已就绪,所有权也已转移给调用方。派生、初始化、新建会话或发布前取消失败时,只有在子进程已回收后才会拒绝;工作目录解析失败则会在派生任何内容前拒绝。
工作目录优先使用已配置的 cwd 覆盖值,否则使用执行委派的父会话 cwd,绝不使用服务器进程自身的 cwd,因为同一个服务器进程会服务来自多个工作区的会话。从父级取得的值必须是绝对路径,指向 harness 可以进入的目录(具备搜索权限,这是子进程 cwd 的要求);解析后的同一路径同时作为子进程 cwd 和 ACP session/new 工作区。
返回的运行 id 在父级命名空间中生成。子服务器的会话 id 只用于 ACP 协议调用,因为 ACP 只保证它在该全新子进程中唯一;若将其用作父级生命周期 id,可能与另一个远程运行或本地 agent 冲突。
发布后,提供方发送提示词,并把流式 agent_message_chunk 文本收集到 SubagentResult.output。提示词/传输失败会以 stopReason: 'error' 兑现;如果必需的请求信号或 dispose 请求了取消,则以 aborted 兑现。
dispose() 是幂等的。它会移除信号监听器,在可行时请求 ACP 取消,关闭 stdin,并等待 disposeEofGraceMs。随后 POSIX 先升级到 SIGTERM,等待 disposeGraceMs 后再使用 SIGKILL;Windows 会直接强制终止,因为 Node 会把两个信号都映射到 TerminateProcess。强制终止后,各平台最多再等待 disposeGraceMs 以确认退出;若信号出错或未退出,则拒绝。每次运行都使用全新进程;尚未实现进程池。
能力与上下文
ACP 不声明任何启动时能力,因为当前进程无法强制执行远程子 agent 的深度、工具过滤、persona 或结构化输出运行时。它也报告 inheritsParentContext: false:远程会话从全新状态开始,唯一源自父级的输入是上述工作区 cwd;对话上下文不会跨越进程边界。
配置
| 键 | 默认值 | 含义 |
|---|---|---|
providerName |
acp |
ctx.subagents 上的注册表名称。 |
command |
必填 | 每次运行时派生的可执行文件。 |
args |
[] |
命令参数。 |
cwd |
父会话 cwd | 子进程及其 ACP 会话的工作目录覆盖值;不得为空。相对值会在加载时以 harness 启动目录为基准解析,结果必须指向 harness 可以进入的目录。 |
permission |
reject |
自动回答权限请求:拒绝,或选择第一个允许形态的选项。 |
env |
{} |
显式子进程环境,叠加到已清理凭据的父进程环境之上。 |
disposeEofGraceMs |
6000 |
stdin EOF 之后、平台终止之前的宽限时间。 |
disposeGraceMs |
3000 |
终止后的退出确认宽限时间;POSIX 在 SIGTERM 后、SIGKILL 前也会等待同样时长。 |
- id: subagent-acp
name: '@deepseek-ai/dsh-subagent-acp'
config:
providerName: acp
command: node
args: ['--import', 'tsx', './packages/examples/acp-demo/src/bin.ts', '--config', './examples/acp-agent/cordis.yml']
permission: reject
env:
DEEPSEEK_API_KEY: !!js process.env.DEEPSEEK_API_KEY
结束原因映射
| ACP | Harness |
|---|---|
end_turn |
completed |
max_tokens |
max-tokens |
refusal |
refusal |
cancelled |
aborted |
max_turn_requests 或未知值 |
error |
进程边界
子进程环境由 buildChildEnv 构建:先移除名称形似凭据的环境变量,再应用显式 config.env 值。ACP 协议是真正的序列化边界;同进程 subagent 值不会为防御目的而克隆。
本包没有默认导出。否则 Cordis loader 的解包会隐藏具名 inject 元数据;见事故复盘 0001。
无密钥测试通过真实 stdio 驱动脚本化 ACP 子进程,其中包括一个由 Loader 组合的 stdio 应用,用于端到端证明父会话 cwd 继承。带密钥 e2e 会驱动仓库中的真实 ACP agent;没有 DEEPSEEK_API_KEY 时自行跳过。
模型体验
子 agent 请求
模型看到的内容
远程子 agent 通过 ACP 接收独立任务内容,并使用其自身进程配置的系统提示词、工具和全新会话。它不接收父级对话。该提供方不声明任何可选启动时能力,因此本地服务会拒绝要求 persona、工具过滤、深度强制或结构化输出的请求,而不是静默省略这些要求。
Token 影响
子 agent 为独立的完整上下文及其多步骤历史支付 token 成本。这些 token 绝不会进入父级上下文。
KV Cache 影响
与父级请求缓存相互独立。每个 ACP 子 agent 只能在其自身提供方、模型、组合和历史均相同时复用前缀;其余情况下,子 agent 步骤仅追加增长。
父级工具结果(间接)
模型看到的内容
通过 dsh-tool-subagent,父级只接收子 agent 最终的流式 assistant 文本,或该消费方给出的精确结束原因错误;不接收中间消息或工具流量。发布前已经取消的请求会精确变为 Error: subagent request was aborted before the ACP child started;其他启动失败按原样传递为 Error: <message>。
Token 影响
父级输入只增加最终结果或错误,其内容依赖数据,并保留到上下文压缩为止。该提供方自身不会添加父级 schema。
KV Cache 影响
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
已知限制与延期工作
- 每次运行使用全新进程:持久进程池属于后续优化(见 seam Agent Note)。
- 仅支持本地工作区:解析后的 cwd 是交给同一台机器上子进程的本地路径;远程 ACP agent 的工作区映射需要独立的后端能力,本包尚未设计。
- 不支持可选启动时能力:该提供方无法在远程进程内应用本地 harness 的
outputSchema、深度上限、工具过滤器或 persona,因此不会声明这些能力;服务会拒绝需要它们的请求。 - 只收集已提交的
agent_message_chunk文本:自动化服务器把推理、工具活动、计划和其他 trace 数据保留在子 agent 会话日志中,不通过 ACP 发出。 - 权限提示自动回答(
permission: allow | reject):当前版本不会把子 agent 的session/request_permission呈现给人。 - 没有快照层回放覆盖率(
TODO(acp-subagent-replay)):ACP 子 agent 拥有独立进程和独立回放形态,该工作延期处理。