通过 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。

运行时映射

Rendering architecture…

处理程序会验证绝对的 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

共享内容模块负责双向维护 ContentBlockadk_core::Part 映射。嵌入式资源提示内容映射到 Part::EmbeddedResource,保留源 URI、可选 MIME 类型和内容;文本资源逐字保留,而二进制资源在线路上传输时进行 base64 编码,并在内部解码为原始字节。图像和音频提示内容映射到 Part::InlineData,保留 MIME 类型、解码后的字节、注释以及图像的可选源 URI。这些字段保留在会话 JSON 中,并由 session/load 恢复。由于提示处理程序接受嵌入式资源、图像和音频内容,服务器会公布 embedded_contextimageaudio 提示能力。携带服务器未公布的内容类型的提示会被拒绝,并返回描述性错误,而不是进行部分处理。

加载和历史记录重放

当客户端重新连接时,session/load 会恢复持久化会话的可见历史记录。处理程序以与 session/resume 相同的方式重新激活会话——验证调用方提供了原始 cwd,并对未知标识符返回会话未找到错误——然后执行重放过程。它通过会话服务读取持久化事件,并按照原始时间顺序,将每个已存储的用户、代理、思考和工具事件映射到相应的 session/update 通知,然后才完成加载请求。服务器公布 load_session 能力,以便客户端知道可以重新连接并重建对话视图。

会话模式、配置选项和分叉

代理通过 AcpServerConfigBuilder::session_controls 提供 SessionControls,即可选择启用交互式会话控制。该提供程序声明可用模式(SessionModeState)、配置选项(选择项和开关)以及 ACP 斜杠命令。服务器会准确公布提供程序所声明的内容——没有提供程序的代理不会公布任何模式或选项——并在 session/newsession/loadsession/resumesession/fork 响应中提供这些内容。

session/set_mode 会根据已公布的集合验证所请求的模式 id,记录该模式并发出 CurrentModeUpdate;未知 id 会被拒绝,当前模式保持不变。session/set_config_option 会根据选项声明的可选值验证该值,记录该值并发出 ConfigOptionUpdate;未知选项或无效值会被拒绝。两项选择都会持久化到 ADK 会话状态中的 acp:modeacp:config:<id> 下,因此在加载、恢复和分叉后仍会保留。

session/fork 会分叉一个持久化会话:它读取源会话,创建新的会话 id,将存储的事件和相关状态(cwd、其他目录、模式和配置)复制到新会话中,并返回新的 id。源会话的持久化历史会逐字节保持不变。对未知会话标识符执行分叉会返回会话未找到错误。由于处理程序已注册,服务器会公布 fork 会话能力。

会话激活时,如果提供程序声明了命令,服务器还会为这些命令发出 AvailableCommandsUpdate(未声明任何命令时则不会发出),并在 acp:title 下记录了会话标题时发出携带该标题的 SessionInfoUpdate(通过 set_session_title 设置)。Plan 更新映射已存在,但只有当 ADK 计划原语提供计划条目时才会启用。

客户端提供的 MCP 服务器

客户端可以在 session/newsession/resume 中包含 stdio MCP 服务器。 服务器会在启动进程前验证名称、命令、参数和环境条目。随后:

  1. 在会话工作区中启动每个子进程;
  2. 执行有界的启动握手;
  3. 将连接封装为 ADK McpToolset
  4. 将工具集注入该 Runner 调用;
  5. 在关闭、删除、启动失败或服务器关闭时取消 MCP 服务。

调用范围内的工具集目前由 LlmAgentCodeActAgent 解析。服务器不会公布可选的 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、限定在工作区内的读取工具、标准错误跟踪以及编辑器进程配置。

后续步骤

通过 ACP 暴露 ADK-Rust agent - ADK-Rust 文档 | ADK-Rust