Protocolo ACP
Responsabilidad
ACP (Agent Client Protocol) es el protocolo estándar de comunicación entre un editor/IDE y un agent. acp_adapter/ expone a Hermes como server ACP, de modo que los clientes compatibles (Zed, extensiones de VS Code, etc.) puedan conducir Hermes directamente: gestionar sesiones (session), leer/escribir recursos (ficheros/imágenes), aprobar ediciones, trazar provenance y aislar herramientas (tool) por permisos. Así Hermes no vive solo en plataformas de mensajes, también se incrusta en flujos de desarrollo.
Motivo de diseño
Hermes nació para plataformas de mensajería — el gateway conecta Telegram/Discord con conversaciones largas. Pero un IDE es otra cosa: el directorio de trabajo lo abre el editor y el cwd debe seguirlo; una modificación de fichero no puede ejecutarse porque el agent lo diga, hay que pasársela al usuario para que la revise; entre sesiones hace falta trazabilidad de «esta sesión se comprimió a partir de cuál». ACP traduce estas restricciones propias del IDE a los primitivos que Hermes ya tiene. No reescribe el bucle del agent: enchufa el flujo de mensajes ACP a run_conversation, convierte los recursos ACP en content parts de OpenAI, y transforma las llamadas a herramienta que escriben ficheros en EditProposal con revisión humana. El principio es «adaptar, no reescribir».
Archivos clave
cabecera server.py:1-92— "ACP agent server — exposes Hermes Agent via the Agent Client Protocol"tratamiento de recursos:96-150—_MAX_ACP_RESOURCE_BYTES,_resource_display_name,_is_text_resource/_is_image_resourceconversión de recursos texto/imagen:201-296—_format_resource_text/_resource_link_to_parts/_image_data_url(recurso → partes de contenido OpenAI)SessionState / SessionManager:159-175— estado y gestor de sesiones ACPtraducción de cwd:29-62—_translate_acp_cwd/_normalize_cwd_for_compare(alineación del directorio de trabajo del editor)expansión de toolsets:129-159—_expand_acp_enabled_toolsetsclass EditProposal:26-51— propuesta de edición (write_file / patch)build_edit_proposal:178-220— construye la propuesta desde la llamada a herramienta (write_file / patch_replace / patch_v4a)requester de aprobación:51-69—set_edit_approval_requester/ mecanismo de tokenpermissions.py— aislamiento de permisos de herramientasprovenance:22-111—build_session_provenance/session_provenance_meta(trazabilidad del origen de operaciones)auth.py/entry.py/events.py__main__.py— entrada del server ACP (5 líneas)acp_registry/agent.json— manifiesto de metadatos del agent (para descubrimiento por los clientes)acp_registry/icon.svg— icono
Flujo de datos
- El cliente ACP (editor) descubre y arranca el server ACP de Hermes a partir de
acp_registry/agent.json(acp_adapter/__main__.py). - El cliente inicia una sesión →
SessionManager:175crea unSessionState, alinea cwd (acp_adapter/session.py:29) y expande toolsets (acp_adapter/session.py:129). - El cliente envía mensajes/recursos → la
conversión de recursos:201traduce el recurso ACP (fichero/imagen, sujeto al límite de tamaño deacp_adapter/server.py:96) a partes de contenido OpenAI y las entrega arun_conversation:588. - Cuando el agent quiere modificar ficheros, la llamada a herramienta pasa por
build_edit_proposal:178y se convierte en unEditProposal, que el requester de aprobación (acp_adapter/edit_approval.py:51) eleva al usuario para confirmar. - La ejecución de herramientas está sujeta a los permisos de
acp_adapter/permissions.py; cada operación anota provenance víaacp_adapter/provenance.py:22. - La salida en streaming y los eventos (
acp_adapter/events.py) se devuelven al cliente.
acp_registry/agent.json es la tarjeta de visita del cliente la primera vez que ve Hermes: versión, distribución (uvx), comando de arranque. Este contrato debe estar alineado con el binario real; si no, el cliente instala una versión equivocada y no arranca.
La traducción de cwd es el lugar donde más fácilmente se pisa la calle en ACP: un cliente Windows lanza Hermes en WSL pero el workspace es E:\Projects o una UNC \\wsl.localhost\.... _translate_acp_cwd lo normaliza a POSIX, si no todas las operaciones con Path del agent se desalinean.
La propuesta de edición es un dataclass frozen; la clave está en old_text — _proposal_for_write_file lee primero el contenido existente, así el diff que se muestra al usuario ve «antes/después» en lugar de un cambio a ciegas:
@dataclass(frozen=True)
class EditProposal:
tool_name: str
path: str
old_text: str | None
new_text: str
arguments: dict[str, Any]El requester de aprobación se vincula con ContextVar, no con una variable global; varias sesiones ACP concurrentes tienen cada una su requester y no se interfieren. .env / id_rsa van por defecto a ask y no a workspace_session, para que la política de «todo el workspace es de confianza» no los abra por error.
Provenance es específico del escenario IDE: en mensajería la sesión es una línea recta, pero en IDE se comprime, se bifurca, se reanuda. build_session_provenance recorre parent_session_id hacia arriba, cuenta las capas con end_reason == 'compression', marca sessionKind y compressionDepth, y pone el session id interno de Hermes junto al session id ACP externo en _meta.hermes.sessionProvenance.
Límites y fallos
- Versión de handshake no coincide:
agent.jsonfijahermes-agent[acp]==0.19.0. Si Hermes sube a 0.20 pero el cliente cachea el manifiesto viejo, el server arrancado y el schema del cliente se desincronizan y el InitializeResponse carece de campos — el handshake revienta. - Traducción cwd en WSL que se cuela: si
translate_cwd_for_wsl_backendno cubre una nueva forma de ruta Windows, el agent recibe un cwd desalineado y todas las operaciones conPathse desplazan sin error inmediato; solo revienta en el primer write_file con un «directorio no encontrado». - Deadlock del requester de aprobación: la aprobación va por
ContextVar+ callback de usuario; si el event loop del cliente se cuelga y no manda el ACK, la espera trasbuild_edit_proposalse queda colgada. Que el cancel del protocolo ACP llegue a ese punto depende de que la ruta de interrupción deevents.pylo cubra. - Cadena de provenance rota: si al bifurcar por compresión (compression) se escribe mal
parent_session_id,build_session_provenancellega al punto de corte y devuelveroot; el cliente enseña la continuación como si fuera una sesión nueva y el historial parece «perdido».
Resumen
ACP incrusta a Hermes en el flujo de trabajo del editor: gestión de sesiones, lectura/escritura de recursos, aprobación de ediciones, aislamiento de permisos y trazabilidad de origen. El núcleo es server.py (adaptación de protocolo) + session.py (sesión) + edit_approval.py (ediciones con revisión humana). Complementa a la capa de gateway: el gateway conecta plataformas de mensajes; ACP conecta IDEs.