DSH / Atlas
2026-08-22implementedfeaturearchived 2026-09-30

Standard ACP v1 automation controls

标准 ACP v1 自动化控制

The automation-only ACP bridge could create a fresh session, submit one prompt at a time, cancel it, receive committed assistant messages, and answer one-shot permission requests. A generic external automation controller still needed private process knowledge to discover models, attach MCP servers, find durable sessions after restart, resume them, close one session independently, and observe reasoning, tool, or conte

English

Problem

The automation-only ACP bridge could create a fresh session, submit one prompt at a time, cancel it, receive committed assistant messages, and answer one-shot permission requests. A generic external automation controller still needed private process knowledge to discover models, attach MCP servers, find durable sessions after restart, resume them, close one session independently, and observe reasoning, tool, or context-pressure progress. Reproducing those controls in an integration-specific runtime would make ACP nominally interoperable while leaving DSH automation dependent on a private side protocol.

The stable ACP v1 protocol already defines the required control vocabulary. Adding private _meta, custom methods, use-case-specific environment handling, or presentation projections would fragment that vocabulary and revive the UI coupling removed by the automation-only decision.

Decision

@deepseek-ai/dsh-acp implements the complete standard ACP v1 automation subset needed by a generic controller: session/new, session/list, session/resume, session/close, session/prompt, session/cancel, session/set_config_option, JSON-RPC $/cancel_request, session/update, and session/request_permission. It uses @agentclientprotocol/sdk 1.4's app/context interface on both sides of every in-repository connection.

Capabilities omit unsupported methods and features. DSH adds no custom method, capability flag, or _meta, and assigns no private meaning to client metadata. session/load, session/delete, session/fork, additional directories, SSE and ACP-transport MCP, modes, commands, plans, terminals, client filesystem operations, and elicitation remain unsupported. Session controls and semantic updates are protocol data for automation; they do not make ACP a human UI.

Per-session ownership

One AcpSession module owns each published Agent handle, selected model state, request MCP mounts, single prompt slot, ordered update chain, and memoized close operation. Global event listeners only identify the exact Agent or Session and delegate to that module. The module associates the admission snapshot with the identified message in memory until inbox claim, then pins it to the admitted turn. Image capability checks, prompt variables, request headers, and every model step therefore use one provider/model/reasoning tuple, while the ordinary durable user source remains unchanged. A concurrent configuration change affects the next ACP turn.

Explicit session/close, connection loss, and plugin disposal call the same close operation. It cancels admission and Agent work before waiting, drains committed updates and continuable descendants, flushes persistence, and releases the Agent scope and its MCP clients. Close retains event routing until the drain completes. Failure reporting waits for all owned session teardowns, and other frontends' Agents and descendants remain untouched.

Persistent session controls

Complete ACP lifecycle support requires session persistence. session/list reads materialized top-level headers, excludes active and descendant sessions, filters by canonical physical cwd, sorts by creation time and id, and returns bounded pages using opaque keyset cursors. Summaries deliberately omit titles and presentation metadata.

session/new explicitly asks persistence to materialize the live session header without inventing a session event, so even an empty session can be closed, listed, and resumed. Other frontends retain the persistence seam's lazy default and leave abandoned empty sessions unmaterialized. session/resume rejects active ids and non-top-level or unknown persisted ids, verifies the requested canonical cwd before Agent composition, restores the durable session without replaying it to the client, and mounts the MCP declarations supplied by that request. session/close leaves the durable log available for a later process.

Persistence deliberately treats create(meta) as a live registration: the shipped JSONL provider creates no artifact until the first event append. That default removes abandoned empty sessions, but ACP cannot inherit it because session/new publishes a session identity before any prompt and the process may stop after the success response without receiving session/close. The bridge materializes only after Agent and MCP composition succeeds and before returning session/new; failed composition remains residue-free, while every returned id survives restart.

The bridge materializes through the ordinary durability barrier: ctx.sessions.flush(session) reaches the session's write handle, whose flush writes header-only materialization when nothing has been appended. JSONL writes one header frame; an out-of-tree provider must materialize equivalent header state atomically or reject the operation. Repeat calls are idempotent. Making create eager would change every frontend's abandoned-session behavior, appending a synthetic event would invent a sequence and replay fact solely to trigger storage, and waiting until close would make durability race process loss.

Standard configuration options

