Assemblage createAgentSession
createAgentSession est l'entrée centrale du SDK. Elle relie AuthStorage, ModelRegistry, SettingsManager, SessionManager, ResourceLoader — les services externes — aux définitions d'outils et au runner d'extensions, pour produire un AgentSession utilisable. main.ts ne l'appelle pas directement : il passe par createAgentSessionRuntime → createAgentSessionServices, mais un appelant SDK (qui embarque pi dans un autre programme) utilise cette fonction directement.
Responsabilités
- Résolution des services : chaque service externe peut être passé ou auto-créé, avec des chemins par défaut fondés sur
agentDir(~/.pi/agent). Voirpackages/coding-agent/src/core/sdk.ts:193-211. - Restauration du modèle : si des données de session existent, on retrouve
modeldepuis le header de session, sinon depuis les settings ; quand le modèle ne peut pas être restauré, on renseignemodelFallbackMessage. Voirpackages/coding-agent/src/core/sdk.ts:214-248. - Clamp du thinking level : on récupère le thinking level depuis la session ou les settings, puis
clampThinkingLevelle restreint aux capacités du modèle. Voirpackages/coding-agent/src/core/sdk.ts:250-269. - Injection de la fonction de stream : le
streamFnde l'Agentn'appelle pas directementstreamSimple— il passe d'abord parmodelRegistry.getApiKeyAndHeaderspour l'auth, puis y ajoute les headers de télémétrie degetAttributionHeaders. Voirpackages/coding-agent/src/core/sdk.ts:328-346. - Wrapping de convertToLlm : quand
blockImagesest activé, on remplace tout ImageContent par du texte placeholder, en relisant dynamiquement les settings pour qu'un changement en cours de session soit pris en compte. Voirpackages/coding-agent/src/core/sdk.ts:282-316. - Headers d'attribution : OpenRouter et Cloudflare reçoivent des headers HTTP dédiés pour le catégorisation. Voir
packages/coding-agent/src/core/sdk.ts:128-156.
Motivation de design
Pourquoi ne pas laisser l'appelant faire lui-même new Agent puis new AgentSession ? Parce que l'assemblage implique une dizaine de services aux dépendances croisées : auth détermine si le modèle est disponible, modèle détermine la plage de thinking level, settings détermine retry/transport/steering, le resource loader charge les extensions et les injecte dans extensionRunnerRef. Exposer tout ça à l'appelant reviendrait à lui faire refaire les mêmes erreurs à chacun. createAgentSession concentre les règles d'assemblage dans une seule fonction — l'appelant SDK ne fournit que cwd et (optionnellement) model.
getAttributionHeaders est isolé dans sa propre fonction parce que les headers attendus varient selon le provider : OpenRouter regarde HTTP-Referer + X-OpenRouter-*, Cloudflare regarde User-Agent. Centraliser évite la dispersion le long du chemin de stream.
Fichiers clés
packages/coding-agent/src/core/sdk.ts:33-80—CreateAgentSessionOptions, tous les paramètres d'assemblage (cwd, authStorage, modelRegistry, model, tools, scopedModels, customTools, resourceLoader, sessionManager, settingsManager).packages/coding-agent/src/core/sdk.ts:82-90—CreateAgentSessionResult:session+extensionsResult+ optionnelmodelFallbackMessage.packages/coding-agent/src/core/sdk.ts:124-126—getDefaultAgentDir, répertoire global de configuration par défaut.packages/coding-agent/src/core/sdk.ts:128-156—getAttributionHeaders, headers de télémétrie propres au provider.packages/coding-agent/src/core/sdk.ts:193-211— début decreateAgentSession: résolution des services et valeurs par défaut.packages/coding-agent/src/core/sdk.ts:320-376— constructionnew Agent({...}), injection destreamFn,onPayload,onResponse,transformContext,steeringMode,transportet tous les paramètres runtime.packages/coding-agent/src/core/sdk.ts:392-413—new AgentSession({...})final et retour duCreateAgentSessionResult.packages/coding-agent/src/core/sdk.ts:108-120— re-export des factories d'outils, pour que l'appelant SDK puisse récupérer directementcreateCodingToolset consorts.
Le point d'injection de streamFn montre comment un échec d'auth court-circuite et comment les headers d'attribution sont fusionnés :
// packages/coding-agent/src/core/sdk.ts:328-346
streamFn: async (model, context, options) => {
const auth = await modelRegistry.getApiKeyAndHeaders(model);
if (!auth.ok) {
throw new Error(auth.error);
}
const providerRetrySettings = settingsManager.getProviderRetrySettings();
const attributionHeaders = getAttributionHeaders(model, settingsManager);
return streamSimple(model, context, {
...options,
apiKey: auth.apiKey,
timeoutMs: options?.timeoutMs ?? providerRetrySettings.timeoutMs,
// ...
headers:
attributionHeaders || auth.headers || options?.headers
? { ...attributionHeaders, ...auth.headers, ...options?.headers }
: undefined,
});
},Le wrapper convertToLlm, quand blockImages est activé, remplace les images par un texte placeholder et déduplique les placeholders consécutifs :
// packages/coding-agent/src/core/sdk.ts:282-298
const convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {
const converted = convertToLlm(messages);
if (!settingsManager.getBlockImages()) {
return converted;
}
return converted.map((msg) => {
if (msg.role === "user" || msg.role === "toolResult") {
const content = msg.content;
if (Array.isArray(content)) {
const hasImages = content.some((c) => c.type === "image");
if (hasImages) {
const filteredContent = content
.map((c) =>
c.type === "image" ? { type: "text" as const, text: "Image reading is disabled." } : c,
)
// ... dedupe ...Flux de données
L'ordre d'assemblage :
Limites et échecs
- Modèle non restaurable :
modelFallbackMessagecouvre à la fois « impossible de restaurer le modèle enregistré » et « aucun modèle configuré », en renvoyant les deux — c'est l'UI qui décide comment l'afficher. Voirpackages/coding-agent/src/core/sdk.ts:243-247. - Pas de modèle ⇒ thinking off :
if (!model) thinkingLevel = "off", pour éviter d'envoyer des paramètres de thinking à un modèle vide. - Session existante sans entrée thinking : à la restauration, on ajoute un
appendThinkingLevelChangepour que les fork/resume ultérieurs retrouvent l'état. Voirpackages/coding-agent/src/core/sdk.ts:378-390. - transformContext des extensions : si
extensionRunnerRef.currentn'existe pas, on renvoie directement les messages d'origine — pas de throw, pour continuer à fonctionner quand l'extension n'est pas encore liée.
Résumé
createAgentSession concentre les règles d'assemblage d'une dizaine de services dans une seule fonction ; l'appelant SDK ne fournit que cwd et un modèle optionnel. Pour les détails de l'assemblage en aval, voir AgentSession : couche d'orchestration ; pour les factories d'outils, voir Ensemble d'outils read/bash/edit/write/grep/find/ls ; pour la conversion des messages, voir Types de messages et convertToLlm.