Skip to content

Punto de entrada y flujo de arranque ​

源码版本v2026.7.20

Responsabilidad ​

Convertir «un comando hermes / un mensaje del gateway» en «un agent corriendo en memoria». La capa de entrada se mantiene deliberadamente fina: run_agent.py solo reenvía y ensambla el CLI; la inyección de dependencias real ocurre en agent_init.py. Así, gateway, TUI, CLI, ACP y cron comparten la misma ruta de inicialización.

Motivo de diseño ​

La capa de entrada es fina y el ensamblaje está centralizado para que todas las rutas de invocación aprendan un solo camino. Si AIAgent.__init__ resolviera por su cuenta el provider, fusionara extra_body y calculara el umbral de compresión (compression), entonces gateway, TUI y cron tendrían que replicar esa lógica cada uno; tocar una cosa exigiría tocar varias. Al reducir __init__ a un mero forwarder y concentrar las decisiones reales en init_agent, añadir un nuevo frontend (p. ej. un daemon MCP futuro) se reduce a construir un AIAgent y obtener toda la capacidad, sin conocer el ensamblaje interno.

hermes_bootstrap.py va al principio por la misma razón: la corrección de UTF-8 en Windows es «cuanto antes, mejor»; si se espera a que un subproceso se haya derivado ya es tarde para remediarlo. Por eso es un módulo aparte que todos los puntos de entrada importan en su primera línea.

Archivos clave ​

Flujo de datos ​

  1. El usuario ejecuta hermes (CLI) o el gateway arranca con main() (run_agent.py:22965).
  2. El proceso pasa por hermes_bootstrap.py para ajustar rutas/entorno, y entra al CLI main:6434 o al bucle del gateway.
  3. Se construye una instancia de AIAgent:400; su __init__ reenvía a init_agent:276.
  4. init_agent resuelve provider, toolsets, umbral de compresión, extra_body de provider personalizado, etc., y ensambla un objeto agent ejecutable.
  5. El gateway, dentro de GatewayRunner en gateway/run.py, mantiene ese agent y le pasa cada mensaje entrante a run_conversation:588.

El cuerpo de AIAgent.__init__ es literalmente la palabra «forwarder» — todos los parámetros de construcción se pasan intactos a init_agent, sin ningún análisis propio:

python
"""Forwarder — see ``agent.agent_init.init_agent``."""
from agent.agent_init import init_agent
init_agent(
    self,
    base_url=base_url,
    api_key=api_key,
    provider=provider,
    api_mode=api_mode,
    ...
)

Y hermes_bootstrap.py, lo primero que toca el proceso, solo hace el arreglo de codificación en Windows; en POSIX pasa de largo. Es corto:

python
if not _IS_WINDOWS:
    return False
if _bootstrap_applied:
    return False
os.environ.setdefault("PYTHONUTF8", "1")
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
for stream_name in ("stdout", "stderr"):
    stream = getattr(sys, stream_name, None)
    ...
    reconfigure(encoding="utf-8", errors="replace")

Que sea setdefault en lugar de = es deliberado: el usuario puede poner PYTHONUTF8=0 en el entorno de antemano para hacer opt-out y no se sobrescribe.

Límites y fallos ​

  • Entry invocada directamente: alguien se salta hermes_bootstrap y arranca el proceso en Windows con un python -m gateway.run directo; stdio sigue siendo cp1252 y una salida no ASCII levanta UnicodeEncodeError. La posición del bootstrap es convención, no imposición; la documentación exige que todos los puntos de entrada lo importen en su primera línea.
  • AIAgent.__init__ lanza antes de init_agent: como el cuerpo de __init__ es solo import + llamada, cualquier fallo viene de dentro de init_agent y la traza se ve «desplazada». Al depurar, la última frame del traceback es init_agent; que el comentario de __init__ diga «forwarder» no significa que el forwarder tenga el bug.
  • El import en init_agent es perezoso: from agent.agent_init import init_agent está dentro del cuerpo de __init__ y no en la cima del módulo, para evitar import circular — agent_init a su vez importa run_agent. El coste es un import extra (~milisegundos) la primera vez que se construye un AIAgent; después se cachea en el módulo.
  • reconfigure de hermes_bootstrap puede fallar: si stdout fue reemplazado por un BytesIO (escenarios de test) o ya está cerrado, reconfigure lanza OSError/ValueError; el código lo atrapa y sigue. La vía del entorno sigue funcionando, así que los subprocesos no se ven afectados.

Resumen ​

La capa de entrada es «reenviar + ensamblar», sin lógica de negocio. AIAgent es una cáscara fina; init_agent es el centro de ensamblaje. Tras entender esta cadena, el bucle principal del agente responde a «qué hace cuando recibe un mensaje».

Sitio de aprendizaje comunitario no oficial. Basado en el código fuente de NousResearch/hermes-agent (licencia MIT). · Privacidad · Términos · Acerca de