The advisory LLM catalog now serves another automation consumer without becoming request validation. ACP exposes a provider-grouped model select whose opaque values retain the provider/model pair, plus a dependent reasoning_effort select from the resolved exact model. A model with efforts but no adapter-configured default includes Provider default, which preserves omission and lets the provider choose. New, resume, and set responses return the complete state. Adapter topology events emit config_option_update; per-session mutations serialize in receive order. The configured ACP provider/model remains the initial selection, and unlisted configured routes are synthesized into the returned choices instead of being rejected.

Standard MCP mapping

session/new and session/resume accept standard stdio and Streamable HTTP MCP declarations. Stdio uses the session cwd; HTTP uses the declared URL and headers; both retain dsh-mcp-client timeout and reconnect defaults. Names, commands, URLs, environment entries, headers, and duplicate normalized namespaces are validated before Agent publication. Initial connection or discovery failure rolls the unpublished Agent back.

MCP namespace reservations follow the nearest DSH registration scope rather than the process root. Independent Agent scopes may use the same server name, while duplicate names inside one Agent still fail. Scoped disposal releases tools, transports, and reservations.

ACP clients are trusted controllers: a stdio declaration authorizes process execution and an HTTP declaration authorizes requests with its headers. DSH does not add per-server private cwd or timeout fields. Ordinary DSH tool policy still governs calls after tools are mounted.

Semantic update projection

Only committed durable facts reach session/update. Assistant text/images become agent_message_chunk; reasoning becomes agent_thought_chunk; tool calls/results become generic tool_call and tool_call_update; known measured context pressure and capacity become usage_update; adapter topology changes become config_option_update. Durable message ids and tool-call ids preserve correlation. The canonical DSH tool name is the standard tool-call title.

The per-session chain serializes all updates and drains before prompt completion. A tool-call notification drains before a permission request refers to it. Raw model deltas, retry attempts, cards, terminal state, diffs, locations, plans, titles, todos, and unsupported content stay off the wire.

session/cancel and $/cancel_request enter the same prompt-owned cancellation path. Correlated endings map only to standard stop reasons and JSON-RPC errors; a model output limit reports max_tokens. ACP returns no additional DSH result structure.

Alternatives considered

Add a private controller extension. Rejected because standard ACP v1 already carries the required lifecycle, configuration, MCP, cancellation, permission, and semantic-update concepts. A private extension would make generic SDK clients incomplete.

Restore the former editor projection. Rejected because plans, terminals, diffs, cards, navigation, and human elicitation are presentation responsibilities. Semantic tool and reasoning facts are useful automation telemetry without importing presentation modules.

Implement every ACP session method. Rejected. List, resume, and close complete the durable automation lifecycle. Load/replay, delete, and fork introduce separate transcript, destructive-storage, and lineage semantics that this use case does not require.

Use unstable provider methods for model discovery. Rejected because standard session configuration options express the choice and remain scoped to the session.

Copy every DSH runtime field to ACP metadata. Rejected because exact token breakdowns, private result statuses, programmatic display names, and per-MCP tunables have no stable ACP v1 equivalent.

Verification

Focused tests cover exact capability advertisement without private metadata; model/reasoning choices, invalid and concurrent mutation, topology updates, and image-route pinning; stdio/HTTP MCP setup, declaration rollback, scope isolation, resume, and disposal; list pagination, canonical workspace checks, active conflicts, close/resume, and restart recovery; message/thought/tool/usage order and ids; tool-before-permission order; standard stop reasons; request and session cancellation; and connection-loss teardown.

A generic keyless conformance test boots the real ACP demo twice and uses only the public ACP SDK to select a model and reasoning effort, attach an MCP server, execute a tool turn, observe standard updates, close, restart, list, resume, and cancel. It contains no integration-specific names, dependencies, metadata, or environment behavior.

Consequences

External automation projects can use DSH through stable ACP v1 instead of maintaining a DSH-specific runtime protocol. The bridge is a larger control surface but remains smaller than a UI: it owns lifecycle and semantic interoperability, while human presentation and interaction stay in product clients.

Persistent lifecycle and request MCP mounting make session creation stricter. Misconfiguration and initial MCP failure reject before publication, and close waits for real quiescence and persistence. This cost is the ownership proof required to avoid partial Agents, leaked tools, or orphaned processes.

中文

问题

纯自动化 ACP 桥接层可以创建新会话、一次提交一个提示词、取消提示词、接收已提交 assistant 消息,并回答一次性权限请求。通用外部自动化控制器仍需依赖私有进程知识,才能发现模型、挂载 MCP 服务器、在重启后找到持久会话、恢复会话、独立关闭一个会话,以及观察 reasoning、工具或上下文压力进度。如果在集成专用 runtime 中复制这些控制,ACP 只会名义上可互操作,而 DSH 自动化仍依赖私有旁路协议。

