Skip to content

AgentSession : couche d'orchestration de l'agent de codage

源码版本v0.73.1

AgentSession est la couche la plus lourde de pi-coding-agent — elle ne fait tourner ni LLM directement, ni rendu UI, elle s'insère entre les deux : vers le haut, elle reçoit les entrées utilisateur et les événements UI ; vers le bas, elle pilote l'Agent de pi-agent-core pour faire tourner la boucle. Le registre de modèles, les définitions d'outils, la construction du system prompt, la compression du context, les retries en cas d'échec, la mise en file de messages — tout ça relève d'elle. On peut la voir comme l'atelier d'assemblage qui « emballe un Agent générique pour en faire un assistant de code avec état, résilient, et équipé de skills et d'outils ».

Responsabilités

AgentSession fait quatre choses :

  1. Assemblage : AgentSessionConfig embarque l'instance Agent, le registre de modèles, les définitions d'outils, le runtime d'extensions et le constructeur de system prompt ; à la construction, on attache les hooks beforeToolCall/afterToolCall et on souscrit aux événements. Voir packages/coding-agent/src/core/agent-session.ts:313-330.
  2. Réception des entrées : prompt(text) est l'entrée principale — elle traite les slash commands /, développe les templates de prompts fichier, convertit le texte en AgentMessage[], puis délègue à l'Agent sous-jacent. Voir packages/coding-agent/src/core/agent-session.ts:967-1000.
  3. Transfert d'événements : on souscrit au flux d'événements de l'Agent et on les ré-emballe en AgentSessionEvent pour l'UI au-dessus. Voir packages/coding-agent/src/core/agent-session.ts:330-335.
  4. Mise en file et retry : pendant que le streaming tourne et que l'utilisateur continue de taper, on décide selon streamingBehavior d'appeler steer (intercalaire) ou followUp (mise en file), plutôt que de simplement jeter ou bloquer. Voir packages/coding-agent/src/core/agent-session.ts:1181-1296.

Motivation de design

Pourquoi ne pas laisser l'UI appeler directement Agent.prompt ? Parce qu'un assistant de codage a besoin d'un tas de logiques transverses « que l'Agent générique ne gère pas » : slash commands (/model, /settings), développement de templates, validation du modèle et de l'API key, compression automatique quand le context est trop long, auth et télémétrie autour des appels d'outils. Mettre tout ça dans Agent alourdirait la boucle générique ; le remonter à la couche UI le dupliquerait entre les modes print, rpc et les extensions. AgentSession s'extrait comme point d'entrée unique : les trois modes d'exécution partagent la même logique d'orchestration, et l'UI ne fait que rendre les événements.

Fichiers clés

Le constructeur attache les hooks et souscrit : c'est le point de départ de toute l'orchestration :

typescript
// packages/coding-agent/src/core/agent-session.ts:313-335
constructor(config: AgentSessionConfig) {
  // ... store config, init state ...
  this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
  // ...略 ...
}

prompt convertit le texte utilisateur en AgentMessage[] puis délègue à l'Agent sous-jacent :

typescript
// packages/coding-agent/src/core/agent-session.ts:1107-1112
  try {
    await this.agent.prompt(messages);
  } catch (error) {
    // ... failure handling ...
  }

Flux de données

L'utilisateur appuie sur Entrée dans l'éditeur du TUI → InteractiveMode.defaultEditor.onSubmitsession.prompt(text) :

Pendant le streaming, si l'utilisateur continue de taper, prompt ne force pas — il dispatch :

Limites et échecs

  • Conflit de slash command : les commandes enregistrées par les extensions peuvent aussi s'exécuter en plein streaming (elles gèrent elles-mêmes l'interaction LLM), sans passer par la file. Si la commande ne peut pas être mise en file, elle throw directement. Voir packages/coding-agent/src/core/agent-session.ts:1255-1259.
  • Modèle / key manquant : le chemin non streaming valide le modèle et l'API key ; en cas d'absence, throw plutôt que d'envoyer une requête vide.
  • Compression abortée : abort annule simultanément la boucle principale, le contrôleur de compression et le contrôleur de résumé de branche. Voir packages/coding-agent/src/core/agent-session.ts:1744-1752.
  • Retry : Agent.emit() appelle _handleAgentEvent en synchrone, tandis que prompt() fait un waitForRetry() ; en cas d'échec, la logique de retry décide si on relance un nouveau tour.

Résumé

AgentSession est à la fois l'« atelier d'assemblage » et le « bus d'événements » de l'assistant de code : elle assemble l'Agent, transfère les événements, met en file les intercalaires, gère les hooks d'outils. Au-dessus se trouvent les trois modes UI InteractiveMode/runPrintMode/runRpcMode, en dessous la boucle générique de pi-agent-core. Pour les détails d'assemblage, voir Assemblage createAgentSession ; pour la boucle sous-jacente, voir Boucle while double.