ai-sdk-provider-env 0.2.0 → 0.4.0

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/README.md CHANGED
@@ -1,60 +1,38 @@
1
- > [中文](./README_zh.md)
1
+ > [For AI agent (llms.txt)](./llms.txt) | [中文](./README_zh.md)
2
2
 
3
3
  # ai-sdk-provider-env
4
4
 
5
- A dynamic, environment-variable-driven provider for [Vercel AI SDK](https://sdk.vercel.ai/). Resolves AI provider configuration from env var conventions at runtime, so you can switch models without touching code.
5
+ Environment-variable-driven provider for [Vercel AI SDK](https://sdk.vercel.ai/). Switch AI providers and models without code changes.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/ai-sdk-provider-env)](https://www.npmjs.com/package/ai-sdk-provider-env)
8
8
  [![license](https://img.shields.io/npm/l/ai-sdk-provider-env)](./LICENSE)
9
9
 
10
- ## Motivation
11
-
12
- Using multiple AI providers with Vercel AI SDK means importing each SDK, configuring API keys and base URLs, and wiring everything together — per provider, per project. Switching providers requires code changes.
13
-
14
- `ai-sdk-provider-env` eliminates this boilerplate. Define provider configurations through environment variables, resolve them at runtime. Add a new provider by setting env vars, switch models by changing a string — no code changes needed.
15
-
16
- ## Features
17
-
18
- - Resolve provider config (base URL, API key, compatibility mode) from environment variables automatically
19
- - Built-in presets for popular providers, so you only need to set an API key
20
- - Supports OpenAI, Anthropic, Google Gemini, and any OpenAI-compatible API
21
- - Implements `ProviderV3`, plugs directly into `createProviderRegistry`
22
- - Provider instances are cached, no redundant initialization
23
- - Fully customizable: custom fetch, env-based headers, custom separator, code-based configs
24
-
25
- ## Installation
10
+ ## Quick Start
26
11
 
27
12
  ```bash
28
13
  pnpm add ai-sdk-provider-env
29
14
  ```
30
15
 
31
- Install provider SDKs as needed:
32
-
33
16
  ```bash
34
- pnpm add @ai-sdk/openai # for OpenAI
35
- pnpm add @ai-sdk/anthropic # for Anthropic
36
- pnpm add @ai-sdk/google # for Google AI Studio (Gemini)
37
- pnpm add @ai-sdk/openai-compatible # for generic OpenAI-compatible APIs
17
+ # .env
18
+ OPENAI_API_KEY=sk-xxx
38
19
  ```
39
20
 
40
- ## Quick Start
41
-
42
21
  ```ts
43
- import { createProviderRegistry, generateText } from 'ai'
22
+ import { generateText } from 'ai'
44
23
  import { envProvider } from 'ai-sdk-provider-env'
45
24
 
46
- const registry = createProviderRegistry({
47
- env: envProvider(),
48
- })
49
-
50
- // Use a preset: only API_KEY is required
51
- // OPENAI_API_KEY=sk-xxx (OPENAI_PRESET=openai is optional — auto-detected)
52
- const model = registry.languageModel('env:openai/gpt-4o')
25
+ const provider = envProvider()
53
26
 
54
- const { text } = await generateText({ model, prompt: 'Hello!' })
27
+ const { text } = await generateText({
28
+ model: provider.languageModel('openai/gpt-4o'),
29
+ prompt: 'Hello!',
30
+ })
55
31
  ```
56
32
 
57
- Any env var prefix is a config set. Two endpoints? Two prefixes, zero code changes:
33
+ The config set name `openai` auto-matches the built-in preset only an API key is needed.
34
+
35
+ Any [valid](#environment-variables) env var prefix becomes a config set. Two endpoints, zero code changes:
58
36
 
59
37
  ```bash
60
38
  # .env
@@ -66,235 +44,86 @@ SMART_API_KEY=key-smart
66
44
  ```
67
45
 
68
46
  ```ts
69
- const draft = await generateText({
70
- model: registry.languageModel('env:fast/llama-3-8b'),
71
- prompt: 'Write a story',
72
- })
73
-
74
- const review = await generateText({
75
- model: registry.languageModel('env:smart/gpt-4o'),
76
- prompt: `Review this: ${draft.text}`,
77
- })
47
+ provider.languageModel('fast/llama-3-8b')
48
+ provider.languageModel('smart/gpt-4o')
78
49
  ```
79
50
 
80
- ## Environment Variable Convention
51
+ ## Environment Variables
81
52
 
82
- The model ID format is `{configSet}/{modelId}`. The config set name maps to an env var prefix (uppercased).
83
-
84
- With the default separator `_`, a config set reads these variables (`[MYAI]` = your config set name, uppercased):
85
-
86
- | Variable | Required | Description |
87
- |---|---|---|
88
- | `[MYAI]_API_KEY` | Yes | API key |
89
- | `[MYAI]_BASE_URL` | Yes (unless preset is set or auto-detected) | API base URL |
90
- | `[MYAI]_PRESET` | No | Built-in preset name (e.g. `openai`) |
91
- | `[MYAI]_COMPATIBLE` | No | Compatibility mode (default: `openai-compatible`) |
92
- | `[MYAI]_HEADERS` | No | Custom HTTP headers (JSON format) |
53
+ Model ID format: `{configSet}/{modelId}`. The config set maps to an uppercased env var prefix.
93
54
 
94
- When `PRESET` is set, `BASE_URL` and `COMPATIBLE` become optional and fall back to the preset's values.
95
-
96
- **Compatibility modes:**
97
-
98
- | Value | Behavior |
99
- |---|---|
100
- | `openai` | Uses `@ai-sdk/openai` |
101
- | `anthropic` | Uses `@ai-sdk/anthropic` |
102
- | `gemini` | Uses `@ai-sdk/google` |
103
- | `openai-compatible` | Uses `@ai-sdk/openai-compatible` with the config set name as the provider name (default) |
104
-
105
- ## Built-in Presets
106
-
107
- | Preset name | Base URL | Compatible |
108
- |---|---|---|
109
- | `openai` | `https://api.openai.com/v1` | `openai` |
110
- | `anthropic` | `https://api.anthropic.com` | `anthropic` |
111
- | `google` | `https://generativelanguage.googleapis.com/v1beta` | `gemini` |
112
- | `deepseek` | `https://api.deepseek.com` | `openai-compatible` |
113
- | `zhipu` | `https://open.bigmodel.cn/api/paas/v4` | `openai-compatible` |
114
- | `groq` | `https://api.groq.com/openai/v1` | `openai-compatible` |
115
- | `together` | `https://api.together.xyz/v1` | `openai-compatible` |
116
- | `fireworks` | `https://api.fireworks.ai/inference/v1` | `openai-compatible` |
117
- | `mistral` | `https://api.mistral.ai/v1` | `openai-compatible` |
118
- | `moonshot` | `https://api.moonshot.cn/v1` | `openai-compatible` |
119
- | `perplexity` | `https://api.perplexity.ai` | `openai-compatible` |
120
- | `openrouter` | `https://openrouter.ai/api/v1` | `openai-compatible` |
121
- | `siliconflow` | `https://api.siliconflow.cn/v1` | `openai-compatible` |
122
-
123
- ## Preset Auto-Detect
124
-
125
- `presetAutoDetect` is enabled by default. When the config set name exactly matches a built-in preset name, the preset is applied automatically — no `_PRESET` env var needed. Only an API key is required:
55
+ Config set names must match `[A-Za-z_][A-Za-z0-9_-]*` ASCII letters, digits, underscores, and hyphens. **Hyphens are automatically normalized to underscores** for env var lookup:
126
56
 
127
57
  ```bash
128
- # OPENROUTER_API_KEY is all you need
129
- OPENROUTER_API_KEY=sk-or-xxx
130
- ```
131
-
132
- ```ts
133
- const provider = envProvider()
134
-
135
- // Works — openrouter preset auto-detected from config set name
136
- const model = provider.languageModel('openrouter/some-model')
58
+ # Config set "my-api" reads MY_API_* env vars
59
+ MY_API_BASE_URL=https://api.example.com/v1
60
+ MY_API_API_KEY=sk-xxx
137
61
  ```
138
62
 
139
- Explicit `_PRESET` and `_BASE_URL` env vars always take precedence over auto-detect. To disable this behavior:
140
-
141
63
  ```ts
142
- envProvider({ presetAutoDetect: false })
64
+ provider.languageModel('my-api/some-model') // reads MY_API_* env vars
65
+ provider.languageModel('my_api/some-model') // same env vars
143
66
  ```
144
67
 
145
- ## API Reference
146
-
147
- ### `envProvider(options?)`
148
-
149
- Returns a `ProviderV3` instance.
150
-
151
- ```ts
152
- import { envProvider } from 'ai-sdk-provider-env'
153
-
154
- const provider = envProvider(options)
155
- ```
156
-
157
- **Options** (`EnvProviderOptions`):
158
-
159
- | Option | Type | Default | Description |
160
- |---|---|---|---|
161
- | `separator` | `string` | `'_'` | Separator between the prefix and the variable name |
162
- | `configs` | `Record<string, ConfigSetEntry>` | `undefined` | Explicit config sets (takes precedence over env vars) |
163
- | `defaults` | `EnvProviderDefaults` | `undefined` | Global defaults applied to all providers (can be overridden per config set) |
164
- | `presetAutoDetect` | `boolean` | `true` | Auto-apply a built-in preset when the config set name matches. Set to `false` to require explicit `_PRESET` configuration. |
165
-
166
- **`EnvProviderDefaults`:**
167
-
168
- | Option | Type | Default | Description |
169
- |---|---|---|---|
170
- | `fetch` | `typeof globalThis.fetch` | `undefined` | Custom fetch implementation passed to all created providers |
171
- | `headers` | `Record<string, string>` | `undefined` | Default HTTP headers for all providers (overridden by config-set headers) |
172
-
173
- **`ConfigSetEntry`:**
68
+ > For config set names outside these rules (e.g. Unicode, dots), use the [`configs` option](./docs/advanced.md#code-based-configs) instead.
174
69
 
175
- ```ts
176
- interface ConfigSetEntry {
177
- apiKey: string
178
- preset?: string
179
- baseURL?: string
180
- compatible?: 'openai' | 'anthropic' | 'gemini' | 'openai-compatible' // default: 'openai-compatible'
181
- headers?: Record<string, string>
182
- }
183
- ```
184
-
185
- **Model ID format:**
186
-
187
- ```
188
- {configSet}/{modelId}
189
- ```
190
-
191
- Examples: `openai/gpt-4o`, `anthropic/claude-sonnet-4-20250514`, `myapi/some-model`.
192
-
193
- ## Advanced Usage
194
-
195
- ### Custom separator
196
-
197
- If single underscores conflict with your naming scheme, use double underscores or any other string:
198
-
199
- ```ts
200
- const provider = envProvider({ separator: '__' })
201
-
202
- // Now reads: OPENAI__BASE_URL, OPENAI__API_KEY, OPENAI__PRESET, OPENAI__COMPATIBLE
203
- ```
204
-
205
- ### Code-based configs
206
-
207
- Skip env vars entirely and pass config directly. This takes the highest precedence:
208
-
209
- ```ts
210
- const provider = envProvider({
211
- configs: {
212
- openai: {
213
- baseURL: 'https://api.openai.com/v1',
214
- apiKey: process.env.OPENAI_KEY!,
215
- compatible: 'openai',
216
- },
217
- claude: {
218
- baseURL: 'https://api.anthropic.com',
219
- apiKey: process.env.ANTHROPIC_KEY!,
220
- compatible: 'anthropic',
221
- },
222
- deepseek: {
223
- preset: 'deepseek',
224
- apiKey: process.env.DEEPSEEK_KEY!,
225
- },
226
- },
227
- })
228
-
229
- const model = provider.languageModel('openai/gpt-4o')
230
- ```
231
-
232
- ### Custom fetch
233
-
234
- Pass a custom fetch implementation to all providers. Useful for proxies, logging, or test mocks:
70
+ | Variable | Required | Description |
71
+ |---|---|---|
72
+ | `{PREFIX}_API_KEY` | Yes | API key |
73
+ | `{PREFIX}_BASE_URL` | Unless preset matches | API base URL |
74
+ | `{PREFIX}_PRESET` | No | Built-in preset name (e.g. `openai`) |
75
+ | `{PREFIX}_COMPATIBLE` | No | `openai` · `anthropic` · `gemini` · `openai-compatible` (default) |
76
+ | `{PREFIX}_HEADERS` | No | Custom HTTP headers (JSON) |
235
77
 
236
- ```ts
237
- const provider = envProvider({ defaults: { fetch: myCustomFetch } })
238
- ```
78
+ When `_PRESET` is set or [auto-detected](#built-in-presets), `_BASE_URL` and `_COMPATIBLE` fall back to preset defaults.
239
79
 
240
- ### Default headers
80
+ ### Compatibility modes
241
81
 
242
- Set HTTP headers that apply to all providers. Per-config-set headers (from env vars or code configs) override defaults with the same key:
82
+ | Value | SDK | Fallback |
83
+ |---|---|---|
84
+ | `openai` | `@ai-sdk/openai` | `@ai-sdk/openai-compatible` if not installed |
85
+ | `anthropic` | `@ai-sdk/anthropic` | None |
86
+ | `gemini` | `@ai-sdk/google` | None |
87
+ | `openai-compatible` | `@ai-sdk/openai-compatible` (default) | — |
243
88
 
244
- ```ts
245
- const provider = envProvider({
246
- defaults: {
247
- headers: { 'X-App-Name': 'my-app', 'X-Request-Source': 'server' },
248
- },
249
- })
250
- ```
89
+ Install provider SDKs as needed: `pnpm add @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google`
251
90
 
252
- ### Custom headers via env vars
91
+ ## Built-in Presets
253
92
 
254
- Set per-config-set HTTP headers using the `HEADERS` env var. The value must be valid JSON:
93
+ When the config set name matches a preset, it auto-applies only `_API_KEY` is needed:
255
94
 
256
95
  ```bash
257
- OPENAI_HEADERS={"X-Custom":"value","X-Request-Source":"my-app"}
96
+ DEEPSEEK_API_KEY=sk-xxx # config set "deepseek" matches the preset
258
97
  ```
259
98
 
260
- These headers are merged into every request made by that config set's provider. When combined with `defaults.headers`, config-set headers take precedence for the same key.
261
-
262
- ### Using with `createProviderRegistry`
263
-
264
- `envProvider()` implements `ProviderV3`, so it works directly with `createProviderRegistry`:
265
-
266
99
  ```ts
267
- import { createProviderRegistry, generateText } from 'ai'
268
- import { envProvider } from 'ai-sdk-provider-env'
269
-
270
- const registry = createProviderRegistry({
271
- env: envProvider(),
272
- })
273
-
274
- // Language model
275
- const model = registry.languageModel('env:openai/gpt-4o')
276
-
277
- // Embedding model
278
- const embedder = registry.embeddingModel('env:openai/text-embedding-3-small')
279
-
280
- // Image model
281
- const imageModel = registry.imageModel('env:openai/dall-e-3')
282
-
283
- const { text } = await generateText({
284
- model,
285
- prompt: 'Hello!',
286
- })
100
+ provider.languageModel('deepseek/deepseek-chat') // just works
287
101
  ```
288
102
 
289
- The model ID format inside the registry is `{registryKey}:{configSet}/{modelId}`. With the setup above, `env:openai/gpt-4o` means config set `openai`, model `gpt-4o`.
103
+ | Preset | Base URL | Compatible |
104
+ |---|---|---|
105
+ | `openai` | `https://api.openai.com/v1` | `openai` |
106
+ | `anthropic` | `https://api.anthropic.com` | `anthropic` |
107
+ | `google` | `https://generativelanguage.googleapis.com/v1beta` | `gemini` |
108
+ | `deepseek` | `https://api.deepseek.com` | `openai-compatible` |
109
+ | `groq` | `https://api.groq.com/openai/v1` | `openai-compatible` |
110
+ | `together` | `https://api.together.xyz/v1` | `openai-compatible` |
111
+ | `fireworks` | `https://api.fireworks.ai/inference/v1` | `openai-compatible` |
112
+ | `mistral` | `https://api.mistral.ai/v1` | `openai-compatible` |
113
+ | `moonshot` | `https://api.moonshot.ai/v1` | `openai-compatible` |
114
+ | `moonshot-china` | `https://api.moonshot.cn/v1` | `openai-compatible` |
115
+ | `perplexity` | `https://api.perplexity.ai` | `openai-compatible` |
116
+ | `openrouter` | `https://openrouter.ai/api/v1` | `openai-compatible` |
117
+ | `siliconflow` | `https://api.siliconflow.com/v1` | `openai-compatible` |
118
+ | `siliconflow-china` | `https://api.siliconflow.cn/v1` | `openai-compatible` |
119
+ | `xai` | `https://api.x.ai/v1` | `openai-compatible` |
120
+ | `zai` | `https://api.z.ai/api/paas/v4` | `openai-compatible` |
121
+ | `zhipu` | `https://open.bigmodel.cn/api/paas/v4` | `openai-compatible` |
290
122
 
291
- You can also mount multiple providers side by side:
123
+ To disable auto-detection: `envProvider({ presetAutoDetect: false })`. See [Advanced Usage](./docs/advanced.md#preset-auto-detect) for details.
292
124
 
293
- ```ts
294
- import { createOpenAI } from '@ai-sdk/openai'
125
+ ## Documentation
295
126
 
296
- const registry = createProviderRegistry({
297
- env: envProvider(),
298
- openai: createOpenAI({ apiKey: process.env.OPENAI_API_KEY }),
299
- })
300
- ```
127
+ - **[API Reference](./docs/api-reference.md)** — `envProvider()` options, types, model ID format
128
+ - **[Advanced Usage](./docs/advanced.md)** — Code-based configs, custom fetch/headers, custom separator, provider registry
129
+ - **[Bundler Usage](./docs/bundler.md)** For `bun build`, `vite build`, and other bundlers