Arquitectura del protocolo Agent Client

ACP estandariza la relación entre una interfaz de codificación y un agente de codificación. Les proporciona una forma común de establecer capacidades, abrir una sesión de proyecto, intercambiar prompts, transmitir el progreso, solicitar permiso, cancelar el trabajo y cerrar o reanudar la sesión.

Los dos roles

RolResponsabilidades
Cliente / hostInicia el proceso del agente, presenta la interfaz humana, selecciona el workspace, proporciona archivos opcionales, terminales y servidores MCP, aplica la política de permisos y muestra actualizaciones en vivo
Agente ACPAcepta sesiones de proyecto y prompts, realiza trabajo de codificación, informa mensajes y actividad de herramientas, solicita permiso cuando es necesario y devuelve una razón de parada tipada

ADK-Rust puede ocupar cualquiera de los dos roles. Estas son dos direcciones de despliegue, no dos protocolos diferentes.

Rendering architecture…

Cuando ADK-Rust consume otro agente de codificación, el lado izquierdo es ADK-Rust y el lado derecho es el proceso externo. Cuando un editor consume un agente ADK-Rust, el editor se hace cargo del lado izquierdo y AcpServer del lado derecho.

Un turno de ACP

Rendering architecture…

La conexión es bidireccional. Un cliente debe seguir leyendo mientras se ejecuta un prompt porque el agente puede enviar notificaciones o solicitudes de permiso antes de la respuesta final del prompt.

Identidad y estado de la sesión

Una sesión ACP identifica una conversación en curso sobre un proyecto. Contiene un cwd absoluto, directorios adicionales opcionales, múltiples prompts, actualizaciones en streaming y un ciclo de vida. En el servidor ADK-Rust, una sesión ACP se asigna a una sesión ADK-Rust para que el historial del modelo y el estado de la sesión permanezcan ligados a la misma conversación.

Cerrar una conexión activa es diferente de eliminar el historial persistido:

  • session/close libera la sesión activa y sus procesos;
  • session/resume se adjunta al estado persistido de la sesión ADK;
  • session/load reactiva una sesión persistida y reproduce su conversación almacenada al cliente como notificaciones session/update ordenadas antes de que se complete la solicitud;
  • session/fork ramifica una sesión persistida en un nuevo id de sesión cuya historia almacenada es una copia de la del origen, dejando intacto el origen;
  • session/delete elimina la sesión persistida;
  • session/list devuelve las sesiones visibles a través del SessionService configurado.

session/load valida el cwd proporcionado frente al directorio de trabajo almacenado de la sesión de la misma manera que session/resume, y devuelve un error de sesión no encontrada para un identificador de sesión desconocido. La reproducción asigna cada evento almacenado de usuario, agente, pensamiento y herramienta a su variante correspondiente de SessionUpdate en el orden cronológico original, de modo que un editor que se reconecta restaura el historial visible en el orden en que ocurrió.

Controles interactivos de sesión

Un agente puede exponer controles interactivos al cliente proporcionando un proveedor SessionControls. Cuando lo hace, el servidor los anuncia en las respuestas session/new, session/load, session/resume y session/fork:

  • Modos — un conjunto de modos con nombre (por ejemplo, "ask" frente a "code") con una selección actual. session/set_mode valida el modo solicitado frente al conjunto anunciado, lo registra y emite un CurrentModeUpdate; un modo desconocido se rechaza y el modo actual no cambia.
  • Opciones de configuración — selectores y alternadores que un cliente puede leer y cambiar. session/set_config_option valida el valor frente a las opciones declaradas de la opción, lo registra y emite un ConfigOptionUpdate; una opción desconocida o un valor inválido se rechaza.
  • Comandos disponibles — comandos con barra ACP mostrados como un AvailableCommandsUpdate cuando una sesión se activa.

Las selecciones de modo y configuración persisten en el estado de la sesión ADK (acp:mode, acp:config:<id>), por lo que sobreviven a la carga, la reanudación y la bifurcación. Un título de sesión registrado aparece como un SessionInfoUpdate al activarse y cada vez que cambia. Existe un mapeo de actualización Plan, pero permanece inactivo hasta que una primitiva de plan ADK exponga entradas de plan. Un agente que no proporciona SessionControls no anuncia modos ni opciones, manteniendo las capacidades anunciadas exactamente alineadas con lo que implementa el servidor.

El contenido cruza la frontera a través de un único mapeo

Los prompts que llegan desde un cliente y las actualizaciones que vuelven en streaming a él pasan ambos por un único módulo de contenido que mapea valores ACP ContentBlock a valores adk_core::Part y viceversa. Mantener un solo mapeo en ambas direcciones significa que el analizador de prompts del servidor, el emisor en streaming del servidor y el cliente coinciden en cómo se representa cada tipo de contenido.