稳定 ACP v1 协议已经定义所需的控制词汇。增加私有 _meta、自定义方法、用例专用环境处理或展示投影会割裂该词汇,并重新引入纯自动化决策已经移除的 UI 耦合。

决策

@deepseek-ai/dsh-acp 实现通用控制器需要的完整标准 ACP v1 自动化子集:session/new、session/list、session/resume、session/close、session/prompt、session/cancel、session/set_config_option、JSON-RPC $/cancel_request、session/update 和 session/request_permission。仓库内每条连接的两端都使用 @agentclientprotocol/sdk 1.4 的 app/context 接口。

能力会省略未支持的方法和功能。DSH 不增加自定义方法、能力标记或 _meta,也不为客户端元数据赋予私有含义。session/load、session/delete、session/fork、附加目录、SSE 和 ACP 传输 MCP、模式、命令、计划、终端、客户端文件系统操作和 elicitation 仍不受支持。会话控制和语义更新是自动化协议数据;它们不会使 ACP 成为人工 UI。

Per-session 所有权

每个已公布 Agent 由一个 AcpSession 模块拥有,该模块同时拥有所选模型状态、请求 MCP 挂载、单提示词槽位、有序更新链和记忆化关闭操作。全局事件监听器只识别确切 Agent 或 Session,再委托给该模块。模块会在内存中把准入快照与已识别消息关联到 inbox claim 时刻,再将其固定到已准入轮次。因此,图片能力检查、提示词变量、请求 header 和每个模型步骤都使用同一个提供方/模型/reasoning tuple,而普通持久用户 source 保持不变。并发配置变更从下一个 ACP 轮次开始生效。

显式 session/close、连接丢失和插件释放调用同一个关闭操作。它会先取消准入和 Agent 工作,再等待;随后 drain 已提交更新和可继续后代、flush 持久化,并释放 Agent scope 及其 MCP 客户端。关闭流程会保留事件路由直到 drain 完成。只有所有自有会话 teardown 都完成后才报告失败,其他前端的 Agent 和后代不受影响。

持久会话控制

完整 ACP 生命周期支持要求挂载会话持久化。session/list 读取已实体化的顶层 header,排除活动会话和后代会话,按规范物理 cwd 过滤,按创建时间和 id 排序,并通过不透明 keyset cursor 返回有界页面。摘要有意省略标题和展示元数据。

session/new 会显式要求持久化在不虚构会话事件的情况下实体化 live session header,因此即使空会话也可以关闭、列出和恢复。其他前端仍保留持久化 seam 的惰性默认行为,不会实体化被放弃的空会话。session/resume 拒绝活动 id,以及非顶层或未知的持久 id;在组合 Agent 前校验请求的规范 cwd;恢复持久日志但不向客户端重放;挂载该请求提供的 MCP 声明。session/close 让持久日志可供后续进程使用。

持久化有意把 create(meta) 视为 live registration:交付的 JSONL provider 在首次追加事件前不创建 artifact。该默认行为会移除被放弃的空会话,但 ACP 不能继承它,因为 session/new 会在任何提示词出现前公布会话身份,而进程可能在返回成功响应后、收到 session/close 前停止。桥接层只在 Agent 和 MCP 组合成功后、返回 session/new 前执行实体化;组合失败仍不留下残留物,每个已返回 id 则都能在重启后继续存在。

bridge 经由普通的持久性屏障实体化:ctx.sessions.flush(session) 抵达该会话的写句柄,其 flush 在尚无任何追加时写入仅 header 实体化。JSONL 写入一个 header frame;仓库外 provider 必须原子实体化等价 header 状态,否则拒绝该操作。重复调用幂等。让 create 全面 eager 会改变所有前端放弃会话的行为;追加 synthetic event 会仅为触发存储而虚构 sequence 与 replay 事实;等到关闭时再写入则会让持久性与进程丢失竞争。

标准配置选项

建议性 LLM catalog 现在服务于另一个自动化 consumer,但不会成为请求校验。ACP 公开按提供方分组的 model select,其不透明值保留提供方/模型对;还会公开来自已解析确切模型的依赖 reasoning_effort select。具有 efforts 但没有 adapter 配置默认值的模型会包含 Provider default,以保留省略状态并让提供方自行选择。新建、恢复和设置响应都返回完整状态。Adapter 拓扑事件发出 config_option_update;每个会话按接收顺序串行处理变更。配置的 ACP 提供方/模型仍是初始选择;未列出的配置路由会合成到返回选项中,而不会被拒绝。

