@molecule/api-resource-ai-models 1.0.2 → 1.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 +238 -27
- package/dist/handlers/list.d.ts +12 -4
- package/dist/handlers/list.d.ts.map +1 -1
- package/dist/handlers/list.js +16 -6
- package/dist/lookup.d.ts +101 -16
- package/dist/lookup.d.ts.map +1 -1
- package/dist/lookup.js +172 -25
- package/dist/models.d.ts +30 -8
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +302 -76
- package/dist/types.d.ts +83 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-08-
|
|
6
|
+
Generated: 2026-08-13T22:10:11.926Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-resource-ai-models
|
|
@@ -260,6 +260,57 @@ interface ModelDefinition {
|
|
|
260
260
|
windows: { startMinuteUtc: number; endMinuteUtc: number }[]
|
|
261
261
|
multiplier: number
|
|
262
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* A price change the provider has ANNOUNCED with a dated effective instant,
|
|
265
|
+
* staged ahead of time. Until `effectiveFrom` the model bills at the base
|
|
266
|
+
* rates above; from that instant on, these rates replace them.
|
|
267
|
+
*
|
|
268
|
+
* This exists because the freshness gate can only ever see prices that are
|
|
269
|
+
* ALREADY live: it diffs the catalog against models.dev's *current* rates, so
|
|
270
|
+
* a change announced today and effective in three days is invisible to it
|
|
271
|
+
* until after it lands — and the cron runs every 8h, so the catalog would
|
|
272
|
+
* under-meter for up to a third of a day at whatever the new rate is. Landing
|
|
273
|
+
* the new numbers early is not an option either: that over-bills every turn
|
|
274
|
+
* until the switch (the exact mistake the removed DeepSeek peak windows made
|
|
275
|
+
* for weeks against the free-tier default model). Staging with a timestamp is
|
|
276
|
+
* the only form that is correct on BOTH sides of the instant, and it needs no
|
|
277
|
+
* one awake at the switch.
|
|
278
|
+
*
|
|
279
|
+
* Applies to the BASE rates only — a `regionPricing` entry is a different
|
|
280
|
+
* host's rate card (a US re-host does not reprice because the native provider
|
|
281
|
+
* did) and is never touched by a scheduled change.
|
|
282
|
+
*
|
|
283
|
+
* `peakPricing` here, when declared, replaces the model's peak windows from
|
|
284
|
+
* the same instant; when omitted, the model's existing windows carry through
|
|
285
|
+
* unchanged. To schedule the END of peak pricing, declare an explicit
|
|
286
|
+
* `{ windows: [], multiplier: 1 }`.
|
|
287
|
+
*
|
|
288
|
+
* Resolution is `effectiveBaseRates()` / `effectivePeakPricing()`, and every
|
|
289
|
+
* consumer reaches it through `modelRegionRates()` / `priceMultiplierAt()` /
|
|
290
|
+
* the `withEffectivePricing()` projection the list handler serves — so a
|
|
291
|
+
* scheduled change lands everywhere at once with no follow-up edit. Once the
|
|
292
|
+
* instant has passed, fold the rates into the base fields and delete this
|
|
293
|
+
* (the freshness gate now verifies them against models.dev normally).
|
|
294
|
+
*/
|
|
295
|
+
scheduledPricing?: {
|
|
296
|
+
/** ISO-8601 UTC instant the new rates take effect. */
|
|
297
|
+
effectiveFrom: string
|
|
298
|
+
/** Input price per million *uncached* tokens in USD, from `effectiveFrom`. */
|
|
299
|
+
inputPricePerMTok: number
|
|
300
|
+
/** Output price per million tokens in USD, from `effectiveFrom`. */
|
|
301
|
+
outputPricePerMTok: number
|
|
302
|
+
/** Prompt-cache *read* price per million tokens in USD, from `effectiveFrom`. */
|
|
303
|
+
cacheReadPricePerMTok: number
|
|
304
|
+
/** Prompt-cache *write* price per million tokens in USD, from `effectiveFrom`. */
|
|
305
|
+
cacheWritePricePerMTok: number
|
|
306
|
+
/** Peak-hour pricing from `effectiveFrom` (omitted → existing windows carry through). */
|
|
307
|
+
peakPricing?: {
|
|
308
|
+
windows: { startMinuteUtc: number; endMinuteUtc: number }[]
|
|
309
|
+
multiplier: number
|
|
310
|
+
}
|
|
311
|
+
/** Where the change was announced, for the re-verify pass after it lands. */
|
|
312
|
+
source?: string
|
|
313
|
+
}
|
|
263
314
|
/**
|
|
264
315
|
* Fast-mode ("priority speed") pricing — the per-MTok rates billed when a
|
|
265
316
|
* request runs with the provider's fast/priority tier (e.g. Anthropic's
|
|
@@ -310,6 +361,35 @@ interface ModelDefinition {
|
|
|
310
361
|
* or its past usage silently meters as free. Omit entirely for active models.
|
|
311
362
|
*/
|
|
312
363
|
disabled?: boolean
|
|
364
|
+
/**
|
|
365
|
+
* The id of the NEWER-generation model that replaces this one, set on the
|
|
366
|
+
* OLDER entry and naming its successor (e.g. `qwen3.7-max` carries
|
|
367
|
+
* `supersededBy: 'qwen3.8-max'`).
|
|
368
|
+
*
|
|
369
|
+
* A superseded model is NOT selectable — like {@link disabled} it is excluded
|
|
370
|
+
* from `MODEL_IDS`, `getAvailableModels()`, the `GET /ai/models` listing and
|
|
371
|
+
* the client-side picker partitions, so a user is only ever offered the
|
|
372
|
+
* newest generation of a family. It differs from `disabled` in *why* and in
|
|
373
|
+
* what it points at: a disabled model is one the provider retired (it can no
|
|
374
|
+
* longer answer), whereas a superseded model is usually still served upstream
|
|
375
|
+
* and simply has nothing to offer over its successor — and the successor id
|
|
376
|
+
* is a real migration target, so a saved selection can resolve forward
|
|
377
|
+
* (`resolveSelectableModelId`) instead of silently falling back to the
|
|
378
|
+
* platform default.
|
|
379
|
+
*
|
|
380
|
+
* `getModel(id)` STILL returns a superseded entry — historical usage must stay
|
|
381
|
+
* priceable, so NEVER delete one.
|
|
382
|
+
*
|
|
383
|
+
* Set this ONLY when the successor covers the same TIER. A cheaper or
|
|
384
|
+
* specialist tier with no newer equivalent is NOT superseded merely because
|
|
385
|
+
* its version number is lower (Google's sole pro tier `gemini-3.1-pro-preview`
|
|
386
|
+
* alongside the newer flash flagship; `qwen3-coder-plus`; `kimi-k2.7-code`) —
|
|
387
|
+
* hiding those would leave a provider with no cheap option. Mark those
|
|
388
|
+
* {@link deprecatedAt} at most. The invariant is enforced by
|
|
389
|
+
* `__tests__/lookup.test.ts`: two selectable models of the same family at
|
|
390
|
+
* different versions fail unless listed there as a documented exception.
|
|
391
|
+
*/
|
|
392
|
+
supersededBy?: string
|
|
313
393
|
}
|
|
314
394
|
```
|
|
315
395
|
|
|
@@ -402,6 +482,25 @@ type EffortLevel = string
|
|
|
402
482
|
|
|
403
483
|
### Functions
|
|
404
484
|
|
|
485
|
+
#### `effectiveBaseRates(modelDef, at)`
|
|
486
|
+
|
|
487
|
+
A model's BASE token rates in effect at a given instant — the staged
|
|
488
|
+
{@link ModelDefinition.scheduledPricing} rates once their `effectiveFrom` has
|
|
489
|
+
passed, else the base fields.
|
|
490
|
+
|
|
491
|
+
These are the native provider's rates. A `regionPricing` override is a
|
|
492
|
+
different host's rate card and is resolved separately by
|
|
493
|
+
{@link modelRegionRates}.
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
function effectiveBaseRates(modelDef: ModelDefinition, at?: Date): ModelTokenRates
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
- `modelDef` — The model definition.
|
|
500
|
+
- `at` — The instant to price at (defaults to now).
|
|
501
|
+
|
|
502
|
+
**Returns:** The base rates in effect at that instant.
|
|
503
|
+
|
|
405
504
|
#### `effectiveModelRegion(modelDef, requested)`
|
|
406
505
|
|
|
407
506
|
Resolve a model's effective processing region: the requested region when the
|
|
@@ -419,12 +518,32 @@ function effectiveModelRegion(modelDef: ModelDefinition | undefined, requested?:
|
|
|
419
518
|
|
|
420
519
|
**Returns:** The effective region code.
|
|
421
520
|
|
|
521
|
+
#### `effectivePeakPricing(modelDef, at)`
|
|
522
|
+
|
|
523
|
+
A model's peak-hour pricing in effect at a given instant: the staged
|
|
524
|
+
{@link ModelDefinition.scheduledPricing} `peakPricing` once its
|
|
525
|
+
`effectiveFrom` has passed (when that entry declares one — an omitted one
|
|
526
|
+
leaves the existing windows in force), else the model's own `peakPricing`.
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
function effectivePeakPricing(
|
|
530
|
+
modelDef: ModelDefinition,
|
|
531
|
+
at?: Date,
|
|
532
|
+
): { windows: { startMinuteUtc: number; endMinuteUtc: number }[]; multiplier: number } | undefined
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
- `modelDef` — The model definition.
|
|
536
|
+
- `at` — The instant to evaluate (defaults to now).
|
|
537
|
+
|
|
538
|
+
**Returns:** The peak-pricing config in effect, or `undefined` when none is.
|
|
539
|
+
|
|
422
540
|
#### `getAvailableModels(availableProviders)`
|
|
423
541
|
|
|
424
542
|
Get models that are currently usable — filtered to only providers that are available.
|
|
425
543
|
|
|
426
544
|
The caller passes in which provider IDs are active (i.e. have a bond wired).
|
|
427
|
-
|
|
545
|
+
Models that are not {@link isSelectableModel} — `disabled` or superseded by a
|
|
546
|
+
newer generation — are excluded; they are never offered for selection.
|
|
428
547
|
|
|
429
548
|
```typescript
|
|
430
549
|
function getAvailableModels(
|
|
@@ -434,16 +553,16 @@ function getAvailableModels(
|
|
|
434
553
|
|
|
435
554
|
- `availableProviders` — Set or array of provider IDs that have active bonds.
|
|
436
555
|
|
|
437
|
-
**Returns:**
|
|
556
|
+
**Returns:** Selectable models whose provider is in the available set.
|
|
438
557
|
|
|
439
558
|
#### `getModel(id)`
|
|
440
559
|
|
|
441
560
|
Look up a model definition by ID.
|
|
442
561
|
|
|
443
|
-
Returns `disabled` models too: a saved selection or a
|
|
444
|
-
may reference a since-retired model,
|
|
445
|
-
{@link MODEL_IDS} / {@link getAvailableModels}
|
|
446
|
-
|
|
562
|
+
Returns `disabled` and `supersededBy` models too: a saved selection or a
|
|
563
|
+
historical usage row may reference a since-retired or since-superseded model,
|
|
564
|
+
and it must stay priceable. Use {@link MODEL_IDS} / {@link getAvailableModels}
|
|
565
|
+
(or {@link isSelectableModel}) to decide what is _selectable_.
|
|
447
566
|
|
|
448
567
|
```typescript
|
|
449
568
|
function getModel(id: string): ModelDefinition | undefined
|
|
@@ -465,6 +584,21 @@ function getModelsByProvider(provider: AIProviderID): readonly ModelDefinition[]
|
|
|
465
584
|
|
|
466
585
|
**Returns:** Array of model definitions for that provider.
|
|
467
586
|
|
|
587
|
+
#### `isSelectableModel(model)`
|
|
588
|
+
|
|
589
|
+
Whether a model may be offered for selection: not `disabled` (retired
|
|
590
|
+
upstream) and not `supersededBy` a newer generation of its own family. Both
|
|
591
|
+
kinds stay in the catalog for pricing — this predicate is the single place
|
|
592
|
+
that decides _exposure_, so every listing/validation surface agrees.
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
function isSelectableModel(model: Pick<ModelDefinition, 'disabled' | 'supersededBy'>): boolean
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
- `model` — The model definition (or the two flags from one).
|
|
599
|
+
|
|
600
|
+
**Returns:** True when the model may be listed and chosen.
|
|
601
|
+
|
|
468
602
|
#### `list(_req, res)`
|
|
469
603
|
|
|
470
604
|
Returns models whose `provider` has a bond registered under the `'ai'`
|
|
@@ -482,41 +616,95 @@ function list(_req: MoleculeRequest, res: MoleculeResponse): Promise<void>
|
|
|
482
616
|
- `_req` — The request object (unused).
|
|
483
617
|
- `res` — The response object.
|
|
484
618
|
|
|
485
|
-
#### `modelRegionRates(modelDef, requested)`
|
|
619
|
+
#### `modelRegionRates(modelDef, requested, at)`
|
|
486
620
|
|
|
487
621
|
The token rates for a model in a given processing region: the model's
|
|
488
622
|
{@link ModelDefinition.regionPricing} override for the region when one
|
|
489
|
-
exists, else the base rates (the native provider's list
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
623
|
+
exists, else the base rates in effect at `at` (the native provider's list
|
|
624
|
+
prices, including any staged {@link ModelDefinition.scheduledPricing} change
|
|
625
|
+
that has landed). Omitted cache fields in an override fall back to the
|
|
626
|
+
override's input price (hosts with no cache discount / no write premium). The
|
|
627
|
+
region is resolved via {@link effectiveModelRegion}, so callers may pass the
|
|
628
|
+
raw user choice.
|
|
629
|
+
|
|
630
|
+
`at` defaults to NOW rather than being required, so an existing caller cannot
|
|
631
|
+
keep billing a superseded rate by omitting it — metering should still pass
|
|
632
|
+
each request's own timestamp, the same way it must for
|
|
633
|
+
{@link priceMultiplierAt}.
|
|
493
634
|
|
|
494
635
|
```typescript
|
|
495
|
-
function modelRegionRates(modelDef: ModelDefinition, requested?: string): ModelTokenRates
|
|
636
|
+
function modelRegionRates(modelDef: ModelDefinition, requested?: string, at?: Date): ModelTokenRates
|
|
496
637
|
```
|
|
497
638
|
|
|
498
639
|
- `modelDef` — The model definition.
|
|
499
640
|
- `requested` — The user's per-model region choice, if any.
|
|
641
|
+
- `at` — The instant to price at (defaults to now).
|
|
500
642
|
|
|
501
643
|
**Returns:** The region-effective rates.
|
|
502
644
|
|
|
503
|
-
#### `priceMultiplierAt(modelDef, at)`
|
|
645
|
+
#### `priceMultiplierAt(modelDef, at, region)`
|
|
504
646
|
|
|
505
|
-
The price multiplier in effect for a model at a given instant.
|
|
647
|
+
The price multiplier in effect for a model at a given instant, in a region.
|
|
506
648
|
|
|
507
649
|
Consults the model's {@link ModelDefinition.peakPricing} windows (UTC,
|
|
508
650
|
half-open, may wrap midnight). Metering MUST call this with each request's
|
|
509
651
|
own timestamp so peak-hour usage bills at the provider's real rate — pricing
|
|
510
652
|
everything at the flat rate silently under-meters peak traffic.
|
|
511
653
|
|
|
654
|
+
Peak windows belong to the NATIVE provider, so they apply only where the base
|
|
655
|
+
rates do. A region with a {@link ModelDefinition.regionPricing} override is a
|
|
656
|
+
different host billing its own complete rate card, including whether it has
|
|
657
|
+
time-of-day pricing at all — and re-hosts generally do not. Applying the
|
|
658
|
+
native provider's surcharge on top of a re-host's flat rates would over-bill
|
|
659
|
+
every turn in its windows (DeepSeek's 2× Beijing-hours pricing charged
|
|
660
|
+
against DeepInfra, which has no peak pricing).
|
|
661
|
+
|
|
512
662
|
```typescript
|
|
513
|
-
function priceMultiplierAt(modelDef: ModelDefinition | undefined, at: Date): number
|
|
663
|
+
function priceMultiplierAt(modelDef: ModelDefinition | undefined, at: Date, region?: string): number
|
|
514
664
|
```
|
|
515
665
|
|
|
516
666
|
- `modelDef` — The model definition (or undefined).
|
|
517
667
|
- `at` — The instant the request was made.
|
|
668
|
+
- `region` — The user's per-model region choice, if any (omitted → the model's default region).
|
|
518
669
|
|
|
519
|
-
**Returns:** The multiplier (`1` outside peak windows
|
|
670
|
+
**Returns:** The multiplier (`1` outside peak windows, when none are declared, or in a region that prices off its own override).
|
|
671
|
+
|
|
672
|
+
#### `resolveSelectableModelId(id)`
|
|
673
|
+
|
|
674
|
+
Resolve a model id FORWARD to the selectable model that replaces it, following
|
|
675
|
+
the {@link ModelDefinition.supersededBy} chain (a saved `qwen3.7-max` →
|
|
676
|
+
`qwen3.8-max`). Lets a persisted selection keep the user's intent — the same
|
|
677
|
+
tier from the same provider — instead of falling back to the platform default
|
|
678
|
+
once the older generation stops being offered.
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
function resolveSelectableModelId(id: string): string | undefined
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
- `id` — The persisted model id.
|
|
685
|
+
|
|
686
|
+
**Returns:** The selectable successor's id, the id itself when it is already selectable, or `undefined` for an unknown or `disabled` model (nothing to forward to).
|
|
687
|
+
|
|
688
|
+
#### `withEffectivePricing(modelDef, at)`
|
|
689
|
+
|
|
690
|
+
A model projected onto the pricing in effect at a given instant: the staged
|
|
691
|
+
{@link ModelDefinition.scheduledPricing} rates folded into the base fields
|
|
692
|
+
(and its peak windows into `peakPricing`) once effective, with the staged
|
|
693
|
+
entry stripped.
|
|
694
|
+
|
|
695
|
+
This is what the `GET /ai/models` handler serves, so a client renders the
|
|
696
|
+
rates that are actually billing right now without needing to resolve a
|
|
697
|
+
schedule against its own clock — the server's clock is the only one that
|
|
698
|
+
decides when a price change lands.
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
function withEffectivePricing(modelDef: ModelDefinition, at?: Date): ModelDefinition
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
- `modelDef` — The model definition.
|
|
705
|
+
- `at` — The instant to project at (defaults to now).
|
|
706
|
+
|
|
707
|
+
**Returns:** The model with effective pricing and no `scheduledPricing`.
|
|
520
708
|
|
|
521
709
|
### Constants
|
|
522
710
|
|
|
@@ -525,8 +713,9 @@ function priceMultiplierAt(modelDef: ModelDefinition | undefined, at: Date): num
|
|
|
525
713
|
Set of _selectable_ model IDs for fast validation.
|
|
526
714
|
|
|
527
715
|
Excludes `disabled` models so a retired model (e.g. `grok-code-fast-1`) can
|
|
528
|
-
never be chosen for a new chat,
|
|
529
|
-
|
|
716
|
+
never be chosen for a new chat, and `supersededBy` models so an older
|
|
717
|
+
generation of a family (e.g. `qwen3.7-max` next to `qwen3.8-max`) is never
|
|
718
|
+
offered — while {@link getModel} still resolves both for historical pricing.
|
|
530
719
|
|
|
531
720
|
```typescript
|
|
532
721
|
const MODEL_IDS: ReadonlySet<string>
|
|
@@ -554,6 +743,18 @@ Effort is each model's OWN native value — there is no abstract scale (see
|
|
|
554
743
|
control) carries `thinkingConfigurable: false` and OMITS both fields —
|
|
555
744
|
there is nothing to tune.
|
|
556
745
|
|
|
746
|
+
ONE GENERATION PER FAMILY. When a provider ships a newer generation of a
|
|
747
|
+
model line, the older entry gets `supersededBy: '<newer id>'` and stops being
|
|
748
|
+
offered — the picker never shows both `qwen3.7-max` and `qwen3.8-max`. The
|
|
749
|
+
entry is NEVER deleted: `getModel()` still resolves it so saved selections and
|
|
750
|
+
historical usage stay priceable, and a persisted id resolves forward to the
|
|
751
|
+
successor. Supersede only within the same TIER: a cheaper or specialist model
|
|
752
|
+
with no newer equivalent (`gemini-3.1-pro-preview`, `qwen3-coder-plus`,
|
|
753
|
+
`kimi-k2.7-code`, `grok-build-0.1`) keeps at most `deprecatedAt`, so every
|
|
754
|
+
provider keeps a real choice. `__tests__/lookup.test.ts` fails on any two
|
|
755
|
+
selectable models of one family at different versions that aren't a
|
|
756
|
+
documented exception.
|
|
757
|
+
|
|
557
758
|
Sources (verified 2026-07-28; OpenAI re-verified 2026-07-31 after the
|
|
558
759
|
2026-07-30 GPT-5.6 repricing — cross-check prices against models.dev with
|
|
559
760
|
`npm run check:model-freshness` from the workspace root):
|
|
@@ -576,21 +777,31 @@ Sources (verified 2026-07-28; OpenAI re-verified 2026-07-31 after the
|
|
|
576
777
|
2026-07-21 $1.50/$7.50 supersedes 3.5-flash as the agentic flagship;
|
|
577
778
|
gemini-3.1-pro-preview still the pro tier — "3.5 Pro" has NOT shipped as
|
|
578
779
|
of 2026-07-28 despite the coming-soon badge; do not add until it has an id)
|
|
780
|
+
(re-verified 2026-08-13: gemini-3.7-flash "New Stable" — supersedes
|
|
781
|
+
3.6-flash as the flash flagship at the SAME list price ($1.50/$7.50, cache
|
|
782
|
+
read $0.15), with a launch promo ($0.75/$3.75, cache read $0.075) through
|
|
783
|
+
2026-12-31 billed here at list; specs from /docs/models/gemini-3.7-flash:
|
|
784
|
+
1M ctx / 65,536 out, thinking low|medium|high (no minimal), vision, tools,
|
|
785
|
+
caching, search grounding, code execution, url context)
|
|
579
786
|
- xAI: https://docs.x.ai/developers/models + /developers/grok-4-5
|
|
580
787
|
(grok-4.5 flagship 2026-07-08: $2/$6, 500K ctx, ≥200K prompts bill 2× —
|
|
581
788
|
not modeled; reasoning_effort low|medium|high default high, image input;
|
|
582
789
|
grok-4.3 still served at $1.25/$2.50 with the bigger 1M window;
|
|
583
790
|
grok-code-fast-1 no longer listed — retires 2026-08-15)
|
|
584
|
-
- DeepSeek: https://api-docs.deepseek.com/quick_start/pricing (
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
791
|
+
- DeepSeek: https://api-docs.deepseek.com/quick_start/pricing (verified
|
|
792
|
+
2026-08-14; legacy deepseek-chat/-reasoner ids fully retired 2026-07-24 —
|
|
793
|
+
never in this catalog. V4-Pro GA on 2026-08-13 came with a price RISE
|
|
794
|
+
effective 2026-08-16T16:00Z plus the long-announced peak-hour 2×: both
|
|
795
|
+
entries carry it as `scheduledPricing`, so today's rates bill until that
|
|
796
|
+
instant and the new ones after. Re-verify weekday-vs-daily peak windows and
|
|
797
|
+
the CN/US region default once it lands — see the entries.)
|
|
798
|
+
- Moonshot: https://platform.kimi.ai/docs/models + DeepInfra's model API for
|
|
799
|
+
the US re-host (kimi-k3 flagship 2026-07-16
|
|
589
800
|
— 2.8T MoE, 1M ctx, $3/$15 — NOT added: thinking is forced-on with
|
|
590
801
|
reasoning_content that must be replayed through tool loops, the same
|
|
591
|
-
constraint that
|
|
592
|
-
|
|
593
|
-
|
|
802
|
+
constraint that kept kimi-k2.7-code out. BOTH are now in the catalog: the
|
|
803
|
+
moonshot bond gained preserved thinking (reasoning replayed through tool
|
|
804
|
+
loops), so kimi-k3 is the Moonshot pick.)
|
|
594
805
|
- MiniMax: https://platform.minimax.io/docs/guides/pricing-paygo (unchanged;
|
|
595
806
|
minimax-m3 $0.30/$1.20 is a "permanent 50% off" list rate)
|
|
596
807
|
- Alibaba: https://www.alibabacloud.com/help/en/model-studio/deep-thinking
|
package/dist/handlers/list.d.ts
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
* `GET /ai/models` — returns the catalog of available AI models.
|
|
3
3
|
*
|
|
4
4
|
* Filters the central `MODELS` list to only those whose provider is currently
|
|
5
|
-
* bonded under the `'ai'` category AND are
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* bonded under the `'ai'` category AND are selectable — neither `disabled` (a
|
|
6
|
+
* model the provider retired) nor superseded by a newer generation of the same
|
|
7
|
+
* family, so the picker offers exactly one generation per family. Both kinds
|
|
8
|
+
* stay priceable via `getModel`.
|
|
9
|
+
*
|
|
10
|
+
* The one projection applied is `withEffectivePricing`: a model carrying a
|
|
11
|
+
* staged `scheduledPricing` change is served at whichever rates are billing at
|
|
12
|
+
* request time, with the schedule stripped. The server's clock decides when an
|
|
13
|
+
* announced price change lands, so a client never renders a rate that is not
|
|
14
|
+
* yet in force (nor keeps rendering one that has been superseded), and no
|
|
15
|
+
* client needs to know that scheduled pricing exists. Every other
|
|
16
|
+
* `ModelDefinition` field is fine to expose to authenticated clients today.
|
|
9
17
|
*
|
|
10
18
|
* Secure-by-default: this handler enforces authentication IN the handler
|
|
11
19
|
* (`res.locals.session.userId`) and fails closed with `401` for an
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/handlers/list.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/handlers/list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAM/E;;;;;;;;;;;GAWG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBtF"}
|
package/dist/handlers/list.js
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
* `GET /ai/models` — returns the catalog of available AI models.
|
|
3
3
|
*
|
|
4
4
|
* Filters the central `MODELS` list to only those whose provider is currently
|
|
5
|
-
* bonded under the `'ai'` category AND are
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* bonded under the `'ai'` category AND are selectable — neither `disabled` (a
|
|
6
|
+
* model the provider retired) nor superseded by a newer generation of the same
|
|
7
|
+
* family, so the picker offers exactly one generation per family. Both kinds
|
|
8
|
+
* stay priceable via `getModel`.
|
|
9
|
+
*
|
|
10
|
+
* The one projection applied is `withEffectivePricing`: a model carrying a
|
|
11
|
+
* staged `scheduledPricing` change is served at whichever rates are billing at
|
|
12
|
+
* request time, with the schedule stripped. The server's clock decides when an
|
|
13
|
+
* announced price change lands, so a client never renders a rate that is not
|
|
14
|
+
* yet in force (nor keeps rendering one that has been superseded), and no
|
|
15
|
+
* client needs to know that scheduled pricing exists. Every other
|
|
16
|
+
* `ModelDefinition` field is fine to expose to authenticated clients today.
|
|
9
17
|
*
|
|
10
18
|
* Secure-by-default: this handler enforces authentication IN the handler
|
|
11
19
|
* (`res.locals.session.userId`) and fails closed with `401` for an
|
|
@@ -19,6 +27,7 @@
|
|
|
19
27
|
*/
|
|
20
28
|
import { getAll } from '@molecule/api-bond';
|
|
21
29
|
import { t } from '@molecule/api-i18n';
|
|
30
|
+
import { isSelectableModel, withEffectivePricing } from '../lookup.js';
|
|
22
31
|
import { MODELS } from '../models.js';
|
|
23
32
|
/**
|
|
24
33
|
* Returns models whose `provider` has a bond registered under the `'ai'`
|
|
@@ -42,7 +51,8 @@ export async function list(_req, res) {
|
|
|
42
51
|
return;
|
|
43
52
|
}
|
|
44
53
|
const bondedProviders = new Set(getAll('ai').keys());
|
|
45
|
-
const
|
|
46
|
-
const
|
|
54
|
+
const now = new Date();
|
|
55
|
+
const models = MODELS.filter((m) => bondedProviders.has(m.provider) && isSelectableModel(m)).map((m) => withEffectivePricing(m, now));
|
|
56
|
+
const response = { models };
|
|
47
57
|
res.json(response);
|
|
48
58
|
}
|
package/dist/lookup.d.ts
CHANGED
|
@@ -4,21 +4,45 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import type { AIProviderID, ModelDefinition } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Whether a model may be offered for selection: not `disabled` (retired
|
|
9
|
+
* upstream) and not `supersededBy` a newer generation of its own family. Both
|
|
10
|
+
* kinds stay in the catalog for pricing — this predicate is the single place
|
|
11
|
+
* that decides *exposure*, so every listing/validation surface agrees.
|
|
12
|
+
*
|
|
13
|
+
* @param model - The model definition (or the two flags from one).
|
|
14
|
+
* @returns True when the model may be listed and chosen.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isSelectableModel(model: Pick<ModelDefinition, 'disabled' | 'supersededBy'>): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a model id FORWARD to the selectable model that replaces it, following
|
|
19
|
+
* the {@link ModelDefinition.supersededBy} chain (a saved `qwen3.7-max` →
|
|
20
|
+
* `qwen3.8-max`). Lets a persisted selection keep the user's intent — the same
|
|
21
|
+
* tier from the same provider — instead of falling back to the platform default
|
|
22
|
+
* once the older generation stops being offered.
|
|
23
|
+
*
|
|
24
|
+
* @param id - The persisted model id.
|
|
25
|
+
* @returns The selectable successor's id, the id itself when it is already
|
|
26
|
+
* selectable, or `undefined` for an unknown or `disabled` model (nothing to
|
|
27
|
+
* forward to).
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveSelectableModelId(id: string): string | undefined;
|
|
7
30
|
/**
|
|
8
31
|
* Set of *selectable* model IDs for fast validation.
|
|
9
32
|
*
|
|
10
33
|
* Excludes `disabled` models so a retired model (e.g. `grok-code-fast-1`) can
|
|
11
|
-
* never be chosen for a new chat,
|
|
12
|
-
*
|
|
34
|
+
* never be chosen for a new chat, and `supersededBy` models so an older
|
|
35
|
+
* generation of a family (e.g. `qwen3.7-max` next to `qwen3.8-max`) is never
|
|
36
|
+
* offered — while {@link getModel} still resolves both for historical pricing.
|
|
13
37
|
*/
|
|
14
38
|
export declare const MODEL_IDS: ReadonlySet<string>;
|
|
15
39
|
/**
|
|
16
40
|
* Look up a model definition by ID.
|
|
17
41
|
*
|
|
18
|
-
* Returns `disabled` models too: a saved selection or a
|
|
19
|
-
* may reference a since-retired model,
|
|
20
|
-
* {@link MODEL_IDS} / {@link getAvailableModels}
|
|
21
|
-
*
|
|
42
|
+
* Returns `disabled` and `supersededBy` models too: a saved selection or a
|
|
43
|
+
* historical usage row may reference a since-retired or since-superseded model,
|
|
44
|
+
* and it must stay priceable. Use {@link MODEL_IDS} / {@link getAvailableModels}
|
|
45
|
+
* (or {@link isSelectableModel}) to decide what is *selectable*.
|
|
22
46
|
*
|
|
23
47
|
* @param id - The API model ID.
|
|
24
48
|
* @returns The model definition, or `undefined` if not found.
|
|
@@ -35,25 +59,78 @@ export declare function getModelsByProvider(provider: AIProviderID): readonly Mo
|
|
|
35
59
|
* Get models that are currently usable — filtered to only providers that are available.
|
|
36
60
|
*
|
|
37
61
|
* The caller passes in which provider IDs are active (i.e. have a bond wired).
|
|
38
|
-
*
|
|
62
|
+
* Models that are not {@link isSelectableModel} — `disabled` or superseded by a
|
|
63
|
+
* newer generation — are excluded; they are never offered for selection.
|
|
39
64
|
*
|
|
40
65
|
* @param availableProviders - Set or array of provider IDs that have active bonds.
|
|
41
|
-
* @returns
|
|
66
|
+
* @returns Selectable models whose provider is in the available set.
|
|
42
67
|
*/
|
|
43
68
|
export declare function getAvailableModels(availableProviders: ReadonlySet<AIProviderID> | readonly AIProviderID[]): readonly ModelDefinition[];
|
|
44
69
|
/**
|
|
45
|
-
*
|
|
70
|
+
* A model's BASE token rates in effect at a given instant — the staged
|
|
71
|
+
* {@link ModelDefinition.scheduledPricing} rates once their `effectiveFrom` has
|
|
72
|
+
* passed, else the base fields.
|
|
73
|
+
*
|
|
74
|
+
* These are the native provider's rates. A `regionPricing` override is a
|
|
75
|
+
* different host's rate card and is resolved separately by
|
|
76
|
+
* {@link modelRegionRates}.
|
|
77
|
+
*
|
|
78
|
+
* @param modelDef - The model definition.
|
|
79
|
+
* @param at - The instant to price at (defaults to now).
|
|
80
|
+
* @returns The base rates in effect at that instant.
|
|
81
|
+
*/
|
|
82
|
+
export declare function effectiveBaseRates(modelDef: ModelDefinition, at?: Date): ModelTokenRates;
|
|
83
|
+
/**
|
|
84
|
+
* A model's peak-hour pricing in effect at a given instant: the staged
|
|
85
|
+
* {@link ModelDefinition.scheduledPricing} `peakPricing` once its
|
|
86
|
+
* `effectiveFrom` has passed (when that entry declares one — an omitted one
|
|
87
|
+
* leaves the existing windows in force), else the model's own `peakPricing`.
|
|
88
|
+
*
|
|
89
|
+
* @param modelDef - The model definition.
|
|
90
|
+
* @param at - The instant to evaluate (defaults to now).
|
|
91
|
+
* @returns The peak-pricing config in effect, or `undefined` when none is.
|
|
92
|
+
*/
|
|
93
|
+
export declare function effectivePeakPricing(modelDef: ModelDefinition, at?: Date): ModelDefinition['peakPricing'];
|
|
94
|
+
/**
|
|
95
|
+
* A model projected onto the pricing in effect at a given instant: the staged
|
|
96
|
+
* {@link ModelDefinition.scheduledPricing} rates folded into the base fields
|
|
97
|
+
* (and its peak windows into `peakPricing`) once effective, with the staged
|
|
98
|
+
* entry stripped.
|
|
99
|
+
*
|
|
100
|
+
* This is what the `GET /ai/models` handler serves, so a client renders the
|
|
101
|
+
* rates that are actually billing right now without needing to resolve a
|
|
102
|
+
* schedule against its own clock — the server's clock is the only one that
|
|
103
|
+
* decides when a price change lands.
|
|
104
|
+
*
|
|
105
|
+
* @param modelDef - The model definition.
|
|
106
|
+
* @param at - The instant to project at (defaults to now).
|
|
107
|
+
* @returns The model with effective pricing and no `scheduledPricing`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function withEffectivePricing(modelDef: ModelDefinition, at?: Date): ModelDefinition;
|
|
110
|
+
/**
|
|
111
|
+
* The price multiplier in effect for a model at a given instant, in a region.
|
|
46
112
|
*
|
|
47
113
|
* Consults the model's {@link ModelDefinition.peakPricing} windows (UTC,
|
|
48
114
|
* half-open, may wrap midnight). Metering MUST call this with each request's
|
|
49
115
|
* own timestamp so peak-hour usage bills at the provider's real rate — pricing
|
|
50
116
|
* everything at the flat rate silently under-meters peak traffic.
|
|
51
117
|
*
|
|
118
|
+
* Peak windows belong to the NATIVE provider, so they apply only where the base
|
|
119
|
+
* rates do. A region with a {@link ModelDefinition.regionPricing} override is a
|
|
120
|
+
* different host billing its own complete rate card, including whether it has
|
|
121
|
+
* time-of-day pricing at all — and re-hosts generally do not. Applying the
|
|
122
|
+
* native provider's surcharge on top of a re-host's flat rates would over-bill
|
|
123
|
+
* every turn in its windows (DeepSeek's 2× Beijing-hours pricing charged
|
|
124
|
+
* against DeepInfra, which has no peak pricing).
|
|
125
|
+
*
|
|
52
126
|
* @param modelDef - The model definition (or undefined).
|
|
53
127
|
* @param at - The instant the request was made.
|
|
54
|
-
* @
|
|
128
|
+
* @param region - The user's per-model region choice, if any (omitted → the
|
|
129
|
+
* model's default region).
|
|
130
|
+
* @returns The multiplier (`1` outside peak windows, when none are declared, or
|
|
131
|
+
* in a region that prices off its own override).
|
|
55
132
|
*/
|
|
56
|
-
export declare function priceMultiplierAt(modelDef: ModelDefinition | undefined, at: Date): number;
|
|
133
|
+
export declare function priceMultiplierAt(modelDef: ModelDefinition | undefined, at: Date, region?: string): number;
|
|
57
134
|
/**
|
|
58
135
|
* Resolve a model's effective processing region: the requested region when the
|
|
59
136
|
* model's {@link ModelDefinition.regions} list offers it, else the model's
|
|
@@ -80,14 +157,22 @@ export interface ModelTokenRates {
|
|
|
80
157
|
/**
|
|
81
158
|
* The token rates for a model in a given processing region: the model's
|
|
82
159
|
* {@link ModelDefinition.regionPricing} override for the region when one
|
|
83
|
-
* exists, else the base rates (the native provider's list
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
160
|
+
* exists, else the base rates in effect at `at` (the native provider's list
|
|
161
|
+
* prices, including any staged {@link ModelDefinition.scheduledPricing} change
|
|
162
|
+
* that has landed). Omitted cache fields in an override fall back to the
|
|
163
|
+
* override's input price (hosts with no cache discount / no write premium). The
|
|
164
|
+
* region is resolved via {@link effectiveModelRegion}, so callers may pass the
|
|
165
|
+
* raw user choice.
|
|
166
|
+
*
|
|
167
|
+
* `at` defaults to NOW rather than being required, so an existing caller cannot
|
|
168
|
+
* keep billing a superseded rate by omitting it — metering should still pass
|
|
169
|
+
* each request's own timestamp, the same way it must for
|
|
170
|
+
* {@link priceMultiplierAt}.
|
|
87
171
|
*
|
|
88
172
|
* @param modelDef - The model definition.
|
|
89
173
|
* @param requested - The user's per-model region choice, if any.
|
|
174
|
+
* @param at - The instant to price at (defaults to now).
|
|
90
175
|
* @returns The region-effective rates.
|
|
91
176
|
*/
|
|
92
|
-
export declare function modelRegionRates(modelDef: ModelDefinition, requested?: string): ModelTokenRates;
|
|
177
|
+
export declare function modelRegionRates(modelDef: ModelDefinition, requested?: string, at?: Date): ModelTokenRates;
|
|
93
178
|
//# sourceMappingURL=lookup.d.ts.map
|
package/dist/lookup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../src/lookup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE/D
|
|
1
|
+
{"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../src/lookup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE/D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,cAAc,CAAC,GACxD,OAAO,CAET;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASvE;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,MAAM,CAEzC,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,eAAe,EAAE,CAEtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,kBAAkB,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,SAAS,YAAY,EAAE,GACtE,SAAS,eAAe,EAAE,CAI5B;AAoBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,eAAe,EACzB,EAAE,GAAE,IAAiB,GACpB,eAAe,CAgBjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,EAAE,GAAE,IAAiB,GACpB,eAAe,CAAC,aAAa,CAAC,CAMhC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,EACzB,EAAE,GAAE,IAAiB,GACpB,eAAe,CASjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,EAAE,EAAE,IAAI,EACR,MAAM,CAAC,EAAE,MAAM,GACd,MAAM,CAcR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAGR;AAED,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,iBAAiB,EAAE,MAAM,CAAA;IACzB,8CAA8C;IAC9C,kBAAkB,EAAE,MAAM,CAAA;IAC1B,yDAAyD;IACzD,qBAAqB,EAAE,MAAM,CAAA;IAC7B,0DAA0D;IAC1D,sBAAsB,EAAE,MAAM,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,EACzB,SAAS,CAAC,EAAE,MAAM,EAClB,EAAE,GAAE,IAAiB,GACpB,eAAe,CAYjB"}
|