Crie um cliente ou host ACP
Use a direção de cliente quando um aplicativo ADK-Rust precisar delegar trabalho de programação a um processo externo ACP. O aplicativo continua sendo o host: ele gerencia a seleção do projeto, a experiência do usuário, as regras de aprovação e quaisquer serviços locais oferecidos ao agente de programação.
Instalação
[dependencies]
adk-acp = "2.1.0"
O conjunto padrão de recursos é a implementação do cliente. O recurso server é
necessário somente ao expor um agente ADK-Rust.
Escolha o formato do cliente
| Formato do produto | API |
|---|---|
| Uma tarefa isolada com um processo novo | prompt_agent_with_policy |
| Uma tarefa isolada com conteúdo que não é texto (imagem, áudio, recurso) | prompt_agent_content_with_policy |
| Um especialista em codificação disponível para um agente LLM | AcpAgentTool |
| Vários especialistas em codificação nomeados | AcpToolset |
| Uma conversa contínua sobre o projeto | AcpSession |
| Progresso de texto e ferramentas exibido enquanto a rodada é executada | stream_prompt |
Prompt único
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 é o padrão porque um agente de codificação gerado pode solicitar operações
com efeitos colaterais reais. Use AutoApprove somente dentro de um fluxo de trabalho local confiável.
Enviar conteúdo avançado no prompt
prompt_agent_content_with_policy transmite um valor adk_core::Content completo —
não apenas uma string — para que um prompt possa transportar conteúdo que não seja texto. Partes de recursos incorporados,
imagens e áudio são mapeadas para o bloco de conteúdo ACP correspondente por meio do
módulo de conteúdo compartilhado, em vez de serem descartadas; o texto é sempre preservado. As partes
que não têm uma representação ACP transmissível são ignoradas, e um prompt que não seja mapeado
para nenhum bloco é rejeitado.
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?;
Delegar a partir de um agente 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()?;
Cada chamada AcpAgentTool inicia um novo processo e uma nova sessão. Escolha este formato
quando a tarefa delegada for independente e o coordenador precisar apenas do
texto final como resultado da ferramenta.
Sessões persistentes e cancelamento
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?;
O identificador de cancelamento envia a notificação oficial session/cancel. O
prompt deve continuar aguardando até que o motivo de parada cancelado chegue; isso permite que a
mesma sessão aceite outro prompt sem uma resposta obsoleta na fila.
Transmitir um turno para uma interface
stream_prompt produz valores OutputChunk para texto do agente, pensamentos, inícios de ferramentas,
decisões de permissão, conclusão e erros. Além desses, ele apresenta
duas visões mais detalhadas do turno de um External_Agent:
OutputChunk::ToolUpdate— o External_Agent'sToolCallUpdate, correlacionado poridde chamada de ferramenta, contendo o status informado, o tipo, o título atualizado, o texto de conteúdo extraído e os locais dos arquivos afetados. Isso permite que uma interface renderize o progresso das ferramentas, os diffs e as listas de arquivos afetados, em vez de apenas o texto final.OutputChunk::Usage— o External_Agent'sUsageUpdate, contendo os tokensusedesizeda janela de contexto, além docostecurrencycumulativos quando o agente os informa, para que uma interface possa exibir o consumo da janela de contexto.
O texto das mensagens do agente continua sendo exposto exatamente como antes, portanto uma interface que lê apenas
os fragmentos de texto não é afetada. A aplicação pode ocultar os fragmentos de pensamento, renderizar a
atividade das ferramentas separadamente e expor o StatusTracker compartilhado em sua interface.
Consulte o crate executável acp_client_host para ver
o ciclo completo.
Permitir que o agente solicite arquivos
Implemente AcpFileSystem e associe-o a AcpAgentConfig::filesystem. As capacidades de leitura
e gravação são anunciadas independentemente por meio de supports_read
e supports_write.
O callback recebe caminhos absolutos. Um host de produção deve:
- canonicalizar o workspace aprovado e o caminho solicitado;
- rejeitar caminhos fora das raízes aprovadas, incluindo escapes por links simbólicos;
- decidir se os buffers não salvos do editor substituem o conteúdo em disco;
- aplicar limites de tamanho de arquivo e de intervalo de linhas;
- anunciar gravações somente quando a aplicação as implementar e autorizar.
O diretório de trabalho é contexto, não um sandbox. A validação do sistema de arquivos e um limite de processo do sistema operacional resolvem problemas diferentes.
Permitir que o agente execute comandos
Implemente AcpTerminal e associe-o a AcpAgentConfig::terminal. ACP
anuncia o terminal como uma única capacidade, portanto o host deve implementar todo o ciclo de vida de
criação, saída, espera, encerramento e liberação.
O host escolhe listas de permissões de comandos, regras de diretório de trabalho, variáveis de ambiente, limites de saída, isolamento de processos e comportamento de limpeza. Os callbacks do terminal são executados fora do loop de despacho JSON-RPC, portanto uma espera longa não congela o tráfego de permissões ou cancelamentos.
Forneça um servidor MCP à sessão
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);
A versão estável ACP v1 exige que os agentes aceitem a configuração stdio MCP. As entradas HTTP e SSE são enviadas somente quando o agente externo anuncia esses transportes opcionais. A saída de depuração de AcpAgentConfig lista nomes e chaves de ambiente sem exibir valores secretos.
Políticas de permissão
Cada solicitação de permissão inclui o ID da sessão, o ID exato da chamada de ferramenta, o tipo de ferramenta, a entrada bruta e todas as opções oferecidas pelo agente. Os IDs das opções são opacos. ADK-Rust corresponde à semântica de permitir e rejeitar e, em seguida, retorna o ID original; uma seleção inventada torna-se um cancelamento.
PermissionPolicy::async_custom pode aguardar uma caixa de diálogo da área de trabalho, uma interface de aprovação web ou um serviço de políticas da organização. Mantenha o loop de despacho responsivo aguardando a interação humana por meio deste API em vez de bloquear uma thread.