language-models 2.1.1 → 2.3.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +36 -0
- package/README.md +106 -43
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +1 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +8 -10
- package/dist/models.js.map +1 -1
- package/dist/policy.d.ts +127 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +246 -0
- package/dist/policy.js.map +1 -0
- package/dist/pricing/index.d.ts +19 -0
- package/dist/pricing/index.d.ts.map +1 -0
- package/dist/pricing/index.js +18 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/pricing/lookup.d.ts +46 -0
- package/dist/pricing/lookup.d.ts.map +1 -0
- package/dist/pricing/lookup.js +94 -0
- package/dist/pricing/lookup.js.map +1 -0
- package/dist/pricing/table.d.ts +46 -0
- package/dist/pricing/table.d.ts.map +1 -0
- package/dist/pricing/table.js +214 -0
- package/dist/pricing/table.js.map +1 -0
- package/dist/pricing/types.d.ts +84 -0
- package/dist/pricing/types.d.ts.map +1 -0
- package/dist/pricing/types.js +32 -0
- package/dist/pricing/types.js.map +1 -0
- package/package.json +6 -2
- package/src/index.ts +42 -1
- package/src/models.ts +8 -12
- package/src/policy.ts +343 -0
- package/src/pricing/index.ts +29 -0
- package/src/pricing/lookup.ts +124 -0
- package/src/pricing/table.ts +235 -0
- package/src/pricing/types.ts +90 -0
- package/{src → test}/aliases.test.ts +20 -22
- package/{src → test}/index.test.ts +9 -9
- package/{src → test}/models.test.ts +8 -6
- package/test/policy.test.ts +203 -0
- package/test/pricing.test.ts +279 -0
- package/vitest.config.ts +21 -1
- package/.turbo/turbo-test.log +0 -7
- package/src/aliases.js +0 -40
- package/src/aliases.test.js +0 -264
- package/src/index.js +0 -9
- package/src/index.test.js +0 -320
- package/src/models.js +0 -108
- package/src/models.test.js +0 -335
- package/vitest.config.js +0 -10
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* language-models / pricing — canonical model pricing table.
|
|
3
|
+
*
|
|
4
|
+
* All rates are USD per 1,000,000 tokens (per1M form, NOT per1k). Sourced
|
|
5
|
+
* from public list prices on 2026-05-07. Where prior repo tables disagree,
|
|
6
|
+
* the most-recently-updated source wins:
|
|
7
|
+
*
|
|
8
|
+
* - **Vertex Gemini 3.x**: startup-builder/packages/llm-vertex-batch
|
|
9
|
+
* (sb-srnl 2026-05-07 verified) is canonical for the flex/batch tier.
|
|
10
|
+
* startup-builder/packages/llm-vertex (same date) is canonical for
|
|
11
|
+
* standard interactive pricing.
|
|
12
|
+
* - **Vertex Gemini 2.5**: startup-builder/llm-vertex-batch is canonical
|
|
13
|
+
* (icps's `gemini-2.5-flash` rates were ~4× off — likely transposed
|
|
14
|
+
* from a different SKU).
|
|
15
|
+
* - **Bedrock Anthropic**: startup-builder/packages/llm-bedrock is the
|
|
16
|
+
* most-recently-curated table (matches AWS Bedrock public pricing on
|
|
17
|
+
* 2026-05-07).
|
|
18
|
+
* - **Embeddings**: icps/packages/llm/pricing.ts is the source for
|
|
19
|
+
* `gemini-embedding-2`. Bedrock has no first-party Gemini embedding
|
|
20
|
+
* SKU; Anthropic has no embedding SKU. Embedding lives under
|
|
21
|
+
* `aistudio/` since the cheapest path is the AI Studio API key (icps's
|
|
22
|
+
* 2026-05-07 fallback chain — the path startup-builder also uses).
|
|
23
|
+
*
|
|
24
|
+
* 200K-context tier breakpoint:
|
|
25
|
+
*
|
|
26
|
+
* Gemini 3.1 Pro Preview list pricing has a 2× rate above 200K input
|
|
27
|
+
* tokens. We model this with `contextTierBreakpoint: 200_000` +
|
|
28
|
+
* `contextTierAbove`. Anthropic Claude has flat pricing (no breakpoint).
|
|
29
|
+
* Gemini 2.5 + 3.x flash-lite + embedding SKUs are flat too.
|
|
30
|
+
*
|
|
31
|
+
* Adding a new SKU:
|
|
32
|
+
*
|
|
33
|
+
* 1. Append a new row keyed on `<provider>/<short-slug>` + `tier`. Both
|
|
34
|
+
* fields together form the lookup key; duplicates are caught by the
|
|
35
|
+
* table-integrity test.
|
|
36
|
+
* 2. If the SKU has a context-tier breakpoint, add
|
|
37
|
+
* `contextTierBreakpoint` + `contextTierAbove`. Otherwise omit them.
|
|
38
|
+
* 3. If both standard + batch tiers exist, add BOTH rows; downstream
|
|
39
|
+
* consumers select via `priceFor({ tier: ... })`. Vertex's batch tier
|
|
40
|
+
* is ~50% of standard; that's not enforced — declare the actual
|
|
41
|
+
* published rates.
|
|
42
|
+
* 4. Bump the package version (semver minor for additions).
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import type { ModelPricing } from './types.js'
|
|
46
|
+
|
|
47
|
+
export const PRICING_TABLE: readonly ModelPricing[] = [
|
|
48
|
+
// ---------------------------------------------------------------------
|
|
49
|
+
// Vertex Gemini 3.x (200K-context breakpoint applies to 3.1 Pro)
|
|
50
|
+
// ---------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
// gemini-3.1-pro-preview standard interactive
|
|
53
|
+
// ≤200K: $2/M in, $12/M out ; >200K: $4/M in, $18/M out
|
|
54
|
+
{
|
|
55
|
+
provider: 'vertex',
|
|
56
|
+
slug: 'vertex/gemini-3.1-pro',
|
|
57
|
+
tier: 'standard',
|
|
58
|
+
inputPer1M: 2.0,
|
|
59
|
+
outputPer1M: 12.0,
|
|
60
|
+
contextTierBreakpoint: 200_000,
|
|
61
|
+
contextTierAbove: { inputPer1M: 4.0, outputPer1M: 18.0 },
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// gemini-3.1-pro-preview flex/batch (sb-srnl 2026-05-07 verified)
|
|
65
|
+
// ≤200K: $1/M in, $6/M out ; >200K: $2/M in, $9/M out
|
|
66
|
+
{
|
|
67
|
+
provider: 'vertex',
|
|
68
|
+
slug: 'vertex/gemini-3.1-pro',
|
|
69
|
+
tier: 'batch',
|
|
70
|
+
inputPer1M: 1.0,
|
|
71
|
+
outputPer1M: 6.0,
|
|
72
|
+
contextTierBreakpoint: 200_000,
|
|
73
|
+
contextTierAbove: { inputPer1M: 2.0, outputPer1M: 9.0 },
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// gemini-3.1-flash-lite-preview standard
|
|
77
|
+
// Flat: $0.25/M in, $1.50/M out (no breakpoint per public table)
|
|
78
|
+
{
|
|
79
|
+
provider: 'vertex',
|
|
80
|
+
slug: 'vertex/gemini-3.1-flash-lite',
|
|
81
|
+
tier: 'standard',
|
|
82
|
+
inputPer1M: 0.25,
|
|
83
|
+
outputPer1M: 1.5,
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// gemini-3.1-flash-lite-preview flex/batch
|
|
87
|
+
// Flat: $0.13/M in, $0.75/M out
|
|
88
|
+
{
|
|
89
|
+
provider: 'vertex',
|
|
90
|
+
slug: 'vertex/gemini-3.1-flash-lite',
|
|
91
|
+
tier: 'batch',
|
|
92
|
+
inputPer1M: 0.13,
|
|
93
|
+
outputPer1M: 0.75,
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
// gemini-3-pro-preview — placeholder pricing using 3.1 sibling rates
|
|
97
|
+
// (Vertex hasn't published separate 3.0 list prices as of 2026-05-07)
|
|
98
|
+
{
|
|
99
|
+
provider: 'vertex',
|
|
100
|
+
slug: 'vertex/gemini-3-pro',
|
|
101
|
+
tier: 'standard',
|
|
102
|
+
inputPer1M: 2.0,
|
|
103
|
+
outputPer1M: 12.0,
|
|
104
|
+
contextTierBreakpoint: 200_000,
|
|
105
|
+
contextTierAbove: { inputPer1M: 4.0, outputPer1M: 18.0 },
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
provider: 'vertex',
|
|
109
|
+
slug: 'vertex/gemini-3-pro',
|
|
110
|
+
tier: 'batch',
|
|
111
|
+
inputPer1M: 1.0,
|
|
112
|
+
outputPer1M: 6.0,
|
|
113
|
+
contextTierBreakpoint: 200_000,
|
|
114
|
+
contextTierAbove: { inputPer1M: 2.0, outputPer1M: 9.0 },
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// gemini-3-flash-preview — placeholder using 3.1 flash-lite sibling rates
|
|
118
|
+
{
|
|
119
|
+
provider: 'vertex',
|
|
120
|
+
slug: 'vertex/gemini-3-flash',
|
|
121
|
+
tier: 'standard',
|
|
122
|
+
inputPer1M: 0.25,
|
|
123
|
+
outputPer1M: 1.5,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
provider: 'vertex',
|
|
127
|
+
slug: 'vertex/gemini-3-flash',
|
|
128
|
+
tier: 'batch',
|
|
129
|
+
inputPer1M: 0.13,
|
|
130
|
+
outputPer1M: 0.75,
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------
|
|
134
|
+
// Vertex Gemini 2.5 (no context-tier breakpoint per public table)
|
|
135
|
+
// ---------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
// gemini-2.5-pro standard: $1.25/M in, $10/M out
|
|
138
|
+
{
|
|
139
|
+
provider: 'vertex',
|
|
140
|
+
slug: 'vertex/gemini-2.5-pro',
|
|
141
|
+
tier: 'standard',
|
|
142
|
+
inputPer1M: 1.25,
|
|
143
|
+
outputPer1M: 10.0,
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
// gemini-2.5-pro batch: ~50% of standard
|
|
147
|
+
{
|
|
148
|
+
provider: 'vertex',
|
|
149
|
+
slug: 'vertex/gemini-2.5-pro',
|
|
150
|
+
tier: 'batch',
|
|
151
|
+
inputPer1M: 0.625,
|
|
152
|
+
outputPer1M: 5.0,
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
// gemini-2.5-flash standard: $0.075/M in, $0.30/M out
|
|
156
|
+
// (startup-builder/llm-vertex-batch source — supersedes icps's stale rate)
|
|
157
|
+
{
|
|
158
|
+
provider: 'vertex',
|
|
159
|
+
slug: 'vertex/gemini-2.5-flash',
|
|
160
|
+
tier: 'standard',
|
|
161
|
+
inputPer1M: 0.075,
|
|
162
|
+
outputPer1M: 0.3,
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
// gemini-2.5-flash batch: ~50% of standard
|
|
166
|
+
{
|
|
167
|
+
provider: 'vertex',
|
|
168
|
+
slug: 'vertex/gemini-2.5-flash',
|
|
169
|
+
tier: 'batch',
|
|
170
|
+
inputPer1M: 0.0375,
|
|
171
|
+
outputPer1M: 0.15,
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// ---------------------------------------------------------------------
|
|
175
|
+
// Bedrock Anthropic Claude (flat pricing — no context-tier breakpoint)
|
|
176
|
+
// ---------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
// claude-opus-4-7: $15/M in, $75/M out
|
|
179
|
+
{
|
|
180
|
+
provider: 'bedrock',
|
|
181
|
+
slug: 'bedrock/claude-opus-4-7',
|
|
182
|
+
tier: 'standard',
|
|
183
|
+
inputPer1M: 15.0,
|
|
184
|
+
outputPer1M: 75.0,
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
// claude-opus-4-6: same as 4-7
|
|
188
|
+
{
|
|
189
|
+
provider: 'bedrock',
|
|
190
|
+
slug: 'bedrock/claude-opus-4-6',
|
|
191
|
+
tier: 'standard',
|
|
192
|
+
inputPer1M: 15.0,
|
|
193
|
+
outputPer1M: 75.0,
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
// claude-sonnet-4-7: $3/M in, $15/M out
|
|
197
|
+
{
|
|
198
|
+
provider: 'bedrock',
|
|
199
|
+
slug: 'bedrock/claude-sonnet-4-7',
|
|
200
|
+
tier: 'standard',
|
|
201
|
+
inputPer1M: 3.0,
|
|
202
|
+
outputPer1M: 15.0,
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
// claude-sonnet-4-6: same as 4-7
|
|
206
|
+
{
|
|
207
|
+
provider: 'bedrock',
|
|
208
|
+
slug: 'bedrock/claude-sonnet-4-6',
|
|
209
|
+
tier: 'standard',
|
|
210
|
+
inputPer1M: 3.0,
|
|
211
|
+
outputPer1M: 15.0,
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
// claude-haiku-4-5: $1/M in, $5/M out
|
|
215
|
+
{
|
|
216
|
+
provider: 'bedrock',
|
|
217
|
+
slug: 'bedrock/claude-haiku-4-5',
|
|
218
|
+
tier: 'standard',
|
|
219
|
+
inputPer1M: 1.0,
|
|
220
|
+
outputPer1M: 5.0,
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
// ---------------------------------------------------------------------
|
|
224
|
+
// Google AI Studio embeddings
|
|
225
|
+
// ---------------------------------------------------------------------
|
|
226
|
+
|
|
227
|
+
// gemini-embedding-2: $0.15/M input (no output side — pure embedding SKU)
|
|
228
|
+
{
|
|
229
|
+
provider: 'google-ai-studio',
|
|
230
|
+
slug: 'aistudio/gemini-embedding-2',
|
|
231
|
+
tier: 'standard',
|
|
232
|
+
inputPer1M: 0.15,
|
|
233
|
+
outputPer1M: 0,
|
|
234
|
+
},
|
|
235
|
+
]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* language-models / pricing — type definitions for the canonical pricing table.
|
|
3
|
+
*
|
|
4
|
+
* Schema design notes (sb-ncer 2026-05-07):
|
|
5
|
+
*
|
|
6
|
+
* 1. **Provider** is the upstream API surface, not the model family. AWS
|
|
7
|
+
* Bedrock hosts Anthropic Claude, but `provider: 'bedrock'` (not
|
|
8
|
+
* `'anthropic'`) — same model, different cost when consumed via
|
|
9
|
+
* Anthropic's first-party API key (provider: 'anthropic' would be a
|
|
10
|
+
* DIFFERENT row with potentially different rates).
|
|
11
|
+
*
|
|
12
|
+
* 2. **Slug** is the caller-facing string: `<provider>/<short-name>`.
|
|
13
|
+
* Multiple slugs (the cascade short slug, the SDK-native id, etc.)
|
|
14
|
+
* can map to the same logical SKU — but for the canonical primitive
|
|
15
|
+
* we only carry the cascade short slug (`vertex/gemini-3.1-pro`,
|
|
16
|
+
* `bedrock/claude-opus-4-7`). Adapter packages can layer their own
|
|
17
|
+
* rewrite tables on top.
|
|
18
|
+
*
|
|
19
|
+
* 3. **Tier** distinguishes pricing modes for the same SKU:
|
|
20
|
+
* - `standard`: synchronous interactive pricing (full price)
|
|
21
|
+
* - `batch`: async batch-prediction pricing (typically 50% discount)
|
|
22
|
+
* - `flex`: flex-tier pricing (Vertex's name for batch, kept as alias)
|
|
23
|
+
* - `provisioned`: provisioned-throughput pricing (per-hour, not
|
|
24
|
+
* currently modeled — placeholder for future PT entries)
|
|
25
|
+
*
|
|
26
|
+
* 4. **contextTierBreakpoint + contextTierAbove**: Gemini 3.x SKUs apply
|
|
27
|
+
* a 2× rate above 200K input tokens; Anthropic Claude pricing is flat.
|
|
28
|
+
* Optional fields — when absent, the base rate applies regardless of
|
|
29
|
+
* input size.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
export type Provider = 'vertex' | 'bedrock' | 'openai' | 'anthropic' | 'google-ai-studio'
|
|
33
|
+
|
|
34
|
+
export type PricingTier = 'standard' | 'batch' | 'flex' | 'provisioned'
|
|
35
|
+
|
|
36
|
+
/** Rates expressed in USD per 1,000,000 tokens. */
|
|
37
|
+
export interface RateBlock {
|
|
38
|
+
/** USD per 1M input tokens. */
|
|
39
|
+
readonly inputPer1M: number
|
|
40
|
+
/** USD per 1M output (completion) tokens. */
|
|
41
|
+
readonly outputPer1M: number
|
|
42
|
+
/**
|
|
43
|
+
* Optional USD per 1M cached input tokens (prompt-caching tier). When
|
|
44
|
+
* absent, callers should fall back to inputPer1M (no cache discount).
|
|
45
|
+
*/
|
|
46
|
+
readonly cachedInputPer1M?: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Single canonical pricing row. Identity is `(slug, tier)` — provider is
|
|
51
|
+
* derived from the slug prefix and stored explicitly only for tooling
|
|
52
|
+
* convenience.
|
|
53
|
+
*/
|
|
54
|
+
export interface ModelPricing extends RateBlock {
|
|
55
|
+
readonly provider: Provider
|
|
56
|
+
readonly slug: string
|
|
57
|
+
readonly tier: PricingTier
|
|
58
|
+
/**
|
|
59
|
+
* Token count at which pricing changes (inclusive — i.e. inputs >=
|
|
60
|
+
* breakpoint use contextTierAbove). Currently only Gemini 3.x SKUs
|
|
61
|
+
* have a breakpoint (200_000). Anthropic Claude has flat pricing.
|
|
62
|
+
*/
|
|
63
|
+
readonly contextTierBreakpoint?: number
|
|
64
|
+
/** Rates that apply when inputTokens >= contextTierBreakpoint. */
|
|
65
|
+
readonly contextTierAbove?: RateBlock
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PriceForArgs {
|
|
69
|
+
readonly slug: string
|
|
70
|
+
readonly tier: PricingTier
|
|
71
|
+
readonly inputTokens: number
|
|
72
|
+
readonly outputTokens: number
|
|
73
|
+
/**
|
|
74
|
+
* Optional cached input tokens (subset of inputTokens that hit a
|
|
75
|
+
* prompt-caching tier). Billed at cachedInputPer1M when the row
|
|
76
|
+
* defines it; otherwise at inputPer1M (i.e. no discount).
|
|
77
|
+
*/
|
|
78
|
+
readonly cachedInputTokens?: number
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface PriceForResult {
|
|
82
|
+
readonly inputUsd: number
|
|
83
|
+
readonly outputUsd: number
|
|
84
|
+
readonly totalUsd: number
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface HasPricingArgs {
|
|
88
|
+
readonly slug: string
|
|
89
|
+
readonly tier: PricingTier
|
|
90
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { describe, it, expect } from 'vitest'
|
|
9
|
-
import { ALIASES } from '
|
|
9
|
+
import { ALIASES } from '../src/aliases.js'
|
|
10
10
|
|
|
11
11
|
describe('ALIASES', () => {
|
|
12
12
|
it('is an object', () => {
|
|
@@ -217,7 +217,7 @@ describe('ALIASES', () => {
|
|
|
217
217
|
})
|
|
218
218
|
|
|
219
219
|
it('has unique lowercase keys', () => {
|
|
220
|
-
const lowerKeys = Object.keys(ALIASES).map(k => k.toLowerCase())
|
|
220
|
+
const lowerKeys = Object.keys(ALIASES).map((k) => k.toLowerCase())
|
|
221
221
|
const uniqueLowerKeys = new Set(lowerKeys)
|
|
222
222
|
expect(lowerKeys.length).toBe(uniqueLowerKeys.size)
|
|
223
223
|
})
|
|
@@ -249,9 +249,7 @@ describe('ALIASES', () => {
|
|
|
249
249
|
|
|
250
250
|
describe('provider coverage', () => {
|
|
251
251
|
it('covers major AI providers', () => {
|
|
252
|
-
const providers = new Set(
|
|
253
|
-
Object.values(ALIASES).map(v => v.split('/')[0])
|
|
254
|
-
)
|
|
252
|
+
const providers = new Set(Object.values(ALIASES).map((v) => v.split('/')[0]))
|
|
255
253
|
|
|
256
254
|
expect(providers.has('anthropic')).toBe(true)
|
|
257
255
|
expect(providers.has('openai')).toBe(true)
|
|
@@ -278,29 +276,29 @@ describe('ALIASES', () => {
|
|
|
278
276
|
it('matches all aliases documented in README', () => {
|
|
279
277
|
// These are the aliases listed in the README.md table
|
|
280
278
|
const documentedAliases = {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
279
|
+
opus: 'anthropic/claude-opus-4.5',
|
|
280
|
+
sonnet: 'anthropic/claude-sonnet-4.5',
|
|
281
|
+
haiku: 'anthropic/claude-haiku-4.5',
|
|
282
|
+
claude: 'anthropic/claude-sonnet-4.5',
|
|
283
|
+
gpt: 'openai/gpt-4o',
|
|
286
284
|
'gpt-4o': 'openai/gpt-4o',
|
|
287
285
|
'4o': 'openai/gpt-4o',
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
o1: 'openai/o1',
|
|
287
|
+
o3: 'openai/o3',
|
|
290
288
|
'o3-mini': 'openai/o3-mini',
|
|
291
|
-
|
|
292
|
-
|
|
289
|
+
gemini: 'google/gemini-2.5-flash',
|
|
290
|
+
flash: 'google/gemini-2.5-flash',
|
|
293
291
|
'gemini-pro': 'google/gemini-2.5-pro',
|
|
294
|
-
|
|
292
|
+
llama: 'meta-llama/llama-4-maverick',
|
|
295
293
|
'llama-4': 'meta-llama/llama-4-maverick',
|
|
296
294
|
'llama-70b': 'meta-llama/llama-3.3-70b-instruct',
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
295
|
+
mistral: 'mistralai/mistral-large-2411',
|
|
296
|
+
codestral: 'mistralai/codestral-2501',
|
|
297
|
+
deepseek: 'deepseek/deepseek-chat',
|
|
298
|
+
r1: 'deepseek/deepseek-r1',
|
|
299
|
+
qwen: 'qwen/qwen3-235b-a22b',
|
|
300
|
+
grok: 'x-ai/grok-3',
|
|
301
|
+
sonar: 'perplexity/sonar-pro',
|
|
304
302
|
}
|
|
305
303
|
|
|
306
304
|
for (const [alias, expectedId] of Object.entries(documentedAliases)) {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
type ProviderEndpoint,
|
|
18
18
|
type ResolvedModel,
|
|
19
19
|
type DirectProvider,
|
|
20
|
-
} from '
|
|
20
|
+
} from '../src/index.js'
|
|
21
21
|
|
|
22
22
|
describe('package exports', () => {
|
|
23
23
|
it('exports resolve function', () => {
|
|
@@ -166,8 +166,8 @@ describe('end-to-end workflows', () => {
|
|
|
166
166
|
expect(allModels.length).toBeGreaterThanOrEqual(0)
|
|
167
167
|
|
|
168
168
|
if (allModels.length > 0) {
|
|
169
|
-
const anthropicModels = allModels.filter(m => m.id.startsWith('anthropic/'))
|
|
170
|
-
const openaiModels = allModels.filter(m => m.id.startsWith('openai/'))
|
|
169
|
+
const anthropicModels = allModels.filter((m) => m.id.startsWith('anthropic/'))
|
|
170
|
+
const openaiModels = allModels.filter((m) => m.id.startsWith('openai/'))
|
|
171
171
|
|
|
172
172
|
if (anthropicModels.length > 0) {
|
|
173
173
|
expect(anthropicModels[0].id).toContain('anthropic/')
|
|
@@ -182,7 +182,7 @@ describe('end-to-end workflows', () => {
|
|
|
182
182
|
const allModels = list()
|
|
183
183
|
|
|
184
184
|
if (allModels.length > 0) {
|
|
185
|
-
const directModels = allModels.filter(m => {
|
|
185
|
+
const directModels = allModels.filter((m) => {
|
|
186
186
|
const provider = m.id.split('/')[0]
|
|
187
187
|
return (DIRECT_PROVIDERS as readonly string[]).includes(provider)
|
|
188
188
|
})
|
|
@@ -282,8 +282,8 @@ describe('end-to-end workflows', () => {
|
|
|
282
282
|
expect(Array.isArray(claudeModels)).toBe(true)
|
|
283
283
|
if (claudeModels.length > 0) {
|
|
284
284
|
expect(
|
|
285
|
-
claudeModels.some(
|
|
286
|
-
m.id.includes('claude') || m.name.toLowerCase().includes('claude')
|
|
285
|
+
claudeModels.some(
|
|
286
|
+
(m) => m.id.includes('claude') || m.name.toLowerCase().includes('claude')
|
|
287
287
|
)
|
|
288
288
|
).toBe(true)
|
|
289
289
|
}
|
|
@@ -329,7 +329,7 @@ describe('end-to-end workflows', () => {
|
|
|
329
329
|
it('models may have architecture info', () => {
|
|
330
330
|
const models = list()
|
|
331
331
|
if (models.length > 0) {
|
|
332
|
-
const modelWithArch = models.find(m => m.architecture)
|
|
332
|
+
const modelWithArch = models.find((m) => m.architecture)
|
|
333
333
|
if (modelWithArch?.architecture) {
|
|
334
334
|
expect(modelWithArch.architecture.modality).toBeDefined()
|
|
335
335
|
expect(Array.isArray(modelWithArch.architecture.input_modalities)).toBe(true)
|
|
@@ -344,7 +344,7 @@ describe('end-to-end workflows', () => {
|
|
|
344
344
|
const directProviders = ['anthropic', 'openai', 'google']
|
|
345
345
|
|
|
346
346
|
for (const provider of directProviders) {
|
|
347
|
-
const models = list().filter(m => m.id.startsWith(`${provider}/`))
|
|
347
|
+
const models = list().filter((m) => m.id.startsWith(`${provider}/`))
|
|
348
348
|
if (models.length > 0) {
|
|
349
349
|
const resolved = resolveWithProvider(models[0].id)
|
|
350
350
|
expect(resolved.supportsDirectRouting).toBe(true)
|
|
@@ -355,7 +355,7 @@ describe('end-to-end workflows', () => {
|
|
|
355
355
|
|
|
356
356
|
it('identifies non-direct routing providers', () => {
|
|
357
357
|
const models = list()
|
|
358
|
-
const nonDirectModel = models.find(m => {
|
|
358
|
+
const nonDirectModel = models.find((m) => {
|
|
359
359
|
const provider = m.id.split('/')[0]
|
|
360
360
|
return !(DIRECT_PROVIDERS as readonly string[]).includes(provider)
|
|
361
361
|
})
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
DIRECT_PROVIDERS,
|
|
15
15
|
type ModelInfo,
|
|
16
16
|
type ResolvedModel,
|
|
17
|
-
} from '
|
|
18
|
-
import { ALIASES } from '
|
|
17
|
+
} from '../src/models.js'
|
|
18
|
+
import { ALIASES } from '../src/aliases.js'
|
|
19
19
|
|
|
20
20
|
describe('list', () => {
|
|
21
21
|
it('returns an array of models', () => {
|
|
@@ -93,7 +93,7 @@ describe('search', () => {
|
|
|
93
93
|
const idPart = model.id.split('/')[0] // Provider name
|
|
94
94
|
const results = search(idPart)
|
|
95
95
|
expect(results.length).toBeGreaterThan(0)
|
|
96
|
-
expect(results.some(m => m.id.includes(idPart))).toBe(true)
|
|
96
|
+
expect(results.some((m) => m.id.includes(idPart))).toBe(true)
|
|
97
97
|
}
|
|
98
98
|
})
|
|
99
99
|
|
|
@@ -123,11 +123,13 @@ describe('search', () => {
|
|
|
123
123
|
const models = list()
|
|
124
124
|
if (models.length > 0) {
|
|
125
125
|
// Find a model and search for part of its name
|
|
126
|
-
const model = models.find(m => m.name.includes(' '))
|
|
126
|
+
const model = models.find((m) => m.name.includes(' '))
|
|
127
127
|
if (model) {
|
|
128
128
|
const namePart = model.name.split(' ')[0].toLowerCase()
|
|
129
129
|
const results = search(namePart)
|
|
130
|
-
expect(
|
|
130
|
+
expect(
|
|
131
|
+
results.some((m) => m.id === model.id || m.name.toLowerCase().includes(namePart))
|
|
132
|
+
).toBe(true)
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
})
|
|
@@ -299,7 +301,7 @@ describe('resolveWithProvider', () => {
|
|
|
299
301
|
it('identifies non-direct providers', () => {
|
|
300
302
|
// Use a model from a provider not in DIRECT_PROVIDERS
|
|
301
303
|
const models = list()
|
|
302
|
-
const nonDirectModel = models.find(m => {
|
|
304
|
+
const nonDirectModel = models.find((m) => {
|
|
303
305
|
const provider = m.id.split('/')[0]
|
|
304
306
|
return !(DIRECT_PROVIDERS as readonly string[]).includes(provider)
|
|
305
307
|
})
|