import { clearApiProviders, registerApiProvider } from "../api-registry.ts"; import type { Api, AssistantMessage, AssistantMessageEvent, Context, Model, SimpleStreamOptions, StreamFunction, StreamOptions, } from "../types.ts"; import { AssistantMessageEventStream } from "../utils/event-stream.ts"; import type { BedrockOptions } from "./amazon-bedrock.ts"; import type { AnthropicOptions } from "./anthropic.ts"; import type { AzureOpenAIResponsesOptions } from "./azure-openai-responses.ts"; import type { GoogleOptions } from "./google.ts"; import type { GoogleVertexOptions } from "./google-vertex.ts"; import type { MistralOptions } from "./mistral.ts"; import type { OpenAICodexResponsesOptions } from "./openai-codex-responses.ts"; import type { OpenAICompletionsOptions } from "./openai-completions.ts"; import type { OpenAIResponsesOptions } from "./openai-responses.ts"; interface LazyProviderModule< TApi extends Api, TOptions extends StreamOptions, TSimpleOptions extends SimpleStreamOptions, > { stream: (model: Model, context: Context, options?: TOptions) => AsyncIterable; streamSimple: ( model: Model, context: Context, options?: TSimpleOptions, ) => AsyncIterable; } interface AnthropicProviderModule { streamAnthropic: StreamFunction<"anthropic-messages", AnthropicOptions>; streamSimpleAnthropic: StreamFunction<"anthropic-messages", SimpleStreamOptions>; } interface AzureOpenAIResponsesProviderModule { streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses", AzureOpenAIResponsesOptions>; streamSimpleAzureOpenAIResponses: StreamFunction<"azure-openai-responses", SimpleStreamOptions>; } interface GoogleProviderModule { streamGoogle: StreamFunction<"google-generative-ai", GoogleOptions>; streamSimpleGoogle: StreamFunction<"google-generative-ai", SimpleStreamOptions>; } interface GoogleVertexProviderModule { streamGoogleVertex: StreamFunction<"google-vertex", GoogleVertexOptions>; streamSimpleGoogleVertex: StreamFunction<"google-vertex", SimpleStreamOptions>; } interface MistralProviderModule { streamMistral: StreamFunction<"mistral-conversations", MistralOptions>; streamSimpleMistral: StreamFunction<"mistral-conversations", SimpleStreamOptions>; } interface OpenAICodexResponsesProviderModule { streamOpenAICodexResponses: StreamFunction<"openai-codex-responses", OpenAICodexResponsesOptions>; streamSimpleOpenAICodexResponses: StreamFunction<"openai-codex-responses", SimpleStreamOptions>; } interface OpenAICompletionsProviderModule { streamOpenAICompletions: StreamFunction<"openai-completions", OpenAICompletionsOptions>; streamSimpleOpenAICompletions: StreamFunction<"openai-completions", SimpleStreamOptions>; } interface OpenAIResponsesProviderModule { streamOpenAIResponses: StreamFunction<"openai-responses", OpenAIResponsesOptions>; streamSimpleOpenAIResponses: StreamFunction<"openai-responses", SimpleStreamOptions>; } interface BedrockProviderModule { streamBedrock: ( model: Model<"bedrock-converse-stream">, context: Context, options?: BedrockOptions, ) => AsyncIterable; streamSimpleBedrock: ( model: Model<"bedrock-converse-stream">, context: Context, options?: SimpleStreamOptions, ) => AsyncIterable; } const importNodeOnlyProvider = (specifier: string): Promise => { const runtimeSpecifier = import.meta.url.endsWith(".js") ? specifier.replace(/\.ts$/, ".js") : specifier; return import(runtimeSpecifier); }; let anthropicProviderModulePromise: | Promise> | undefined; let azureOpenAIResponsesProviderModulePromise: | Promise> | undefined; let googleProviderModulePromise: | Promise> | undefined; let googleVertexProviderModulePromise: | Promise> | undefined; let mistralProviderModulePromise: | Promise> | undefined; let openAICodexResponsesProviderModulePromise: | Promise> | undefined; let openAICompletionsProviderModulePromise: | Promise> | undefined; let openAIResponsesProviderModulePromise: | Promise> | undefined; let bedrockProviderModuleOverride: | LazyProviderModule<"bedrock-converse-stream", BedrockOptions, SimpleStreamOptions> | undefined; let bedrockProviderModulePromise: | Promise> | undefined; export function setBedrockProviderModule(module: BedrockProviderModule): void { bedrockProviderModuleOverride = { stream: module.streamBedrock, streamSimple: module.streamSimpleBedrock, }; } function forwardStream(target: AssistantMessageEventStream, source: AsyncIterable): void { (async () => { for await (const event of source) { target.push(event); } target.end(); })(); } function createLazyLoadErrorMessage(model: Model, error: unknown): AssistantMessage { return { role: "assistant", content: [], api: model.api, provider: model.provider, model: model.id, usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, }, stopReason: "error", errorMessage: error instanceof Error ? error.message : String(error), timestamp: Date.now(), }; } function createLazyStream( loadModule: () => Promise>, ): StreamFunction { 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; }; } function createLazySimpleStream< TApi extends Api, TOptions extends StreamOptions, TSimpleOptions extends SimpleStreamOptions, >(loadModule: () => Promise>): StreamFunction { return (model, context, options) => { const outer = new AssistantMessageEventStream(); loadModule() .then((module) => { const inner = module.streamSimple(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; }; } function loadAnthropicProviderModule(): Promise< LazyProviderModule<"anthropic-messages", AnthropicOptions, SimpleStreamOptions> > { anthropicProviderModulePromise ||= import("./anthropic.ts").then((module) => { const provider = module as AnthropicProviderModule; return { stream: provider.streamAnthropic, streamSimple: provider.streamSimpleAnthropic, }; }); return anthropicProviderModulePromise; } function loadAzureOpenAIResponsesProviderModule(): Promise< LazyProviderModule<"azure-openai-responses", AzureOpenAIResponsesOptions, SimpleStreamOptions> > { azureOpenAIResponsesProviderModulePromise ||= import("./azure-openai-responses.ts").then((module) => { const provider = module as AzureOpenAIResponsesProviderModule; return { stream: provider.streamAzureOpenAIResponses, streamSimple: provider.streamSimpleAzureOpenAIResponses, }; }); return azureOpenAIResponsesProviderModulePromise; } function loadGoogleProviderModule(): Promise< LazyProviderModule<"google-generative-ai", GoogleOptions, SimpleStreamOptions> > { googleProviderModulePromise ||= import("./google.ts").then((module) => { const provider = module as GoogleProviderModule; return { stream: provider.streamGoogle, streamSimple: provider.streamSimpleGoogle, }; }); return googleProviderModulePromise; } function loadGoogleVertexProviderModule(): Promise< LazyProviderModule<"google-vertex", GoogleVertexOptions, SimpleStreamOptions> > { googleVertexProviderModulePromise ||= import("./google-vertex.ts").then((module) => { const provider = module as GoogleVertexProviderModule; return { stream: provider.streamGoogleVertex, streamSimple: provider.streamSimpleGoogleVertex, }; }); return googleVertexProviderModulePromise; } function loadMistralProviderModule(): Promise< LazyProviderModule<"mistral-conversations", MistralOptions, SimpleStreamOptions> > { mistralProviderModulePromise ||= import("./mistral.ts").then((module) => { const provider = module as MistralProviderModule; return { stream: provider.streamMistral, streamSimple: provider.streamSimpleMistral, }; }); return mistralProviderModulePromise; } function loadOpenAICodexResponsesProviderModule(): Promise< LazyProviderModule<"openai-codex-responses", OpenAICodexResponsesOptions, SimpleStreamOptions> > { openAICodexResponsesProviderModulePromise ||= import("./openai-codex-responses.ts").then((module) => { const provider = module as OpenAICodexResponsesProviderModule; return { stream: provider.streamOpenAICodexResponses, streamSimple: provider.streamSimpleOpenAICodexResponses, }; }); return openAICodexResponsesProviderModulePromise; } function loadOpenAICompletionsProviderModule(): Promise< LazyProviderModule<"openai-completions", OpenAICompletionsOptions, SimpleStreamOptions> > { openAICompletionsProviderModulePromise ||= import("./openai-completions.ts").then((module) => { const provider = module as OpenAICompletionsProviderModule; return { stream: provider.streamOpenAICompletions, streamSimple: provider.streamSimpleOpenAICompletions, }; }); return openAICompletionsProviderModulePromise; } function loadOpenAIResponsesProviderModule(): Promise< LazyProviderModule<"openai-responses", OpenAIResponsesOptions, SimpleStreamOptions> > { openAIResponsesProviderModulePromise ||= import("./openai-responses.ts").then((module) => { const provider = module as OpenAIResponsesProviderModule; return { stream: provider.streamOpenAIResponses, streamSimple: provider.streamSimpleOpenAIResponses, }; }); return openAIResponsesProviderModulePromise; } function loadBedrockProviderModule(): Promise< LazyProviderModule<"bedrock-converse-stream", BedrockOptions, SimpleStreamOptions> > { if (bedrockProviderModuleOverride) { return Promise.resolve(bedrockProviderModuleOverride); } bedrockProviderModulePromise ||= importNodeOnlyProvider("./amazon-bedrock.ts").then((module) => { const provider = module as BedrockProviderModule; return { stream: provider.streamBedrock, streamSimple: provider.streamSimpleBedrock, }; }); return bedrockProviderModulePromise; } export const streamAnthropic = createLazyStream(loadAnthropicProviderModule); export const streamSimpleAnthropic = createLazySimpleStream(loadAnthropicProviderModule); export const streamAzureOpenAIResponses = createLazyStream(loadAzureOpenAIResponsesProviderModule); export const streamSimpleAzureOpenAIResponses = createLazySimpleStream(loadAzureOpenAIResponsesProviderModule); export const streamGoogle = createLazyStream(loadGoogleProviderModule); export const streamSimpleGoogle = createLazySimpleStream(loadGoogleProviderModule); export const streamGoogleVertex = createLazyStream(loadGoogleVertexProviderModule); export const streamSimpleGoogleVertex = createLazySimpleStream(loadGoogleVertexProviderModule); export const streamMistral = createLazyStream(loadMistralProviderModule); export const streamSimpleMistral = createLazySimpleStream(loadMistralProviderModule); export const streamOpenAICodexResponses = createLazyStream(loadOpenAICodexResponsesProviderModule); export const streamSimpleOpenAICodexResponses = createLazySimpleStream(loadOpenAICodexResponsesProviderModule); export const streamOpenAICompletions = createLazyStream(loadOpenAICompletionsProviderModule); export const streamSimpleOpenAICompletions = createLazySimpleStream(loadOpenAICompletionsProviderModule); export const streamOpenAIResponses = createLazyStream(loadOpenAIResponsesProviderModule); export const streamSimpleOpenAIResponses = createLazySimpleStream(loadOpenAIResponsesProviderModule); const streamBedrockLazy = createLazyStream(loadBedrockProviderModule); const streamSimpleBedrockLazy = createLazySimpleStream(loadBedrockProviderModule); export function registerBuiltInApiProviders(): void { registerApiProvider({ api: "anthropic-messages", stream: streamAnthropic, streamSimple: streamSimpleAnthropic, }); registerApiProvider({ api: "openai-completions", stream: streamOpenAICompletions, streamSimple: streamSimpleOpenAICompletions, }); registerApiProvider({ api: "mistral-conversations", stream: streamMistral, streamSimple: streamSimpleMistral, }); registerApiProvider({ api: "openai-responses", stream: streamOpenAIResponses, streamSimple: streamSimpleOpenAIResponses, }); registerApiProvider({ api: "azure-openai-responses", stream: streamAzureOpenAIResponses, streamSimple: streamSimpleAzureOpenAIResponses, }); registerApiProvider({ api: "openai-codex-responses", stream: streamOpenAICodexResponses, streamSimple: streamSimpleOpenAICodexResponses, }); registerApiProvider({ api: "google-generative-ai", stream: streamGoogle, streamSimple: streamSimpleGoogle, }); registerApiProvider({ api: "google-vertex", stream: streamGoogleVertex, streamSimple: streamSimpleGoogleVertex, }); registerApiProvider({ api: "bedrock-converse-stream", stream: streamBedrockLazy, streamSimple: streamSimpleBedrockLazy, }); } export function resetApiProviders(): void { clearApiProviders(); registerBuiltInApiProviders(); } registerBuiltInApiProviders();