Skip to content

createAgentSession Zusammenbau

源码版本v0.73.1

createAgentSession ist der Kern-Eingang des SDK. Es setzt aus AuthStorage, ModelRegistry, SettingsManager, SessionManager, ResourceLoader als externen Services, plus Werkzeugdefinitionen und Extension-Runner, ein verwendbares AgentSession zusammen. main.ts ruft es nicht direkt auf, sondern geht über createAgentSessionRuntime zu createAgentSessionServices, aber ein SDK-Aufrufer (der pi in ein anderes Programm einbettet) nutzt diese Funktion direkt.

Verantwortung

  1. Service-Auflösung: Jeder externe Service kann übergeben oder automatisch erzeugt werden, der default-Pfad basiert auf agentDir (~/.pi/agent). Siehe packages/coding-agent/src/core/sdk.ts:193-211.
  2. Modell-Wiederherstellung: Wenn Session-Daten vorhanden sind, wird model aus dem session-Header geholt, sonst aus den settings als default; wenn das Modell nicht wiederherstellbar ist, wird modelFallbackMessage gesetzt. Siehe packages/coding-agent/src/core/sdk.ts:214-248.
  3. thinking-Level-Klammerung: thinking level wird aus session oder settings geholt, dann von clampThinkingLevel auf den Modell-Fähigkeitsbereich begrenzt. Siehe packages/coding-agent/src/core/sdk.ts:250-269.
  4. stream-Funktion-Injektion: streamFn des Agent ruft nicht direkt streamSimple auf, sondern holt zuerst über modelRegistry.getApiKeyAndHeaders die Auth und fügt die Telemetrie-Header von getAttributionHeaders hinzu. Siehe packages/coding-agent/src/core/sdk.ts:328-346.
  5. convertToLlm-Wrapper: Wenn blockImages aktiv ist, wird der gesamte ImageContent durch Platzhaltertext ersetzt, dabei wird settings dynamisch gelesen, damit Änderungen während der Session greifen. Siehe packages/coding-agent/src/core/sdk.ts:282-316.
  6. Attribution-Header: OpenRouter und Cloudflare bekommen proprietäre HTTP-Header für die Zuordnung. Siehe packages/coding-agent/src/core/sdk.ts:128-156.

Entwurfsmotivation

Warum nicht den Aufrufer selbst new Agent und dann new AgentSession machen lassen? Weil die Zusammenbau-Schritte mehr als zehn Services mit gegenseitigen Abhängigkeiten berühren: auth entscheidet, ob model verfügbar ist; model entscheidet den Bereich des thinking level; settings entscheiden retry/transport/steering; der resource loader lädt Extensions und injiziert sie in extensionRunnerRef. Das dem Aufrufer aufzubürden hieße, jeder müsste die gleichen Fehler nochmal machen. createAgentSession konzentriert die Zusammenbau-Regeln in einer Funktion, der SDK-Aufrufer muss nur cwd und (optional) model übergeben.

getAttributionHeaders ist deshalb separat herausgezogen, weil verschiedene Provider unterschiedliche Header wollen: OpenRouter will HTTP-Referer + X-OpenRouter-*, Cloudflare will User-Agent. Zentral an einer Stelle zu sammeln vermeidet, dass es sich über den stream-Pfad verstreut.

Wichtige Dateien

An der streamFn-Injektion sieht man, wie Auth-Versagen kurzschließt und Attribution-Header zusammengeführt werden:

typescript
// 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,
	});
},

Die convertToLlm-Wrapper-Schicht ersetzt bei aktivem blockImages Bilder durch Textplatzhalter und dedupliziert aufeinanderfolgende Platzhalter:

typescript
// 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,
						)
						// ... dedup ...

Datenfluss

Reihenfolge des Zusammenbaus:

Grenzen und Fehler

  • Modell nicht wiederherstellbar: modelFallbackMessage sagt sowohl "Modell konnte nicht wiederhergestellt werden" als auch "keine Modelle konfiguriert", beides wird zurückgegeben, die UI entscheidet, wie es angezeigt wird, siehe packages/coding-agent/src/core/sdk.ts:243-247.
  • Ohne model thinking off: if (!model) thinkingLevel = "off", um thinking-Parameter an ein leeres Modell zu vermeiden.
  • Session vorhanden aber ohne thinking-Eintrag: Beim Wiederherstellen wird ein appendThinkingLevelChange ergänzt, damit ein späteres fork/resume den Zustand bekommt, siehe packages/coding-agent/src/core/sdk.ts:378-390.
  • Extension transformContext: Wenn extensionRunnerRef.current nicht existiert, wird direkt das Original messages zurückgegeben, ohne zu werfen, damit es ohne gebundene Extension weiterläuft.

Zusammenfassung

createAgentSession konzentriert die Zusammenbau-Regeln von mehr als zehn Services in einer Funktion, der SDK-Aufrufer muss nur cwd und optionales model übergeben. Zusammenbau-Details nach unten siehe AgentSession Orchestrierungsschicht; die Werkzeugfabriken siehe Werkzeugset read/bash/edit/write/grep/find/ls; die Nachrichtenkonvertierung siehe Nachrichtentypen und convertToLlm.