ai-sdk-provider-env 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +8 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +13 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +8 -5
- package/dist/index.mjs.map +1 -1
- package/llms.txt +4 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -260,6 +260,7 @@ function createEnvProvider(factories, options = {}) {
|
|
|
260
260
|
apiKey: config.apiKey,
|
|
261
261
|
compatible: config.compatible ?? preset.compatible,
|
|
262
262
|
nativeRouting: config.nativeRouting ?? preset.nativeRouting,
|
|
263
|
+
...config.providerOptions && { providerOptions: config.providerOptions },
|
|
263
264
|
...config.headers && { headers: config.headers }
|
|
264
265
|
};
|
|
265
266
|
}
|
|
@@ -269,6 +270,7 @@ function createEnvProvider(factories, options = {}) {
|
|
|
269
270
|
apiKey: config.apiKey,
|
|
270
271
|
compatible: config.compatible ?? "openai-compatible",
|
|
271
272
|
nativeRouting: config.nativeRouting,
|
|
273
|
+
...config.providerOptions && { providerOptions: config.providerOptions },
|
|
272
274
|
...config.headers && { headers: config.headers }
|
|
273
275
|
};
|
|
274
276
|
}
|
|
@@ -330,12 +332,13 @@ function createEnvProvider(factories, options = {}) {
|
|
|
330
332
|
* Create the underlying provider based on the compatibility mode.
|
|
331
333
|
*/
|
|
332
334
|
function createUnderlying(configSet, config) {
|
|
333
|
-
const { baseURL, apiKey, compatible, headers } = config;
|
|
335
|
+
const { baseURL, apiKey, compatible, headers, providerOptions } = config;
|
|
334
336
|
const mergedHeaders = defaultHeaders || headers ? {
|
|
335
337
|
...defaultHeaders,
|
|
336
338
|
...headers
|
|
337
339
|
} : void 0;
|
|
338
340
|
const baseOpts = {
|
|
341
|
+
...providerOptions,
|
|
339
342
|
baseURL,
|
|
340
343
|
apiKey,
|
|
341
344
|
...mergedHeaders && { headers: mergedHeaders },
|
|
@@ -347,8 +350,8 @@ function createEnvProvider(factories, options = {}) {
|
|
|
347
350
|
} catch (error) {
|
|
348
351
|
if (isModuleNotFoundError(error, "@ai-sdk/openai") || error instanceof ProviderNotAvailableError) try {
|
|
349
352
|
return factories.createOpenAICompatible({
|
|
350
|
-
|
|
351
|
-
|
|
353
|
+
...baseOpts,
|
|
354
|
+
name: configSet
|
|
352
355
|
});
|
|
353
356
|
} catch (fallbackError) {
|
|
354
357
|
if (isModuleNotFoundError(fallbackError, "@ai-sdk/openai-compatible") || fallbackError instanceof ProviderNotAvailableError) throw new Error("[ai-sdk-provider-env] Could not load @ai-sdk/openai or its openai-compatible fallback. Install @ai-sdk/openai for full OpenAI features, or if using a bundler, provide factories: { openai: createOpenAI }");
|
|
@@ -370,8 +373,8 @@ function createEnvProvider(factories, options = {}) {
|
|
|
370
373
|
}
|
|
371
374
|
case "openai-compatible": try {
|
|
372
375
|
return factories.createOpenAICompatible({
|
|
373
|
-
|
|
374
|
-
|
|
376
|
+
...baseOpts,
|
|
377
|
+
name: configSet
|
|
375
378
|
});
|
|
376
379
|
} catch (error) {
|
|
377
380
|
if (isModuleNotFoundError(error, "@ai-sdk/openai-compatible")) throw new Error("[ai-sdk-provider-env] Could not load @ai-sdk/openai-compatible. If using a bundler, provide factories: { openaiCompatible: createOpenAICompatible }");
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["process","NoSuchModelError"],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, ProviderV3Compatible } from './types'\n\n/**\n * Check if an error is a \"module not found\" error for a specific package.\n *\n * Handles Node.js (error.code), Bun, and Bun compiled binaries\n * which may throw non-standard error objects.\n */\nexport function isModuleNotFoundError(error: unknown, packageName: string): boolean {\n if (typeof error !== 'object' || error === null)\n return false\n\n const message = 'message' in error && typeof error.message === 'string' ? error.message : ''\n const code = 'code' in error ? (error as Record<string, unknown>).code : undefined\n\n // Only match the module name in the \"Cannot find module/package 'X'\" part,\n // not in the require stack that follows. This prevents false positives when\n // a sub-dependency fails but the parent package appears in the stack trace.\n const isResolutionError = code === 'MODULE_NOT_FOUND'\n || code === 'ERR_MODULE_NOT_FOUND'\n || message.startsWith('Cannot find module')\n || message.startsWith('Cannot find package')\n\n if (!isResolutionError)\n return false\n\n // Extract the quoted module name from \"Cannot find module 'X'\" or \"Cannot find package 'X'\"\n // Handles both single and double quote styles across runtimes.\n const quoted = message.match(/Cannot find (?:module|package) ['\"]([^'\"]+)['\"]/)\n if (quoted)\n return quoted[1] === packageName || quoted[1].startsWith(`${packageName}/`)\n\n // Fallback for non-standard message formats (e.g. some Bun versions):\n // check if the package name appears before any \"Require stack:\" section,\n // with boundary checking to avoid false positives (e.g. @ai-sdk/openai matching @ai-sdk/openai-compatible).\n const requireStackIndex = message.indexOf('\\nRequire stack:')\n const relevantPart = requireStackIndex !== -1 ? message.slice(0, requireStackIndex) : message\n const boundaryPattern = new RegExp(`(?:^|[\\\\s'\"/@])${packageName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?:[\\\\s'\"/@]|$)`)\n return boundaryPattern.test(relevantPart)\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n * When not installed, errors propagate to allow fallback to OpenAI-compatible provider.\n */\nexport function createOpenAIProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n * No fallback is available — Anthropic does not support the OpenAI-compatible protocol.\n */\nexport function createAnthropicProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n * No fallback is available — Google does not support the OpenAI-compatible protocol.\n */\nexport function createGeminiProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * `@ai-sdk/openai-compatible` is a regular dependency and always available.\n */\nexport function createOpenAICompatibleProvider(opts: EnvProviderNamedFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n 'openai': {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n 'anthropic': {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n 'google': {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n 'deepseek': {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n 'zhipu': {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n 'groq': {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n 'together': {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n 'fireworks': {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n 'mistral': {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (international)\n 'moonshot': {\n baseURL: 'https://api.moonshot.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (China mainland)\n 'moonshot-china': {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n 'perplexity': {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n 'openrouter': {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (international)\n 'siliconflow': {\n baseURL: 'https://api.siliconflow.com/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (China mainland)\n 'siliconflow-china': {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // xAI (Grok series)\n 'xai': {\n baseURL: 'https://api.x.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI International (Z.AI — global endpoint for GLM series)\n 'zai': {\n baseURL: 'https://api.z.ai/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // OpenCode Zen (curated multi-model AI gateway)\n 'opencode-zen': {\n baseURL: 'https://opencode.ai/zen/v1',\n compatible: 'openai-compatible',\n nativeRouting: true,\n },\n\n // OpenCode Go (low-cost subscription for open coding models)\n 'opencode-go': {\n baseURL: 'https://opencode.ai/zen/go/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { EnvProviderFactories, EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, EnvProviderOptions, ProviderV3Compatible } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider, isModuleNotFoundError } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Thrown when a provider is not available (factory not provided by user).\n * Used internally to trigger fallback to OpenAI-compatible provider.\n */\nclass ProviderNotAvailableError extends Error {\n constructor(provider: string) {\n super(`Provider \"${provider}\" is not available`)\n this.name = 'ProviderNotAvailableError'\n }\n}\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n *\n * Return types use `ProviderV3Compatible` so that both `ProviderV3`\n * (from `@ai-sdk/provider@3.x`) and `ProviderV4` (`@ai-sdk/provider@4.x`)\n * are accepted.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createAnthropic: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createGemini: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createOpenAICompatible: (opts: EnvProviderNamedFactoryOptions) => ProviderV3Compatible\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Detect the native compatible mode for a model based on its ID prefix.\n *\n * Used by nativeRouting to auto-route model families to their native provider SDKs.\n * Only `claude-*`, `gemini-*`, and `gpt-*` prefixes are matched.\n * Known limitation: `o1-*`, `o3-*`, `chatgpt-*` are NOT matched (use explicit compatible mode).\n *\n * @returns The detected compatible mode, or `undefined` if no match.\n */\nexport function detectNativeCompatible(model: string): 'openai' | 'anthropic' | 'gemini' | undefined {\n if (model.startsWith('claude-'))\n return 'anthropic'\n if (model.startsWith('gemini-'))\n return 'gemini'\n if (model.startsWith('gpt-'))\n return 'openai'\n return undefined\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n nativeRouting?: boolean\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: Omit<EnvProviderOptions, 'factories'> = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n // Stored as ProviderV3 via safe cast from ProviderV3Compatible,\n // since V3 and V4 provider interfaces are structurally identical.\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string, nativeRouting?: boolean } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n nativeRouting: preset.nativeRouting,\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n nativeRouting: config.nativeRouting ?? preset.nativeRouting,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n nativeRouting: config.nativeRouting,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n // --- All checks below apply only to the env-var resolution path ---\n // The configs option (above) bypasses these and accepts arbitrary names/separators.\n\n // Validate separator produces shell-safe env var names (deferred to first env-var use)\n if (!/^\\w+$/.test(separator)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid separator \"${separator}\". `\n + `Separator must only contain ASCII letters, digits, or underscores to produce shell-safe env var names.`,\n )\n }\n\n // Validate config set name (ASCII shell-safe names only)\n if (!/^[A-Z_][\\w-]*$/i.test(configSet)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid config set name \"${configSet}\". `\n + `Names must start with a letter or underscore, followed by letters, digits, underscores, or hyphens. `\n + `For arbitrary names, use the configs option instead.`,\n )\n }\n\n // Normalize hyphens to underscores for POSIX shell-safe env var names.\n // e.g. \"my-api\" → \"MY_API\", so env vars are MY_API_API_KEY, MY_API_BASE_URL, etc.\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Parse NATIVE_ROUTING env var (boolean: 'true'/'false', case-insensitive)\n const nativeRoutingRaw = env('NATIVE_ROUTING')\n let nativeRoutingFromEnv: boolean | undefined\n if (nativeRoutingRaw !== undefined) {\n const lower = nativeRoutingRaw.toLowerCase()\n if (lower === 'true') {\n nativeRoutingFromEnv = true\n }\n else if (lower === 'false') {\n nativeRoutingFromEnv = false\n }\n else {\n throw new Error(\n `[ai-sdk-provider-env] Invalid value for ${prefix}${separator}NATIVE_ROUTING: \"${nativeRoutingRaw}\". `\n + `Expected \"true\" or \"false\".`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n nativeRouting: nativeRoutingFromEnv ?? preset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv,\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv ?? autoPreset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3Compatible {\n const { baseURL, apiKey, compatible, headers } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n try {\n return factories.createOpenAI(baseOpts)\n }\n catch (error) {\n // Fallback to OpenAI-compatible when:\n // - @ai-sdk/openai is not installed (module not found)\n // - User-provided factories don't include openai (ProviderNotAvailableError)\n if (isModuleNotFoundError(error, '@ai-sdk/openai') || error instanceof ProviderNotAvailableError) {\n try {\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n }\n catch (fallbackError) {\n // Only swallow module-not-found errors from the fallback itself\n if (isModuleNotFoundError(fallbackError, '@ai-sdk/openai-compatible') || fallbackError instanceof ProviderNotAvailableError) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai or its openai-compatible fallback. '\n + 'Install @ai-sdk/openai for full OpenAI features, or if using a bundler, '\n + 'provide factories: { openai: createOpenAI }',\n )\n }\n // Non-module-not-found errors from openai-compatible (e.g. config issues) should propagate\n throw fallbackError\n }\n }\n throw error\n }\n case 'anthropic':\n try {\n return factories.createAnthropic(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n case 'gemini':\n try {\n return factories.createGemini(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n case 'openai-compatible':\n try {\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/openai-compatible')) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai-compatible. '\n + 'If using a bundler, provide factories: { openaiCompatible: createOpenAICompatible }',\n )\n }\n throw error\n }\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Compute a cache key for the given config set.\n *\n * Explicit configs use the raw (uppercased) name, so `foo-bar` and `foo_bar`\n * remain distinct when both are defined in `configs`.\n * Env-var-backed config sets normalize hyphens to underscores, so aliases\n * like `my-api` and `my_api` share one cached provider.\n */\n function getCacheKey(configSet: string, config: ResolvedConfig, effectiveCompatible: string): string {\n if (options.configs?.[configSet]) {\n if (config.nativeRouting) {\n return `config:${configSet.toUpperCase()}:${effectiveCompatible}`\n }\n return `config:${configSet.toUpperCase()}`\n }\n if (config.nativeRouting) {\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}:${effectiveCompatible}`\n }\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}`\n }\n\n /**\n * Get or create a cached provider for the given config set.\n *\n * Returns `ProviderV3` via a safe cast from `ProviderV3Compatible`.\n * This is safe because `ProviderV3` and `ProviderV4` have identical\n * method signatures — only `specificationVersion` and model type brands differ.\n */\n function getProvider(configSet: string, model?: string): ProviderV3 {\n const config = resolveConfig(configSet)\n\n const detectedCompatible = (config.nativeRouting && model)\n ? detectNativeCompatible(model)\n : undefined\n const effectiveCompatible = detectedCompatible ?? config.compatible\n const wasAutoRouted = detectedCompatible != null && detectedCompatible !== config.compatible\n\n const key = getCacheKey(configSet, config, effectiveCompatible)\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const configForProvider = wasAutoRouted\n ? { ...config, compatible: effectiveCompatible }\n : config\n\n try {\n // Safe cast: V3 and V4 providers are structurally identical.\n // The underlying provider may be ProviderV3 or ProviderV4 depending\n // on which SDK version the user has installed.\n const provider = createUnderlying(configSet, configForProvider) as unknown as ProviderV3\n cache.set(key, provider)\n return provider\n }\n catch (error) {\n // When nativeRouting auto-routed to a provider whose SDK is not installed,\n // append a hint so users know they can disable routing to fall back.\n // Only for module-not-found errors — other errors (config issues, SDK bugs)\n // should propagate without misleading nativeRouting context.\n if (wasAutoRouted && error instanceof Error && error.message.includes('[ai-sdk-provider-env]')) {\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n throw new Error(\n `${error.message}`\n + ` (nativeRouting auto-detected this model as ${effectiveCompatible}.`\n + ` Disable with ${prefix}${separator}NATIVE_ROUTING=false to use ${config.compatible} instead.)`,\n { cause: error },\n )\n }\n throw error\n }\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet, model).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n // Prefer textEmbeddingModel if the underlying provider has it (V3).\n if (provider.textEmbeddingModel) {\n return provider.textEmbeddingModel(model)\n }\n // V4 providers removed textEmbeddingModel — fall back to embeddingModel\n // which exists in both V3 and V4 interfaces.\n if (provider.embeddingModel) {\n return provider.embeddingModel(model)\n }\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.\n *\n * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.\n * If the user provided a factory for a given compatible mode, it is used;\n * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).\n */\nfunction buildUserFactories(userFactories: EnvProviderFactories): ProviderFactories {\n function missingFactory(key: string, fnName: string, pkg: string): never {\n throw new Error(\n `[ai-sdk-provider-env] No factory provided for \"${key}\". `\n + `When using the factories option, provide a factory for each compatibility mode you use. `\n + `Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`,\n )\n }\n\n return {\n createOpenAI: (opts) => {\n if (userFactories.openai)\n return userFactories.openai(opts)\n // Signal fallback — createUnderlying will catch this and use openai-compatible\n throw new ProviderNotAvailableError('openai')\n },\n createAnthropic: opts =>\n userFactories.anthropic\n ? userFactories.anthropic(opts)\n : missingFactory('anthropic', 'createAnthropic', '@ai-sdk/anthropic'),\n createGemini: opts =>\n userFactories.gemini\n ? userFactories.gemini(opts)\n : missingFactory('gemini', 'createGoogleGenerativeAI', '@ai-sdk/google'),\n createOpenAICompatible: opts =>\n userFactories.openaiCompatible\n ? userFactories.openaiCompatible(opts)\n : createOpenAICompatibleProvider(opts),\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Config set naming rules:\n * - Names must match `[A-Za-z_][A-Za-z0-9_-]*` (ASCII letters, digits, underscores, hyphens)\n * - Hyphens are normalized to underscores for env var lookup:\n * `my-api/model` → reads `MY_API_API_KEY`, `MY_API_BASE_URL`, etc.\n * - For arbitrary names, use the `configs` option instead\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n *\n * @example Bundler-safe usage with explicit factories\n * ```ts\n * import { createOpenAI } from '@ai-sdk/openai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const provider = envProvider({\n * factories: { openai: createOpenAI },\n * })\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n const factories = options.factories\n ? buildUserFactories(options.factories)\n : defaultFactories\n return createEnvProvider(factories, options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["process","NoSuchModelError"],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, ProviderV3Compatible } from './types'\n\n/**\n * Check if an error is a \"module not found\" error for a specific package.\n *\n * Handles Node.js (error.code), Bun, and Bun compiled binaries\n * which may throw non-standard error objects.\n */\nexport function isModuleNotFoundError(error: unknown, packageName: string): boolean {\n if (typeof error !== 'object' || error === null)\n return false\n\n const message = 'message' in error && typeof error.message === 'string' ? error.message : ''\n const code = 'code' in error ? (error as Record<string, unknown>).code : undefined\n\n // Only match the module name in the \"Cannot find module/package 'X'\" part,\n // not in the require stack that follows. This prevents false positives when\n // a sub-dependency fails but the parent package appears in the stack trace.\n const isResolutionError = code === 'MODULE_NOT_FOUND'\n || code === 'ERR_MODULE_NOT_FOUND'\n || message.startsWith('Cannot find module')\n || message.startsWith('Cannot find package')\n\n if (!isResolutionError)\n return false\n\n // Extract the quoted module name from \"Cannot find module 'X'\" or \"Cannot find package 'X'\"\n // Handles both single and double quote styles across runtimes.\n const quoted = message.match(/Cannot find (?:module|package) ['\"]([^'\"]+)['\"]/)\n if (quoted)\n return quoted[1] === packageName || quoted[1].startsWith(`${packageName}/`)\n\n // Fallback for non-standard message formats (e.g. some Bun versions):\n // check if the package name appears before any \"Require stack:\" section,\n // with boundary checking to avoid false positives (e.g. @ai-sdk/openai matching @ai-sdk/openai-compatible).\n const requireStackIndex = message.indexOf('\\nRequire stack:')\n const relevantPart = requireStackIndex !== -1 ? message.slice(0, requireStackIndex) : message\n const boundaryPattern = new RegExp(`(?:^|[\\\\s'\"/@])${packageName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?:[\\\\s'\"/@]|$)`)\n return boundaryPattern.test(relevantPart)\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n * When not installed, errors propagate to allow fallback to OpenAI-compatible provider.\n */\nexport function createOpenAIProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n * No fallback is available — Anthropic does not support the OpenAI-compatible protocol.\n */\nexport function createAnthropicProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n * No fallback is available — Google does not support the OpenAI-compatible protocol.\n */\nexport function createGeminiProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * `@ai-sdk/openai-compatible` is a regular dependency and always available.\n */\nexport function createOpenAICompatibleProvider(opts: EnvProviderNamedFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n 'openai': {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n 'anthropic': {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n 'google': {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n 'deepseek': {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n 'zhipu': {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n 'groq': {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n 'together': {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n 'fireworks': {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n 'mistral': {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (international)\n 'moonshot': {\n baseURL: 'https://api.moonshot.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (China mainland)\n 'moonshot-china': {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n 'perplexity': {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n 'openrouter': {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (international)\n 'siliconflow': {\n baseURL: 'https://api.siliconflow.com/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (China mainland)\n 'siliconflow-china': {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // xAI (Grok series)\n 'xai': {\n baseURL: 'https://api.x.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI International (Z.AI — global endpoint for GLM series)\n 'zai': {\n baseURL: 'https://api.z.ai/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // OpenCode Zen (curated multi-model AI gateway)\n 'opencode-zen': {\n baseURL: 'https://opencode.ai/zen/v1',\n compatible: 'openai-compatible',\n nativeRouting: true,\n },\n\n // OpenCode Go (low-cost subscription for open coding models)\n 'opencode-go': {\n baseURL: 'https://opencode.ai/zen/go/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { EnvProviderFactories, EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, EnvProviderOptions, ProviderV3Compatible } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider, isModuleNotFoundError } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Thrown when a provider is not available (factory not provided by user).\n * Used internally to trigger fallback to OpenAI-compatible provider.\n */\nclass ProviderNotAvailableError extends Error {\n constructor(provider: string) {\n super(`Provider \"${provider}\" is not available`)\n this.name = 'ProviderNotAvailableError'\n }\n}\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n *\n * Return types use `ProviderV3Compatible` so that both `ProviderV3`\n * (from `@ai-sdk/provider@3.x`) and `ProviderV4` (`@ai-sdk/provider@4.x`)\n * are accepted.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createAnthropic: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createGemini: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createOpenAICompatible: (opts: EnvProviderNamedFactoryOptions) => ProviderV3Compatible\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Detect the native compatible mode for a model based on its ID prefix.\n *\n * Used by nativeRouting to auto-route model families to their native provider SDKs.\n * Only `claude-*`, `gemini-*`, and `gpt-*` prefixes are matched.\n * Known limitation: `o1-*`, `o3-*`, `chatgpt-*` are NOT matched (use explicit compatible mode).\n *\n * @returns The detected compatible mode, or `undefined` if no match.\n */\nexport function detectNativeCompatible(model: string): 'openai' | 'anthropic' | 'gemini' | undefined {\n if (model.startsWith('claude-'))\n return 'anthropic'\n if (model.startsWith('gemini-'))\n return 'gemini'\n if (model.startsWith('gpt-'))\n return 'openai'\n return undefined\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n providerOptions?: Record<string, unknown>\n nativeRouting?: boolean\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: Omit<EnvProviderOptions, 'factories'> = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n // Stored as ProviderV3 via safe cast from ProviderV3Compatible,\n // since V3 and V4 provider interfaces are structurally identical.\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string, nativeRouting?: boolean } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n nativeRouting: preset.nativeRouting,\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n nativeRouting: config.nativeRouting ?? preset.nativeRouting,\n ...(config.providerOptions && { providerOptions: config.providerOptions }),\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n nativeRouting: config.nativeRouting,\n ...(config.providerOptions && { providerOptions: config.providerOptions }),\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n // --- All checks below apply only to the env-var resolution path ---\n // The configs option (above) bypasses these and accepts arbitrary names/separators.\n\n // Validate separator produces shell-safe env var names (deferred to first env-var use)\n if (!/^\\w+$/.test(separator)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid separator \"${separator}\". `\n + `Separator must only contain ASCII letters, digits, or underscores to produce shell-safe env var names.`,\n )\n }\n\n // Validate config set name (ASCII shell-safe names only)\n if (!/^[A-Z_][\\w-]*$/i.test(configSet)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid config set name \"${configSet}\". `\n + `Names must start with a letter or underscore, followed by letters, digits, underscores, or hyphens. `\n + `For arbitrary names, use the configs option instead.`,\n )\n }\n\n // Normalize hyphens to underscores for POSIX shell-safe env var names.\n // e.g. \"my-api\" → \"MY_API\", so env vars are MY_API_API_KEY, MY_API_BASE_URL, etc.\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Parse NATIVE_ROUTING env var (boolean: 'true'/'false', case-insensitive)\n const nativeRoutingRaw = env('NATIVE_ROUTING')\n let nativeRoutingFromEnv: boolean | undefined\n if (nativeRoutingRaw !== undefined) {\n const lower = nativeRoutingRaw.toLowerCase()\n if (lower === 'true') {\n nativeRoutingFromEnv = true\n }\n else if (lower === 'false') {\n nativeRoutingFromEnv = false\n }\n else {\n throw new Error(\n `[ai-sdk-provider-env] Invalid value for ${prefix}${separator}NATIVE_ROUTING: \"${nativeRoutingRaw}\". `\n + `Expected \"true\" or \"false\".`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n nativeRouting: nativeRoutingFromEnv ?? preset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv,\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv ?? autoPreset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3Compatible {\n const { baseURL, apiKey, compatible, headers, providerOptions } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n ...providerOptions,\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n try {\n return factories.createOpenAI(baseOpts)\n }\n catch (error) {\n // Fallback to OpenAI-compatible when:\n // - @ai-sdk/openai is not installed (module not found)\n // - User-provided factories don't include openai (ProviderNotAvailableError)\n if (isModuleNotFoundError(error, '@ai-sdk/openai') || error instanceof ProviderNotAvailableError) {\n try {\n return factories.createOpenAICompatible({ ...baseOpts, name: configSet })\n }\n catch (fallbackError) {\n // Only swallow module-not-found errors from the fallback itself\n if (isModuleNotFoundError(fallbackError, '@ai-sdk/openai-compatible') || fallbackError instanceof ProviderNotAvailableError) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai or its openai-compatible fallback. '\n + 'Install @ai-sdk/openai for full OpenAI features, or if using a bundler, '\n + 'provide factories: { openai: createOpenAI }',\n )\n }\n // Non-module-not-found errors from openai-compatible (e.g. config issues) should propagate\n throw fallbackError\n }\n }\n throw error\n }\n case 'anthropic':\n try {\n return factories.createAnthropic(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n case 'gemini':\n try {\n return factories.createGemini(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n case 'openai-compatible':\n try {\n return factories.createOpenAICompatible({ ...baseOpts, name: configSet })\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/openai-compatible')) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai-compatible. '\n + 'If using a bundler, provide factories: { openaiCompatible: createOpenAICompatible }',\n )\n }\n throw error\n }\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Compute a cache key for the given config set.\n *\n * Explicit configs use the raw (uppercased) name, so `foo-bar` and `foo_bar`\n * remain distinct when both are defined in `configs`.\n * Env-var-backed config sets normalize hyphens to underscores, so aliases\n * like `my-api` and `my_api` share one cached provider.\n */\n function getCacheKey(configSet: string, config: ResolvedConfig, effectiveCompatible: string): string {\n if (options.configs?.[configSet]) {\n if (config.nativeRouting) {\n return `config:${configSet.toUpperCase()}:${effectiveCompatible}`\n }\n return `config:${configSet.toUpperCase()}`\n }\n if (config.nativeRouting) {\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}:${effectiveCompatible}`\n }\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}`\n }\n\n /**\n * Get or create a cached provider for the given config set.\n *\n * Returns `ProviderV3` via a safe cast from `ProviderV3Compatible`.\n * This is safe because `ProviderV3` and `ProviderV4` have identical\n * method signatures — only `specificationVersion` and model type brands differ.\n */\n function getProvider(configSet: string, model?: string): ProviderV3 {\n const config = resolveConfig(configSet)\n\n const detectedCompatible = (config.nativeRouting && model)\n ? detectNativeCompatible(model)\n : undefined\n const effectiveCompatible = detectedCompatible ?? config.compatible\n const wasAutoRouted = detectedCompatible != null && detectedCompatible !== config.compatible\n\n const key = getCacheKey(configSet, config, effectiveCompatible)\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const configForProvider = wasAutoRouted\n ? { ...config, compatible: effectiveCompatible }\n : config\n\n try {\n // Safe cast: V3 and V4 providers are structurally identical.\n // The underlying provider may be ProviderV3 or ProviderV4 depending\n // on which SDK version the user has installed.\n const provider = createUnderlying(configSet, configForProvider) as unknown as ProviderV3\n cache.set(key, provider)\n return provider\n }\n catch (error) {\n // When nativeRouting auto-routed to a provider whose SDK is not installed,\n // append a hint so users know they can disable routing to fall back.\n // Only for module-not-found errors — other errors (config issues, SDK bugs)\n // should propagate without misleading nativeRouting context.\n if (wasAutoRouted && error instanceof Error && error.message.includes('[ai-sdk-provider-env]')) {\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n throw new Error(\n `${error.message}`\n + ` (nativeRouting auto-detected this model as ${effectiveCompatible}.`\n + ` Disable with ${prefix}${separator}NATIVE_ROUTING=false to use ${config.compatible} instead.)`,\n { cause: error },\n )\n }\n throw error\n }\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet, model).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n // Prefer textEmbeddingModel if the underlying provider has it (V3).\n if (provider.textEmbeddingModel) {\n return provider.textEmbeddingModel(model)\n }\n // V4 providers removed textEmbeddingModel — fall back to embeddingModel\n // which exists in both V3 and V4 interfaces.\n if (provider.embeddingModel) {\n return provider.embeddingModel(model)\n }\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.\n *\n * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.\n * If the user provided a factory for a given compatible mode, it is used;\n * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).\n */\nfunction buildUserFactories(userFactories: EnvProviderFactories): ProviderFactories {\n function missingFactory(key: string, fnName: string, pkg: string): never {\n throw new Error(\n `[ai-sdk-provider-env] No factory provided for \"${key}\". `\n + `When using the factories option, provide a factory for each compatibility mode you use. `\n + `Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`,\n )\n }\n\n return {\n createOpenAI: (opts) => {\n if (userFactories.openai)\n return userFactories.openai(opts)\n // Signal fallback — createUnderlying will catch this and use openai-compatible\n throw new ProviderNotAvailableError('openai')\n },\n createAnthropic: opts =>\n userFactories.anthropic\n ? userFactories.anthropic(opts)\n : missingFactory('anthropic', 'createAnthropic', '@ai-sdk/anthropic'),\n createGemini: opts =>\n userFactories.gemini\n ? userFactories.gemini(opts)\n : missingFactory('gemini', 'createGoogleGenerativeAI', '@ai-sdk/google'),\n createOpenAICompatible: opts =>\n userFactories.openaiCompatible\n ? userFactories.openaiCompatible(opts)\n : createOpenAICompatibleProvider(opts),\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Config set naming rules:\n * - Names must match `[A-Za-z_][A-Za-z0-9_-]*` (ASCII letters, digits, underscores, hyphens)\n * - Hyphens are normalized to underscores for env var lookup:\n * `my-api/model` → reads `MY_API_API_KEY`, `MY_API_BASE_URL`, etc.\n * - For arbitrary names, use the `configs` option instead\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n *\n * @example Bundler-safe usage with explicit factories\n * ```ts\n * import { createOpenAI } from '@ai-sdk/openai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const provider = envProvider({\n * factories: { openai: createOpenAI },\n * })\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n const factories = options.factories\n ? buildUserFactories(options.factories)\n : defaultFactories\n return createEnvProvider(factories, options)\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -58,6 +58,19 @@ interface ConfigSetEntry {
|
|
|
58
58
|
* `{PREFIX}_HEADERS={"X-Custom-Header":"value"}`
|
|
59
59
|
*/
|
|
60
60
|
headers?: Record<string, string>;
|
|
61
|
+
/**
|
|
62
|
+
* Extra options passed through to the underlying provider SDK factory.
|
|
63
|
+
*
|
|
64
|
+
* These are spread directly into the factory call (`createOpenAI`, `createAnthropic`,
|
|
65
|
+
* `createOpenAICompatible`, etc.), allowing any SDK-specific option without
|
|
66
|
+
* `ai-sdk-provider-env` needing to know about it.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* providerOptions: { supportsStructuredOutputs: true }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
providerOptions?: Record<string, unknown>;
|
|
61
74
|
/**
|
|
62
75
|
* When enabled, auto-detects model family from model ID prefix and routes to the
|
|
63
76
|
* native provider SDK (`claude-*`→anthropic, `gemini-*`→gemini, `gpt-*`→openai).
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;AAcA;;;;;;;;;;;UAAiB,oBAAA;EAAA,SACN,oBAAA;EACT,aAAA,GAAgB,OAAA;EAChB,cAAA,GAAiB,OAAA;EACjB,UAAA,GAAa,OAAA;EACb,kBAAA,KAAuB,OAAA;EACvB,kBAAA,KAAuB,OAAA;EACvB,WAAA,KAAgB,OAAA;EAChB,cAAA,KAAmB,OAAA;AAAA;AASrB;;;;;;AAAA,UAAiB,cAAA;EAmBf;EAjBA,MAAA;EAwBU
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;AAcA;;;;;;;;;;;UAAiB,oBAAA;EAAA,SACN,oBAAA;EACT,aAAA,GAAgB,OAAA;EAChB,cAAA,GAAiB,OAAA;EACjB,UAAA,GAAa,OAAA;EACb,kBAAA,KAAuB,OAAA;EACvB,kBAAA,KAAuB,OAAA;EACvB,WAAA,KAAgB,OAAA;EAChB,cAAA,KAAmB,OAAA;AAAA;AASrB;;;;;;AAAA,UAAiB,cAAA;EAmBf;EAjBA,MAAA;EAwBU;;;;;EAlBV,MAAA;EA+Ce;EA7Cf,OAAA;;;;;;;;AAwEF;EA/DE,UAAA;;;;;;;EAOA,OAAA,GAAU,MAAA;EAgFM;;AASlB;;;;;;;;;;EA5EE,eAAA,GAAkB,MAAA;EAoFa;;AASjC;;;;;EArFE,aAAA;AAAA;;;;;;UAQe,YAAA;EA2HkC;EAzHjD,OAAA;EAgIgE;;;;;;;;EAvHhE,UAAA;EA0Ga;;;;;;;EAlGb,aAAA;AAAA;;;;AAqHF;;UA7GiB,mBAAA;EAmJU;;;;;;;;EA1IzB,KAAA,UAAe,UAAA,CAAW,KAAA;EA0ID;;;;;;;;;;;ACoV3B;;ED/cE,OAAA,GAAU,MAAA;AAAA;;;;;;;UASK,yBAAA;;EAEf,OAAA;EEzBD;EF2BC,MAAA;EE9I2B;EFgJ3B,OAAA,GAAU,MAAA;;EAEV,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;UASX,8BAAA,SAAuC,yBAAA;;EAEtD,IAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;UAwBe,oBAAA;;;;;;;;EAQf,MAAA,IAAU,OAAA,EAAS,yBAAA,KAA8B,oBAAA;;;;;;EAMjD,SAAA,IAAa,OAAA,EAAS,yBAAA,KAA8B,oBAAA;;;;;;EAMpD,MAAA,IAAU,OAAA,EAAS,yBAAA,KAA8B,oBAAA;;;;;;;EAOjD,gBAAA,IAAoB,OAAA,EAAS,8BAAA,KAAmC,oBAAA;AAAA;;;;UAMjD,kBAAA;;;;;;;;;;;;;;;;;;EAkBf,SAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA,GAAU,MAAA,SAAe,cAAA;;;;;;;;;;;;;;;EAgBzB,QAAA,GAAW,mBAAA;;;;;;;;;;;;;;;;;;;EAoBX,gBAAA;;;;;;;;;;;;;;;;;;EAmBA,SAAA,GAAY,oBAAA;AAAA;;;;;;;AArOd;;;;;;;;;AA2BA;;;;;;;;;;;AAiCA;;;;;;;;;;;;;AAiBA;;;;;AA0BA;;;;;;;iBC2ZgB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,UAAA;;;;;AD1kB/D;;;;cENa,cAAA,EAAgB,MAAA,SAAe,YAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -58,6 +58,19 @@ interface ConfigSetEntry {
|
|
|
58
58
|
* `{PREFIX}_HEADERS={"X-Custom-Header":"value"}`
|
|
59
59
|
*/
|
|
60
60
|
headers?: Record<string, string>;
|
|
61
|
+
/**
|
|
62
|
+
* Extra options passed through to the underlying provider SDK factory.
|
|
63
|
+
*
|
|
64
|
+
* These are spread directly into the factory call (`createOpenAI`, `createAnthropic`,
|
|
65
|
+
* `createOpenAICompatible`, etc.), allowing any SDK-specific option without
|
|
66
|
+
* `ai-sdk-provider-env` needing to know about it.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* providerOptions: { supportsStructuredOutputs: true }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
providerOptions?: Record<string, unknown>;
|
|
61
74
|
/**
|
|
62
75
|
* When enabled, auto-detects model family from model ID prefix and routes to the
|
|
63
76
|
* native provider SDK (`claude-*`→anthropic, `gemini-*`→gemini, `gpt-*`→openai).
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;AAcA;;;;;;;;;;;UAAiB,oBAAA;EAAA,SACN,oBAAA;EACT,aAAA,GAAgB,OAAA;EAChB,cAAA,GAAiB,OAAA;EACjB,UAAA,GAAa,OAAA;EACb,kBAAA,KAAuB,OAAA;EACvB,kBAAA,KAAuB,OAAA;EACvB,WAAA,KAAgB,OAAA;EAChB,cAAA,KAAmB,OAAA;AAAA;AASrB;;;;;;AAAA,UAAiB,cAAA;EAmBf;EAjBA,MAAA;EAwBU
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/env-provider.ts","../src/presets.ts"],"mappings":";;;;;;AAcA;;;;;;;;;;;UAAiB,oBAAA;EAAA,SACN,oBAAA;EACT,aAAA,GAAgB,OAAA;EAChB,cAAA,GAAiB,OAAA;EACjB,UAAA,GAAa,OAAA;EACb,kBAAA,KAAuB,OAAA;EACvB,kBAAA,KAAuB,OAAA;EACvB,WAAA,KAAgB,OAAA;EAChB,cAAA,KAAmB,OAAA;AAAA;AASrB;;;;;;AAAA,UAAiB,cAAA;EAmBf;EAjBA,MAAA;EAwBU;;;;;EAlBV,MAAA;EA+Ce;EA7Cf,OAAA;;;;;;;;AAwEF;EA/DE,UAAA;;;;;;;EAOA,OAAA,GAAU,MAAA;EAgFM;;AASlB;;;;;;;;;;EA5EE,eAAA,GAAkB,MAAA;EAoFa;;AASjC;;;;;EArFE,aAAA;AAAA;;;;;;UAQe,YAAA;EA2HkC;EAzHjD,OAAA;EAgIgE;;;;;;;;EAvHhE,UAAA;EA0Ga;;;;;;;EAlGb,aAAA;AAAA;;;;AAqHF;;UA7GiB,mBAAA;EAmJU;;;;;;;;EA1IzB,KAAA,UAAe,UAAA,CAAW,KAAA;EA0ID;;;;;;;;;;;ACoV3B;;ED/cE,OAAA,GAAU,MAAA;AAAA;;;;;;;UASK,yBAAA;;EAEf,OAAA;EEzBD;EF2BC,MAAA;EE9I2B;EFgJ3B,OAAA,GAAU,MAAA;;EAEV,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;UASX,8BAAA,SAAuC,yBAAA;;EAEtD,IAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;UAwBe,oBAAA;;;;;;;;EAQf,MAAA,IAAU,OAAA,EAAS,yBAAA,KAA8B,oBAAA;;;;;;EAMjD,SAAA,IAAa,OAAA,EAAS,yBAAA,KAA8B,oBAAA;;;;;;EAMpD,MAAA,IAAU,OAAA,EAAS,yBAAA,KAA8B,oBAAA;;;;;;;EAOjD,gBAAA,IAAoB,OAAA,EAAS,8BAAA,KAAmC,oBAAA;AAAA;;;;UAMjD,kBAAA;;;;;;;;;;;;;;;;;;EAkBf,SAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA,GAAU,MAAA,SAAe,cAAA;;;;;;;;;;;;;;;EAgBzB,QAAA,GAAW,mBAAA;;;;;;;;;;;;;;;;;;;EAoBX,gBAAA;;;;;;;;;;;;;;;;;;EAmBA,SAAA,GAAY,oBAAA;AAAA;;;;;;;AArOd;;;;;;;;;AA2BA;;;;;;;;;;;AAiCA;;;;;;;;;;;;;AAiBA;;;;;AA0BA;;;;;;;iBC2ZgB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,UAAA;;;;;AD1kB/D;;;;cENa,cAAA,EAAgB,MAAA,SAAe,YAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -236,6 +236,7 @@ function createEnvProvider(factories, options = {}) {
|
|
|
236
236
|
apiKey: config.apiKey,
|
|
237
237
|
compatible: config.compatible ?? preset.compatible,
|
|
238
238
|
nativeRouting: config.nativeRouting ?? preset.nativeRouting,
|
|
239
|
+
...config.providerOptions && { providerOptions: config.providerOptions },
|
|
239
240
|
...config.headers && { headers: config.headers }
|
|
240
241
|
};
|
|
241
242
|
}
|
|
@@ -245,6 +246,7 @@ function createEnvProvider(factories, options = {}) {
|
|
|
245
246
|
apiKey: config.apiKey,
|
|
246
247
|
compatible: config.compatible ?? "openai-compatible",
|
|
247
248
|
nativeRouting: config.nativeRouting,
|
|
249
|
+
...config.providerOptions && { providerOptions: config.providerOptions },
|
|
248
250
|
...config.headers && { headers: config.headers }
|
|
249
251
|
};
|
|
250
252
|
}
|
|
@@ -306,12 +308,13 @@ function createEnvProvider(factories, options = {}) {
|
|
|
306
308
|
* Create the underlying provider based on the compatibility mode.
|
|
307
309
|
*/
|
|
308
310
|
function createUnderlying(configSet, config) {
|
|
309
|
-
const { baseURL, apiKey, compatible, headers } = config;
|
|
311
|
+
const { baseURL, apiKey, compatible, headers, providerOptions } = config;
|
|
310
312
|
const mergedHeaders = defaultHeaders || headers ? {
|
|
311
313
|
...defaultHeaders,
|
|
312
314
|
...headers
|
|
313
315
|
} : void 0;
|
|
314
316
|
const baseOpts = {
|
|
317
|
+
...providerOptions,
|
|
315
318
|
baseURL,
|
|
316
319
|
apiKey,
|
|
317
320
|
...mergedHeaders && { headers: mergedHeaders },
|
|
@@ -323,8 +326,8 @@ function createEnvProvider(factories, options = {}) {
|
|
|
323
326
|
} catch (error) {
|
|
324
327
|
if (isModuleNotFoundError(error, "@ai-sdk/openai") || error instanceof ProviderNotAvailableError) try {
|
|
325
328
|
return factories.createOpenAICompatible({
|
|
326
|
-
|
|
327
|
-
|
|
329
|
+
...baseOpts,
|
|
330
|
+
name: configSet
|
|
328
331
|
});
|
|
329
332
|
} catch (fallbackError) {
|
|
330
333
|
if (isModuleNotFoundError(fallbackError, "@ai-sdk/openai-compatible") || fallbackError instanceof ProviderNotAvailableError) throw new Error("[ai-sdk-provider-env] Could not load @ai-sdk/openai or its openai-compatible fallback. Install @ai-sdk/openai for full OpenAI features, or if using a bundler, provide factories: { openai: createOpenAI }");
|
|
@@ -346,8 +349,8 @@ function createEnvProvider(factories, options = {}) {
|
|
|
346
349
|
}
|
|
347
350
|
case "openai-compatible": try {
|
|
348
351
|
return factories.createOpenAICompatible({
|
|
349
|
-
|
|
350
|
-
|
|
352
|
+
...baseOpts,
|
|
353
|
+
name: configSet
|
|
351
354
|
});
|
|
352
355
|
} catch (error) {
|
|
353
356
|
if (isModuleNotFoundError(error, "@ai-sdk/openai-compatible")) throw new Error("[ai-sdk-provider-env] Could not load @ai-sdk/openai-compatible. If using a bundler, provide factories: { openaiCompatible: createOpenAICompatible }");
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, ProviderV3Compatible } from './types'\n\n/**\n * Check if an error is a \"module not found\" error for a specific package.\n *\n * Handles Node.js (error.code), Bun, and Bun compiled binaries\n * which may throw non-standard error objects.\n */\nexport function isModuleNotFoundError(error: unknown, packageName: string): boolean {\n if (typeof error !== 'object' || error === null)\n return false\n\n const message = 'message' in error && typeof error.message === 'string' ? error.message : ''\n const code = 'code' in error ? (error as Record<string, unknown>).code : undefined\n\n // Only match the module name in the \"Cannot find module/package 'X'\" part,\n // not in the require stack that follows. This prevents false positives when\n // a sub-dependency fails but the parent package appears in the stack trace.\n const isResolutionError = code === 'MODULE_NOT_FOUND'\n || code === 'ERR_MODULE_NOT_FOUND'\n || message.startsWith('Cannot find module')\n || message.startsWith('Cannot find package')\n\n if (!isResolutionError)\n return false\n\n // Extract the quoted module name from \"Cannot find module 'X'\" or \"Cannot find package 'X'\"\n // Handles both single and double quote styles across runtimes.\n const quoted = message.match(/Cannot find (?:module|package) ['\"]([^'\"]+)['\"]/)\n if (quoted)\n return quoted[1] === packageName || quoted[1].startsWith(`${packageName}/`)\n\n // Fallback for non-standard message formats (e.g. some Bun versions):\n // check if the package name appears before any \"Require stack:\" section,\n // with boundary checking to avoid false positives (e.g. @ai-sdk/openai matching @ai-sdk/openai-compatible).\n const requireStackIndex = message.indexOf('\\nRequire stack:')\n const relevantPart = requireStackIndex !== -1 ? message.slice(0, requireStackIndex) : message\n const boundaryPattern = new RegExp(`(?:^|[\\\\s'\"/@])${packageName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?:[\\\\s'\"/@]|$)`)\n return boundaryPattern.test(relevantPart)\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n * When not installed, errors propagate to allow fallback to OpenAI-compatible provider.\n */\nexport function createOpenAIProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n * No fallback is available — Anthropic does not support the OpenAI-compatible protocol.\n */\nexport function createAnthropicProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n * No fallback is available — Google does not support the OpenAI-compatible protocol.\n */\nexport function createGeminiProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * `@ai-sdk/openai-compatible` is a regular dependency and always available.\n */\nexport function createOpenAICompatibleProvider(opts: EnvProviderNamedFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n 'openai': {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n 'anthropic': {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n 'google': {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n 'deepseek': {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n 'zhipu': {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n 'groq': {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n 'together': {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n 'fireworks': {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n 'mistral': {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (international)\n 'moonshot': {\n baseURL: 'https://api.moonshot.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (China mainland)\n 'moonshot-china': {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n 'perplexity': {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n 'openrouter': {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (international)\n 'siliconflow': {\n baseURL: 'https://api.siliconflow.com/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (China mainland)\n 'siliconflow-china': {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // xAI (Grok series)\n 'xai': {\n baseURL: 'https://api.x.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI International (Z.AI — global endpoint for GLM series)\n 'zai': {\n baseURL: 'https://api.z.ai/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // OpenCode Zen (curated multi-model AI gateway)\n 'opencode-zen': {\n baseURL: 'https://opencode.ai/zen/v1',\n compatible: 'openai-compatible',\n nativeRouting: true,\n },\n\n // OpenCode Go (low-cost subscription for open coding models)\n 'opencode-go': {\n baseURL: 'https://opencode.ai/zen/go/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { EnvProviderFactories, EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, EnvProviderOptions, ProviderV3Compatible } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider, isModuleNotFoundError } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Thrown when a provider is not available (factory not provided by user).\n * Used internally to trigger fallback to OpenAI-compatible provider.\n */\nclass ProviderNotAvailableError extends Error {\n constructor(provider: string) {\n super(`Provider \"${provider}\" is not available`)\n this.name = 'ProviderNotAvailableError'\n }\n}\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n *\n * Return types use `ProviderV3Compatible` so that both `ProviderV3`\n * (from `@ai-sdk/provider@3.x`) and `ProviderV4` (`@ai-sdk/provider@4.x`)\n * are accepted.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createAnthropic: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createGemini: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createOpenAICompatible: (opts: EnvProviderNamedFactoryOptions) => ProviderV3Compatible\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Detect the native compatible mode for a model based on its ID prefix.\n *\n * Used by nativeRouting to auto-route model families to their native provider SDKs.\n * Only `claude-*`, `gemini-*`, and `gpt-*` prefixes are matched.\n * Known limitation: `o1-*`, `o3-*`, `chatgpt-*` are NOT matched (use explicit compatible mode).\n *\n * @returns The detected compatible mode, or `undefined` if no match.\n */\nexport function detectNativeCompatible(model: string): 'openai' | 'anthropic' | 'gemini' | undefined {\n if (model.startsWith('claude-'))\n return 'anthropic'\n if (model.startsWith('gemini-'))\n return 'gemini'\n if (model.startsWith('gpt-'))\n return 'openai'\n return undefined\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n nativeRouting?: boolean\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: Omit<EnvProviderOptions, 'factories'> = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n // Stored as ProviderV3 via safe cast from ProviderV3Compatible,\n // since V3 and V4 provider interfaces are structurally identical.\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string, nativeRouting?: boolean } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n nativeRouting: preset.nativeRouting,\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n nativeRouting: config.nativeRouting ?? preset.nativeRouting,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n nativeRouting: config.nativeRouting,\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n // --- All checks below apply only to the env-var resolution path ---\n // The configs option (above) bypasses these and accepts arbitrary names/separators.\n\n // Validate separator produces shell-safe env var names (deferred to first env-var use)\n if (!/^\\w+$/.test(separator)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid separator \"${separator}\". `\n + `Separator must only contain ASCII letters, digits, or underscores to produce shell-safe env var names.`,\n )\n }\n\n // Validate config set name (ASCII shell-safe names only)\n if (!/^[A-Z_][\\w-]*$/i.test(configSet)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid config set name \"${configSet}\". `\n + `Names must start with a letter or underscore, followed by letters, digits, underscores, or hyphens. `\n + `For arbitrary names, use the configs option instead.`,\n )\n }\n\n // Normalize hyphens to underscores for POSIX shell-safe env var names.\n // e.g. \"my-api\" → \"MY_API\", so env vars are MY_API_API_KEY, MY_API_BASE_URL, etc.\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Parse NATIVE_ROUTING env var (boolean: 'true'/'false', case-insensitive)\n const nativeRoutingRaw = env('NATIVE_ROUTING')\n let nativeRoutingFromEnv: boolean | undefined\n if (nativeRoutingRaw !== undefined) {\n const lower = nativeRoutingRaw.toLowerCase()\n if (lower === 'true') {\n nativeRoutingFromEnv = true\n }\n else if (lower === 'false') {\n nativeRoutingFromEnv = false\n }\n else {\n throw new Error(\n `[ai-sdk-provider-env] Invalid value for ${prefix}${separator}NATIVE_ROUTING: \"${nativeRoutingRaw}\". `\n + `Expected \"true\" or \"false\".`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n nativeRouting: nativeRoutingFromEnv ?? preset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv,\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv ?? autoPreset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3Compatible {\n const { baseURL, apiKey, compatible, headers } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n try {\n return factories.createOpenAI(baseOpts)\n }\n catch (error) {\n // Fallback to OpenAI-compatible when:\n // - @ai-sdk/openai is not installed (module not found)\n // - User-provided factories don't include openai (ProviderNotAvailableError)\n if (isModuleNotFoundError(error, '@ai-sdk/openai') || error instanceof ProviderNotAvailableError) {\n try {\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n }\n catch (fallbackError) {\n // Only swallow module-not-found errors from the fallback itself\n if (isModuleNotFoundError(fallbackError, '@ai-sdk/openai-compatible') || fallbackError instanceof ProviderNotAvailableError) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai or its openai-compatible fallback. '\n + 'Install @ai-sdk/openai for full OpenAI features, or if using a bundler, '\n + 'provide factories: { openai: createOpenAI }',\n )\n }\n // Non-module-not-found errors from openai-compatible (e.g. config issues) should propagate\n throw fallbackError\n }\n }\n throw error\n }\n case 'anthropic':\n try {\n return factories.createAnthropic(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n case 'gemini':\n try {\n return factories.createGemini(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n case 'openai-compatible':\n try {\n return factories.createOpenAICompatible({ name: configSet, ...baseOpts })\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/openai-compatible')) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai-compatible. '\n + 'If using a bundler, provide factories: { openaiCompatible: createOpenAICompatible }',\n )\n }\n throw error\n }\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Compute a cache key for the given config set.\n *\n * Explicit configs use the raw (uppercased) name, so `foo-bar` and `foo_bar`\n * remain distinct when both are defined in `configs`.\n * Env-var-backed config sets normalize hyphens to underscores, so aliases\n * like `my-api` and `my_api` share one cached provider.\n */\n function getCacheKey(configSet: string, config: ResolvedConfig, effectiveCompatible: string): string {\n if (options.configs?.[configSet]) {\n if (config.nativeRouting) {\n return `config:${configSet.toUpperCase()}:${effectiveCompatible}`\n }\n return `config:${configSet.toUpperCase()}`\n }\n if (config.nativeRouting) {\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}:${effectiveCompatible}`\n }\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}`\n }\n\n /**\n * Get or create a cached provider for the given config set.\n *\n * Returns `ProviderV3` via a safe cast from `ProviderV3Compatible`.\n * This is safe because `ProviderV3` and `ProviderV4` have identical\n * method signatures — only `specificationVersion` and model type brands differ.\n */\n function getProvider(configSet: string, model?: string): ProviderV3 {\n const config = resolveConfig(configSet)\n\n const detectedCompatible = (config.nativeRouting && model)\n ? detectNativeCompatible(model)\n : undefined\n const effectiveCompatible = detectedCompatible ?? config.compatible\n const wasAutoRouted = detectedCompatible != null && detectedCompatible !== config.compatible\n\n const key = getCacheKey(configSet, config, effectiveCompatible)\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const configForProvider = wasAutoRouted\n ? { ...config, compatible: effectiveCompatible }\n : config\n\n try {\n // Safe cast: V3 and V4 providers are structurally identical.\n // The underlying provider may be ProviderV3 or ProviderV4 depending\n // on which SDK version the user has installed.\n const provider = createUnderlying(configSet, configForProvider) as unknown as ProviderV3\n cache.set(key, provider)\n return provider\n }\n catch (error) {\n // When nativeRouting auto-routed to a provider whose SDK is not installed,\n // append a hint so users know they can disable routing to fall back.\n // Only for module-not-found errors — other errors (config issues, SDK bugs)\n // should propagate without misleading nativeRouting context.\n if (wasAutoRouted && error instanceof Error && error.message.includes('[ai-sdk-provider-env]')) {\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n throw new Error(\n `${error.message}`\n + ` (nativeRouting auto-detected this model as ${effectiveCompatible}.`\n + ` Disable with ${prefix}${separator}NATIVE_ROUTING=false to use ${config.compatible} instead.)`,\n { cause: error },\n )\n }\n throw error\n }\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet, model).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n // Prefer textEmbeddingModel if the underlying provider has it (V3).\n if (provider.textEmbeddingModel) {\n return provider.textEmbeddingModel(model)\n }\n // V4 providers removed textEmbeddingModel — fall back to embeddingModel\n // which exists in both V3 and V4 interfaces.\n if (provider.embeddingModel) {\n return provider.embeddingModel(model)\n }\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.\n *\n * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.\n * If the user provided a factory for a given compatible mode, it is used;\n * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).\n */\nfunction buildUserFactories(userFactories: EnvProviderFactories): ProviderFactories {\n function missingFactory(key: string, fnName: string, pkg: string): never {\n throw new Error(\n `[ai-sdk-provider-env] No factory provided for \"${key}\". `\n + `When using the factories option, provide a factory for each compatibility mode you use. `\n + `Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`,\n )\n }\n\n return {\n createOpenAI: (opts) => {\n if (userFactories.openai)\n return userFactories.openai(opts)\n // Signal fallback — createUnderlying will catch this and use openai-compatible\n throw new ProviderNotAvailableError('openai')\n },\n createAnthropic: opts =>\n userFactories.anthropic\n ? userFactories.anthropic(opts)\n : missingFactory('anthropic', 'createAnthropic', '@ai-sdk/anthropic'),\n createGemini: opts =>\n userFactories.gemini\n ? userFactories.gemini(opts)\n : missingFactory('gemini', 'createGoogleGenerativeAI', '@ai-sdk/google'),\n createOpenAICompatible: opts =>\n userFactories.openaiCompatible\n ? userFactories.openaiCompatible(opts)\n : createOpenAICompatibleProvider(opts),\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Config set naming rules:\n * - Names must match `[A-Za-z_][A-Za-z0-9_-]*` (ASCII letters, digits, underscores, hyphens)\n * - Hyphens are normalized to underscores for env var lookup:\n * `my-api/model` → reads `MY_API_API_KEY`, `MY_API_BASE_URL`, etc.\n * - For arbitrary names, use the `configs` option instead\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n *\n * @example Bundler-safe usage with explicit factories\n * ```ts\n * import { createOpenAI } from '@ai-sdk/openai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const provider = envProvider({\n * factories: { openai: createOpenAI },\n * })\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n const factories = options.factories\n ? buildUserFactories(options.factories)\n : defaultFactories\n return createEnvProvider(factories, options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/factories.ts","../src/presets.ts","../src/env-provider.ts"],"sourcesContent":["import type { EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, ProviderV3Compatible } from './types'\n\n/**\n * Check if an error is a \"module not found\" error for a specific package.\n *\n * Handles Node.js (error.code), Bun, and Bun compiled binaries\n * which may throw non-standard error objects.\n */\nexport function isModuleNotFoundError(error: unknown, packageName: string): boolean {\n if (typeof error !== 'object' || error === null)\n return false\n\n const message = 'message' in error && typeof error.message === 'string' ? error.message : ''\n const code = 'code' in error ? (error as Record<string, unknown>).code : undefined\n\n // Only match the module name in the \"Cannot find module/package 'X'\" part,\n // not in the require stack that follows. This prevents false positives when\n // a sub-dependency fails but the parent package appears in the stack trace.\n const isResolutionError = code === 'MODULE_NOT_FOUND'\n || code === 'ERR_MODULE_NOT_FOUND'\n || message.startsWith('Cannot find module')\n || message.startsWith('Cannot find package')\n\n if (!isResolutionError)\n return false\n\n // Extract the quoted module name from \"Cannot find module 'X'\" or \"Cannot find package 'X'\"\n // Handles both single and double quote styles across runtimes.\n const quoted = message.match(/Cannot find (?:module|package) ['\"]([^'\"]+)['\"]/)\n if (quoted)\n return quoted[1] === packageName || quoted[1].startsWith(`${packageName}/`)\n\n // Fallback for non-standard message formats (e.g. some Bun versions):\n // check if the package name appears before any \"Require stack:\" section,\n // with boundary checking to avoid false positives (e.g. @ai-sdk/openai matching @ai-sdk/openai-compatible).\n const requireStackIndex = message.indexOf('\\nRequire stack:')\n const relevantPart = requireStackIndex !== -1 ? message.slice(0, requireStackIndex) : message\n const boundaryPattern = new RegExp(`(?:^|[\\\\s'\"/@])${packageName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?:[\\\\s'\"/@]|$)`)\n return boundaryPattern.test(relevantPart)\n}\n\n/**\n * Create an OpenAI provider.\n *\n * Dynamically requires `@ai-sdk/openai`, so it only needs to be installed when actually used.\n * When not installed, errors propagate to allow fallback to OpenAI-compatible provider.\n */\nexport function createOpenAIProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAI } = require('@ai-sdk/openai')\n return createOpenAI(opts)\n}\n\n/**\n * Create an Anthropic provider.\n *\n * Dynamically requires `@ai-sdk/anthropic`, so it only needs to be installed when actually used.\n * No fallback is available — Anthropic does not support the OpenAI-compatible protocol.\n */\nexport function createAnthropicProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createAnthropic } = require('@ai-sdk/anthropic')\n return createAnthropic(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n}\n\n/**\n * Create a Google Generative AI (Gemini) provider.\n *\n * Dynamically requires `@ai-sdk/google`, so it only needs to be installed when actually used.\n * No fallback is available — Google does not support the OpenAI-compatible protocol.\n */\nexport function createGeminiProvider(opts: EnvProviderFactoryOptions): ProviderV3Compatible {\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { createGoogleGenerativeAI } = require('@ai-sdk/google')\n return createGoogleGenerativeAI(opts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n}\n\n/**\n * Create an OpenAI Compatible provider.\n *\n * `@ai-sdk/openai-compatible` is a regular dependency and always available.\n */\nexport function createOpenAICompatibleProvider(opts: EnvProviderNamedFactoryOptions): ProviderV3Compatible {\n // eslint-disable-next-line ts/no-require-imports\n const { createOpenAICompatible } = require('@ai-sdk/openai-compatible')\n return createOpenAICompatible(opts)\n}\n","import type { PresetConfig } from './types'\n\n/**\n * Built-in preset configurations for common providers.\n *\n * When using a preset, only `{PREFIX}__PRESET` and `{PREFIX}__API_KEY`\n * are required; `BASE_URL` and `COMPATIBLE` are provided by the preset.\n */\nexport const builtinPresets: Record<string, PresetConfig> = {\n // OpenAI\n 'openai': {\n baseURL: 'https://api.openai.com/v1',\n compatible: 'openai',\n },\n\n // Anthropic\n 'anthropic': {\n baseURL: 'https://api.anthropic.com',\n compatible: 'anthropic',\n },\n\n // Google AI Studio (Gemini)\n 'google': {\n baseURL: 'https://generativelanguage.googleapis.com/v1beta',\n compatible: 'gemini',\n },\n\n // DeepSeek\n 'deepseek': {\n baseURL: 'https://api.deepseek.com',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI (GLM series)\n 'zhipu': {\n baseURL: 'https://open.bigmodel.cn/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // Groq\n 'groq': {\n baseURL: 'https://api.groq.com/openai/v1',\n compatible: 'openai-compatible',\n },\n\n // Together AI\n 'together': {\n baseURL: 'https://api.together.xyz/v1',\n compatible: 'openai-compatible',\n },\n\n // Fireworks AI\n 'fireworks': {\n baseURL: 'https://api.fireworks.ai/inference/v1',\n compatible: 'openai-compatible',\n },\n\n // Mistral AI\n 'mistral': {\n baseURL: 'https://api.mistral.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (international)\n 'moonshot': {\n baseURL: 'https://api.moonshot.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Moonshot AI (China mainland)\n 'moonshot-china': {\n baseURL: 'https://api.moonshot.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // Perplexity\n 'perplexity': {\n baseURL: 'https://api.perplexity.ai',\n compatible: 'openai-compatible',\n },\n\n // OpenRouter\n 'openrouter': {\n baseURL: 'https://openrouter.ai/api/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (international)\n 'siliconflow': {\n baseURL: 'https://api.siliconflow.com/v1',\n compatible: 'openai-compatible',\n },\n\n // SiliconFlow (China mainland)\n 'siliconflow-china': {\n baseURL: 'https://api.siliconflow.cn/v1',\n compatible: 'openai-compatible',\n },\n\n // xAI (Grok series)\n 'xai': {\n baseURL: 'https://api.x.ai/v1',\n compatible: 'openai-compatible',\n },\n\n // Zhipu AI International (Z.AI — global endpoint for GLM series)\n 'zai': {\n baseURL: 'https://api.z.ai/api/paas/v4',\n compatible: 'openai-compatible',\n },\n\n // OpenCode Zen (curated multi-model AI gateway)\n 'opencode-zen': {\n baseURL: 'https://opencode.ai/zen/v1',\n compatible: 'openai-compatible',\n nativeRouting: true,\n },\n\n // OpenCode Go (low-cost subscription for open coding models)\n 'opencode-go': {\n baseURL: 'https://opencode.ai/zen/go/v1',\n compatible: 'openai-compatible',\n },\n}\n","import type { ProviderV3 } from '@ai-sdk/provider'\nimport type { EnvProviderFactories, EnvProviderFactoryOptions, EnvProviderNamedFactoryOptions, EnvProviderOptions, ProviderV3Compatible } from './types'\nimport process from 'node:process'\nimport { NoSuchModelError } from '@ai-sdk/provider'\nimport { createAnthropicProvider, createGeminiProvider, createOpenAICompatibleProvider, createOpenAIProvider, isModuleNotFoundError } from './factories'\nimport { builtinPresets } from './presets'\n\n/**\n * Thrown when a provider is not available (factory not provided by user).\n * Used internally to trigger fallback to OpenAI-compatible provider.\n */\nclass ProviderNotAvailableError extends Error {\n constructor(provider: string) {\n super(`Provider \"${provider}\" is not available`)\n this.name = 'ProviderNotAvailableError'\n }\n}\n\n/**\n * Interface for provider factory functions, used for dependency injection.\n *\n * In production, `defaultFactories` delegates to the real SDK implementations.\n * In tests, fake factories can be injected to avoid module mocking.\n *\n * Return types use `ProviderV3Compatible` so that both `ProviderV3`\n * (from `@ai-sdk/provider@3.x`) and `ProviderV4` (`@ai-sdk/provider@4.x`)\n * are accepted.\n */\nexport interface ProviderFactories {\n createOpenAI: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createAnthropic: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createGemini: (opts: EnvProviderFactoryOptions) => ProviderV3Compatible\n createOpenAICompatible: (opts: EnvProviderNamedFactoryOptions) => ProviderV3Compatible\n}\n\n/**\n * Default factories that delegate to the real implementations in `factories.ts`.\n */\nconst defaultFactories: ProviderFactories = {\n createOpenAI: createOpenAIProvider,\n createAnthropic: createAnthropicProvider,\n createGemini: createGeminiProvider,\n createOpenAICompatible: createOpenAICompatibleProvider,\n}\n\n/**\n * Detect the native compatible mode for a model based on its ID prefix.\n *\n * Used by nativeRouting to auto-route model families to their native provider SDKs.\n * Only `claude-*`, `gemini-*`, and `gpt-*` prefixes are matched.\n * Known limitation: `o1-*`, `o3-*`, `chatgpt-*` are NOT matched (use explicit compatible mode).\n *\n * @returns The detected compatible mode, or `undefined` if no match.\n */\nexport function detectNativeCompatible(model: string): 'openai' | 'anthropic' | 'gemini' | undefined {\n if (model.startsWith('claude-'))\n return 'anthropic'\n if (model.startsWith('gemini-'))\n return 'gemini'\n if (model.startsWith('gpt-'))\n return 'openai'\n return undefined\n}\n\n/**\n * Internally resolved configuration with all required fields determined.\n */\ninterface ResolvedConfig {\n baseURL: string\n apiKey: string\n compatible: string\n headers?: Record<string, string>\n providerOptions?: Record<string, unknown>\n nativeRouting?: boolean\n}\n\n/**\n * Testable core implementation that accepts injected provider factories.\n *\n * In tests, call this function directly with fake factories\n * to avoid module mocking entirely.\n */\nexport function createEnvProvider(\n factories: ProviderFactories,\n options: Omit<EnvProviderOptions, 'factories'> = {},\n): ProviderV3 {\n const separator = options.separator ?? '_'\n const defaultFetch = options.defaults?.fetch\n const defaultHeaders = options.defaults?.headers\n\n // Cache created providers to avoid redundant initialization\n // Stored as ProviderV3 via safe cast from ProviderV3Compatible,\n // since V3 and V4 provider interfaces are structurally identical.\n const cache = new Map<string, ProviderV3>()\n\n /**\n * Resolve baseURL and compatible from a preset name.\n */\n function resolvePreset(presetName: string): { baseURL: string, compatible: string, nativeRouting?: boolean } {\n const preset = builtinPresets[presetName]\n if (!preset) {\n const available = Object.keys(builtinPresets).join(', ')\n throw new Error(\n `[ai-sdk-provider-env] Unknown preset \"${presetName}\". Available presets: ${available}`,\n )\n }\n return {\n baseURL: preset.baseURL,\n compatible: preset.compatible ?? 'openai-compatible',\n nativeRouting: preset.nativeRouting,\n }\n }\n\n /**\n * Resolve config set configuration from explicit configs, presets, or environment variables.\n */\n function resolveConfig(configSet: string): ResolvedConfig {\n // Explicit configs take precedence over env vars\n if (options.configs?.[configSet]) {\n const config = options.configs[configSet]\n\n // Code-based configs also support presets\n if (config.preset) {\n const preset = resolvePreset(config.preset)\n return {\n baseURL: config.baseURL ?? preset.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? preset.compatible,\n nativeRouting: config.nativeRouting ?? preset.nativeRouting,\n ...(config.providerOptions && { providerOptions: config.providerOptions }),\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n if (!config.baseURL) {\n throw new Error(\n `[ai-sdk-provider-env] Missing baseURL in config for \"${configSet}\"`\n + ` (or set preset to use a built-in preset)`,\n )\n }\n\n return {\n baseURL: config.baseURL,\n apiKey: config.apiKey,\n compatible: config.compatible ?? 'openai-compatible',\n nativeRouting: config.nativeRouting,\n ...(config.providerOptions && { providerOptions: config.providerOptions }),\n ...(config.headers && { headers: config.headers }),\n }\n }\n\n // --- All checks below apply only to the env-var resolution path ---\n // The configs option (above) bypasses these and accepts arbitrary names/separators.\n\n // Validate separator produces shell-safe env var names (deferred to first env-var use)\n if (!/^\\w+$/.test(separator)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid separator \"${separator}\". `\n + `Separator must only contain ASCII letters, digits, or underscores to produce shell-safe env var names.`,\n )\n }\n\n // Validate config set name (ASCII shell-safe names only)\n if (!/^[A-Z_][\\w-]*$/i.test(configSet)) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid config set name \"${configSet}\". `\n + `Names must start with a letter or underscore, followed by letters, digits, underscores, or hyphens. `\n + `For arbitrary names, use the configs option instead.`,\n )\n }\n\n // Normalize hyphens to underscores for POSIX shell-safe env var names.\n // e.g. \"my-api\" → \"MY_API\", so env vars are MY_API_API_KEY, MY_API_BASE_URL, etc.\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n const env = (key: string): string | undefined => process.env[`${prefix}${separator}${key}`]\n\n const apiKey = env('API_KEY')\n if (!apiKey) {\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}API_KEY`,\n )\n }\n\n // Parse headers from env var (JSON format)\n const headersRaw = env('HEADERS')\n let headers: Record<string, string> | undefined\n if (headersRaw) {\n try {\n headers = JSON.parse(headersRaw)\n }\n catch {\n throw new Error(\n `[ai-sdk-provider-env] Invalid JSON in ${prefix}${separator}HEADERS: ${headersRaw}`,\n )\n }\n }\n\n // Parse NATIVE_ROUTING env var (boolean: 'true'/'false', case-insensitive)\n const nativeRoutingRaw = env('NATIVE_ROUTING')\n let nativeRoutingFromEnv: boolean | undefined\n if (nativeRoutingRaw !== undefined) {\n const lower = nativeRoutingRaw.toLowerCase()\n if (lower === 'true') {\n nativeRoutingFromEnv = true\n }\n else if (lower === 'false') {\n nativeRoutingFromEnv = false\n }\n else {\n throw new Error(\n `[ai-sdk-provider-env] Invalid value for ${prefix}${separator}NATIVE_ROUTING: \"${nativeRoutingRaw}\". `\n + `Expected \"true\" or \"false\".`,\n )\n }\n }\n\n // Check for preset\n const presetName = env('PRESET')\n if (presetName) {\n const preset = resolvePreset(presetName)\n return {\n baseURL: env('BASE_URL') ?? preset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? preset.compatible,\n nativeRouting: nativeRoutingFromEnv ?? preset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n\n // Without a preset, try BASE_URL first\n const baseURL = env('BASE_URL')\n if (baseURL) {\n return {\n baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv,\n ...(headers && { headers }),\n }\n }\n\n // Auto-detect: if configSet name matches a built-in preset, use it automatically\n if (options.presetAutoDetect !== false) {\n const autoPreset = builtinPresets[configSet.toLowerCase()]\n if (autoPreset) {\n return {\n baseURL: autoPreset.baseURL,\n apiKey,\n compatible: env('COMPATIBLE') ?? autoPreset.compatible ?? 'openai-compatible',\n nativeRouting: nativeRoutingFromEnv ?? autoPreset.nativeRouting,\n ...(headers && { headers }),\n }\n }\n }\n\n // Error: neither BASE_URL nor a matching preset found\n const available = Object.keys(builtinPresets).join(', ')\n const presetHint = builtinPresets[configSet.toLowerCase()]\n ? ` (Note: \"${configSet}\" matches a built-in preset, but presetAutoDetect is disabled.)`\n : ''\n throw new Error(\n `[ai-sdk-provider-env] Missing env var ${prefix}${separator}BASE_URL`\n + ` (or set ${prefix}${separator}PRESET to use a preset.`\n + ` Available presets: ${available})${presetHint}`,\n )\n }\n\n /**\n * Create the underlying provider based on the compatibility mode.\n */\n function createUnderlying(configSet: string, config: ResolvedConfig): ProviderV3Compatible {\n const { baseURL, apiKey, compatible, headers, providerOptions } = config\n\n // Merge headers: defaults.headers as base, config-set headers override matching keys\n const mergedHeaders = (defaultHeaders || headers)\n ? { ...defaultHeaders, ...headers }\n : undefined\n\n const baseOpts = {\n ...providerOptions,\n baseURL,\n apiKey,\n ...(mergedHeaders && { headers: mergedHeaders }),\n ...(defaultFetch && { fetch: defaultFetch }),\n }\n\n switch (compatible) {\n case 'openai':\n try {\n return factories.createOpenAI(baseOpts)\n }\n catch (error) {\n // Fallback to OpenAI-compatible when:\n // - @ai-sdk/openai is not installed (module not found)\n // - User-provided factories don't include openai (ProviderNotAvailableError)\n if (isModuleNotFoundError(error, '@ai-sdk/openai') || error instanceof ProviderNotAvailableError) {\n try {\n return factories.createOpenAICompatible({ ...baseOpts, name: configSet })\n }\n catch (fallbackError) {\n // Only swallow module-not-found errors from the fallback itself\n if (isModuleNotFoundError(fallbackError, '@ai-sdk/openai-compatible') || fallbackError instanceof ProviderNotAvailableError) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai or its openai-compatible fallback. '\n + 'Install @ai-sdk/openai for full OpenAI features, or if using a bundler, '\n + 'provide factories: { openai: createOpenAI }',\n )\n }\n // Non-module-not-found errors from openai-compatible (e.g. config issues) should propagate\n throw fallbackError\n }\n }\n throw error\n }\n case 'anthropic':\n try {\n return factories.createAnthropic(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/anthropic')) {\n throw new Error(\n '[ai-sdk-provider-env] Anthropic provider requires @ai-sdk/anthropic. '\n + 'Run: npm install @ai-sdk/anthropic',\n )\n }\n throw error\n }\n case 'gemini':\n try {\n return factories.createGemini(baseOpts)\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/google')) {\n throw new Error(\n '[ai-sdk-provider-env] Google provider requires @ai-sdk/google. '\n + 'Run: npm install @ai-sdk/google',\n )\n }\n throw error\n }\n case 'openai-compatible':\n try {\n return factories.createOpenAICompatible({ ...baseOpts, name: configSet })\n }\n catch (error) {\n if (isModuleNotFoundError(error, '@ai-sdk/openai-compatible')) {\n throw new Error(\n '[ai-sdk-provider-env] Could not load @ai-sdk/openai-compatible. '\n + 'If using a bundler, provide factories: { openaiCompatible: createOpenAICompatible }',\n )\n }\n throw error\n }\n default:\n throw new Error(\n `[ai-sdk-provider-env] Unknown compatible mode \"${compatible}\".`\n + ` Supported values: \"openai\", \"anthropic\", \"gemini\", \"openai-compatible\".`\n + ` Set COMPATIBLE=openai-compatible (or omit it) to use the OpenAI-compatible provider.`,\n )\n }\n }\n\n /**\n * Compute a cache key for the given config set.\n *\n * Explicit configs use the raw (uppercased) name, so `foo-bar` and `foo_bar`\n * remain distinct when both are defined in `configs`.\n * Env-var-backed config sets normalize hyphens to underscores, so aliases\n * like `my-api` and `my_api` share one cached provider.\n */\n function getCacheKey(configSet: string, config: ResolvedConfig, effectiveCompatible: string): string {\n if (options.configs?.[configSet]) {\n if (config.nativeRouting) {\n return `config:${configSet.toUpperCase()}:${effectiveCompatible}`\n }\n return `config:${configSet.toUpperCase()}`\n }\n if (config.nativeRouting) {\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}:${effectiveCompatible}`\n }\n return `env:${configSet.replace(/-/g, '_').toUpperCase()}`\n }\n\n /**\n * Get or create a cached provider for the given config set.\n *\n * Returns `ProviderV3` via a safe cast from `ProviderV3Compatible`.\n * This is safe because `ProviderV3` and `ProviderV4` have identical\n * method signatures — only `specificationVersion` and model type brands differ.\n */\n function getProvider(configSet: string, model?: string): ProviderV3 {\n const config = resolveConfig(configSet)\n\n const detectedCompatible = (config.nativeRouting && model)\n ? detectNativeCompatible(model)\n : undefined\n const effectiveCompatible = detectedCompatible ?? config.compatible\n const wasAutoRouted = detectedCompatible != null && detectedCompatible !== config.compatible\n\n const key = getCacheKey(configSet, config, effectiveCompatible)\n const cached = cache.get(key)\n if (cached)\n return cached\n\n const configForProvider = wasAutoRouted\n ? { ...config, compatible: effectiveCompatible }\n : config\n\n try {\n // Safe cast: V3 and V4 providers are structurally identical.\n // The underlying provider may be ProviderV3 or ProviderV4 depending\n // on which SDK version the user has installed.\n const provider = createUnderlying(configSet, configForProvider) as unknown as ProviderV3\n cache.set(key, provider)\n return provider\n }\n catch (error) {\n // When nativeRouting auto-routed to a provider whose SDK is not installed,\n // append a hint so users know they can disable routing to fall back.\n // Only for module-not-found errors — other errors (config issues, SDK bugs)\n // should propagate without misleading nativeRouting context.\n if (wasAutoRouted && error instanceof Error && error.message.includes('[ai-sdk-provider-env]')) {\n const prefix = configSet.replace(/-/g, '_').toUpperCase()\n throw new Error(\n `${error.message}`\n + ` (nativeRouting auto-detected this model as ${effectiveCompatible}.`\n + ` Disable with ${prefix}${separator}NATIVE_ROUTING=false to use ${config.compatible} instead.)`,\n { cause: error },\n )\n }\n throw error\n }\n }\n\n /**\n * Parse a model ID. The first `/` separates the config set name from the actual model ID.\n */\n function parseModelId(modelId: string): { configSet: string, model: string } {\n const slashIndex = modelId.indexOf('/')\n if (slashIndex === -1) {\n throw new Error(\n `[ai-sdk-provider-env] Invalid model ID \"${modelId}\". `\n + `Expected format: \"{configSet}/{modelId}\", e.g. \"zhipu/glm-4\"`,\n )\n }\n return {\n configSet: modelId.slice(0, slashIndex),\n model: modelId.slice(slashIndex + 1),\n }\n }\n\n return {\n specificationVersion: 'v3' as const,\n\n languageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet, model).languageModel(model)\n },\n\n embeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).embeddingModel(model)\n },\n\n imageModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n return getProvider(configSet).imageModel(model)\n },\n\n textEmbeddingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n // Prefer textEmbeddingModel if the underlying provider has it (V3).\n if (provider.textEmbeddingModel) {\n return provider.textEmbeddingModel(model)\n }\n // V4 providers removed textEmbeddingModel — fall back to embeddingModel\n // which exists in both V3 and V4 interfaces.\n if (provider.embeddingModel) {\n return provider.embeddingModel(model)\n }\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' })\n },\n\n transcriptionModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.transcriptionModel) {\n throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' })\n }\n return provider.transcriptionModel(model)\n },\n\n speechModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.speechModel) {\n throw new NoSuchModelError({ modelId, modelType: 'speechModel' })\n }\n return provider.speechModel(model)\n },\n\n rerankingModel(modelId: string) {\n const { configSet, model } = parseModelId(modelId)\n const provider = getProvider(configSet)\n if (!provider.rerankingModel) {\n throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' })\n }\n return provider.rerankingModel(model)\n },\n }\n}\n\n/**\n * Build internal `ProviderFactories` from user-provided `EnvProviderFactories`.\n *\n * Uses lazy-strict semantics: each factory slot is only evaluated when actually called.\n * If the user provided a factory for a given compatible mode, it is used;\n * otherwise, a clear error is thrown (no silent fallback to dynamic `require()`).\n */\nfunction buildUserFactories(userFactories: EnvProviderFactories): ProviderFactories {\n function missingFactory(key: string, fnName: string, pkg: string): never {\n throw new Error(\n `[ai-sdk-provider-env] No factory provided for \"${key}\". `\n + `When using the factories option, provide a factory for each compatibility mode you use. `\n + `Add: import { ${fnName} } from '${pkg}' and set factories: { ${key}: ${fnName} }`,\n )\n }\n\n return {\n createOpenAI: (opts) => {\n if (userFactories.openai)\n return userFactories.openai(opts)\n // Signal fallback — createUnderlying will catch this and use openai-compatible\n throw new ProviderNotAvailableError('openai')\n },\n createAnthropic: opts =>\n userFactories.anthropic\n ? userFactories.anthropic(opts)\n : missingFactory('anthropic', 'createAnthropic', '@ai-sdk/anthropic'),\n createGemini: opts =>\n userFactories.gemini\n ? userFactories.gemini(opts)\n : missingFactory('gemini', 'createGoogleGenerativeAI', '@ai-sdk/google'),\n createOpenAICompatible: opts =>\n userFactories.openaiCompatible\n ? userFactories.openaiCompatible(opts)\n : createOpenAICompatibleProvider(opts),\n }\n}\n\n/**\n * Create a dynamic, environment-variable-driven AI SDK provider.\n *\n * Automatically resolves provider configurations from env var naming conventions,\n * with built-in preset support for quick setup.\n *\n * Config set naming rules:\n * - Names must match `[A-Za-z_][A-Za-z0-9_-]*` (ASCII letters, digits, underscores, hyphens)\n * - Hyphens are normalized to underscores for env var lookup:\n * `my-api/model` → reads `MY_API_API_KEY`, `MY_API_BASE_URL`, etc.\n * - For arbitrary names, use the `configs` option instead\n *\n * Env var convention (using config set `ZHIPU` with default separator `_` as example):\n * - `ZHIPU_PRESET` — use a built-in preset (BASE_URL and COMPATIBLE become optional)\n * - `ZHIPU_BASE_URL` — API base URL\n * - `ZHIPU_API_KEY` — API key (required)\n * - `ZHIPU_COMPATIBLE` — compatibility mode (defaults to `'openai-compatible'`)\n * - `ZHIPU_HEADERS` — custom HTTP headers (JSON format)\n *\n * @example\n * ```ts\n * import { createProviderRegistry } from 'ai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const registry = createProviderRegistry({\n * env: envProvider(),\n * })\n *\n * // Use a preset (only API_KEY is required)\n * // DEEPSEEK_PRESET=deepseek\n * // DEEPSEEK_API_KEY=sk-xxx\n * const model = registry.languageModel('env:deepseek/deepseek-chat')\n *\n * // Specify all parameters manually\n * // MYAPI_BASE_URL=https://api.example.com/v1\n * // MYAPI_API_KEY=xxx\n * const model2 = registry.languageModel('env:myapi/some-model')\n * ```\n *\n * @example Bundler-safe usage with explicit factories\n * ```ts\n * import { createOpenAI } from '@ai-sdk/openai'\n * import { envProvider } from 'ai-sdk-provider-env'\n *\n * const provider = envProvider({\n * factories: { openai: createOpenAI },\n * })\n * ```\n */\nexport function envProvider(options: EnvProviderOptions = {}): ProviderV3 {\n const factories = options.factories\n ? buildUserFactories(options.factories)\n : defaultFactories\n return createEnvProvider(factories, options)\n}\n"],"mappings":"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"}
|
package/llms.txt
CHANGED
|
@@ -75,6 +75,7 @@ interface ConfigSetEntry {
|
|
|
75
75
|
baseURL?: string // optional when preset is set
|
|
76
76
|
compatible?: 'openai' | 'anthropic' | 'gemini' | 'openai-compatible'
|
|
77
77
|
headers?: Record<string, string>
|
|
78
|
+
providerOptions?: Record<string, unknown> // extra options passed through to the underlying SDK factory
|
|
78
79
|
nativeRouting?: boolean // enable native SDK routing per model prefix
|
|
79
80
|
}
|
|
80
81
|
```
|
|
@@ -134,11 +135,14 @@ const provider = envProvider({
|
|
|
134
135
|
apiKey: 'key',
|
|
135
136
|
baseURL: 'https://custom.api.com/v1',
|
|
136
137
|
compatible: 'openai-compatible',
|
|
138
|
+
providerOptions: { supportsStructuredOutputs: true },
|
|
137
139
|
},
|
|
138
140
|
},
|
|
139
141
|
})
|
|
140
142
|
```
|
|
141
143
|
|
|
144
|
+
Use `providerOptions` to pass any SDK-specific option (e.g. `supportsStructuredOutputs`) directly to the underlying provider factory.
|
|
145
|
+
|
|
142
146
|
### Provider registry
|
|
143
147
|
```ts
|
|
144
148
|
import { createProviderRegistry } from 'ai'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-sdk-provider-env",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"description": "A dynamic, environment-variable-driven provider for Vercel AI SDK — resolves provider configurations from env var conventions at runtime",
|
|
6
6
|
"author": "maou-shonen",
|
|
7
7
|
"license": "MIT",
|