通过 ACP 暴露 ADK-Rust agent
当编辑器或其他 ACP 客户端需要启动你的 ADK-Rust 二进制文件,并在编码界面中使用其 agent 时,请使用服务器方向。你的 Rust 进程 拥有 agent、模型、工具、工作流、会话、记忆和运行策略。客户端只能看到通过 ACP 发布的功能和会话生命周期。
安装服务器功能
[dependencies]
adk-acp = { version = "2.1.0", features = ["server"] }
构建并运行 agent
use adk_acp::server::{AcpServer, AcpServerConfigBuilder};
use adk_session::InMemorySessionService;
use std::sync::Arc;
let config = AcpServerConfigBuilder::new()
.agent(Arc::new(repository_agent))
.session_service(Arc::new(InMemorySessionService::new()))
.agent_name("repository-guide")
.agent_description("Explains and improves this Rust workspace")
.max_sessions(16)
.build()?;
let handle = AcpServer::run(config).await?;
handle.wait().await?;
服务器使用官方的 SDK Agent 构建器和 stdio 传输。协议
流量是写入 stdout 的唯一数据;配置跟踪和诊断信息时请使用 stderr。
运行时映射
处理程序会验证绝对的 cwd,预留会话容量,创建或
恢复 ADK 会话,并运行已配置的 agent。类型化的 ADK 事件会
在提示处于活动状态时转换为 ACP session/update 通知。
已实现的生命周期
| ACP 操作 | ADK-Rust 行为 |
|---|---|
initialize | 协商协议 v1,并返回准确的实现和能力元数据 |
session/new | 验证工作区路径,并创建一个持久化的 ADK 会话 |
session/prompt | 转换受支持的内容块(文本、资源链接、嵌入式资源、图像、音频),并流式运行 Runner |
session/load | 重新激活持久化会话(验证 cwd),并在完成前将其存储的对话作为有序的 session/update 通知重新播放 |
session/cancel | 取消活动的 Runner 调用,并返回已取消的停止原因 |
$/cancel_request | 取消匹配的 JSON-RPC 请求,而不损坏会话 |
session/close | 取消活动工作并释放会话所有的进程 |
session/list | 列出对 ACP 可见的已持久化会话 |
session/resume | 重新连接到原始会话和工作区 |
session/fork | 将已持久化会话分支为新的会话 ID,复制其历史记录和相关状态,同时保持源会话不变 |
session/set_mode | 验证并记录 agent 的 SessionControls 所声明的会话模式,发出 CurrentModeUpdate |
session/set_config_option | 验证并记录 agent 的 SessionControls 所声明的配置值,发出 ConfigOptionUpdate |
session/delete | 删除持久化历史记录并释放活动资源 |
每个会话一次只能运行一个提示。不同会话最多可并发运行 max_sessions。
事件映射
- 模型文本变为
agent_message_chunk; - 模型思维内容变为
agent_thought_chunk; - 嵌入式资源内容变为一个 ACP 嵌入式资源
agent_message_chunk; - ADK 函数调用变为带有推断工具
kind的 ACP 工具启动更新; - 函数响应变为工具完成更新,其中包含结果内容和任何受影响的文件位置,并根据发起该工具调用的调用进行关联;
- 携带使用情况元数据的事件变为
UsageUpdate通知(令牌数量,以及在报告时提供的美元成本); - 代理声明的命令会在会话变为活动状态时变为一个
AvailableCommandsUpdate,记录的会话标题则变为一个SessionInfoUpdate; - 计划条目会变为一个
Plan更新——此映射已存在,但在 ADK 计划原语呈现计划条目之前会一直处于休眠状态; - 取消变为
StopReason::Cancelled; - 正常完成变为
StopReason::EndTurn。
共享内容模块负责双向维护 ContentBlock ↔ adk_core::Part 映射。嵌入式资源提示内容映射到 Part::EmbeddedResource,保留源 URI、可选 MIME 类型和内容;文本资源逐字保留,而二进制资源在线路上传输时进行 base64 编码,并在内部解码为原始字节。图像和音频提示内容映射到 Part::InlineData,保留 MIME 类型、解码后的字节、注释以及图像的可选源 URI。这些字段保留在会话 JSON 中,并由 session/load 恢复。由于提示处理程序接受嵌入式资源、图像和音频内容,服务器会公布 embedded_context、image 和 audio 提示能力。携带服务器未公布的内容类型的提示会被拒绝,并返回描述性错误,而不是进行部分处理。
加载和历史记录重放
当客户端重新连接时,session/load 会恢复持久化会话的可见历史记录。处理程序以与 session/resume 相同的方式重新激活会话——验证调用方提供了原始 cwd,并对未知标识符返回会话未找到错误——然后执行重放过程。它通过会话服务读取持久化事件,并按照原始时间顺序,将每个已存储的用户、代理、思考和工具事件映射到相应的 session/update 通知,然后才完成加载请求。服务器公布 load_session 能力,以便客户端知道可以重新连接并重建对话视图。
会话模式、配置选项和分叉
代理通过 AcpServerConfigBuilder::session_controls 提供 SessionControls,即可选择启用交互式会话控制。该提供程序声明可用模式(SessionModeState)、配置选项(选择项和开关)以及 ACP 斜杠命令。服务器会准确公布提供程序所声明的内容——没有提供程序的代理不会公布任何模式或选项——并在 session/new、session/load、session/resume 和 session/fork 响应中提供这些内容。
session/set_mode 会根据已公布的集合验证所请求的模式 id,记录该模式并发出 CurrentModeUpdate;未知 id 会被拒绝,当前模式保持不变。session/set_config_option 会根据选项声明的可选值验证该值,记录该值并发出 ConfigOptionUpdate;未知选项或无效值会被拒绝。两项选择都会持久化到 ADK 会话状态中的 acp:mode 和 acp:config:<id> 下,因此在加载、恢复和分叉后仍会保留。
session/fork 会分叉一个持久化会话:它读取源会话,创建新的会话 id,将存储的事件和相关状态(cwd、其他目录、模式和配置)复制到新会话中,并返回新的 id。源会话的持久化历史会逐字节保持不变。对未知会话标识符执行分叉会返回会话未找到错误。由于处理程序已注册,服务器会公布 fork 会话能力。
会话激活时,如果提供程序声明了命令,服务器还会为这些命令发出 AvailableCommandsUpdate(未声明任何命令时则不会发出),并在 acp:title 下记录了会话标题时发出携带该标题的 SessionInfoUpdate(通过 set_session_title 设置)。Plan 更新映射已存在,但只有当 ADK 计划原语提供计划条目时才会启用。
客户端提供的 MCP 服务器
客户端可以在 session/new 或 session/resume 中包含 stdio MCP 服务器。
服务器会在启动进程前验证名称、命令、参数和环境条目。随后:
- 在会话工作区中启动每个子进程;
- 执行有界的启动握手;
- 将连接封装为 ADK
McpToolset; - 将工具集注入该 Runner 调用;
- 在关闭、删除、启动失败或服务器关闭时取消 MCP 服务。
调用范围内的工具集目前由 LlmAgent 和
CodeActAgent 解析。服务器不会公布可选的 HTTP 和 SSE MCP 传输。
持久化决策
InMemorySessionService 适用于本地编辑器进程和测试。当会话必须在进程重启后继续存在时,请使用持久服务。恢复操作会验证调用方提供的是原始 cwd;会话无法被静默地重新连接到其他项目。
工具批准边界
服务器会将 ADK 工具确认桥接到原生 ACP 权限请求。
当配置的代理在提示轮次期间因 ToolConfirmationRequest 而暂停时——当代理等待人工批准工具调用时,该状态会在 event.actions.tool_confirmation 上呈现——服务器会发送描述工具及其参数的 session/request_permission 请求,等待客户端的结果,然后使用映射后的决策恢复执行。批准会映射为允许,而拒绝或取消都会映射为拒绝,因此已取消的请求绝不会执行工具。每个结果都会通过其函数调用标识符与确切的调用关联,并通过
RunConfig::tool_confirmation_decisions 反馈给 runner。
嵌套的 session/request_permission 由已经处理外层 session/prompt 的任务发起,该任务通过 ConnectionTo::spawn 生成,因此不会阻塞连接的调度循环,外层提示响应仍会完成。此前有人担心,官方 Rust SDK 在嵌套双向请求后会丢失外层提示响应,但在这种暂停/恢复流程中并不会复现;内存互操作性测试已覆盖这一情况。
当审批必须完全在 ADK-Rust 进程内部完成时,服务器拥有的工具授权、只读工具、RBAC、防护机制和工作流中断仍然可用。面向外部 ACP agent 的客户端权限路径也已完整实现。
安全部署
- 使用预期的项目工作区启动二进制文件。
- 将
cwd和其他根目录视为上下文,而不是操作系统隔离。 - 对不受信任的提示和命令应用
adk-sandbox、容器或其他进程边界。 - 将模型和 MCP 凭据保存在客户端机密存储或进程环境中。
- 切勿将横幅、调试对象或日志写入协议标准输出。
- 当恢复操作必须跨进程重启持续有效时,使用持久化的
SessionService。 - 设置有限的会话时长,并关闭不活跃的会话。
可运行的 acp_server crate 包含 Gemini 支持的 agent、限定在工作区内的读取工具、标准错误跟踪以及编辑器进程配置。