Skip to content

Einstieg und Startfluss ​

源码版本v2026.7.20

Verantwortung ​

Aus «einem hermes-Befehl / einer Gateway-Nachricht (gateway message)» wird «ein im Speicher laufender Agent». Die Einstiegsschicht ist bewusst dünn gehalten – run_agent.py tut nur Weiterleiten und CLI-Zusammenbau; die echte Dependency-Injection steckt in agent_init.py. So teilen sich Gateway, TUI, CLI, ACP und cron denselben Initialisierungspfad.

Designmotiv ​

Einstiegsschicht dünn, Assembly zentralisiert — damit alle Aufrufpfade nur ein einziges Mal lernen. Würde AIAgent.__init__ selbst Provider (provider) auflösen, extra_body mergen, Kompressionsschwelle (compression threshold) berechnen, müssten Gateway, TUI und cron diese Logik jeweils nachbauen; eine Änderung an einer Stelle würde viele Stellen berühren. __init__ degeneriert zum reinen Forwarder; die eigentliche Entscheidung konvergiert in einer Funktion init_agent. Ein neu angedocktes Frontend (etwa ein künftiger MCP-Daemon) bekommt durch Konstruktion eines AIAgent die volle Fähigkeit, ohne die Assembly-Details zu kennen.

Dasselbe gilt für die Platzierung von hermes_bootstrap.py ganz vorne: Windows-UTF-8 ist eine «so früh wie möglich»-Korrektur; nachdem ein Kindprozess gespawned wurde, ist es zu spät. Also ist es ein eigenes Modul, das jeder Einstiegspunkt in der ersten Zeile importiert.

Schlüsseldateien ​

Datenfluss ​

  1. Der Nutzer führt hermes (CLI) aus oder das Gateway startet mit main() (run_agent.py:22965).
  2. Der Prozess durchläuft hermes_bootstrap.py für Pfad-/Umgebungskorrekturen und tritt in den CLI-Main:6434 oder die Gateway-Schleife ein.
  3. Es wird eine AIAgent:400-Instanz erzeugt; deren __init__ leitet an init_agent:276 weiter.
  4. init_agent löst Provider, Toolsets, Kompressionsschwellen, Custom-Provider-extra_body usw. auf und baut ein lauffähiges Agent-Objekt zusammen.
  5. Das Gateway hält diesen Agenten in GatewayRunner (gateway/run.py) und füttert jede eingehende Nachricht an run_conversation:588.

Der Funktionskörper von AIAgent.__init__ ist die wörtliche Ausführung von «Forwarder» — die Konstruktionsparameter werden unverändert an init_agent weitergereicht, ohne eigene Auflösung:

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,
    ...
)

Und das hermes_bootstrap.py, das als Erstes mit dem Prozess in Berührung kommt, macht nur auf Windows eine Codierung-Reparatur; auf POSIX gibt es direkt zurück — die Logik ist kurz:

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")

Dass setdefault statt = verwendet wird, ist Absicht: Ein Nutzer kann vorab PYTHONUTF8=0 in die Umgebungsvariablen legen, um aktiv opt-out, und wird nicht überschrieben.

Grenzen und Fehler ​

  • Einstieg direkt konstruiert: Jemand umgeht hermes_bootstrap und startet auf Windows direkt python -m gateway.run; stdio bleibt cp1252, und nicht-ASCII-Output wirft UnicodeEncodeError. Die Position des Bootstrap ist Konvention, nicht erzwungen; die Doku verlangt, dass jeder Einstiegspunkt ihn in der ersten Zeile importiert.
  • AIAgent.__init__ wirft vor init_agent: Da der __init__-Körper nur aus Import + Aufruf besteht, kommt jeder Fehler aus dem Inneren von init_agent; der Stackframe wirkt «verschoben». Beim Debuggen ist der letzte Frame des Traceback init_agent — nicht von dem «Forwarder»-Kommentar in __init__ in die Irre führen lassen, als sei der Forwarder selbst buggy.
  • init_agent-Import ist lazy: from agent.agent_init import init_agent steht im __init__-Körper, nicht auf Modulebene, um Circular Imports zu vermeiden — agent_init importiert wiederum run_agent. Kosten: ein zusätzlicher Import bei der ersten Konstruktion eines AIAgent (Größenordnung Millisekunden); danach läuft alles über den Modul-Cache.
  • hermes_bootstrap-reconfigure kann scheitern: Ist stdout ersetzt durch BytesIO (Testszenario) oder bereits geschlossen, wirft reconfigure OSError/ValueError; der Code fängt das und überspringt stillschweigend. Der Umgebungsvariablen-Pfad greift trotzdem, sodass Kindprozesse nicht betroffen sind.

Zusammenfassung ​

Die Einstiegsschicht ist «Weiterleiten + Zusammenbauen» und trägt keine Geschäftslogik. AIAgent ist eine dünne Hülle, init_agent ist das eigentliche Assembly-Zentrum. Wenn diese Kette verstanden ist, beantwortet die Hauptschleife des Agenten die Frage «was passiert, nachdem eine Nachricht gefüttert wurde».