AgentSession: Orchestrierungsschicht des Coding-Agent
AgentSession ist die schwerste Schicht in pi-coding-agent - sie betreibt weder direkt den LLM noch rendert sie direkt die UI, sondern liegt dazwischen: nach oben empfängt sie Nutzereingaben und UI-Events; nach unten treibt sie den Agent von pi-agent-core an, um die Schleife zu laufen. Modell-Registrierung, Werkzeugdefinitionen, Systemprompt-Aufbau, Kontext-Kompression, Fehler-Retry, Nachrichten-Warteschlange gehören alle zu ihr. Man kann es als eine Montage-Werkstatt verstehen, die einen generischen Agent in einen zustandsbehafteten, wiederherstellbaren, mit Skills und Werkzeugen ausgestatteten Coding-Assistenten verwandelt.
Verantwortung
AgentSession macht vier Dinge:
- Zusammenbau:
AgentSessionConfignimmt eineAgent-Instanz, Modell-Registry, Werkzeugdefinitionen, Extension-Runtime und Systemprompt-Builder auf; beim Konstruieren werdenbeforeToolCall/afterToolCall-Hooks und Event-Subscription eingehängt. Siehepackages/coding-agent/src/core/agent-session.ts:313-330. - Eingaben empfangen:
prompt(text)ist der Haupteingang, verarbeitet/-Slash-Befehle, klappt dateibasierte Prompt-Templates auf, wandelt Text inAgentMessage[]um und übergibt an den darunterliegendenAgent. Siehepackages/coding-agent/src/core/agent-session.ts:967-1000. - Event-Weiterleitung: Abonniert den Event-Stream des
Agent, verpackt ihn alsAgentSessionEventund schickt ihn an die obere UI. Siehepackages/coding-agent/src/core/agent-session.ts:330-335. - Warteschlange und Retry: Wenn der Nutzer während des Streamings weiter tippt, entscheidet
streamingBehavior, ob es alssteer(Einwurf) oderfollowUp(Warteschlange) läuft, statt einfach zu verwerfen oder zu blockieren. Siehepackages/coding-agent/src/core/agent-session.ts:1181-1296.
Entwurfsmotivation
Warum nicht die UI direkt Agent.prompt aufrufen lassen? Weil ein Coding-Assistent eine Reihe von Querschnitts-Logik braucht, die "den generischen Agent nichts angeht": Slash-Befehle (/model, /settings), Prompt-Templates, Modell/API-Key-Prüfung, automatische Kompression bei zu langem Kontext, Auth und Telemetrie vor und nach Werkzeugaufrufen. Das alles in Agent zu stopfen, würde die generische Schleife schwer machen; auf die UI-Schicht zu legen, würde in print-Modus, rpc-Modus und Extensions dupliziert. AgentSession wird als einziger Eingang herausgezogen, die drei Laufmodi teilen sich dieselbe Orchestrierungslogik, die UI kümmert sich nur ums Rendern der Events.
Wichtige Dateien
packages/coding-agent/src/core/agent-session.ts:121-149—AgentSessionEventundAgentSessionConfig-Typen, definieren Event-Form und Zusammenbau-Schnittstelle.packages/coding-agent/src/core/agent-session.ts:244-253—class AgentSessionDeklaration und interne Zustandsfelder.packages/coding-agent/src/core/agent-session.ts:313-335— Konstruktor: hängtbeforeToolCall/afterToolCall-Hooks ein, abonniertAgent-Events.packages/coding-agent/src/core/agent-session.ts:379-435— Hook-Implementierung vor und nach Werkzeugaufrufen, macht Auth und Event-Weiterleitung.packages/coding-agent/src/core/agent-session.ts:967-1109—prompt-Hauptfluss: Befehls-Verteilung, Template-Ausklappen,this.agent.prompt(messages).packages/coding-agent/src/core/agent-session.ts:1181-1296—steer/followUp-Warteschlangen-Semantik.packages/coding-agent/src/core/agent-session.ts:1317-1389—sendUserMessage(programmierter Eingang) undabort.packages/coding-agent/src/core/agent-session.ts:713-743—subscribe, die UI holt sich darüber Events.
Der Konstruktor hängt Hooks ein und abonniert, das ist der Startpunkt der gesamten Orchestrierung:
// packages/coding-agent/src/core/agent-session.ts:313-335
constructor(config: AgentSessionConfig) {
// ... config speichern, Zustand initialisieren ...
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
// ... uebersprungen ...
}prompt macht aus Nutzertext ein AgentMessage[] und übergibt an den darunterliegenden Agent:
// packages/coding-agent/src/core/agent-session.ts:1107-1112
try {
await this.agent.prompt(messages);
} catch (error) {
// ... Fehlerbehandlung ...
}Datenfluss
Nutzer drückt im TUI-Editor Enter → InteractiveMode.defaultEditor.onSubmit → session.prompt(text):
Wenn der Nutzer während des Streamings weiter tippt, drückt prompt nicht einfach durch, sondern verteilt:
Grenzen und Fehler
- Slash-Befehl-Konflikt: Ein von einer Extension registrierter Befehl kann auch während des Streamings sofort ausgeführt werden (er verwaltet seine eigene LLM-Interaktion), geht nicht durch die Warteschlange. Wenn ein Befehl nicht in eine Warteschlange kann, wird direkt ein Fehler geworfen, siehe
packages/coding-agent/src/core/agent-session.ts:1255-1259. - Modell/Key fehlt: Der nicht-streaming Pfad prüft Modell und API-Key, bei Fehlen wird ein Fehler geworfen statt eine leere Anfrage zu senden.
- Kompression abgebrochen:
abortbricht gleichzeitig die Hauptschleife, den Kompressions-Controller und den Branch-Summary-Controller ab, siehepackages/coding-agent/src/core/agent-session.ts:1744-1752. - Retry:
Agent.emit()ruft synchron_handleAgentEventauf, währendprompt()mitwaitForRetry()wartet, nach einem Fehler entscheidet die Retry-Logik, ob ein neuer Turn gesendet wird.
Zusammenfassung
AgentSession ist die "Montage-Werkstatt plus Event-Bus" des Coding-Assistenten: baut Agent zusammen, leitet Events weiter, reiht Einwürfe ein, verwaltet Werkzeug-Hooks. Nach oben sind das die drei UI-Modi InteractiveMode/runPrintMode/runRpcMode, nach unten die generische Schleife von pi-agent-core. Zusammenbau-Details siehe createAgentSession Zusammenbau; die darunterliegende Schleife siehe Doppelte while-Hauptschleife.