Exponer un agente ADK-Rust mediante ACP
Usa la modalidad de servidor cuando un editor u otro cliente ACP deba iniciar tu binario ADK-Rust y utilizar su agente dentro de una interfaz de programación. Tu proceso de Rust es propietario del agente, el modelo, las herramientas, los flujos de trabajo, las sesiones, la memoria y la política operativa. El cliente solo ve las capacidades y el ciclo de vida de las sesiones publicados mediante ACP.
Instalar la función del servidor
[dependencies]
adk-acp = { version = "2.1.0", features = ["server"] }
Compilar y servir un agente
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?;
El servidor utiliza el constructor oficial SDK Agent y el transporte stdio. El
tráfico del protocolo es el único dato escrito en stdout; configura el registro
y los diagnósticos para que utilicen stderr.
Mapeo en tiempo de ejecución
El controlador valida un cwd absoluto, reserva capacidad para la sesión, crea o
reanuda la sesión ADK y ejecuta el agente configurado. Los eventos tipados
ADK se traducen en notificaciones session/update de ACP mientras el mensaje está
activo.
Ciclo de vida implementado
| operación ACP | comportamiento ADK-Rust |
|---|---|
initialize | Negocia el protocolo v1 y devuelve metadatos exactos de implementación y capacidades |
session/new | Valida las rutas del espacio de trabajo y crea una sesión ADK persistida |
session/prompt | Convierte los bloques de contenido compatibles (texto, enlace a recurso, recurso incrustado, imagen, audio) y transmite el Runner |
session/load | Reactiva una sesión persistida (validando cwd) y reproduce su conversación almacenada como notificaciones session/update ordenadas antes de completarse |
session/cancel | Cancela la invocación activa del Runner y devuelve un motivo de detención cancelado |
$/cancel_request | Cancela la solicitud JSON-RPC coincidente sin corromper la sesión |
session/close | Cancela el trabajo activo y libera los procesos propiedad de la sesión |
session/list | Enumera las sesiones persistentes visibles para ACP |
session/resume | Se vuelve a conectar con la sesión y el espacio de trabajo originales |
session/fork | Ramifica una sesión persistente en un nuevo id de sesión, copiando su historial y el estado pertinente, y dejando el origen sin cambios |
session/set_mode | Valida y registra un modo de sesión declarado por el SessionControls del agente, emitiendo un CurrentModeUpdate |
session/set_config_option | Valida y registra un valor de configuración declarado por el SessionControls del agente, emitiendo un ConfigOptionUpdate |
session/delete | Elimina el historial persistido y libera los recursos activos |
Solo puede ejecutarse una solicitud a la vez en una sesión. Se pueden ejecutar sesiones diferentes
de forma simultánea hasta max_sessions.
Mapeo de eventos
- el texto del modelo se convierte en
agent_message_chunk; - el contenido del razonamiento del modelo se convierte en
agent_thought_chunk; - el contenido del recurso incrustado se convierte en un recurso incrustado ACP
agent_message_chunk; - las llamadas a funciones ADK se convierten en actualizaciones de inicio de herramienta ACP con una
kindde herramienta inferida; - las respuestas de las funciones se convierten en actualizaciones de finalización de herramienta enriquecidas con el contenido del resultado y cualquier ubicación de archivo afectada, vinculadas a la llamada de herramienta de origen;
- los eventos que contienen metadatos de uso se convierten en notificaciones
UsageUpdate(recuentos de tokens, además del coste en USD cuando se informa); - los comandos declarados por el agente se convierten en un
AvailableCommandsUpdatecuando una sesión se activa, y el título registrado de la sesión se convierte en unSessionInfoUpdate; - las entradas del plan se convertirían en una actualización
Plan— este mapeo existe, pero permanece inactivo hasta que una primitiva de plan ADK exponga las entradas del plan; - la cancelación se convierte en
StopReason::Cancelled; - la finalización normal se convierte en
StopReason::EndTurn.
Un módulo de contenido compartido gestiona la asignación ContentBlock ↔ adk_core::Part
en ambas direcciones. El contenido de las indicaciones de recursos incrustados se asigna a
Part::EmbeddedResource, conservando el URI de origen, el tipo MIME opcional y
el contenido; los recursos de texto se conservan literalmente, mientras que los recursos
binarios se codifican en base64 durante la transmisión y se decodifican internamente como
bytes sin procesar. El contenido de las indicaciones de imágenes y audio se asigna a
Part::InlineData, conservando el tipo MIME, los bytes decodificados, las anotaciones y el
URI de origen opcional de una imagen. Estos campos permanecen en la
JSON de sesión y son restaurados por session/load. Puesto que el
controlador de indicaciones acepta contenido de recursos incrustados, imágenes y audio, el
servidor anuncia las capacidades de indicaciones embedded_context, image y
audio. Una indicación que contiene un tipo de contenido que el servidor no ha
anunciado se rechaza con un error descriptivo en lugar de gestionarse parcialmente.
Carga y reproducción del historial
session/load restaura el historial visible de una sesión persistida cuando un cliente
se vuelve a conectar. El controlador reactiva la sesión del mismo modo que lo hace
session/resume: valida que la persona que realiza la llamada haya proporcionado el
cwd original y devuelve un error de sesión no encontrada para un identificador
desconocido; después, realiza una pasada de reproducción. Lee los eventos persistidos a
través del servicio de sesiones y asigna cada evento almacenado de usuario, agente,
pensamiento y herramienta a su notificación session/update correspondiente, en el orden
cronológico original, antes de que se complete la solicitud de carga. El servidor anuncia la
capacidad load_session para que un cliente sepa que puede volver a conectarse y
reconstruir la vista de la conversación.
Modos de sesión, opciones de configuración y bifurcación
Un agente opta por los controles de sesión interactiva proporcionando un SessionControls
mediante AcpServerConfigBuilder::session_controls. El proveedor declara los modos disponibles (un SessionModeState), las opciones de configuración (selectores y conmutadores) y los comandos slash ACP. El servidor anuncia exactamente lo que declara el proveedor —un agente sin proveedor no anuncia modos ni opciones— y los expone en las respuestas session/new, session/load, session/resume y
session/fork.
session/set_mode valida el id del modo solicitado con respecto al conjunto anunciado,
lo registra y emite un CurrentModeUpdate; un id desconocido se rechaza y el
modo actual no cambia. session/set_config_option valida el valor
con respecto a las opciones declaradas de la opción, lo registra y emite un
ConfigOptionUpdate; una opción desconocida o un valor no válido se rechaza. Ambas
selecciones persisten en el estado de sesión ADK bajo acp:mode y acp:config:<id>,
por lo que sobreviven a la carga, la reanudación y la bifurcación.
session/fork bifurca una sesión persistida: lee la sesión de origen, crea
un nuevo id de sesión, copia en ella los eventos almacenados y el estado relevante (cwd, directorios adicionales, modo y configuración) y devuelve el nuevo id. El historial persistido de la sesión de origen queda sin cambios, byte por byte. Una bifurcación para un identificador de sesión desconocido devuelve un error de sesión no encontrada. El servidor anuncia la capacidad de sesión fork porque el controlador está registrado.
Al activar una sesión, el servidor también emite un AvailableCommandsUpdate para cualquier
comando que declare el proveedor (y ninguno cuando no declare ninguno), y un
SessionInfoUpdate que contiene el título de la sesión cuando hay uno registrado bajo
acp:title (establecido mediante set_session_title). Existe una asignación de actualización Plan, pero
permanece inactiva hasta que una primitiva de plan ADK expone entradas del plan.
Servidores MCP proporcionados por el cliente
El cliente puede incluir servidores MCP stdio en session/new o session/resume.
El servidor valida los nombres, comandos, argumentos y entradas de entorno antes de
iniciar un proceso. Luego:
- inicia cada proceso secundario en el espacio de trabajo de la sesión;
- aplica un protocolo de enlace de inicio con límites;
- encapsula la conexión como un ADK
McpToolset; - inyecta el conjunto de herramientas en esa invocación de Runner;
- cancela los servicios MCP al cerrar, eliminar, producirse un fallo durante el inicio o apagar el servidor.
Actualmente, los conjuntos de herramientas con ámbito de invocación se resuelven mediante LlmAgent y
CodeActAgent. Los transportes opcionales HTTP y SSE MCP no son anunciados por el
servidor.
Decisiones de persistencia
InMemorySessionService es adecuado para un proceso de editor local y para pruebas. Usa
un servicio duradero cuando las sesiones deban sobrevivir a los reinicios del proceso. Reanudar valida
que el llamador proporcione el cwd original; una sesión no puede volver a
adjuntarse silenciosamente a un proyecto diferente.
Límite de aprobación de herramientas
El servidor conecta las confirmaciones de herramientas de ADK con las solicitudes nativas de permisos de ACP.
Cuando el agente configurado se pausa en un ToolConfirmationRequest durante un turno
de solicitud —que se muestra en event.actions.tool_confirmation cuando un agente espera la
aprobación humana de una llamada de herramienta—, el servidor envía una solicitud session/request_permission
que describe la herramienta y sus argumentos, espera el resultado del cliente y
reanuda la ejecución con la decisión asignada. Una aprobación se asigna a permitir, y una
denegación o cancelación se asignan a denegar, por lo que una solicitud cancelada nunca ejecuta
la herramienta. Cada resultado se correlaciona con la llamada exacta mediante su identificador de llamada de función y se
devuelve al ejecutor mediante
RunConfig::tool_confirmation_decisions.
El session/request_permission anidado se emite desde la tarea que ya gestiona el
session/prompt externo, iniciado mediante ConnectionTo::spawn, por lo que no
bloquea el bucle de despacho de la conexión y la respuesta de la solicitud
externa sigue completándose. Una preocupación anterior de que el SDK oficial de Rust
pierda la respuesta de la solicitud externa después de una solicitud bidireccional anidada
no se reproduce con este flujo de pausa/reanudación; está cubierta por las pruebas de
interoperabilidad en memoria.
La autorización de herramientas gestionada por el servidor, las herramientas de solo lectura, RBAC, las barreras de protección y las interrupciones del flujo de trabajo siguen disponibles cuando la aprobación debe realizarse por completo dentro del proceso ADK-Rust. La ruta de permisos del cliente para agentes ACP externos también está completamente implementada.
Desplegar de forma segura
- Inicia el binario con el espacio de trabajo del proyecto previsto.
- Trata
cwdy las raíces adicionales como contexto, no como aislamiento del sistema operativo. - Aplica
adk-sandbox, un contenedor u otra frontera de procesos para las solicitudes y los comandos que no sean de confianza. - Mantén las credenciales del modelo y de MCP en un almacén de secretos del cliente o en el entorno del proceso.
- No escribas nunca banners, objetos de depuración ni registros en la salida estándar del protocolo.
- Usa un
SessionServiceduradero cuando la reanudación deba sobrevivir al reinicio del proceso. - Establece un límite de sesión finito y cierra las sesiones inactivas.
El crate ejecutable acp_server incluye un agente respaldado por Gemini, herramientas de lectura limitadas al espacio de trabajo, trazas en stderr y configuración del proceso del editor.