createAgentSession 装配
createAgentSession は SDK のコア入り口だ。AuthStorage、ModelRegistry、SettingsManager、SessionManager、ResourceLoader といった外部サービスに、ツール定義と拡張ランタイムを加え、使える AgentSession に組み立てる。main.ts は直接これを呼ばず、createAgentSessionRuntime 経由で createAgentSessionServices を走らせるが、SDK の呼び出し側 (pi を別プログラムに組み込む) はこの関数を直接使う。
責務
- サービス解決:各外部サービスは渡しても自動生成してもよく、デフォルトパスは
agentDir(~/.pi/agent) に基づく。packages/coding-agent/src/core/sdk.ts:193-211参照。 - モデル復元:session データがある時、session header から
modelを取り戻し、無ければ settings のデフォルトから探す。モデルが復元できない時はmodelFallbackMessageを付ける。packages/coding-agent/src/core/sdk.ts:214-248参照。 - thinking level クランプ:session か settings から thinking level を取り、
clampThinkingLevelでモデル能力の範囲内に制限する。packages/coding-agent/src/core/sdk.ts:250-269参照。 - stream 関数注入:
AgentのstreamFnは直接streamSimpleを呼ばず、先にmodelRegistry.getApiKeyAndHeadersで auth を取り、getAttributionHeadersのテレメトリヘッダを併せる。packages/coding-agent/src/core/sdk.ts:328-346参照。 - convertToLlm ラップ:
blockImages設定が有効な時、すべての ImageContent をプレースホルダーテキストに置き換える。settings を動的に読むので、session 中途半ばで設定を変えても効く。packages/coding-agent/src/core/sdk.ts:282-316参照。 - attribution ヘッダ:OpenRouter と Cloudflare には归类用の専属 HTTP ヘッダを付ける。
packages/coding-agent/src/core/sdk.ts:128-156参照。
設計動機
なぜ呼び出し側に new Agent して new AgentSession させないのか? 組み立て手順が十数個のサービスの相互依存にまたがるからだ。auth が model が使えるかを決め、model が thinking level の範囲を決め、settings が retry/transport/steering を決め、resource loader が拡張を読み込んで extensionRunnerRef に注入する。これを呼び出し側に晒せば、誰もが同じ罠を踏み直すことになる。createAgentSession は組み立てルールを 1 関数に集め、SDK 呼び出し側は cwd と (任意の) model だけを渡せばいい。
getAttributionHeaders が独立して切り出されているのは、provider ごとに必要なヘッダが違うからだ:OpenRouter は HTTP-Referer + X-OpenRouter-* を見て、Cloudflare は User-Agent を見る。一箇所に集めないと stream パスに散らばる。
主要ファイル
packages/coding-agent/src/core/sdk.ts:33-80—CreateAgentSessionOptions。すべての組み立て引数 (cwd、authStorage、modelRegistry、model、tools、scopedModels、customTools、resourceLoader、sessionManager、settingsManager)。packages/coding-agent/src/core/sdk.ts:82-90—CreateAgentSessionResult:session+extensionsResult+ 任意のmodelFallbackMessage。packages/coding-agent/src/core/sdk.ts:124-126—getDefaultAgentDir。デフォルトのグローバル設定ディレクトリ。packages/coding-agent/src/core/sdk.ts:128-156—getAttributionHeaders。provider 専属のテレメトリヘッダ。packages/coding-agent/src/core/sdk.ts:193-211—createAgentSession冒頭:サービス解決とデフォルト値。packages/coding-agent/src/core/sdk.ts:320-376—new Agent({...})構築。streamFn、onPayload、onResponse、transformContext、steeringMode、transportなどすべてのランタイム引数を注入。packages/coding-agent/src/core/sdk.ts:392-413— 最後のnew AgentSession({...})とCreateAgentSessionResultの返却。packages/coding-agent/src/core/sdk.ts:108-120— ツールファクトリの re-export。SDK 呼び出し側はcreateCodingToolsなどをそのまま取れる。
streamFn 注入箇所で、auth 失敗がどうショートサーキットし、attribution ヘッダがどうマージされるかが分かる:
// 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,
});
},convertToLlm ラッパー層は blockImages が有効な時、画像をテキストプレースホルダーに置き換え、連続プレースホルダーを重複排除する:
// 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,
)
// ... 重複排除 ...データフロー
組み立て順序:
境界と失敗
- モデル復元不能:
modelFallbackMessageは「保存されたモデルを復元できなかった」と「設定済みモデルが一つもない」の両方を伝える。両方とも返して、UI にどう表示するかは任せる。packages/coding-agent/src/core/sdk.ts:243-247参照。 - model がない時は thinking off:
if (!model) thinkingLevel = "off"で、空モデルに thinking パラメータを送らないようにする。 - session はあるが thinking entry がない:復元時に一条
appendThinkingLevelChangeを補い、後続の fork/resume が状態を取れるようにする。packages/coding-agent/src/core/sdk.ts:378-390参照。 - 拡張 transformContext:
extensionRunnerRef.currentが無ければ元の messages をそのまま返す。throw せず、拡張が未バインドでも正常に動くようにする。
小ねた
createAgentSession は十数個のサービスの組み立てルールを 1 関数に集め、SDK 呼び出し側は cwd と任意の model だけを渡せばいい。組み立ての詳細は下に AgentSession オーケストレーション層、ツールファクトリは ツール集 read/bash/edit/write/grep/find/ls、メッセージ変換は メッセージ型と convertToLlm 参照。