标准 MCP 映射

session/new 和 session/resume 接受标准 stdio 和 Streamable HTTP MCP 声明。Stdio 使用会话 cwd;HTTP 使用已声明 URL 和 header;两者都保留 dsh-mcp-client 的超时和重连默认值。名称、命令、URL、环境项、header 和重复的规范化 namespace 都会在 Agent 公布前校验。初始连接或发现失败会回滚尚未公布的 Agent。

MCP namespace reservation 跟随最近的 DSH registration scope,而不是进程 root。独立 Agent scope 可以使用同一服务器名,同一 Agent 内的重复名称仍会失败。Scoped disposal 会释放工具、传输和 reservation。

ACP 客户端是受信任的控制器:stdio 声明授权执行进程,HTTP 声明授权携带其 header 发起请求。DSH 不增加每服务器私有 cwd 或超时字段。工具挂载后,普通 DSH 工具策略仍然约束调用。

语义更新投影

只有已提交的持久事实会进入 session/update。Assistant 文本/图片变成 agent_message_chunk;reasoning 变成 agent_thought_chunk;工具调用/结果变成通用 tool_call 和 tool_call_update;已知的测量上下文压力与容量变成 usage_update;adapter 拓扑变化变成 config_option_update。持久消息 id 和工具调用 id 保留关联。规范 DSH 工具名作为标准工具调用 title。

Per-session 链会串行处理所有更新,并在提示词完成前 drain。引用工具调用的权限请求只会在该工具调用通知 drain 后发送。原始模型 delta、重试尝试、卡片、终端状态、diff、位置、计划、标题、todo 和不受支持内容不会进入 wire。

session/cancel 和 $/cancel_request 进入同一个提示词自有取消路径。关联结尾只映射到标准 stop reason 和 JSON-RPC error;模型输出达到上限时报告 max_tokens。ACP 不返回额外 DSH 结果结构。

考虑过的替代方案

增加私有控制器扩展。 已拒绝,因为标准 ACP v1 已经承载所需生命周期、配置、MCP、取消、权限和语义更新概念。私有扩展会使通用 SDK 客户端不完整。

恢复之前的编辑器投影。 已拒绝,因为计划、终端、diff、卡片、导航和人工 elicitation 属于展示职责。语义工具和 reasoning 事实可以作为有用的自动化遥测,而无需导入展示模块。

实现所有 ACP 会话方法。 已拒绝。列出、恢复和关闭已经完成持久自动化生命周期。加载/重放、删除和 fork 会引入本用例不需要的独立 transcript、破坏性存储和 lineage 语义。

使用不稳定 provider 方法发现模型。 已拒绝,因为标准会话配置选项可以表达该选择,并保持会话 scope。

把每个 DSH runtime 字段复制到 ACP 元数据。 已拒绝,因为精确 token 明细、私有结果状态、程序化展示名称和每 MCP tunable 没有稳定 ACP v1 对应项。

验证

聚焦测试覆盖:无私有元数据的确切能力公布;模型/reasoning 选择、无效和并发变更、拓扑更新以及图片路由固定;stdio/HTTP MCP 设置、声明回滚、scope 隔离、恢复和释放;列表分页、规范 workspace 校验、活动冲突、关闭/恢复和重启恢复;消息/思考/工具/用量顺序与 id;工具先于权限;标准 stop reason;请求和会话取消;连接丢失 teardown。

通用 keyless conformance 测试会启动真实 ACP demo 两次,并且只使用公开 ACP SDK:选择模型和 reasoning effort、挂载 MCP 服务器、执行工具轮次、观察标准更新、关闭、重启、列出、恢复和取消。它不包含集成专用名称、依赖、元数据或环境行为。

后果

外部自动化项目可以通过稳定 ACP v1 使用 DSH,而无需维护 DSH 专用 runtime 协议。桥接层的控制接口变大,但仍小于 UI:它拥有生命周期和语义互操作,而人工展示和交互仍属于产品客户端。

持久生命周期和请求 MCP 挂载让会话创建更严格。配置错误和初始 MCP 失败会在公布前拒绝,关闭会等待真实完全停稳和持久化。这是避免部分 Agent、泄漏工具或孤儿进程所需的所有权证明。