@jecruz/merc-ai 0.1.4 → 0.2.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 +34 -7
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +1 -1
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.generated.d.ts +345 -0
- package/dist/image-models.generated.d.ts.map +1 -1
- package/dist/image-models.generated.js +348 -3
- package/dist/image-models.generated.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts +15282 -3882
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +18368 -10964
- package/dist/models.generated.js.map +1 -1
- package/dist/models.js +4 -1
- package/dist/models.js.map +1 -1
- package/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.js +188 -19
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +101 -34
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/azure-openai-responses.d.ts +2 -0
- package/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.js +8 -3
- package/dist/providers/azure-openai-responses.js.map +1 -1
- package/dist/providers/google-shared.d.ts +15 -4
- package/dist/providers/google-shared.d.ts.map +1 -1
- package/dist/providers/google-shared.js +80 -15
- package/dist/providers/google-shared.js.map +1 -1
- package/dist/providers/google-vertex.d.ts.map +1 -1
- package/dist/providers/google-vertex.js +23 -60
- package/dist/providers/google-vertex.js.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +19 -68
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/mistral.d.ts +1 -1
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/mistral.js +44 -60
- package/dist/providers/mistral.js.map +1 -1
- package/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/dist/providers/openai-codex-responses.js +250 -124
- package/dist/providers/openai-codex-responses.js.map +1 -1
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +94 -46
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/providers/openai-prompt-cache.d.ts +3 -0
- package/dist/providers/openai-prompt-cache.d.ts.map +1 -0
- package/dist/providers/openai-prompt-cache.js +10 -0
- package/dist/providers/openai-prompt-cache.js.map +1 -0
- package/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/dist/providers/openai-responses-shared.js +154 -211
- package/dist/providers/openai-responses-shared.js.map +1 -1
- package/dist/providers/openai-responses.d.ts.map +1 -1
- package/dist/providers/openai-responses.js +15 -9
- package/dist/providers/openai-responses.js.map +1 -1
- package/dist/providers/openrouter-images.d.ts.map +1 -1
- package/dist/providers/openrouter-images.js +5 -2
- package/dist/providers/openrouter-images.js.map +1 -1
- package/dist/providers/simple-options.d.ts +15 -3
- package/dist/providers/simple-options.d.ts.map +1 -1
- package/dist/providers/simple-options.js +36 -4
- package/dist/providers/simple-options.js.map +1 -1
- package/dist/types.d.ts +35 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/error-body.d.ts +5 -0
- package/dist/utils/error-body.d.ts.map +1 -1
- package/dist/utils/error-body.js +53 -5
- package/dist/utils/error-body.js.map +1 -1
- package/dist/utils/estimate.d.ts +22 -0
- package/dist/utils/estimate.d.ts.map +1 -0
- package/dist/utils/estimate.js +104 -0
- package/dist/utils/estimate.js.map +1 -0
- package/dist/utils/event-stream.d.ts.map +1 -1
- package/dist/utils/event-stream.js +25 -7
- package/dist/utils/event-stream.js.map +1 -1
- package/dist/utils/json-parse.d.ts +3 -0
- package/dist/utils/json-parse.d.ts.map +1 -1
- package/dist/utils/json-parse.js +15 -0
- package/dist/utils/json-parse.js.map +1 -1
- package/dist/utils/oauth/anthropic.d.ts.map +1 -1
- package/dist/utils/oauth/anthropic.js +16 -10
- package/dist/utils/oauth/anthropic.js.map +1 -1
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/dist/utils/oauth/github-copilot.js +57 -21
- package/dist/utils/oauth/github-copilot.js.map +1 -1
- package/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/dist/utils/oauth/openai-codex.js +73 -16
- package/dist/utils/oauth/openai-codex.js.map +1 -1
- package/dist/utils/oauth/types.d.ts +2 -0
- package/dist/utils/oauth/types.d.ts.map +1 -1
- package/dist/utils/oauth/types.js.map +1 -1
- package/dist/utils/overflow.d.ts +10 -1
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js +47 -7
- package/dist/utils/overflow.js.map +1 -1
- package/dist/utils/provider-env.d.ts.map +1 -1
- package/dist/utils/provider-env.js +45 -10
- package/dist/utils/provider-env.js.map +1 -1
- package/dist/utils/tool-call-id.d.ts +11 -0
- package/dist/utils/tool-call-id.d.ts.map +1 -0
- package/dist/utils/tool-call-id.js +96 -0
- package/dist/utils/tool-call-id.js.map +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +9 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -4,6 +4,12 @@ Unified LLM API with automatic model discovery, provider configuration, token an
|
|
|
4
4
|
|
|
5
5
|
**Note**: This library only includes models that support tool calling (function calling), as this is essential for agentic workflows.
|
|
6
6
|
|
|
7
|
+
Simple provider requests reserve shared context safety headroom and reject a clamped output allowance below `min(256, requested maxTokens)` with `OutputTokenBudgetError` before dispatch. Unknown context windows (`<= 0`) retain their previous behavior. Coding-agent sessions attempt guarded compaction before surfacing this error.
|
|
8
|
+
|
|
9
|
+
Context estimation uses the larger of the latest assistant usage plus trailing messages and a fresh estimate of all current messages, system instructions and tool schemas. A larger current prefix therefore cannot be hidden by an older usage report. Usage-source metadata remains available independently of this conservative total.
|
|
10
|
+
|
|
11
|
+
Provider failures may include `AssistantMessage.errorMetadata`, containing only bounded `code` and `type` identifiers for retry decisions, separate from `errorMessage`. `isDeterministicProviderError()` recognizes known request failures that require explicit retry.
|
|
12
|
+
|
|
7
13
|
## Table of Contents
|
|
8
14
|
|
|
9
15
|
- [Supported Providers](#supported-providers)
|
|
@@ -52,6 +58,8 @@ Unified LLM API with automatic model discovery, provider configuration, token an
|
|
|
52
58
|
|
|
53
59
|
## Supported Providers
|
|
54
60
|
|
|
61
|
+
Catalog generation preserves explicit DeepSeek effort levels from OpenRouter and models.dev for OpenCode Go V4.1 Flash. When those sources advertise `low`/`high`/`max`, those exact levels remain selectable; legacy fallback mappings apply only when effort metadata is absent. For mandatory OpenRouter reasoning without advertised efforts, the legacy mapping is applied first and only `off` is then forbidden. Generator changes take effect at the next catalog refresh, not by editing `models.generated.ts` manually.
|
|
62
|
+
|
|
55
63
|
- **OpenAI**
|
|
56
64
|
- **Azure OpenAI (Responses)**
|
|
57
65
|
- **OpenAI Codex** (ChatGPT Plus/Pro subscription, requires OAuth, see below)
|
|
@@ -76,7 +84,7 @@ Unified LLM API with automatic model discovery, provider configuration, token an
|
|
|
76
84
|
- **OpenCode Go**
|
|
77
85
|
- **Fireworks** (uses Anthropic-compatible API)
|
|
78
86
|
- **Kimi For Coding** (Moonshot AI, uses Anthropic-compatible API)
|
|
79
|
-
- **Xiaomi MiMo** (uses
|
|
87
|
+
- **Xiaomi MiMo** (uses OpenAI-compatible API; defaults to API billing endpoint, with separate Token Plan providers for `cn`/`ams`/`sgp` regions)
|
|
80
88
|
- **Any OpenAI-compatible API**: Ollama, vLLM, LM Studio, etc.
|
|
81
89
|
|
|
82
90
|
## Installation
|
|
@@ -319,7 +327,7 @@ for await (const event of s) {
|
|
|
319
327
|
}
|
|
320
328
|
|
|
321
329
|
if (event.type === 'toolcall_end') {
|
|
322
|
-
//
|
|
330
|
+
// Completed arguments must pass validateToolCall before execution
|
|
323
331
|
const toolCall = event.toolCall;
|
|
324
332
|
console.log(`Tool completed: ${toolCall.name}`, toolCall.arguments);
|
|
325
333
|
}
|
|
@@ -333,12 +341,17 @@ for await (const event of s) {
|
|
|
333
341
|
- Arrays may be incomplete
|
|
334
342
|
- Nested objects may be partially populated
|
|
335
343
|
- At minimum, `arguments` will be an empty object `{}`, never `undefined`
|
|
344
|
+
- Completed raw JSON must be a valid JSON object. Malformed input sets `argumentsError` and clears `arguments`; `validateToolCall` and `validateToolArguments` reject it before schema coercion. `finalizeToolCallArguments` provides this boundary for custom streaming adapters. Partial-JSON repair is for previews only. Anthropic preserves its structured initial `input` when no JSON text arrives (including empty deltas); input from a repaired SSE envelope is rejected. Chat, Responses, Mistral and Bedrock reject empty completed argument text; no-parameter tools can provide `{}`.
|
|
336
345
|
- The Google provider does not support function call streaming. Instead, you will receive a single `toolcall_delta` event with the full arguments.
|
|
337
346
|
|
|
338
347
|
### Validating Tool Arguments
|
|
339
348
|
|
|
349
|
+
`createProviderToolCallIdNormalizer(model)` creates the provider replay-ID transformation; reuse one instance per request for Mistral collision tracking. `normalizeResponsesToolCallId(id, source, target)` handles Responses correlation/item identities, including foreign item hashes and valid fallbacks for empty components.
|
|
350
|
+
|
|
340
351
|
When using `agentLoop`, tool arguments are automatically validated against your TypeBox schemas before execution. If validation fails, the error is returned to the model as a tool result, allowing it to retry.
|
|
341
352
|
|
|
353
|
+
Malformed completed JSON also becomes a tool error. Argument preparation, preflight hooks and execution are skipped for that call.
|
|
354
|
+
|
|
342
355
|
When implementing your own tool execution loop with `stream()` or `complete()`, use `validateToolCall` to validate arguments before passing them to your tools:
|
|
343
356
|
|
|
344
357
|
```typescript
|
|
@@ -373,6 +386,11 @@ for await (const event of s) {
|
|
|
373
386
|
|
|
374
387
|
### Complete Event Reference
|
|
375
388
|
|
|
389
|
+
Buffered events and waiting consumers use an amortized O(1) FIFO queue, so draining
|
|
390
|
+
large backlogs does not repeatedly shift the remaining buffer. Event ordering,
|
|
391
|
+
terminal results, and image-stream behavior are unchanged. Buffering remains
|
|
392
|
+
unbounded; this optimization does not add backpressure or drop events.
|
|
393
|
+
|
|
376
394
|
All streaming events emitted during assistant message generation:
|
|
377
395
|
|
|
378
396
|
| Event Type | Description | Key Properties |
|
|
@@ -552,7 +570,7 @@ import { getModel, streamSimple, completeSimple } from '@jecruz/merc-ai';
|
|
|
552
570
|
const model = getModel('anthropic', 'claude-sonnet-4-20250514');
|
|
553
571
|
// or getModel('openai', 'gpt-5-mini');
|
|
554
572
|
// or getModel('google', 'gemini-2.5-flash');
|
|
555
|
-
// or getModel('xai', 'grok-
|
|
573
|
+
// or getModel('xai', 'grok-4.5');
|
|
556
574
|
// or getModel('groq', 'openai/gpt-oss-20b');
|
|
557
575
|
// or getModel('cerebras', 'gpt-oss-120b');
|
|
558
576
|
// or getModel('openrouter', 'z-ai/glm-4.5v');
|
|
@@ -943,6 +961,10 @@ Some OpenAI-compatible servers do not understand the `developer` role used for r
|
|
|
943
961
|
|
|
944
962
|
Use model-level `thinkingLevelMap` to describe model-specific thinking controls. Keys are pi thinking levels (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`). Missing standard levels through `high` use provider defaults; `xhigh` and `max` are opt-in and require an explicit map entry. String values are sent to the provider, and `null` marks a level unsupported.
|
|
945
963
|
|
|
964
|
+
Mistral models with catalog effort metadata use `reasoning_effort` and expose only those supported levels. Thinking off sends `none` when the map explicitly supports it. GLM-5.2 offers off/high/max; GLM-5.3 offers low/high/max without off. The current Magistral Medium latest catalog also maps none/high; unmapped reasoning models still use `prompt_mode` when thinking is enabled.
|
|
965
|
+
|
|
966
|
+
The interactive catalog excludes Vercel AI Gateway model IDs ending in `-batch`, even if their feed tags include tool use. This provider-scoped suffix rule reserves delayed-processing variants for a separate batch client, not Merc's streaming tool loop. Other providers and IDs containing `batch` elsewhere are unaffected. See [Vercel's batch-processing contract](https://vercel.com/docs/ai-gateway/models-and-providers/batch-processing).
|
|
967
|
+
|
|
946
968
|
This commonly applies to Ollama, vLLM, SGLang, and similar OpenAI-compatible servers. You can set `compat` at the provider level or per model.
|
|
947
969
|
|
|
948
970
|
```typescript
|
|
@@ -981,8 +1003,10 @@ interface OpenAICompletionsCompat {
|
|
|
981
1003
|
supportsDeveloperRole?: boolean; // Whether provider supports `developer` role vs `system` (default: true)
|
|
982
1004
|
supportsReasoningEffort?: boolean; // Whether provider supports `reasoning_effort` (default: true)
|
|
983
1005
|
supportsUsageInStreaming?: boolean; // Whether provider supports `stream_options: { include_usage: true }` (default: true)
|
|
1006
|
+
supportsFinishReason?: boolean; // Whether streamed responses include `finish_reason`; false infers stop/toolUse at stream end (default: true)
|
|
984
1007
|
supportsStrictMode?: boolean; // Whether provider supports `strict` in tool definitions (default: true)
|
|
985
|
-
sendSessionAffinityHeaders?: boolean; //
|
|
1008
|
+
sendSessionAffinityHeaders?: boolean; // Send session-affinity data from `sessionId` (default: true for OpenRouter, false otherwise)
|
|
1009
|
+
sessionAffinityFormat?: 'openai' | 'openai-nosession' | 'openrouter'; // 'openai' uses `session_id`, `x-client-request-id`, and `x-session-affinity`; 'openai-nosession' omits `session_id`; 'openrouter' uses `x-session-id` (default: auto-detected)
|
|
986
1010
|
maxTokensField?: 'max_completion_tokens' | 'max_tokens'; // Which field name to use (default: max_completion_tokens)
|
|
987
1011
|
requiresToolResultName?: boolean; // Whether tool results require the `name` field (default: false)
|
|
988
1012
|
requiresAssistantAfterToolResult?: boolean; // Whether tool results must be followed by an assistant message (default: false)
|
|
@@ -996,11 +1020,14 @@ interface OpenAICompletionsCompat {
|
|
|
996
1020
|
|
|
997
1021
|
interface OpenAIResponsesCompat {
|
|
998
1022
|
supportsDeveloperRole?: boolean; // Whether provider supports `developer` role vs `system` (default: true)
|
|
999
|
-
|
|
1023
|
+
sessionAffinityFormat?: 'openai' | 'openai-nosession' | 'openrouter'; // Session-affinity header format: 'openai' sends `session_id` and `x-client-request-id`; 'openai-nosession' sends `x-client-request-id`; 'openrouter' sends `x-session-id` (default: auto-detected)
|
|
1000
1024
|
supportsLongCacheRetention?: boolean; // Whether the provider supports `prompt_cache_retention: "24h"`. Default: true
|
|
1025
|
+
supportsMaxOutputTokens?: boolean; // Whether the provider accepts `max_output_tokens`; false omits it from requests. Default: true
|
|
1001
1026
|
}
|
|
1002
1027
|
```
|
|
1003
1028
|
|
|
1029
|
+
OpenRouter requests send `x-session-id` from `sessionId` when prompt caching is enabled. Chat Completions and Anthropic Messages both auto-detect OpenRouter endpoints unless `sendSessionAffinityHeaders` is explicitly false. On Anthropic-compatible models, `sessionAffinityFormat: "openrouter"` selects `x-session-id`; when unset, the `x-session-affinity` format is used. Explicit request headers take precedence over generated headers.
|
|
1030
|
+
|
|
1004
1031
|
If `compat` is not set, the library falls back to URL-based detection. If `compat` is partially set, unspecified fields use the detected defaults. This is useful for:
|
|
1005
1032
|
|
|
1006
1033
|
- **LiteLLM proxies**: May not support `store` field
|
|
@@ -1175,7 +1202,7 @@ In Node.js environments, you can set environment variables to avoid passing API
|
|
|
1175
1202
|
| Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` |
|
|
1176
1203
|
| Xiaomi MiMo Token Plan (Amsterdam) | `XIAOMI_TOKEN_PLAN_AMS_API_KEY` |
|
|
1177
1204
|
| Xiaomi MiMo Token Plan (Singapore) | `XIAOMI_TOKEN_PLAN_SGP_API_KEY` |
|
|
1178
|
-
| GitHub Copilot | `COPILOT_GITHUB_TOKEN`
|
|
1205
|
+
| GitHub Copilot | `COPILOT_GITHUB_TOKEN` |
|
|
1179
1206
|
|
|
1180
1207
|
When set, the library automatically uses these keys:
|
|
1181
1208
|
|
|
@@ -1350,7 +1377,7 @@ const response = await complete(model, {
|
|
|
1350
1377
|
|
|
1351
1378
|
### Provider Notes
|
|
1352
1379
|
|
|
1353
|
-
**OpenAI Codex**: Requires a ChatGPT Plus or Pro subscription. Provides access to GPT-5.x Codex models with extended context windows and reasoning capabilities. The library automatically handles session-based prompt caching when `sessionId` is provided in stream options
|
|
1380
|
+
**OpenAI Codex**: Requires a ChatGPT Plus or Pro subscription. Provides access to GPT-5.x Codex models with extended context windows and reasoning capabilities. The library automatically handles session-based prompt caching when `sessionId` is provided in stream options unless `cacheRetention` is `"none"`. You can set `transport` in stream options to `"sse"`, `"websocket"`, or `"auto"` for Codex Responses transport selection. When using WebSocket with a `sessionId` and cache retention enabled, connections are reused per session and expire after 5 minutes of inactivity.
|
|
1354
1381
|
|
|
1355
1382
|
**Azure OpenAI (Responses)**: Uses the Responses API only. Set `AZURE_OPENAI_API_KEY` and either `AZURE_OPENAI_BASE_URL` or `AZURE_OPENAI_RESOURCE_NAME`. `AZURE_OPENAI_BASE_URL` supports both `https://<resource>.openai.azure.com` and `https://<resource>.cognitiveservices.azure.com`; root endpoints are normalized to `.../openai/v1` automatically. Use `AZURE_OPENAI_API_VERSION` (defaults to `v1`) to override the API version if needed. Deployment names are treated as model IDs by default, override with `azureDeploymentName` or `AZURE_OPENAI_DEPLOYMENT_NAME_MAP` using comma-separated `model-id=deployment` pairs (for example `gpt-4o-mini=my-deployment,gpt-4o=prod`). Legacy deployment-based URLs are intentionally unsupported.
|
|
1356
1383
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-api-keys.d.ts","sourceRoot":"","sources":["../src/env-api-keys.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA+E7D;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAC9F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AASvF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAC7F,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC","sourcesContent":["// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)\nlet _existsSync: typeof import(\"node:fs\").existsSync | null = null;\nlet _homedir: typeof import(\"node:os\").homedir | null = null;\nlet _join: typeof import(\"node:path\").join | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_FS_SPECIFIER = \"node:\" + \"fs\";\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\nconst NODE_PATH_SPECIFIER = \"node:\" + \"path\";\n\n// Eagerly load in Node.js/Bun environment only\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_FS_SPECIFIER).then((m) => {\n\t\t_existsSync = (m as typeof import(\"node:fs\")).existsSync;\n\t});\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_homedir = (m as typeof import(\"node:os\")).homedir;\n\t});\n\tdynamicImport(NODE_PATH_SPECIFIER).then((m) => {\n\t\t_join = (m as typeof import(\"node:path\")).join;\n\t});\n}\n\nimport type { KnownProvider, ProviderEnv } from \"./types.js\";\nimport { getProviderEnvValue } from \"./utils/provider-env.js\";\n\nlet cachedVertexAdcCredentialsExists: boolean | null = null;\n\nfunction hasVertexAdcCredentials(env?: ProviderEnv): boolean {\n\tif (cachedVertexAdcCredentialsExists === null) {\n\t\t// If node modules haven't loaded yet (async import race at startup),\n\t\t// return false WITHOUT caching so the next call retries once they're ready.\n\t\t// Only cache false permanently in a browser environment where fs is never available.\n\t\tif (!_existsSync || !_homedir || !_join) {\n\t\t\tconst isNode = typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun);\n\t\t\tif (!isNode) {\n\t\t\t\t// Definitively in a browser — safe to cache false permanently\n\t\t\t\tcachedVertexAdcCredentialsExists = false;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)\n\t\tconst gacPath = getProviderEnvValue(\"GOOGLE_APPLICATION_CREDENTIALS\", env);\n\t\tif (gacPath) {\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(gacPath);\n\t\t} else {\n\t\t\t// Fall back to default ADC path (lazy evaluation)\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(\n\t\t\t\t_join(_homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"),\n\t\t\t);\n\t\t}\n\t}\n\treturn cachedVertexAdcCredentialsExists;\n}\n\nfunction getApiKeyEnvVars(provider: string): readonly string[] | undefined {\n\tif (provider === \"github-copilot\") {\n\t\treturn [\"COPILOT_GITHUB_TOKEN\"
|
|
1
|
+
{"version":3,"file":"env-api-keys.d.ts","sourceRoot":"","sources":["../src/env-api-keys.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA+E7D;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAC9F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AASvF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAC7F,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC","sourcesContent":["// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)\nlet _existsSync: typeof import(\"node:fs\").existsSync | null = null;\nlet _homedir: typeof import(\"node:os\").homedir | null = null;\nlet _join: typeof import(\"node:path\").join | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_FS_SPECIFIER = \"node:\" + \"fs\";\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\nconst NODE_PATH_SPECIFIER = \"node:\" + \"path\";\n\n// Eagerly load in Node.js/Bun environment only\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_FS_SPECIFIER).then((m) => {\n\t\t_existsSync = (m as typeof import(\"node:fs\")).existsSync;\n\t});\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_homedir = (m as typeof import(\"node:os\")).homedir;\n\t});\n\tdynamicImport(NODE_PATH_SPECIFIER).then((m) => {\n\t\t_join = (m as typeof import(\"node:path\")).join;\n\t});\n}\n\nimport type { KnownProvider, ProviderEnv } from \"./types.js\";\nimport { getProviderEnvValue } from \"./utils/provider-env.js\";\n\nlet cachedVertexAdcCredentialsExists: boolean | null = null;\n\nfunction hasVertexAdcCredentials(env?: ProviderEnv): boolean {\n\tif (cachedVertexAdcCredentialsExists === null) {\n\t\t// If node modules haven't loaded yet (async import race at startup),\n\t\t// return false WITHOUT caching so the next call retries once they're ready.\n\t\t// Only cache false permanently in a browser environment where fs is never available.\n\t\tif (!_existsSync || !_homedir || !_join) {\n\t\t\tconst isNode = typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun);\n\t\t\tif (!isNode) {\n\t\t\t\t// Definitively in a browser — safe to cache false permanently\n\t\t\t\tcachedVertexAdcCredentialsExists = false;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)\n\t\tconst gacPath = getProviderEnvValue(\"GOOGLE_APPLICATION_CREDENTIALS\", env);\n\t\tif (gacPath) {\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(gacPath);\n\t\t} else {\n\t\t\t// Fall back to default ADC path (lazy evaluation)\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(\n\t\t\t\t_join(_homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"),\n\t\t\t);\n\t\t}\n\t}\n\treturn cachedVertexAdcCredentialsExists;\n}\n\nfunction getApiKeyEnvVars(provider: string): readonly string[] | undefined {\n\tif (provider === \"github-copilot\") {\n\t\treturn [\"COPILOT_GITHUB_TOKEN\"];\n\t}\n\n\t// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY\n\tif (provider === \"anthropic\") {\n\t\treturn [\"ANTHROPIC_OAUTH_TOKEN\", \"ANTHROPIC_API_KEY\"];\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\t\"azure-openai-responses\": \"AZURE_OPENAI_API_KEY\",\n\t\tdeepseek: \"DEEPSEEK_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\t\"google-vertex\": \"GOOGLE_CLOUD_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\t\"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t\tminimax: \"MINIMAX_API_KEY\",\n\t\t\"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n\t\tmoonshotai: \"MOONSHOT_API_KEY\",\n\t\t\"moonshotai-cn\": \"MOONSHOT_API_KEY\",\n\t\thuggingface: \"HF_TOKEN\",\n\t\tfireworks: \"FIREWORKS_API_KEY\",\n\t\ttogether: \"TOGETHER_API_KEY\",\n\t\t\"ant-ling\": \"ANT_LING_API_KEY\",\n\t\topencode: \"OPENCODE_API_KEY\",\n\t\t\"opencode-go\": \"OPENCODE_API_KEY\",\n\t\t\"kimi-coding\": \"KIMI_API_KEY\",\n\t\t\"cloudflare-workers-ai\": \"CLOUDFLARE_API_KEY\",\n\t\t\"cloudflare-ai-gateway\": \"CLOUDFLARE_API_KEY\",\n\t\txiaomi: \"XIAOMI_API_KEY\",\n\t\t\"xiaomi-token-plan-cn\": \"XIAOMI_TOKEN_PLAN_CN_API_KEY\",\n\t\t\"xiaomi-token-plan-ams\": \"XIAOMI_TOKEN_PLAN_AMS_API_KEY\",\n\t\t\"xiaomi-token-plan-sgp\": \"XIAOMI_TOKEN_PLAN_SGP_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? [envVar] : undefined;\n}\n\n/**\n * Find configured environment variables that can provide an API key for a provider.\n *\n * This only reports actual API key variables. It intentionally excludes ambient\n * credential sources such as AWS profiles, AWS IAM credentials, and Google\n * Application Default Credentials.\n */\nexport function findEnvKeys(provider: KnownProvider, env?: ProviderEnv): string[] | undefined;\nexport function findEnvKeys(provider: string, env?: ProviderEnv): string[] | undefined;\nexport function findEnvKeys(provider: string, env?: ProviderEnv): string[] | undefined {\n\tconst envVars = getApiKeyEnvVars(provider);\n\tif (!envVars) return undefined;\n\n\tconst found = envVars.filter((envVar) => !!getProviderEnvValue(envVar, env));\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.\n *\n * Will not return API keys for providers that require OAuth tokens.\n */\nexport function getEnvApiKey(provider: KnownProvider, env?: ProviderEnv): string | undefined;\nexport function getEnvApiKey(provider: string, env?: ProviderEnv): string | undefined;\nexport function getEnvApiKey(provider: string, env?: ProviderEnv): string | undefined {\n\tconst envKeys = findEnvKeys(provider, env);\n\tif (envKeys?.[0]) {\n\t\treturn getProviderEnvValue(envKeys[0], env);\n\t}\n\n\t// Vertex AI supports either an explicit API key or Application Default Credentials.\n\t// Auth is configured via `gcloud auth application-default login`.\n\tif (provider === \"google-vertex\") {\n\t\tconst hasCredentials = hasVertexAdcCredentials(env);\n\t\tconst hasProject = !!(\n\t\t\tgetProviderEnvValue(\"GOOGLE_CLOUD_PROJECT\", env) || getProviderEnvValue(\"GCLOUD_PROJECT\", env)\n\t\t);\n\t\tconst hasLocation = !!getProviderEnvValue(\"GOOGLE_CLOUD_LOCATION\", env);\n\n\t\tif (hasCredentials && hasProject && hasLocation) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tif (provider === \"claude-cli\") {\n\t\treturn \"<native>\";\n\t}\n\n\tif (provider === \"amazon-bedrock\") {\n\t\t// Amazon Bedrock supports multiple credential sources:\n\t\t// 1. AWS_PROFILE - named profile from ~/.aws/credentials\n\t\t// 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys\n\t\t// 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock bearer token\n\t\t// 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles\n\t\t// 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI)\n\t\t// 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts)\n\t\tif (\n\t\t\tgetProviderEnvValue(\"AWS_PROFILE\", env) ||\n\t\t\t(getProviderEnvValue(\"AWS_ACCESS_KEY_ID\", env) && getProviderEnvValue(\"AWS_SECRET_ACCESS_KEY\", env)) ||\n\t\t\tgetProviderEnvValue(\"AWS_BEARER_TOKEN_BEDROCK\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_FULL_URI\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_WEB_IDENTITY_TOKEN_FILE\", env)\n\t\t) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\treturn undefined;\n}\n"]}
|
package/dist/env-api-keys.js
CHANGED
|
@@ -47,7 +47,7 @@ function hasVertexAdcCredentials(env) {
|
|
|
47
47
|
}
|
|
48
48
|
function getApiKeyEnvVars(provider) {
|
|
49
49
|
if (provider === "github-copilot") {
|
|
50
|
-
return ["COPILOT_GITHUB_TOKEN"
|
|
50
|
+
return ["COPILOT_GITHUB_TOKEN"];
|
|
51
51
|
}
|
|
52
52
|
// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY
|
|
53
53
|
if (provider === "anthropic") {
|
package/dist/env-api-keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-api-keys.js","sourceRoot":"","sources":["../src/env-api-keys.ts"],"names":[],"mappings":"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","sourcesContent":["// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)\nlet _existsSync: typeof import(\"node:fs\").existsSync | null = null;\nlet _homedir: typeof import(\"node:os\").homedir | null = null;\nlet _join: typeof import(\"node:path\").join | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_FS_SPECIFIER = \"node:\" + \"fs\";\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\nconst NODE_PATH_SPECIFIER = \"node:\" + \"path\";\n\n// Eagerly load in Node.js/Bun environment only\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_FS_SPECIFIER).then((m) => {\n\t\t_existsSync = (m as typeof import(\"node:fs\")).existsSync;\n\t});\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_homedir = (m as typeof import(\"node:os\")).homedir;\n\t});\n\tdynamicImport(NODE_PATH_SPECIFIER).then((m) => {\n\t\t_join = (m as typeof import(\"node:path\")).join;\n\t});\n}\n\nimport type { KnownProvider, ProviderEnv } from \"./types.js\";\nimport { getProviderEnvValue } from \"./utils/provider-env.js\";\n\nlet cachedVertexAdcCredentialsExists: boolean | null = null;\n\nfunction hasVertexAdcCredentials(env?: ProviderEnv): boolean {\n\tif (cachedVertexAdcCredentialsExists === null) {\n\t\t// If node modules haven't loaded yet (async import race at startup),\n\t\t// return false WITHOUT caching so the next call retries once they're ready.\n\t\t// Only cache false permanently in a browser environment where fs is never available.\n\t\tif (!_existsSync || !_homedir || !_join) {\n\t\t\tconst isNode = typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun);\n\t\t\tif (!isNode) {\n\t\t\t\t// Definitively in a browser — safe to cache false permanently\n\t\t\t\tcachedVertexAdcCredentialsExists = false;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)\n\t\tconst gacPath = getProviderEnvValue(\"GOOGLE_APPLICATION_CREDENTIALS\", env);\n\t\tif (gacPath) {\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(gacPath);\n\t\t} else {\n\t\t\t// Fall back to default ADC path (lazy evaluation)\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(\n\t\t\t\t_join(_homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"),\n\t\t\t);\n\t\t}\n\t}\n\treturn cachedVertexAdcCredentialsExists;\n}\n\nfunction getApiKeyEnvVars(provider: string): readonly string[] | undefined {\n\tif (provider === \"github-copilot\") {\n\t\treturn [\"COPILOT_GITHUB_TOKEN\", \"GH_TOKEN\", \"GITHUB_TOKEN\"];\n\t}\n\n\t// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY\n\tif (provider === \"anthropic\") {\n\t\treturn [\"ANTHROPIC_OAUTH_TOKEN\", \"ANTHROPIC_API_KEY\"];\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\t\"azure-openai-responses\": \"AZURE_OPENAI_API_KEY\",\n\t\tdeepseek: \"DEEPSEEK_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\t\"google-vertex\": \"GOOGLE_CLOUD_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\t\"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t\tminimax: \"MINIMAX_API_KEY\",\n\t\t\"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n\t\tmoonshotai: \"MOONSHOT_API_KEY\",\n\t\t\"moonshotai-cn\": \"MOONSHOT_API_KEY\",\n\t\thuggingface: \"HF_TOKEN\",\n\t\tfireworks: \"FIREWORKS_API_KEY\",\n\t\ttogether: \"TOGETHER_API_KEY\",\n\t\t\"ant-ling\": \"ANT_LING_API_KEY\",\n\t\topencode: \"OPENCODE_API_KEY\",\n\t\t\"opencode-go\": \"OPENCODE_API_KEY\",\n\t\t\"kimi-coding\": \"KIMI_API_KEY\",\n\t\t\"cloudflare-workers-ai\": \"CLOUDFLARE_API_KEY\",\n\t\t\"cloudflare-ai-gateway\": \"CLOUDFLARE_API_KEY\",\n\t\txiaomi: \"XIAOMI_API_KEY\",\n\t\t\"xiaomi-token-plan-cn\": \"XIAOMI_TOKEN_PLAN_CN_API_KEY\",\n\t\t\"xiaomi-token-plan-ams\": \"XIAOMI_TOKEN_PLAN_AMS_API_KEY\",\n\t\t\"xiaomi-token-plan-sgp\": \"XIAOMI_TOKEN_PLAN_SGP_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? [envVar] : undefined;\n}\n\n/**\n * Find configured environment variables that can provide an API key for a provider.\n *\n * This only reports actual API key variables. It intentionally excludes ambient\n * credential sources such as AWS profiles, AWS IAM credentials, and Google\n * Application Default Credentials.\n */\nexport function findEnvKeys(provider: KnownProvider, env?: ProviderEnv): string[] | undefined;\nexport function findEnvKeys(provider: string, env?: ProviderEnv): string[] | undefined;\nexport function findEnvKeys(provider: string, env?: ProviderEnv): string[] | undefined {\n\tconst envVars = getApiKeyEnvVars(provider);\n\tif (!envVars) return undefined;\n\n\tconst found = envVars.filter((envVar) => !!getProviderEnvValue(envVar, env));\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.\n *\n * Will not return API keys for providers that require OAuth tokens.\n */\nexport function getEnvApiKey(provider: KnownProvider, env?: ProviderEnv): string | undefined;\nexport function getEnvApiKey(provider: string, env?: ProviderEnv): string | undefined;\nexport function getEnvApiKey(provider: string, env?: ProviderEnv): string | undefined {\n\tconst envKeys = findEnvKeys(provider, env);\n\tif (envKeys?.[0]) {\n\t\treturn getProviderEnvValue(envKeys[0], env);\n\t}\n\n\t// Vertex AI supports either an explicit API key or Application Default Credentials.\n\t// Auth is configured via `gcloud auth application-default login`.\n\tif (provider === \"google-vertex\") {\n\t\tconst hasCredentials = hasVertexAdcCredentials(env);\n\t\tconst hasProject = !!(\n\t\t\tgetProviderEnvValue(\"GOOGLE_CLOUD_PROJECT\", env) || getProviderEnvValue(\"GCLOUD_PROJECT\", env)\n\t\t);\n\t\tconst hasLocation = !!getProviderEnvValue(\"GOOGLE_CLOUD_LOCATION\", env);\n\n\t\tif (hasCredentials && hasProject && hasLocation) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tif (provider === \"claude-cli\") {\n\t\treturn \"<native>\";\n\t}\n\n\tif (provider === \"amazon-bedrock\") {\n\t\t// Amazon Bedrock supports multiple credential sources:\n\t\t// 1. AWS_PROFILE - named profile from ~/.aws/credentials\n\t\t// 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys\n\t\t// 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock bearer token\n\t\t// 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles\n\t\t// 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI)\n\t\t// 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts)\n\t\tif (\n\t\t\tgetProviderEnvValue(\"AWS_PROFILE\", env) ||\n\t\t\t(getProviderEnvValue(\"AWS_ACCESS_KEY_ID\", env) && getProviderEnvValue(\"AWS_SECRET_ACCESS_KEY\", env)) ||\n\t\t\tgetProviderEnvValue(\"AWS_BEARER_TOKEN_BEDROCK\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_FULL_URI\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_WEB_IDENTITY_TOKEN_FILE\", env)\n\t\t) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\treturn undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"env-api-keys.js","sourceRoot":"","sources":["../src/env-api-keys.ts"],"names":[],"mappings":"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","sourcesContent":["// NEVER convert to top-level imports - breaks browser/Vite builds (web-ui)\nlet _existsSync: typeof import(\"node:fs\").existsSync | null = null;\nlet _homedir: typeof import(\"node:os\").homedir | null = null;\nlet _join: typeof import(\"node:path\").join | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_FS_SPECIFIER = \"node:\" + \"fs\";\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\nconst NODE_PATH_SPECIFIER = \"node:\" + \"path\";\n\n// Eagerly load in Node.js/Bun environment only\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_FS_SPECIFIER).then((m) => {\n\t\t_existsSync = (m as typeof import(\"node:fs\")).existsSync;\n\t});\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_homedir = (m as typeof import(\"node:os\")).homedir;\n\t});\n\tdynamicImport(NODE_PATH_SPECIFIER).then((m) => {\n\t\t_join = (m as typeof import(\"node:path\")).join;\n\t});\n}\n\nimport type { KnownProvider, ProviderEnv } from \"./types.js\";\nimport { getProviderEnvValue } from \"./utils/provider-env.js\";\n\nlet cachedVertexAdcCredentialsExists: boolean | null = null;\n\nfunction hasVertexAdcCredentials(env?: ProviderEnv): boolean {\n\tif (cachedVertexAdcCredentialsExists === null) {\n\t\t// If node modules haven't loaded yet (async import race at startup),\n\t\t// return false WITHOUT caching so the next call retries once they're ready.\n\t\t// Only cache false permanently in a browser environment where fs is never available.\n\t\tif (!_existsSync || !_homedir || !_join) {\n\t\t\tconst isNode = typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun);\n\t\t\tif (!isNode) {\n\t\t\t\t// Definitively in a browser — safe to cache false permanently\n\t\t\t\tcachedVertexAdcCredentialsExists = false;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)\n\t\tconst gacPath = getProviderEnvValue(\"GOOGLE_APPLICATION_CREDENTIALS\", env);\n\t\tif (gacPath) {\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(gacPath);\n\t\t} else {\n\t\t\t// Fall back to default ADC path (lazy evaluation)\n\t\t\tcachedVertexAdcCredentialsExists = _existsSync(\n\t\t\t\t_join(_homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"),\n\t\t\t);\n\t\t}\n\t}\n\treturn cachedVertexAdcCredentialsExists;\n}\n\nfunction getApiKeyEnvVars(provider: string): readonly string[] | undefined {\n\tif (provider === \"github-copilot\") {\n\t\treturn [\"COPILOT_GITHUB_TOKEN\"];\n\t}\n\n\t// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY\n\tif (provider === \"anthropic\") {\n\t\treturn [\"ANTHROPIC_OAUTH_TOKEN\", \"ANTHROPIC_API_KEY\"];\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\t\"azure-openai-responses\": \"AZURE_OPENAI_API_KEY\",\n\t\tdeepseek: \"DEEPSEEK_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\t\"google-vertex\": \"GOOGLE_CLOUD_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\t\"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t\tminimax: \"MINIMAX_API_KEY\",\n\t\t\"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n\t\tmoonshotai: \"MOONSHOT_API_KEY\",\n\t\t\"moonshotai-cn\": \"MOONSHOT_API_KEY\",\n\t\thuggingface: \"HF_TOKEN\",\n\t\tfireworks: \"FIREWORKS_API_KEY\",\n\t\ttogether: \"TOGETHER_API_KEY\",\n\t\t\"ant-ling\": \"ANT_LING_API_KEY\",\n\t\topencode: \"OPENCODE_API_KEY\",\n\t\t\"opencode-go\": \"OPENCODE_API_KEY\",\n\t\t\"kimi-coding\": \"KIMI_API_KEY\",\n\t\t\"cloudflare-workers-ai\": \"CLOUDFLARE_API_KEY\",\n\t\t\"cloudflare-ai-gateway\": \"CLOUDFLARE_API_KEY\",\n\t\txiaomi: \"XIAOMI_API_KEY\",\n\t\t\"xiaomi-token-plan-cn\": \"XIAOMI_TOKEN_PLAN_CN_API_KEY\",\n\t\t\"xiaomi-token-plan-ams\": \"XIAOMI_TOKEN_PLAN_AMS_API_KEY\",\n\t\t\"xiaomi-token-plan-sgp\": \"XIAOMI_TOKEN_PLAN_SGP_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? [envVar] : undefined;\n}\n\n/**\n * Find configured environment variables that can provide an API key for a provider.\n *\n * This only reports actual API key variables. It intentionally excludes ambient\n * credential sources such as AWS profiles, AWS IAM credentials, and Google\n * Application Default Credentials.\n */\nexport function findEnvKeys(provider: KnownProvider, env?: ProviderEnv): string[] | undefined;\nexport function findEnvKeys(provider: string, env?: ProviderEnv): string[] | undefined;\nexport function findEnvKeys(provider: string, env?: ProviderEnv): string[] | undefined {\n\tconst envVars = getApiKeyEnvVars(provider);\n\tif (!envVars) return undefined;\n\n\tconst found = envVars.filter((envVar) => !!getProviderEnvValue(envVar, env));\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.\n *\n * Will not return API keys for providers that require OAuth tokens.\n */\nexport function getEnvApiKey(provider: KnownProvider, env?: ProviderEnv): string | undefined;\nexport function getEnvApiKey(provider: string, env?: ProviderEnv): string | undefined;\nexport function getEnvApiKey(provider: string, env?: ProviderEnv): string | undefined {\n\tconst envKeys = findEnvKeys(provider, env);\n\tif (envKeys?.[0]) {\n\t\treturn getProviderEnvValue(envKeys[0], env);\n\t}\n\n\t// Vertex AI supports either an explicit API key or Application Default Credentials.\n\t// Auth is configured via `gcloud auth application-default login`.\n\tif (provider === \"google-vertex\") {\n\t\tconst hasCredentials = hasVertexAdcCredentials(env);\n\t\tconst hasProject = !!(\n\t\t\tgetProviderEnvValue(\"GOOGLE_CLOUD_PROJECT\", env) || getProviderEnvValue(\"GCLOUD_PROJECT\", env)\n\t\t);\n\t\tconst hasLocation = !!getProviderEnvValue(\"GOOGLE_CLOUD_LOCATION\", env);\n\n\t\tif (hasCredentials && hasProject && hasLocation) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tif (provider === \"claude-cli\") {\n\t\treturn \"<native>\";\n\t}\n\n\tif (provider === \"amazon-bedrock\") {\n\t\t// Amazon Bedrock supports multiple credential sources:\n\t\t// 1. AWS_PROFILE - named profile from ~/.aws/credentials\n\t\t// 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys\n\t\t// 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock bearer token\n\t\t// 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles\n\t\t// 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI)\n\t\t// 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts)\n\t\tif (\n\t\t\tgetProviderEnvValue(\"AWS_PROFILE\", env) ||\n\t\t\t(getProviderEnvValue(\"AWS_ACCESS_KEY_ID\", env) && getProviderEnvValue(\"AWS_SECRET_ACCESS_KEY\", env)) ||\n\t\t\tgetProviderEnvValue(\"AWS_BEARER_TOKEN_BEDROCK\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_CONTAINER_CREDENTIALS_FULL_URI\", env) ||\n\t\t\tgetProviderEnvValue(\"AWS_WEB_IDENTITY_TOKEN_FILE\", env)\n\t\t) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\treturn undefined;\n}\n"]}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
export declare const IMAGE_MODELS: {
|
|
2
2
|
readonly openrouter: {
|
|
3
|
+
readonly "black-forest-labs/flux-3-image": {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
api: "openrouter-images";
|
|
7
|
+
provider: string;
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
input: ("image" | "text")[];
|
|
10
|
+
output: "image"[];
|
|
11
|
+
cost: {
|
|
12
|
+
input: number;
|
|
13
|
+
output: number;
|
|
14
|
+
cacheRead: number;
|
|
15
|
+
cacheWrite: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
3
18
|
readonly "black-forest-labs/flux.2-flex": {
|
|
4
19
|
id: string;
|
|
5
20
|
name: string;
|
|
@@ -75,6 +90,36 @@ export declare const IMAGE_MODELS: {
|
|
|
75
90
|
cacheWrite: number;
|
|
76
91
|
};
|
|
77
92
|
};
|
|
93
|
+
readonly "bytedance-seed/seedream-5-0-lite": {
|
|
94
|
+
id: string;
|
|
95
|
+
name: string;
|
|
96
|
+
api: "openrouter-images";
|
|
97
|
+
provider: string;
|
|
98
|
+
baseUrl: string;
|
|
99
|
+
input: ("image" | "text")[];
|
|
100
|
+
output: "image"[];
|
|
101
|
+
cost: {
|
|
102
|
+
input: number;
|
|
103
|
+
output: number;
|
|
104
|
+
cacheRead: number;
|
|
105
|
+
cacheWrite: number;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
readonly "bytedance-seed/seedream-5-0-pro": {
|
|
109
|
+
id: string;
|
|
110
|
+
name: string;
|
|
111
|
+
api: "openrouter-images";
|
|
112
|
+
provider: string;
|
|
113
|
+
baseUrl: string;
|
|
114
|
+
input: ("image" | "text")[];
|
|
115
|
+
output: "image"[];
|
|
116
|
+
cost: {
|
|
117
|
+
input: number;
|
|
118
|
+
output: number;
|
|
119
|
+
cacheRead: number;
|
|
120
|
+
cacheWrite: number;
|
|
121
|
+
};
|
|
122
|
+
};
|
|
78
123
|
readonly "google/gemini-2.5-flash-image": {
|
|
79
124
|
id: string;
|
|
80
125
|
name: string;
|
|
@@ -165,6 +210,96 @@ export declare const IMAGE_MODELS: {
|
|
|
165
210
|
cacheWrite: number;
|
|
166
211
|
};
|
|
167
212
|
};
|
|
213
|
+
readonly "inclusionai/ming-image-0.1-design": {
|
|
214
|
+
id: string;
|
|
215
|
+
name: string;
|
|
216
|
+
api: "openrouter-images";
|
|
217
|
+
provider: string;
|
|
218
|
+
baseUrl: string;
|
|
219
|
+
input: "text"[];
|
|
220
|
+
output: "image"[];
|
|
221
|
+
cost: {
|
|
222
|
+
input: number;
|
|
223
|
+
output: number;
|
|
224
|
+
cacheRead: number;
|
|
225
|
+
cacheWrite: number;
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
readonly "inclusionai/ming-image-0.1-design-layer": {
|
|
229
|
+
id: string;
|
|
230
|
+
name: string;
|
|
231
|
+
api: "openrouter-images";
|
|
232
|
+
provider: string;
|
|
233
|
+
baseUrl: string;
|
|
234
|
+
input: ("image" | "text")[];
|
|
235
|
+
output: "image"[];
|
|
236
|
+
cost: {
|
|
237
|
+
input: number;
|
|
238
|
+
output: number;
|
|
239
|
+
cacheRead: number;
|
|
240
|
+
cacheWrite: number;
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
readonly "krea/krea-2-large": {
|
|
244
|
+
id: string;
|
|
245
|
+
name: string;
|
|
246
|
+
api: "openrouter-images";
|
|
247
|
+
provider: string;
|
|
248
|
+
baseUrl: string;
|
|
249
|
+
input: ("image" | "text")[];
|
|
250
|
+
output: "image"[];
|
|
251
|
+
cost: {
|
|
252
|
+
input: number;
|
|
253
|
+
output: number;
|
|
254
|
+
cacheRead: number;
|
|
255
|
+
cacheWrite: number;
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
readonly "krea/krea-2-medium": {
|
|
259
|
+
id: string;
|
|
260
|
+
name: string;
|
|
261
|
+
api: "openrouter-images";
|
|
262
|
+
provider: string;
|
|
263
|
+
baseUrl: string;
|
|
264
|
+
input: ("image" | "text")[];
|
|
265
|
+
output: "image"[];
|
|
266
|
+
cost: {
|
|
267
|
+
input: number;
|
|
268
|
+
output: number;
|
|
269
|
+
cacheRead: number;
|
|
270
|
+
cacheWrite: number;
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
readonly "krea/krea-2-medium-turbo": {
|
|
274
|
+
id: string;
|
|
275
|
+
name: string;
|
|
276
|
+
api: "openrouter-images";
|
|
277
|
+
provider: string;
|
|
278
|
+
baseUrl: string;
|
|
279
|
+
input: ("image" | "text")[];
|
|
280
|
+
output: "image"[];
|
|
281
|
+
cost: {
|
|
282
|
+
input: number;
|
|
283
|
+
output: number;
|
|
284
|
+
cacheRead: number;
|
|
285
|
+
cacheWrite: number;
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
readonly "meta/muse-image": {
|
|
289
|
+
id: string;
|
|
290
|
+
name: string;
|
|
291
|
+
api: "openrouter-images";
|
|
292
|
+
provider: string;
|
|
293
|
+
baseUrl: string;
|
|
294
|
+
input: ("image" | "text")[];
|
|
295
|
+
output: "image"[];
|
|
296
|
+
cost: {
|
|
297
|
+
input: number;
|
|
298
|
+
output: number;
|
|
299
|
+
cacheRead: number;
|
|
300
|
+
cacheWrite: number;
|
|
301
|
+
};
|
|
302
|
+
};
|
|
168
303
|
readonly "microsoft/mai-image-2.5": {
|
|
169
304
|
id: string;
|
|
170
305
|
name: string;
|
|
@@ -180,6 +315,51 @@ export declare const IMAGE_MODELS: {
|
|
|
180
315
|
cacheWrite: number;
|
|
181
316
|
};
|
|
182
317
|
};
|
|
318
|
+
readonly "microsoft/mai-image-2.5-pro": {
|
|
319
|
+
id: string;
|
|
320
|
+
name: string;
|
|
321
|
+
api: "openrouter-images";
|
|
322
|
+
provider: string;
|
|
323
|
+
baseUrl: string;
|
|
324
|
+
input: ("image" | "text")[];
|
|
325
|
+
output: "image"[];
|
|
326
|
+
cost: {
|
|
327
|
+
input: number;
|
|
328
|
+
output: number;
|
|
329
|
+
cacheRead: number;
|
|
330
|
+
cacheWrite: number;
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
readonly "microsoft/mai-image-2.6": {
|
|
334
|
+
id: string;
|
|
335
|
+
name: string;
|
|
336
|
+
api: "openrouter-images";
|
|
337
|
+
provider: string;
|
|
338
|
+
baseUrl: string;
|
|
339
|
+
input: ("image" | "text")[];
|
|
340
|
+
output: "image"[];
|
|
341
|
+
cost: {
|
|
342
|
+
input: number;
|
|
343
|
+
output: number;
|
|
344
|
+
cacheRead: number;
|
|
345
|
+
cacheWrite: number;
|
|
346
|
+
};
|
|
347
|
+
};
|
|
348
|
+
readonly "microsoft/mai-image-2.6-flash": {
|
|
349
|
+
id: string;
|
|
350
|
+
name: string;
|
|
351
|
+
api: "openrouter-images";
|
|
352
|
+
provider: string;
|
|
353
|
+
baseUrl: string;
|
|
354
|
+
input: ("image" | "text")[];
|
|
355
|
+
output: "image"[];
|
|
356
|
+
cost: {
|
|
357
|
+
input: number;
|
|
358
|
+
output: number;
|
|
359
|
+
cacheRead: number;
|
|
360
|
+
cacheWrite: number;
|
|
361
|
+
};
|
|
362
|
+
};
|
|
183
363
|
readonly "openai/gpt-5-image": {
|
|
184
364
|
id: string;
|
|
185
365
|
name: string;
|
|
@@ -270,6 +450,36 @@ export declare const IMAGE_MODELS: {
|
|
|
270
450
|
cacheWrite: number;
|
|
271
451
|
};
|
|
272
452
|
};
|
|
453
|
+
readonly "openai/gpt-image-2.5-flare": {
|
|
454
|
+
id: string;
|
|
455
|
+
name: string;
|
|
456
|
+
api: "openrouter-images";
|
|
457
|
+
provider: string;
|
|
458
|
+
baseUrl: string;
|
|
459
|
+
input: ("image" | "text")[];
|
|
460
|
+
output: "image"[];
|
|
461
|
+
cost: {
|
|
462
|
+
input: number;
|
|
463
|
+
output: number;
|
|
464
|
+
cacheRead: number;
|
|
465
|
+
cacheWrite: number;
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
readonly "openai/gpt-image-2.5-sunburst": {
|
|
469
|
+
id: string;
|
|
470
|
+
name: string;
|
|
471
|
+
api: "openrouter-images";
|
|
472
|
+
provider: string;
|
|
473
|
+
baseUrl: string;
|
|
474
|
+
input: ("image" | "text")[];
|
|
475
|
+
output: "image"[];
|
|
476
|
+
cost: {
|
|
477
|
+
input: number;
|
|
478
|
+
output: number;
|
|
479
|
+
cacheRead: number;
|
|
480
|
+
cacheWrite: number;
|
|
481
|
+
};
|
|
482
|
+
};
|
|
273
483
|
readonly "openrouter/auto": {
|
|
274
484
|
id: string;
|
|
275
485
|
name: string;
|
|
@@ -285,6 +495,51 @@ export declare const IMAGE_MODELS: {
|
|
|
285
495
|
cacheWrite: number;
|
|
286
496
|
};
|
|
287
497
|
};
|
|
498
|
+
readonly "openrouter/auto-beta": {
|
|
499
|
+
id: string;
|
|
500
|
+
name: string;
|
|
501
|
+
api: "openrouter-images";
|
|
502
|
+
provider: string;
|
|
503
|
+
baseUrl: string;
|
|
504
|
+
input: ("image" | "text")[];
|
|
505
|
+
output: ("image" | "text")[];
|
|
506
|
+
cost: {
|
|
507
|
+
input: number;
|
|
508
|
+
output: number;
|
|
509
|
+
cacheRead: number;
|
|
510
|
+
cacheWrite: number;
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
readonly "qwen/qwen-image-3": {
|
|
514
|
+
id: string;
|
|
515
|
+
name: string;
|
|
516
|
+
api: "openrouter-images";
|
|
517
|
+
provider: string;
|
|
518
|
+
baseUrl: string;
|
|
519
|
+
input: ("image" | "text")[];
|
|
520
|
+
output: "image"[];
|
|
521
|
+
cost: {
|
|
522
|
+
input: number;
|
|
523
|
+
output: number;
|
|
524
|
+
cacheRead: number;
|
|
525
|
+
cacheWrite: number;
|
|
526
|
+
};
|
|
527
|
+
};
|
|
528
|
+
readonly "qwen/qwen-image-3-pro": {
|
|
529
|
+
id: string;
|
|
530
|
+
name: string;
|
|
531
|
+
api: "openrouter-images";
|
|
532
|
+
provider: string;
|
|
533
|
+
baseUrl: string;
|
|
534
|
+
input: ("image" | "text")[];
|
|
535
|
+
output: "image"[];
|
|
536
|
+
cost: {
|
|
537
|
+
input: number;
|
|
538
|
+
output: number;
|
|
539
|
+
cacheRead: number;
|
|
540
|
+
cacheWrite: number;
|
|
541
|
+
};
|
|
542
|
+
};
|
|
288
543
|
readonly "recraft/recraft-v3": {
|
|
289
544
|
id: string;
|
|
290
545
|
name: string;
|
|
@@ -345,6 +600,66 @@ export declare const IMAGE_MODELS: {
|
|
|
345
600
|
cacheWrite: number;
|
|
346
601
|
};
|
|
347
602
|
};
|
|
603
|
+
readonly "recraft/recraft-v4-styles": {
|
|
604
|
+
id: string;
|
|
605
|
+
name: string;
|
|
606
|
+
api: "openrouter-images";
|
|
607
|
+
provider: string;
|
|
608
|
+
baseUrl: string;
|
|
609
|
+
input: ("image" | "text")[];
|
|
610
|
+
output: "image"[];
|
|
611
|
+
cost: {
|
|
612
|
+
input: number;
|
|
613
|
+
output: number;
|
|
614
|
+
cacheRead: number;
|
|
615
|
+
cacheWrite: number;
|
|
616
|
+
};
|
|
617
|
+
};
|
|
618
|
+
readonly "recraft/recraft-v4-styles-pro": {
|
|
619
|
+
id: string;
|
|
620
|
+
name: string;
|
|
621
|
+
api: "openrouter-images";
|
|
622
|
+
provider: string;
|
|
623
|
+
baseUrl: string;
|
|
624
|
+
input: ("image" | "text")[];
|
|
625
|
+
output: "image"[];
|
|
626
|
+
cost: {
|
|
627
|
+
input: number;
|
|
628
|
+
output: number;
|
|
629
|
+
cacheRead: number;
|
|
630
|
+
cacheWrite: number;
|
|
631
|
+
};
|
|
632
|
+
};
|
|
633
|
+
readonly "recraft/recraft-v4-styles-pro-vector": {
|
|
634
|
+
id: string;
|
|
635
|
+
name: string;
|
|
636
|
+
api: "openrouter-images";
|
|
637
|
+
provider: string;
|
|
638
|
+
baseUrl: string;
|
|
639
|
+
input: ("image" | "text")[];
|
|
640
|
+
output: "image"[];
|
|
641
|
+
cost: {
|
|
642
|
+
input: number;
|
|
643
|
+
output: number;
|
|
644
|
+
cacheRead: number;
|
|
645
|
+
cacheWrite: number;
|
|
646
|
+
};
|
|
647
|
+
};
|
|
648
|
+
readonly "recraft/recraft-v4-styles-vector": {
|
|
649
|
+
id: string;
|
|
650
|
+
name: string;
|
|
651
|
+
api: "openrouter-images";
|
|
652
|
+
provider: string;
|
|
653
|
+
baseUrl: string;
|
|
654
|
+
input: ("image" | "text")[];
|
|
655
|
+
output: "image"[];
|
|
656
|
+
cost: {
|
|
657
|
+
input: number;
|
|
658
|
+
output: number;
|
|
659
|
+
cacheRead: number;
|
|
660
|
+
cacheWrite: number;
|
|
661
|
+
};
|
|
662
|
+
};
|
|
348
663
|
readonly "recraft/recraft-v4-vector": {
|
|
349
664
|
id: string;
|
|
350
665
|
name: string;
|
|
@@ -375,6 +690,21 @@ export declare const IMAGE_MODELS: {
|
|
|
375
690
|
cacheWrite: number;
|
|
376
691
|
};
|
|
377
692
|
};
|
|
693
|
+
readonly "recraft/recraft-v4.1-flash": {
|
|
694
|
+
id: string;
|
|
695
|
+
name: string;
|
|
696
|
+
api: "openrouter-images";
|
|
697
|
+
provider: string;
|
|
698
|
+
baseUrl: string;
|
|
699
|
+
input: "text"[];
|
|
700
|
+
output: "image"[];
|
|
701
|
+
cost: {
|
|
702
|
+
input: number;
|
|
703
|
+
output: number;
|
|
704
|
+
cacheRead: number;
|
|
705
|
+
cacheWrite: number;
|
|
706
|
+
};
|
|
707
|
+
};
|
|
378
708
|
readonly "recraft/recraft-v4.1-pro": {
|
|
379
709
|
id: string;
|
|
380
710
|
name: string;
|
|
@@ -510,6 +840,21 @@ export declare const IMAGE_MODELS: {
|
|
|
510
840
|
cacheWrite: number;
|
|
511
841
|
};
|
|
512
842
|
};
|
|
843
|
+
readonly "x-ai/grok-imagine-image-2.0": {
|
|
844
|
+
id: string;
|
|
845
|
+
name: string;
|
|
846
|
+
api: "openrouter-images";
|
|
847
|
+
provider: string;
|
|
848
|
+
baseUrl: string;
|
|
849
|
+
input: ("image" | "text")[];
|
|
850
|
+
output: "image"[];
|
|
851
|
+
cost: {
|
|
852
|
+
input: number;
|
|
853
|
+
output: number;
|
|
854
|
+
cacheRead: number;
|
|
855
|
+
cacheWrite: number;
|
|
856
|
+
};
|
|
857
|
+
};
|
|
513
858
|
readonly "x-ai/grok-imagine-image-quality": {
|
|
514
859
|
id: string;
|
|
515
860
|
name: string;
|