Provider 抽象と 9 社の組み込み登録
@mariozechner/pi-ai が provider に要求する定義は三つのフィールドだけだ: api、stream、streamSimple。register-builtins.ts は registerApiProvider を使って 9 社の実装をレジストリに登録する。登録時に具体的な provider モジュールを直接 import するのではなく、createLazyStream / createLazySimpleStream で dynamic import を一层被せる。初回呼び出しの時点で初めて SDK が読み込まれ、モジュールサイズと起動時間を巻き込まない。
役割
- Provider 抽象の定義:
ApiProviderインターフェースはapi識別子 +stream/streamSimpleの二関数を要求する。packages/ai/src/api-registry.ts:23-27参照。 - 遅延読み込みラップ:
createLazyStream/createLazySimpleStreamは同期的な stream 関数を返し、内部でimport()してからforwardStreamする。packages/ai/src/providers/register-builtins.ts:159-178参照。 - 9 社の登録:
registerBuiltInApiProvidersが各家をregisterApiProviderする。packages/ai/src/providers/register-builtins.ts:342-396参照。 - モジュール読み込み即登録: ファイル末尾のトップレベルで
registerBuiltInApiProviders()を呼ぶ。stream.tsが import すれば必ず発火する。packages/ai/src/providers/register-builtins.ts:403-403参照。 - 9 種の Api 型:
KnownApiユニオン型が 9 個のリテラルを列挙する。packages/ai/src/types.ts:6-17参照。
設計動機
なぜすべての provider を遅延読み込みするのか? SDK には重いものがあるからだ。Bedrock は AWS SDK の @aws-sdk/client-bedrock-runtime を丸ごと引き込み、OpenAI Responses も依存を一山持ってくる。もしトップレベルで静的 import すると、ユーザーが Anthropic しか使わなくてもすべての SDK が読み込まれる。createLazyStream は初回呼び出しを dynamic import に変え、起動時は register-builtins.ts 自体の数十行だけを解析する。実際に使う一家を読み込むのはその時点だ。
なぜ registerBuiltInApiProviders を export して呼び出し側に委ねるのではなく、ファイル末尾のトップレベルで呼ぶのか? stream.ts の先頭が import "./providers/register-builtins.js" しており、副作用のための import だからだ。誰かが @mariozechner/pi-ai の stream を import すれば、登録が起きる。呼び出し側は設定ゼロで使える。resetApiProviders はテストのリセット用。
主要ファイル
packages/ai/src/types.ts:6-17—KnownApiの 9 リテラル +Apiは拡張文字列を許す。packages/ai/src/api-registry.ts:23-27—ApiProviderインターフェース、三点セット。packages/ai/src/providers/register-builtins.ts:159-178—createLazyStream: 外側 stream + 動的読み込み + forwardStream + エラー push。packages/ai/src/providers/register-builtins.ts:180-220—createLazySimpleStream。simple 版も同じパターン。packages/ai/src/providers/register-builtins.ts:323-340— 9 社の lazy 関数 + Bedrock のプライベート lazy。packages/ai/src/providers/register-builtins.ts:342-396—registerBuiltInApiProviders本体。packages/ai/src/providers/register-builtins.ts:398-403—resetApiProvidersとトップレベル登録。packages/ai/src/types.ts:155-159—StreamFunctionシグネチャ。AssistantMessageEventStreamを返す。
遅延読み込みラップの核心は、外側の stream が即座に返り、読み込み失敗も push 経由で error イベントに変わること:
// packages/ai/src/providers/register-builtins.ts:159-178
function createLazyStream<TApi extends Api, TOptions extends StreamOptions, TSimpleOptions extends SimpleStreamOptions>(
loadModule: () => Promise<LazyProviderModule<TApi, TOptions, TSimpleOptions>>,
): StreamFunction<TApi, TOptions> {
return (model, context, options) => {
const outer = new AssistantMessageEventStream();
loadModule()
.then((module) => {
const inner = module.stream(model, context, options);
forwardStream(outer, inner);
})
.catch((error) => {
const message = createLazyLoadErrorMessage(model, error);
outer.push({ type: "error", reason: "error", error: message });
outer.end(message);
});
return outer;
};
}9 社の登録は registerApiProvider を一家ずつ呼ぶだけ。一家に一つの api リテラル:
// packages/ai/src/providers/register-builtins.ts:343-347
registerApiProvider({
api: "anthropic-messages",
stream: streamAnthropic,
streamSimple: streamSimpleAnthropic,
});データフロー
provider の登録と初回呼び出しの二段:
境界と失敗
- 遅延読み込み失敗:
loadModule().catchが error を{ type: "error" }イベントとして outer stream に push する。呼び出し側はfor awaitで受け取れる。packages/ai/src/providers/register-builtins.ts:170-174参照。 - 9 社のリスト:
anthropic-messages、openai-completions、mistral-conversations、openai-responses、azure-openai-responses、openai-codex-responses、google-generative-ai、google-vertex、bedrock-converse-stream。packages/ai/src/providers/register-builtins.ts:343-395参照。 - Bedrock の单独扱い: AWS SDK の重量のため、
streamBedrockLazy/streamSimpleBedrockLazyは export せず内部利用のみ。packages/ai/src/providers/register-builtins.ts:339-340参照。 - 拡張の登録: 第三者拡張は
registerApiProviderを呼んで自分のapi文字列を登録できる。Api型はstring & {}でフォールバックする。packages/ai/src/types.ts:17-17参照。
まとめ
Provider 抽象は api + stream + streamSimple の三点セットで、9 社の組み込みはすべて createLazyStream で遅延読み込みする。ファサードのディスパッチロジックは stream/complete ファサード、レジストリのデータ構造は Provider レジストリ、ある一家の具体的な SSE 解析は Anthropic SSE 実装 を参照。