El mapeo preserva las cargas útiles fielmente. Los bloques de texto se mapean a Part::Text con la cadena intacta. Los bloques de recurso incrustado se mapean a Part::EmbeddedResource, conservando el URI de origen, el tipo MIME opcional y el contenido. Un recurso de texto viaja literalmente en ambas direcciones y nunca se codifica en base64; un recurso binario se codifica en base64 en el cable y se decodifica a bytes sin procesar en el lado ADK de la frontera. Los bloques de imagen y audio se mapean a Part::InlineData, preservando el tipo MIME y los bytes decodificados; el servidor anuncia y acepta esos medios del prompt, y el cliente transmite contenido no textual ADK (recurso incrustado, imagen, audio) como el bloque ACP correspondiente en lugar de descartarlo.

Las actualizaciones en streaming llevan más que texto

Mientras se ejecuta un prompt, el servidor traduce eventos ADK tipados en notificaciones ACP session/update. El texto y los pensamientos del modelo se convierten en fragmentos de mensaje y pensamiento, y el contenido de recurso incrustado se convierte en un fragmento de mensaje de recurso incrustado. Más allá de esa superficie, dos tipos de actualización dan al cliente una vista más rica del turno:

  • Actualizaciones de uso. Cuando un evento ADK lleva metadatos de uso, el servidor envía una UsageUpdate que refleja los recuentos de tokens informados, además del costo en USD cuando el entorno de ejecución lo informa. Los eventos sin metadatos de uso no producen ninguna actualización, y el servidor nunca inventa recuentos.
  • Actualizaciones enriquecidas de llamadas a herramientas. Una llamada a herramienta comienza como una ToolCall con un kind de herramienta inferido del comportamiento declarado de la herramienta. Su ToolCallUpdate posterior lleva el contenido del resultado de la herramienta y las ubicaciones de archivo que la herramienta informa como afectadas, de modo que un editor puede renderizar diffs y listas de archivos afectados. La actualización conserva el mismo identificador que la ToolCall de origen, preservando la correlación a lo largo del turno.

La dirección del cliente tiene la fidelidad correspondiente. Cuando una aplicación ADK-Rust consume un External_Agent, su superficie de streaming (OutputChunk) expone no solo el texto y los pensamientos del agente, sino también el External_Agent ToolCallUpdate (como una actualización de herramienta correlacionada por id que lleva estado, tipo, título, texto de contenido y ubicaciones de archivo afectadas) y su UsageUpdate (tokens usados y tamaño, además de costo y moneda cuando se informa). El texto del mensaje del agente se muestra exactamente igual que antes, por lo que los consumidores de texto existentes no se ven afectados.

Las solicitudes de permiso enlazan confirmaciones de herramientas

Un agente ADK-Rust puede pausar un turno en espera de la aprobación humana de una llamada de herramienta (ToolConfirmationRequest). En el lado del servidor, esa pausa se convierte en una solicitud nativa de ACP session/request_permission que describe la herramienta y sus argumentos. El resultado del cliente reanuda el turno: una aprobación se asigna a permitir, y una denegación o una cancelación se asignan a denegar, de modo 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 a través de sus decisiones de confirmación de herramienta. La solicitud de permiso anidada se emite desde la tarea de prompt generada, por lo que la respuesta externa del session/prompt aún se completa normalmente.

Las capacidades son un contrato

La inicialización no es un intercambio decorativo. Cada lado anuncia solo las operaciones y el contenido que admite. ADK-Rust usa esas capacidades para evitar enviar configuración opcional de HTTP o SSE MCP a un agente que acepta solo stdio, y anuncia operaciones de host del sistema de archivos o del terminal solo cuando la aplicación proporciona la implementación correspondiente.

El servidor anuncia exactamente los tipos de contenido que acepta su controlador de prompt. Anuncia las capacidades de prompt embedded_context, image y audio porque el contenido de recurso incrustado se asigna a adk_core::Part::EmbeddedResource y el contenido de imagen y audio se asigna a adk_core::Part::InlineData. Anuncia load_session porque registra un controlador session/load, y la capacidad de sesión fork porque registra un controlador session/fork. Los modos de sesión y las opciones de configuración solo se anuncian cuando el agente proporciona un proveedor de SessionControls, por lo que un agente sin uno no anuncia ninguno de los dos. Los transportes remotos, los selectores de modelo y las adiciones experimentales al protocolo permanecen sin anunciar. Un prompt que lleva un tipo de contenido que el servidor no ha anunciado se rechaza con un error descriptivo en lugar de manejarse parcialmente. Los llamadores deben diseñar en función del objeto de capacidad negociado en lugar de asumir que cada implementación de ACP tiene la misma superficie.

Siguiente