ACP 클라이언트 또는 호스트 빌드
ADK-Rust 애플리케이션이 코딩 작업을 외부 ACP 프로세스에 위임해야 하는 경우 클라이언트 방향을 사용합니다. 애플리케이션은 호스트로 남아 프로젝트 선택, 사용자 경험, 승인 규칙 및 코딩 에이전트에 제공되는 모든 로컬 서비스를 관리합니다.
설치
[dependencies]
adk-acp = "2.1.0"
기본 기능 세트는 클라이언트 구현입니다. server 기능은 ADK-Rust 에이전트를 노출할 때만 필요합니다.
클라이언트 형태 선택
| 제품 형태 | 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는 최종 텍스트만 표시하는 대신 도구 진행 상황, diff 및 영향을 받는 파일 목록을 렌더링할 수 있습니다.OutputChunk::Usage— External_Agent의UsageUpdate로, 토큰used및 컨텍스트 윈도우size와 함께, 에이전트가 보고하는 경우 누적된cost및currency를 전달하여 UI가 컨텍스트 윈도우 사용량을 표시할 수 있도록 합니다.
에이전트 메시지 텍스트는 이전과 정확히 동일하게 노출되므로, 텍스트 청크만 읽는 UI에는 영향을 주지 않습니다.
애플리케이션은 사고 청크를 숨기고, 도구 활동을 별도로 렌더링하며, 공유되는 StatusTracker을
인터페이스에 노출할 수 있습니다.
전체 루프는 실행 가능한 acp_client_host crate에서 확인할 수 있습니다.
에이전트가 파일을 요청하도록 하기
AcpFileSystem를 구현하고 AcpAgentConfig::filesystem으로 연결합니다. 읽기 및
쓰기 기능은 각각 supports_read 및 supports_write를 통해 독립적으로 광고됩니다.
콜백은 절대 경로를 받습니다. 프로덕션 호스트는 다음을 수행해야 합니다.
- 승인된 작업 공간과 요청된 경로를 정규화합니다.
- 심볼릭 링크를 통한 탈출을 포함하여 승인된 루트 외부의 경로를 거부합니다.
- 저장되지 않은 편집기 버퍼가 디스크 콘텐츠를 덮어쓸지 결정합니다.
- 파일 크기 및 줄 범위 제한을 적용합니다.
- 애플리케이션이 쓰기를 구현하고 권한을 부여한 경우에만 쓰기 기능을 광고합니다.
작업 디렉터리는 컨텍스트이지 샌드박스가 아닙니다. 파일 시스템 검증과 OS 프로세스 경계는 서로 다른 문제를 해결합니다.
에이전트가 명령을 실행하도록 하기
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는 데스크톱 대화 상자, 웹 승인 UI 또는 조직 정책 서비스를 기다릴 수 있습니다. 스레드를 차단하는 대신 이 API를 통해 사람의 상호 작용을 기다려 디스패치 루프의 응답성을 유지하세요.