构建 ACP 客户端或主机
当 ADK-Rust 应用需要将编码工作委托给外部 ACP 进程时,请使用客户端方向。应用仍然是主机:它负责项目选择、用户体验、审批规则,以及向编码代理提供的任何本地服务。
安装
[dependencies]
adk-acp = "2.1.0"
默认功能集是客户端实现。只有在公开 ADK-Rust 代理时才需要 server 功能。
选择客户端形态
| 产品形态 | API |
|---|---|
| 使用全新进程执行的单个隔离任务 | prompt_agent_with_policy |
| 包含非文本(图像、音频、资源)内容的单个隔离任务 | prompt_agent_content_with_policy |
| 可供 LLM 代理使用的编码专家 | AcpAgentTool |
| 多个具名编码专家 | AcpToolset |
| 持续的项目对话 | AcpSession |
| 回合运行期间呈现的文本和工具进度 | stream_prompt |
单次提示
use adk_acp::{
AcpAgentConfig, PermissionPolicy, prompt_agent_with_policy,
};
use std::sync::Arc;
let config = AcpAgentConfig::new("my-coding-agent --acp")
.working_dir("/absolute/path/to/project");
let answer = prompt_agent_with_policy(
&config,
"Inspect the failing test and explain the cause.",
Arc::new(PermissionPolicy::DenyAll),
).await?;
DenyAll 是默认设置,因为生成的编码代理可能会请求执行具有实际副作用的操作。仅在受信任的本地工作流中使用 AutoApprove。
发送富提示内容
prompt_agent_content_with_policy 传输完整的 adk_core::Content 值——
而不仅仅是字符串——因此提示可以携带非文本内容。嵌入式资源、图像和音频部分会通过共享内容模块映射到匹配的 ACP 内容块,而不会被丢弃;文本始终会被保留。没有可传输 ACP 表示形式的部分会被跳过,而完全未映射到任何内容块的提示则会被拒绝。
use adk_acp::{AcpAgentConfig, PermissionPolicy};
use adk_acp::connection::prompt_agent_content_with_policy;
use adk_core::{Content, Part};
use std::sync::Arc;
let mut content = Content::new("user");
content.parts.push(Part::Text { text: "What is in this image?".into() });
content.parts.push(Part::InlineData { mime_type: "image/png".into(), data: png_bytes });
let config = AcpAgentConfig::new("my-coding-agent --acp")
.working_dir("/absolute/path/to/project");
let answer = prompt_agent_content_with_policy(
&config,
&content,
Arc::new(PermissionPolicy::DenyAll),
).await?;
从 ADK 代理进行委派
use adk_acp::{AcpAgentTool, PermissionDecision, PermissionPolicy};
use adk_agent::LlmAgentBuilder;
use std::sync::Arc;
let policy = PermissionPolicy::Custom(Box::new(|request| {
if request.title.to_ascii_lowercase().contains("delete") {
PermissionDecision::deny()
} else {
PermissionDecision::allow_once()
}
}));
let coding_agent = AcpAgentTool::new("my-coding-agent --acp")
.name("repository_specialist")
.description("Inspect and improve the current Rust repository")
.working_dir("/absolute/path/to/project")
.permission_policy(policy);
let coordinator = LlmAgentBuilder::new("coordinator")
.model(model)
.instruction("Delegate repository changes to repository_specialist.")
.tool(Arc::new(coding_agent))
.build()?;
每次 AcpAgentTool 调用都会启动一个新的进程和会话。当委派的任务是自包含的,并且协调器只需要将最终文本作为工具结果时,应选择这种方式。
持久会话与取消
use adk_acp::{AcpAgentConfig, AcpSession, PermissionPolicy};
use std::sync::Arc;
let config = AcpAgentConfig::new("my-coding-agent --acp")
.working_dir("/absolute/path/to/project");
let mut session = AcpSession::start(
config,
Arc::new(PermissionPolicy::DenyAll),
).await?;
let first = session.prompt("Map the error-handling modules.").await?;
let second = session.prompt("Now inspect the most central one.").await?;
let cancel = session.cancellation_handle()?;
// Move `cancel` into a stop-button, timeout, or shutdown task while another
// task awaits `session.prompt(...)`.
session.close().await?;
取消句柄会发送官方的 session/cancel 通知。在收到已取消的停止原因之前,应保持等待提示;这样,同一会话便可接受另一个提示,而不会在其队列中留下过时的响应。
将一轮交互流式传输到 UI
stream_prompt 会为代理文本、思考过程、工具启动、权限决策、完成和错误生成 OutputChunk 值。除此之外,它还会展示 External_Agent 一轮交互的两个更丰富的视图:
OutputChunk::ToolUpdate— External_Agent 的ToolCallUpdate,按工具调用id进行关联,携带报告的状态、类型、更新后的标题、提取的内容文本以及受影响的文件位置。这使 UI 能够呈现工具进度、差异和受影响文件列表,而不只是最终文本。OutputChunk::Usage— External_Agent 的UsageUpdate,携带令牌used和上下文窗口size,以及 agent 报告时提供的累计cost和currency, 这样 UI 就可以显示上下文窗口的消耗情况。
Agent 消息文本的呈现方式与之前完全相同,因此只读取文本块的 UI 不受影响。应用可以隐藏思考块、单独呈现工具活动,并在其界面中公开共享的 StatusTracker。
请参阅可运行的 acp_client_host crate,
了解完整循环。
让 agent 请求文件
实现 AcpFileSystem,并通过 AcpAgentConfig::filesystem 将其附加。读写能力通过 supports_read
和 supports_write 独立声明。
回调接收绝对路径。生产环境主机应当:
- 规范化已批准的工作区和请求的路径;
- 拒绝位于已批准根目录之外的路径,包括符号链接逃逸;
- 决定未保存的编辑器缓冲区是否覆盖磁盘内容;
- 应用文件大小和行范围限制;
- 仅在应用实现并授权写入时声明写入能力。
工作目录是上下文,而不是沙箱。文件系统验证和操作系统进程边界解决的是不同的问题。
让 agent 运行命令
实现 AcpTerminal,并通过 AcpAgentConfig::terminal 将其附加。ACP
将终端声明为一项能力,因此主机必须实现完整的创建、输出、等待、终止和释放生命周期。
主机选择命令允许列表、工作目录规则、环境变量、输出限制、进程隔离和清理行为。终端回调在 JSON-RPC 调度循环之外执行,因此长时间等待不会冻结权限或取消请求。
向会话提供 MCP 服务器
use adk_acp::AcpAgentConfig;
use adk_acp::agent_client_protocol::schema::v1::{
McpServer, McpServerStdio,
};
let tools = McpServer::Stdio(
McpServerStdio::new("project-tools", "/absolute/path/to/mcp-server")
.args(vec!["--read-only".into()]),
);
let config = AcpAgentConfig::new("my-coding-agent --acp")
.working_dir("/absolute/path/to/project")
.mcp_server(tools);
稳定的 ACP v1 要求代理接受 stdio MCP 配置。仅当外部代理声明支持这些可选传输方式时,才会发送 HTTP 和 SSE 条目。AcpAgentConfig 调试输出会列出名称和环境变量键,但不会打印机密值。
权限策略
每个权限请求都包含会话 ID、精确的工具调用 ID、工具类型、原始输入以及代理提供的所有选项。选项 ID 是不透明的。ADK-Rust 匹配允许和拒绝语义,然后返回原始 ID;伪造的选择将变为取消操作。
PermissionPolicy::async_custom 可以等待桌面对话框、网页审批界面或组织策略服务。通过此 API 等待人工交互,而不是阻塞线程,以保持调度循环的响应能力。