@stll/ai-catalog 0.1.5 → 0.1.7
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 +8 -0
- package/dist/index.d.ts +1040 -946
- package/dist/index.js +952 -839
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import * as v from "valibot";
|
|
|
6
6
|
*/
|
|
7
7
|
const MODEL_DOCUMENT_INPUT_OPTIONS = {
|
|
8
8
|
google: [
|
|
9
|
+
"gemini-3.8-flash",
|
|
9
10
|
"gemini-3.7-flash",
|
|
10
11
|
"gemini-3.6-flash",
|
|
11
12
|
"gemini-3.5-flash-lite",
|
|
@@ -16,6 +17,7 @@ const MODEL_DOCUMENT_INPUT_OPTIONS = {
|
|
|
16
17
|
openrouter: [
|
|
17
18
|
"openai/gpt-5.6-luna",
|
|
18
19
|
"openai/gpt-5.6-terra",
|
|
20
|
+
"google/gemini-3.8-flash",
|
|
19
21
|
"google/gemini-3.7-flash",
|
|
20
22
|
"google/gemini-3.6-flash",
|
|
21
23
|
"google/gemini-3.5-flash-lite",
|
|
@@ -65,6 +67,11 @@ const MODEL_DOCUMENT_INPUT_OPTIONS = {
|
|
|
65
67
|
* through `resolveReasoningEffort`.
|
|
66
68
|
*/
|
|
67
69
|
const MODEL_REASONING_EFFORTS = {
|
|
70
|
+
"gemini-3.8-flash": [
|
|
71
|
+
"low",
|
|
72
|
+
"medium",
|
|
73
|
+
"high"
|
|
74
|
+
],
|
|
68
75
|
"gemini-3.7-flash": [
|
|
69
76
|
"low",
|
|
70
77
|
"medium",
|
|
@@ -115,6 +122,11 @@ const MODEL_REASONING_EFFORTS = {
|
|
|
115
122
|
"xhigh",
|
|
116
123
|
"max"
|
|
117
124
|
],
|
|
125
|
+
"google/gemini-3.8-flash": [
|
|
126
|
+
"low",
|
|
127
|
+
"medium",
|
|
128
|
+
"high"
|
|
129
|
+
],
|
|
118
130
|
"google/gemini-3.7-flash": [
|
|
119
131
|
"low",
|
|
120
132
|
"medium",
|
|
@@ -339,6 +351,7 @@ const MODEL_REASONING_EFFORTS = {
|
|
|
339
351
|
* a truthful named default, so clients must retain a separate Default choice.
|
|
340
352
|
*/
|
|
341
353
|
const MODEL_DEFAULT_REASONING_EFFORTS = {
|
|
354
|
+
"gemini-3.8-flash": null,
|
|
342
355
|
"gemini-3.7-flash": null,
|
|
343
356
|
"gemini-3.6-flash": null,
|
|
344
357
|
"gemini-3.5-flash-lite": null,
|
|
@@ -347,6 +360,7 @@ const MODEL_DEFAULT_REASONING_EFFORTS = {
|
|
|
347
360
|
"gemini-3.1-flash-lite": null,
|
|
348
361
|
"openai/gpt-5.6-luna": "medium",
|
|
349
362
|
"openai/gpt-5.6-terra": "medium",
|
|
363
|
+
"google/gemini-3.8-flash": "medium",
|
|
350
364
|
"google/gemini-3.7-flash": "medium",
|
|
351
365
|
"google/gemini-3.6-flash": "medium",
|
|
352
366
|
"google/gemini-3.5-flash-lite": "minimal",
|
|
@@ -397,6 +411,7 @@ const MODEL_DEFAULT_REASONING_EFFORTS = {
|
|
|
397
411
|
* parameters. Consumers must go through `shouldEmitTemperature`.
|
|
398
412
|
*/
|
|
399
413
|
const MODEL_TEMPERATURE_POLICIES = {
|
|
414
|
+
"gemini-3.8-flash": "omit",
|
|
400
415
|
"gemini-3.7-flash": "omit",
|
|
401
416
|
"gemini-3.6-flash": "omit",
|
|
402
417
|
"gemini-3.5-flash-lite": "omit",
|
|
@@ -405,6 +420,7 @@ const MODEL_TEMPERATURE_POLICIES = {
|
|
|
405
420
|
"gemini-3.1-flash-lite": "emit",
|
|
406
421
|
"openai/gpt-5.6-luna": "omit",
|
|
407
422
|
"openai/gpt-5.6-terra": "omit",
|
|
423
|
+
"google/gemini-3.8-flash": "omit",
|
|
408
424
|
"google/gemini-3.7-flash": "omit",
|
|
409
425
|
"google/gemini-3.6-flash": "omit",
|
|
410
426
|
"google/gemini-3.5-flash-lite": "omit",
|
|
@@ -450,981 +466,1076 @@ const MODEL_TEMPERATURE_POLICIES = {
|
|
|
450
466
|
"pixtral-large-latest": "emit"
|
|
451
467
|
};
|
|
452
468
|
//#endregion
|
|
453
|
-
//#region src/
|
|
454
|
-
const
|
|
455
|
-
"
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
reason: "2026-07-20: absent from the models.dev amazon-bedrock catalog; Bedrock Converse accepts temperature and Nova has no reasoning dial"
|
|
469
|
+
//#region src/model-rates.gen.ts
|
|
470
|
+
const MODEL_RATES = {
|
|
471
|
+
"gemini-3.8-flash": {
|
|
472
|
+
kind: "flat",
|
|
473
|
+
inputPerMTok: 75e3,
|
|
474
|
+
outputPerMTok: 375e3,
|
|
475
|
+
cachedInputPerMTok: 7500
|
|
461
476
|
},
|
|
462
|
-
"
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
reason: "2026-07-20: absent from the models.dev amazon-bedrock catalog; Bedrock Converse accepts temperature and Nova has no reasoning dial"
|
|
477
|
+
"gemini-3.7-flash": {
|
|
478
|
+
kind: "flat",
|
|
479
|
+
inputPerMTok: 75e3,
|
|
480
|
+
outputPerMTok: 375e3,
|
|
481
|
+
cachedInputPerMTok: 7500
|
|
468
482
|
},
|
|
469
|
-
"
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
reason: "2026-07-20: absent from the models.dev amazon-bedrock catalog; Bedrock Converse accepts temperature and Nova has no reasoning dial"
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
//#endregion
|
|
478
|
-
//#region src/document-input-overrides.ts
|
|
479
|
-
/**
|
|
480
|
-
* Reviewed document-input corrections for models.dev records that exist but
|
|
481
|
-
* under-report the provider API's file-input support. The generator rejects an
|
|
482
|
-
* override once upstream agrees, so sourced data takes ownership automatically.
|
|
483
|
-
*/
|
|
484
|
-
const DOCUMENT_INPUT_OVERRIDES = {
|
|
485
|
-
"gpt-5.4-mini": {
|
|
486
|
-
supported: true,
|
|
487
|
-
reason: "2026-08-20: OpenAI Responses accepts input_file PDF content for this vision-capable model; models.dev currently omits the pdf modality"
|
|
483
|
+
"gemini-3.6-flash": {
|
|
484
|
+
kind: "flat",
|
|
485
|
+
inputPerMTok: 75e3,
|
|
486
|
+
outputPerMTok: 375e3,
|
|
487
|
+
cachedInputPerMTok: 7500
|
|
488
488
|
},
|
|
489
|
-
"
|
|
490
|
-
|
|
491
|
-
|
|
489
|
+
"gemini-3.5-flash-lite": {
|
|
490
|
+
kind: "flat",
|
|
491
|
+
inputPerMTok: 3e4,
|
|
492
|
+
outputPerMTok: 25e4,
|
|
493
|
+
cachedInputPerMTok: 3e3
|
|
492
494
|
},
|
|
493
|
-
"
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
* and the BYOK settings UI (`apps/web`), so the picker can never offer
|
|
507
|
-
* a model the backend rejects, and vice versa.
|
|
508
|
-
*
|
|
509
|
-
* Pure data: no provider SDKs, no env access, no side effects. This is
|
|
510
|
-
* deliberate so scripts (the nightly upstream-validation check) and
|
|
511
|
-
* both apps can import it cheaply. Keep it that way. The only runtime
|
|
512
|
-
* dependency is valibot, used solely to construct branded types the
|
|
513
|
-
* same way the rest of the repo does.
|
|
514
|
-
*
|
|
515
|
-
* Model IDs go stale when providers rename or retire models. The
|
|
516
|
-
* nightly `model-catalog-upstream` check
|
|
517
|
-
* (`packages/scripts/src/model-catalog-upstream.ts`) validates every
|
|
518
|
-
* ID here against live provider/aggregator listings so a retired model
|
|
519
|
-
* fails CI instead of 400-ing a user at runtime.
|
|
520
|
-
*/
|
|
521
|
-
/**
|
|
522
|
-
* Logical model roles. Call sites declare *what* they need, not
|
|
523
|
-
* *which* model to use.
|
|
524
|
-
*
|
|
525
|
-
* - fast: classification, extraction, short generation
|
|
526
|
-
* - chat: conversational with tool use and streaming
|
|
527
|
-
* - reasoning: complex multi-step legal analysis
|
|
528
|
-
* - pdf: native PDF/image understanding
|
|
529
|
-
*/
|
|
530
|
-
const MODEL_ROLES = [
|
|
531
|
-
"fast",
|
|
532
|
-
"chat",
|
|
533
|
-
"reasoning",
|
|
534
|
-
"pdf"
|
|
535
|
-
];
|
|
536
|
-
const TEMPERATURE_POLICIES = ["emit", "omit"];
|
|
537
|
-
const AI_PROVIDERS = [
|
|
538
|
-
"google",
|
|
539
|
-
"openrouter",
|
|
540
|
-
"openai",
|
|
541
|
-
"azure_foundry",
|
|
542
|
-
"anthropic",
|
|
543
|
-
"bedrock",
|
|
544
|
-
"mistral",
|
|
545
|
-
"openai_compatible",
|
|
546
|
-
"huggingface"
|
|
547
|
-
];
|
|
548
|
-
const TANSTACK_AI_PROVIDERS = [
|
|
549
|
-
"google",
|
|
550
|
-
"openrouter",
|
|
551
|
-
"openai",
|
|
552
|
-
"anthropic",
|
|
553
|
-
"bedrock",
|
|
554
|
-
"mistral"
|
|
555
|
-
];
|
|
556
|
-
const MODEL_CATALOG_PROVIDER_KIND = {
|
|
557
|
-
google: "first-party",
|
|
558
|
-
openrouter: "aggregator",
|
|
559
|
-
openai: "first-party",
|
|
560
|
-
anthropic: "first-party",
|
|
561
|
-
bedrock: "platform",
|
|
562
|
-
mistral: "first-party"
|
|
563
|
-
};
|
|
564
|
-
/**
|
|
565
|
-
* Runtime form of the first-party provider union. The conditional annotation
|
|
566
|
-
* makes adding a first-party policy without adding its discovery implementation
|
|
567
|
-
* a compile error.
|
|
568
|
-
*/
|
|
569
|
-
const FIRST_PARTY_MODEL_PROVIDERS = [
|
|
570
|
-
"google",
|
|
571
|
-
"openai",
|
|
572
|
-
"anthropic",
|
|
573
|
-
"mistral"
|
|
574
|
-
];
|
|
575
|
-
/**
|
|
576
|
-
* Per-role default model IDs for the BYOK-capable cloud providers.
|
|
577
|
-
* Shared between the instance default table (`DEFAULT_MODELS`) and the
|
|
578
|
-
* settings-UI default selection, so a default is defined exactly once.
|
|
579
|
-
*/
|
|
580
|
-
const BYOK_DEFAULT_MODELS = {
|
|
581
|
-
google: {
|
|
582
|
-
fast: "gemini-3.7-flash",
|
|
583
|
-
chat: "gemini-3.7-flash",
|
|
584
|
-
reasoning: "gemini-3.7-flash",
|
|
585
|
-
pdf: "gemini-3.7-flash"
|
|
495
|
+
"gemini-3.1-pro-preview": {
|
|
496
|
+
kind: "input-token-tiered",
|
|
497
|
+
inputTokenThreshold: 2e5,
|
|
498
|
+
standard: {
|
|
499
|
+
inputPerMTok: 2e5,
|
|
500
|
+
outputPerMTok: 12e5,
|
|
501
|
+
cachedInputPerMTok: 2e4
|
|
502
|
+
},
|
|
503
|
+
aboveThreshold: {
|
|
504
|
+
inputPerMTok: 4e5,
|
|
505
|
+
outputPerMTok: 18e5,
|
|
506
|
+
cachedInputPerMTok: 4e4
|
|
507
|
+
}
|
|
586
508
|
},
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
509
|
+
"gemini-3.5-flash": {
|
|
510
|
+
kind: "flat",
|
|
511
|
+
inputPerMTok: 15e4,
|
|
512
|
+
outputPerMTok: 9e5,
|
|
513
|
+
cachedInputPerMTok: 15e3
|
|
592
514
|
},
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
515
|
+
"gemini-3.1-flash-lite": {
|
|
516
|
+
kind: "flat",
|
|
517
|
+
inputPerMTok: 25e3,
|
|
518
|
+
outputPerMTok: 15e4,
|
|
519
|
+
cachedInputPerMTok: 2500
|
|
598
520
|
},
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
521
|
+
"gpt-5.6": {
|
|
522
|
+
kind: "input-token-tiered",
|
|
523
|
+
inputTokenThreshold: 272e3,
|
|
524
|
+
standard: {
|
|
525
|
+
inputPerMTok: 4e5,
|
|
526
|
+
outputPerMTok: 2e6,
|
|
527
|
+
cachedInputPerMTok: 4e4,
|
|
528
|
+
cachedWriteInputPerMTok: 5e5
|
|
529
|
+
},
|
|
530
|
+
aboveThreshold: {
|
|
531
|
+
inputPerMTok: 8e5,
|
|
532
|
+
outputPerMTok: 3e6,
|
|
533
|
+
cachedInputPerMTok: 8e4,
|
|
534
|
+
cachedWriteInputPerMTok: 1e6
|
|
535
|
+
}
|
|
604
536
|
},
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
537
|
+
"gpt-5.6-terra": {
|
|
538
|
+
kind: "input-token-tiered",
|
|
539
|
+
inputTokenThreshold: 272e3,
|
|
540
|
+
standard: {
|
|
541
|
+
inputPerMTok: 2e5,
|
|
542
|
+
outputPerMTok: 12e5,
|
|
543
|
+
cachedInputPerMTok: 2e4,
|
|
544
|
+
cachedWriteInputPerMTok: 25e4
|
|
545
|
+
},
|
|
546
|
+
aboveThreshold: {
|
|
547
|
+
inputPerMTok: 4e5,
|
|
548
|
+
outputPerMTok: 18e5,
|
|
549
|
+
cachedInputPerMTok: 4e4,
|
|
550
|
+
cachedWriteInputPerMTok: 5e5
|
|
551
|
+
}
|
|
610
552
|
},
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
fast: "gpt-5.4-nano",
|
|
627
|
-
chat: "gpt-5.4-mini",
|
|
628
|
-
reasoning: "gpt-5.4",
|
|
629
|
-
pdf: "gpt-5.4"
|
|
553
|
+
"gpt-5.6-luna": {
|
|
554
|
+
kind: "input-token-tiered",
|
|
555
|
+
inputTokenThreshold: 272e3,
|
|
556
|
+
standard: {
|
|
557
|
+
inputPerMTok: 2e4,
|
|
558
|
+
outputPerMTok: 12e4,
|
|
559
|
+
cachedInputPerMTok: 2e3,
|
|
560
|
+
cachedWriteInputPerMTok: 25e3
|
|
561
|
+
},
|
|
562
|
+
aboveThreshold: {
|
|
563
|
+
inputPerMTok: 4e4,
|
|
564
|
+
outputPerMTok: 18e4,
|
|
565
|
+
cachedInputPerMTok: 4e3,
|
|
566
|
+
cachedWriteInputPerMTok: 5e4
|
|
567
|
+
}
|
|
630
568
|
},
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* BYOK-offered model IDs per provider — the curated catalog users pick
|
|
646
|
-
* from in org settings, and the server-side allowlist the API enforces.
|
|
647
|
-
* The frontend list is not a security boundary; this is what the API
|
|
648
|
-
* accepts.
|
|
649
|
-
*
|
|
650
|
-
* Limited to providers the TanStack AI integration supports for BYOK.
|
|
651
|
-
* Providers without a first-class TanStack adapter path are intentionally
|
|
652
|
-
* not accepted at this boundary.
|
|
653
|
-
*/
|
|
654
|
-
const BYOK_MODEL_OPTIONS = {
|
|
655
|
-
google: [
|
|
656
|
-
"gemini-3.7-flash",
|
|
657
|
-
"gemini-3.6-flash",
|
|
658
|
-
"gemini-3.5-flash-lite",
|
|
659
|
-
"gemini-3.1-pro-preview",
|
|
660
|
-
"gemini-3.5-flash",
|
|
661
|
-
"gemini-3.1-flash-lite"
|
|
662
|
-
],
|
|
663
|
-
anthropic: [
|
|
664
|
-
"claude-sonnet-5",
|
|
665
|
-
"claude-fable-5-1",
|
|
666
|
-
"claude-fable-5",
|
|
667
|
-
"claude-opus-5",
|
|
668
|
-
"claude-opus-4-8",
|
|
669
|
-
"claude-opus-4-7",
|
|
670
|
-
"claude-sonnet-4-6",
|
|
671
|
-
"claude-opus-4-6",
|
|
672
|
-
"claude-haiku-4-5-20251001"
|
|
673
|
-
],
|
|
674
|
-
openai: [
|
|
675
|
-
"gpt-5.6",
|
|
676
|
-
"gpt-5.6-terra",
|
|
677
|
-
"gpt-5.6-luna",
|
|
678
|
-
"gpt-5.5",
|
|
679
|
-
"gpt-5.4",
|
|
680
|
-
"gpt-5.4-mini",
|
|
681
|
-
"gpt-5.4-nano",
|
|
682
|
-
"gpt-5.2"
|
|
683
|
-
],
|
|
684
|
-
openrouter: [
|
|
685
|
-
"openai/gpt-5.6-luna",
|
|
686
|
-
"openai/gpt-5.6-terra",
|
|
687
|
-
"google/gemini-3.7-flash",
|
|
688
|
-
"google/gemini-3.6-flash",
|
|
689
|
-
"google/gemini-3.5-flash-lite",
|
|
690
|
-
"google/gemini-3.1-pro-preview",
|
|
691
|
-
"google/gemini-3.5-flash",
|
|
692
|
-
"google/gemini-3.1-flash-lite",
|
|
693
|
-
"anthropic/claude-sonnet-5",
|
|
694
|
-
"anthropic/claude-opus-5",
|
|
695
|
-
"anthropic/claude-opus-4.8",
|
|
696
|
-
"anthropic/claude-sonnet-4.6",
|
|
697
|
-
"openai/gpt-5.5",
|
|
698
|
-
"openai/gpt-5.4-mini"
|
|
699
|
-
],
|
|
700
|
-
bedrock: [
|
|
701
|
-
"us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
702
|
-
"us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
703
|
-
"us.amazon.nova-pro-v1:0",
|
|
704
|
-
"us.amazon.nova-lite-v1:0",
|
|
705
|
-
"us.amazon.nova-micro-v1:0",
|
|
706
|
-
"openai.gpt-oss-120b-1:0",
|
|
707
|
-
"openai.gpt-oss-20b-1:0",
|
|
708
|
-
"us.deepseek.r1-v1:0"
|
|
709
|
-
],
|
|
710
|
-
mistral: [
|
|
711
|
-
"mistral-large-latest",
|
|
712
|
-
"mistral-medium-latest",
|
|
713
|
-
"mistral-small-latest",
|
|
714
|
-
"magistral-medium-latest",
|
|
715
|
-
"magistral-small",
|
|
716
|
-
"pixtral-large-latest"
|
|
717
|
-
]
|
|
718
|
-
};
|
|
719
|
-
/**
|
|
720
|
-
* Presentation metadata for every offered model. Keeping this exhaustive beside
|
|
721
|
-
* the allowlist prevents a newly offered model from leaking a raw provider ID
|
|
722
|
-
* into user-facing pickers. OpenRouter entries deliberately carry their model
|
|
723
|
-
* creator's icon while their routing provider remains available separately.
|
|
724
|
-
*/
|
|
725
|
-
const MODEL_DISPLAY_METADATA = {
|
|
726
|
-
"gemini-3.7-flash": {
|
|
727
|
-
displayName: "Gemini 3.7 Flash",
|
|
728
|
-
iconProvider: "google"
|
|
729
|
-
},
|
|
730
|
-
"gemini-3.6-flash": {
|
|
731
|
-
displayName: "Gemini 3.6 Flash",
|
|
732
|
-
iconProvider: "google"
|
|
569
|
+
"gpt-5.5": {
|
|
570
|
+
kind: "input-token-tiered",
|
|
571
|
+
inputTokenThreshold: 272e3,
|
|
572
|
+
standard: {
|
|
573
|
+
inputPerMTok: 5e5,
|
|
574
|
+
outputPerMTok: 3e6,
|
|
575
|
+
cachedInputPerMTok: 5e4
|
|
576
|
+
},
|
|
577
|
+
aboveThreshold: {
|
|
578
|
+
inputPerMTok: 1e6,
|
|
579
|
+
outputPerMTok: 45e5,
|
|
580
|
+
cachedInputPerMTok: 1e5
|
|
581
|
+
}
|
|
733
582
|
},
|
|
734
|
-
"
|
|
735
|
-
|
|
736
|
-
|
|
583
|
+
"gpt-5.4": {
|
|
584
|
+
kind: "input-token-tiered",
|
|
585
|
+
inputTokenThreshold: 272e3,
|
|
586
|
+
standard: {
|
|
587
|
+
inputPerMTok: 25e4,
|
|
588
|
+
outputPerMTok: 15e5,
|
|
589
|
+
cachedInputPerMTok: 25e3
|
|
590
|
+
},
|
|
591
|
+
aboveThreshold: {
|
|
592
|
+
inputPerMTok: 5e5,
|
|
593
|
+
outputPerMTok: 225e4,
|
|
594
|
+
cachedInputPerMTok: 5e4
|
|
595
|
+
}
|
|
737
596
|
},
|
|
738
|
-
"
|
|
739
|
-
|
|
740
|
-
|
|
597
|
+
"gpt-5.4-mini": {
|
|
598
|
+
kind: "flat",
|
|
599
|
+
inputPerMTok: 75e3,
|
|
600
|
+
outputPerMTok: 45e4,
|
|
601
|
+
cachedInputPerMTok: 7500
|
|
741
602
|
},
|
|
742
|
-
"
|
|
743
|
-
|
|
744
|
-
|
|
603
|
+
"gpt-5.4-nano": {
|
|
604
|
+
kind: "flat",
|
|
605
|
+
inputPerMTok: 2e4,
|
|
606
|
+
outputPerMTok: 125e3,
|
|
607
|
+
cachedInputPerMTok: 2e3
|
|
745
608
|
},
|
|
746
|
-
"
|
|
747
|
-
|
|
748
|
-
|
|
609
|
+
"gpt-5.2": {
|
|
610
|
+
kind: "flat",
|
|
611
|
+
inputPerMTok: 175e3,
|
|
612
|
+
outputPerMTok: 14e5,
|
|
613
|
+
cachedInputPerMTok: 17500
|
|
749
614
|
},
|
|
750
615
|
"claude-sonnet-5": {
|
|
751
|
-
|
|
752
|
-
|
|
616
|
+
kind: "flat",
|
|
617
|
+
inputPerMTok: 2e5,
|
|
618
|
+
outputPerMTok: 1e6,
|
|
619
|
+
cachedInputPerMTok: 2e4,
|
|
620
|
+
cachedWriteInputPerMTok: 25e4
|
|
753
621
|
},
|
|
754
622
|
"claude-fable-5-1": {
|
|
755
|
-
|
|
756
|
-
|
|
623
|
+
kind: "flat",
|
|
624
|
+
inputPerMTok: 1e6,
|
|
625
|
+
outputPerMTok: 5e6,
|
|
626
|
+
cachedInputPerMTok: 25e3,
|
|
627
|
+
cachedWriteInputPerMTok: 125e4
|
|
757
628
|
},
|
|
758
629
|
"claude-fable-5": {
|
|
759
|
-
|
|
760
|
-
|
|
630
|
+
kind: "flat",
|
|
631
|
+
inputPerMTok: 1e6,
|
|
632
|
+
outputPerMTok: 5e6,
|
|
633
|
+
cachedInputPerMTok: 1e5,
|
|
634
|
+
cachedWriteInputPerMTok: 125e4
|
|
761
635
|
},
|
|
762
636
|
"claude-opus-5": {
|
|
763
|
-
|
|
764
|
-
|
|
637
|
+
kind: "flat",
|
|
638
|
+
inputPerMTok: 5e5,
|
|
639
|
+
outputPerMTok: 25e5,
|
|
640
|
+
cachedInputPerMTok: 5e4,
|
|
641
|
+
cachedWriteInputPerMTok: 625e3
|
|
765
642
|
},
|
|
766
643
|
"claude-opus-4-8": {
|
|
767
|
-
|
|
768
|
-
|
|
644
|
+
kind: "flat",
|
|
645
|
+
inputPerMTok: 5e5,
|
|
646
|
+
outputPerMTok: 25e5,
|
|
647
|
+
cachedInputPerMTok: 5e4,
|
|
648
|
+
cachedWriteInputPerMTok: 625e3
|
|
769
649
|
},
|
|
770
650
|
"claude-opus-4-7": {
|
|
771
|
-
|
|
772
|
-
|
|
651
|
+
kind: "flat",
|
|
652
|
+
inputPerMTok: 5e5,
|
|
653
|
+
outputPerMTok: 25e5,
|
|
654
|
+
cachedInputPerMTok: 5e4,
|
|
655
|
+
cachedWriteInputPerMTok: 625e3
|
|
773
656
|
},
|
|
774
657
|
"claude-sonnet-4-6": {
|
|
775
|
-
|
|
776
|
-
|
|
658
|
+
kind: "flat",
|
|
659
|
+
inputPerMTok: 3e5,
|
|
660
|
+
outputPerMTok: 15e5,
|
|
661
|
+
cachedInputPerMTok: 3e4,
|
|
662
|
+
cachedWriteInputPerMTok: 375e3
|
|
777
663
|
},
|
|
778
664
|
"claude-opus-4-6": {
|
|
779
|
-
|
|
780
|
-
|
|
665
|
+
kind: "flat",
|
|
666
|
+
inputPerMTok: 5e5,
|
|
667
|
+
outputPerMTok: 25e5,
|
|
668
|
+
cachedInputPerMTok: 5e4,
|
|
669
|
+
cachedWriteInputPerMTok: 625e3
|
|
781
670
|
},
|
|
782
671
|
"claude-haiku-4-5-20251001": {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
iconProvider: "openai"
|
|
672
|
+
kind: "flat",
|
|
673
|
+
inputPerMTok: 1e5,
|
|
674
|
+
outputPerMTok: 5e5,
|
|
675
|
+
cachedInputPerMTok: 1e4,
|
|
676
|
+
cachedWriteInputPerMTok: 125e3
|
|
789
677
|
},
|
|
790
|
-
"
|
|
791
|
-
|
|
792
|
-
|
|
678
|
+
"us.anthropic.claude-sonnet-4-5-20250929-v1:0": {
|
|
679
|
+
kind: "flat",
|
|
680
|
+
inputPerMTok: 3e5,
|
|
681
|
+
outputPerMTok: 15e5,
|
|
682
|
+
cachedInputPerMTok: 3e4,
|
|
683
|
+
cachedWriteInputPerMTok: 375e3
|
|
793
684
|
},
|
|
794
|
-
"
|
|
795
|
-
|
|
796
|
-
|
|
685
|
+
"us.anthropic.claude-haiku-4-5-20251001-v1:0": {
|
|
686
|
+
kind: "flat",
|
|
687
|
+
inputPerMTok: 1e5,
|
|
688
|
+
outputPerMTok: 5e5,
|
|
689
|
+
cachedInputPerMTok: 1e4,
|
|
690
|
+
cachedWriteInputPerMTok: 125e3
|
|
797
691
|
},
|
|
798
|
-
"
|
|
799
|
-
|
|
800
|
-
|
|
692
|
+
"us.amazon.nova-pro-v1:0": {
|
|
693
|
+
kind: "flat",
|
|
694
|
+
inputPerMTok: 8e4,
|
|
695
|
+
outputPerMTok: 32e4,
|
|
696
|
+
cachedInputPerMTok: 2e4
|
|
801
697
|
},
|
|
802
|
-
"
|
|
803
|
-
|
|
804
|
-
|
|
698
|
+
"us.amazon.nova-lite-v1:0": {
|
|
699
|
+
kind: "flat",
|
|
700
|
+
inputPerMTok: 6e3,
|
|
701
|
+
outputPerMTok: 24e3,
|
|
702
|
+
cachedInputPerMTok: 1500
|
|
805
703
|
},
|
|
806
|
-
"
|
|
807
|
-
|
|
808
|
-
|
|
704
|
+
"us.amazon.nova-micro-v1:0": {
|
|
705
|
+
kind: "flat",
|
|
706
|
+
inputPerMTok: 3500,
|
|
707
|
+
outputPerMTok: 14e3,
|
|
708
|
+
cachedInputPerMTok: 875
|
|
809
709
|
},
|
|
810
|
-
"gpt-
|
|
811
|
-
|
|
812
|
-
|
|
710
|
+
"openai.gpt-oss-120b-1:0": {
|
|
711
|
+
kind: "flat",
|
|
712
|
+
inputPerMTok: 15e3,
|
|
713
|
+
outputPerMTok: 6e4
|
|
813
714
|
},
|
|
814
|
-
"gpt-
|
|
815
|
-
|
|
816
|
-
|
|
715
|
+
"openai.gpt-oss-20b-1:0": {
|
|
716
|
+
kind: "flat",
|
|
717
|
+
inputPerMTok: 7e3,
|
|
718
|
+
outputPerMTok: 3e4
|
|
817
719
|
},
|
|
818
|
-
"
|
|
819
|
-
|
|
820
|
-
|
|
720
|
+
"us.deepseek.r1-v1:0": {
|
|
721
|
+
kind: "flat",
|
|
722
|
+
inputPerMTok: 135e3,
|
|
723
|
+
outputPerMTok: 54e4
|
|
821
724
|
},
|
|
822
|
-
"
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
"google/gemini-3.7-flash": {
|
|
827
|
-
displayName: "Gemini 3.7 Flash",
|
|
828
|
-
iconProvider: "google"
|
|
829
|
-
},
|
|
830
|
-
"google/gemini-3.6-flash": {
|
|
831
|
-
displayName: "Gemini 3.6 Flash",
|
|
832
|
-
iconProvider: "google"
|
|
833
|
-
},
|
|
834
|
-
"google/gemini-3.5-flash-lite": {
|
|
835
|
-
displayName: "Gemini 3.5 Flash Lite",
|
|
836
|
-
iconProvider: "google"
|
|
725
|
+
"mistral-large-latest": {
|
|
726
|
+
kind: "flat",
|
|
727
|
+
inputPerMTok: 5e4,
|
|
728
|
+
outputPerMTok: 15e4
|
|
837
729
|
},
|
|
838
|
-
"
|
|
839
|
-
|
|
840
|
-
|
|
730
|
+
"mistral-medium-latest": {
|
|
731
|
+
kind: "flat",
|
|
732
|
+
inputPerMTok: 15e4,
|
|
733
|
+
outputPerMTok: 75e4
|
|
841
734
|
},
|
|
842
|
-
"
|
|
843
|
-
|
|
844
|
-
|
|
735
|
+
"mistral-small-latest": {
|
|
736
|
+
kind: "flat",
|
|
737
|
+
inputPerMTok: 15e3,
|
|
738
|
+
outputPerMTok: 6e4
|
|
845
739
|
},
|
|
846
|
-
"
|
|
847
|
-
|
|
848
|
-
|
|
740
|
+
"magistral-medium-latest": {
|
|
741
|
+
kind: "flat",
|
|
742
|
+
inputPerMTok: 2e5,
|
|
743
|
+
outputPerMTok: 5e5
|
|
849
744
|
},
|
|
850
|
-
"
|
|
851
|
-
|
|
852
|
-
|
|
745
|
+
"magistral-small": {
|
|
746
|
+
kind: "flat",
|
|
747
|
+
inputPerMTok: 5e4,
|
|
748
|
+
outputPerMTok: 15e4
|
|
853
749
|
},
|
|
854
|
-
"
|
|
855
|
-
|
|
856
|
-
|
|
750
|
+
"pixtral-large-latest": {
|
|
751
|
+
kind: "flat",
|
|
752
|
+
inputPerMTok: 2e5,
|
|
753
|
+
outputPerMTok: 6e5
|
|
857
754
|
},
|
|
858
|
-
"
|
|
859
|
-
|
|
860
|
-
|
|
755
|
+
"gemini-2.5-flash": {
|
|
756
|
+
kind: "flat",
|
|
757
|
+
inputPerMTok: 3e4,
|
|
758
|
+
outputPerMTok: 25e4,
|
|
759
|
+
cachedInputPerMTok: 3e3
|
|
861
760
|
},
|
|
862
|
-
"
|
|
863
|
-
|
|
864
|
-
|
|
761
|
+
"gemini-2.5-pro": {
|
|
762
|
+
kind: "input-token-tiered",
|
|
763
|
+
inputTokenThreshold: 2e5,
|
|
764
|
+
standard: {
|
|
765
|
+
inputPerMTok: 125e3,
|
|
766
|
+
outputPerMTok: 1e6,
|
|
767
|
+
cachedInputPerMTok: 12500
|
|
768
|
+
},
|
|
769
|
+
aboveThreshold: {
|
|
770
|
+
inputPerMTok: 25e4,
|
|
771
|
+
outputPerMTok: 15e5,
|
|
772
|
+
cachedInputPerMTok: 25e3
|
|
773
|
+
}
|
|
865
774
|
},
|
|
866
|
-
"
|
|
867
|
-
|
|
868
|
-
|
|
775
|
+
"gpt-4o-mini": {
|
|
776
|
+
kind: "flat",
|
|
777
|
+
inputPerMTok: 15e3,
|
|
778
|
+
outputPerMTok: 6e4,
|
|
779
|
+
cachedInputPerMTok: 7500
|
|
869
780
|
},
|
|
870
|
-
"
|
|
871
|
-
|
|
872
|
-
|
|
781
|
+
"gpt-4o": {
|
|
782
|
+
kind: "flat",
|
|
783
|
+
inputPerMTok: 25e4,
|
|
784
|
+
outputPerMTok: 1e6,
|
|
785
|
+
cachedInputPerMTok: 125e3
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
//#endregion
|
|
789
|
+
//#region src/model-rate.ts
|
|
790
|
+
/**
|
|
791
|
+
* models.dev publishes USD prices per one million tokens. Stella stores the
|
|
792
|
+
* same rates as integer ledger units so usage arithmetic never depends on
|
|
793
|
+
* floating point values.
|
|
794
|
+
*/
|
|
795
|
+
const MODEL_RATE_UNITS_PER_USD = 1e5;
|
|
796
|
+
const getStandardModelRate = (rate) => rate.kind === "flat" ? rate : rate.standard;
|
|
797
|
+
const resolveModelRate = (rate, inputTokens) => rate.kind === "input-token-tiered" && inputTokens > rate.inputTokenThreshold ? rate.aboveThreshold : getStandardModelRate(rate);
|
|
798
|
+
//#endregion
|
|
799
|
+
//#region src/model-rate-policy.ts
|
|
800
|
+
const MODELS_DEV_RATE_PROVIDER_BY_CATALOG_PROVIDER = {
|
|
801
|
+
google: "google",
|
|
802
|
+
openai: "openai",
|
|
803
|
+
anthropic: "anthropic",
|
|
804
|
+
bedrock: "amazon-bedrock",
|
|
805
|
+
mistral: "mistral"
|
|
806
|
+
};
|
|
807
|
+
const defineRateSourceAliases = (aliases) => aliases;
|
|
808
|
+
/**
|
|
809
|
+
* Explicit source coordinates for non-offered model IDs that remain valid in
|
|
810
|
+
* deployment overrides and usage attribution. Their numeric rates still come
|
|
811
|
+
* exclusively from models.dev.
|
|
812
|
+
*/
|
|
813
|
+
const RETAINED_MODELS_DEV_RATE_ENTRIES = {
|
|
814
|
+
"gemini-2.5-flash": {
|
|
815
|
+
modelId: "gemini-2.5-flash",
|
|
816
|
+
provider: "google"
|
|
873
817
|
},
|
|
874
|
-
"
|
|
875
|
-
|
|
876
|
-
|
|
818
|
+
"gemini-2.5-pro": {
|
|
819
|
+
modelId: "gemini-2.5-pro",
|
|
820
|
+
provider: "google"
|
|
877
821
|
},
|
|
878
|
-
"
|
|
879
|
-
|
|
880
|
-
|
|
822
|
+
"gpt-4o-mini": {
|
|
823
|
+
modelId: "gpt-4o-mini",
|
|
824
|
+
provider: "openai"
|
|
881
825
|
},
|
|
826
|
+
"gpt-4o": {
|
|
827
|
+
modelId: "gpt-4o",
|
|
828
|
+
provider: "openai"
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
/**
|
|
832
|
+
* Exact mappings where Stella uses a provider routing ID while models.dev
|
|
833
|
+
* publishes pricing under the corresponding base model ID. Generation rejects
|
|
834
|
+
* a mapping once models.dev begins publishing the Stella ID directly.
|
|
835
|
+
*/
|
|
836
|
+
const MODELS_DEV_RATE_SOURCE_ALIASES = defineRateSourceAliases({
|
|
882
837
|
"us.amazon.nova-pro-v1:0": {
|
|
883
|
-
|
|
884
|
-
|
|
838
|
+
modelId: "amazon.nova-pro-v1:0",
|
|
839
|
+
provider: "amazon-bedrock",
|
|
840
|
+
reason: "2026-09-03: stella uses the Bedrock US inference-profile ID; models.dev prices its corresponding base model ID",
|
|
841
|
+
sourceUrl: "https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html"
|
|
885
842
|
},
|
|
886
843
|
"us.amazon.nova-lite-v1:0": {
|
|
887
|
-
|
|
888
|
-
|
|
844
|
+
modelId: "amazon.nova-lite-v1:0",
|
|
845
|
+
provider: "amazon-bedrock",
|
|
846
|
+
reason: "2026-09-03: stella uses the Bedrock US inference-profile ID; models.dev prices its corresponding base model ID",
|
|
847
|
+
sourceUrl: "https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html"
|
|
889
848
|
},
|
|
890
849
|
"us.amazon.nova-micro-v1:0": {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
"mistral-large-latest": {
|
|
907
|
-
displayName: "Mistral Large",
|
|
908
|
-
iconProvider: "mistral"
|
|
909
|
-
},
|
|
910
|
-
"mistral-medium-latest": {
|
|
911
|
-
displayName: "Mistral Medium",
|
|
912
|
-
iconProvider: "mistral"
|
|
913
|
-
},
|
|
914
|
-
"mistral-small-latest": {
|
|
915
|
-
displayName: "Mistral Small",
|
|
916
|
-
iconProvider: "mistral"
|
|
917
|
-
},
|
|
918
|
-
"magistral-medium-latest": {
|
|
919
|
-
displayName: "Magistral Medium",
|
|
920
|
-
iconProvider: "mistral"
|
|
850
|
+
modelId: "amazon.nova-micro-v1:0",
|
|
851
|
+
provider: "amazon-bedrock",
|
|
852
|
+
reason: "2026-09-03: stella uses the Bedrock US inference-profile ID; models.dev prices its corresponding base model ID",
|
|
853
|
+
sourceUrl: "https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html"
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
//#endregion
|
|
857
|
+
//#region src/capabilities-overrides.ts
|
|
858
|
+
const CAPABILITY_OVERRIDES = {
|
|
859
|
+
"us.amazon.nova-pro-v1:0": {
|
|
860
|
+
documentInput: true,
|
|
861
|
+
documentInputReason: "2026-08-20: AWS documents PDF input for Nova Pro through Bedrock Converse",
|
|
862
|
+
reasoningEfforts: null,
|
|
863
|
+
temperatureSupported: true,
|
|
864
|
+
reason: "2026-07-20: absent from the models.dev amazon-bedrock catalog; Bedrock Converse accepts temperature and Nova has no reasoning dial"
|
|
921
865
|
},
|
|
922
|
-
"
|
|
923
|
-
|
|
924
|
-
|
|
866
|
+
"us.amazon.nova-lite-v1:0": {
|
|
867
|
+
documentInput: true,
|
|
868
|
+
documentInputReason: "2026-08-20: AWS documents PDF input for Nova Lite through Bedrock Converse",
|
|
869
|
+
reasoningEfforts: null,
|
|
870
|
+
temperatureSupported: true,
|
|
871
|
+
reason: "2026-07-20: absent from the models.dev amazon-bedrock catalog; Bedrock Converse accepts temperature and Nova has no reasoning dial"
|
|
925
872
|
},
|
|
926
|
-
"
|
|
927
|
-
|
|
928
|
-
|
|
873
|
+
"us.amazon.nova-micro-v1:0": {
|
|
874
|
+
documentInput: false,
|
|
875
|
+
documentInputReason: "2026-08-20: AWS documents Nova Micro as text-only",
|
|
876
|
+
reasoningEfforts: null,
|
|
877
|
+
temperatureSupported: true,
|
|
878
|
+
reason: "2026-07-20: absent from the models.dev amazon-bedrock catalog; Bedrock Converse accepts temperature and Nova has no reasoning dial"
|
|
929
879
|
}
|
|
930
880
|
};
|
|
931
|
-
|
|
932
|
-
|
|
881
|
+
//#endregion
|
|
882
|
+
//#region src/document-input-overrides.ts
|
|
933
883
|
/**
|
|
934
|
-
*
|
|
935
|
-
*
|
|
936
|
-
*
|
|
884
|
+
* Reviewed document-input corrections for models.dev records that exist but
|
|
885
|
+
* under-report the provider API's file-input support. The generator rejects an
|
|
886
|
+
* override once upstream agrees, so sourced data takes ownership automatically.
|
|
937
887
|
*/
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
888
|
+
const DOCUMENT_INPUT_OVERRIDES = {
|
|
889
|
+
"gpt-5.4-mini": {
|
|
890
|
+
supported: true,
|
|
891
|
+
reason: "2026-08-20: OpenAI Responses accepts input_file PDF content for this vision-capable model; models.dev currently omits the pdf modality"
|
|
892
|
+
},
|
|
893
|
+
"gpt-5.4-nano": {
|
|
894
|
+
supported: true,
|
|
895
|
+
reason: "2026-08-20: OpenAI Responses accepts input_file PDF content for this vision-capable model; models.dev currently omits the pdf modality"
|
|
896
|
+
},
|
|
897
|
+
"gpt-5.2": {
|
|
898
|
+
supported: true,
|
|
899
|
+
reason: "2026-08-20: OpenAI Responses accepts input_file PDF content for this vision-capable model; models.dev currently omits the pdf modality"
|
|
900
|
+
}
|
|
943
901
|
};
|
|
902
|
+
//#endregion
|
|
903
|
+
//#region src/index.ts
|
|
944
904
|
/**
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
* `
|
|
951
|
-
*
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
*
|
|
955
|
-
*
|
|
905
|
+
* Canonical AI provider and model catalog.
|
|
906
|
+
*
|
|
907
|
+
* Single source of truth for every provider/model identifier stella
|
|
908
|
+
* offers. Imported by the API runtime
|
|
909
|
+
* (`apps/api/src/lib/tanstack-ai-models.ts`)
|
|
910
|
+
* and the BYOK settings UI (`apps/web`), so the picker can never offer
|
|
911
|
+
* a model the backend rejects, and vice versa.
|
|
912
|
+
*
|
|
913
|
+
* Pure data: no provider SDKs, no env access, no side effects. This is
|
|
914
|
+
* deliberate so scripts (the nightly upstream-validation check) and
|
|
915
|
+
* both apps can import it cheaply. Keep it that way. The only runtime
|
|
916
|
+
* dependency is valibot, used solely to construct branded types the
|
|
917
|
+
* same way the rest of the repo does.
|
|
918
|
+
*
|
|
919
|
+
* Model IDs go stale when providers rename or retire models. The
|
|
920
|
+
* nightly `model-catalog-upstream` check
|
|
921
|
+
* (`packages/scripts/src/model-catalog-upstream.ts`) validates every
|
|
922
|
+
* ID here against live provider/aggregator listings so a retired model
|
|
923
|
+
* fails CI instead of 400-ing a user at runtime.
|
|
956
924
|
*/
|
|
957
|
-
const CHAT_PDF_ATTACHMENT_MODEL_OPTIONS = {
|
|
958
|
-
...BYOK_DOCUMENT_INPUT_MODEL_OPTIONS,
|
|
959
|
-
mistral: [
|
|
960
|
-
"mistral-medium-latest",
|
|
961
|
-
"mistral-small-latest",
|
|
962
|
-
"pixtral-large-latest"
|
|
963
|
-
]
|
|
964
|
-
};
|
|
965
|
-
const isChatPdfAttachmentModelSupported = ({ provider, modelId }) => {
|
|
966
|
-
return CHAT_PDF_ATTACHMENT_MODEL_OPTIONS[provider].includes(modelId);
|
|
967
|
-
};
|
|
968
925
|
/**
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
* role's input-modality constraint (PDF needs a document-capable
|
|
972
|
-
* model). This is the runtime allowlist, so a model dropped by a
|
|
973
|
-
* catalog bump stops being valid here even though it is still a
|
|
974
|
-
* non-empty string in a stored org config.
|
|
975
|
-
*/
|
|
976
|
-
const isOfferedBYOKModelForRole = ({ provider, modelId, role }) => {
|
|
977
|
-
return BYOK_MODEL_OPTIONS[provider].includes(modelId) && isBYOKModelRoleSupported({
|
|
978
|
-
provider,
|
|
979
|
-
modelId,
|
|
980
|
-
role
|
|
981
|
-
});
|
|
982
|
-
};
|
|
983
|
-
/**
|
|
984
|
-
* Resolve a model id that will actually work for this provider+role,
|
|
985
|
-
* keeping the SAME provider. Returns the caller's model unchanged when
|
|
986
|
-
* it is still offered; otherwise falls back to the provider's per-role
|
|
987
|
-
* default (`BYOK_DEFAULT_MODELS`). Returns `null` only when the
|
|
988
|
-
* provider has no valid model for the role at all — the sole case
|
|
989
|
-
* today is `mistral` + `pdf`, because the TanStack Mistral adapter
|
|
990
|
-
* exposes no `document` input modality, so no Mistral model (not even
|
|
991
|
-
* the default) can serve the PDF role.
|
|
926
|
+
* Logical model roles. Call sites declare *what* they need, not
|
|
927
|
+
* *which* model to use.
|
|
992
928
|
*
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
*
|
|
996
|
-
|
|
997
|
-
const resolveWorkingBYOKModelForRole = ({ provider, modelId, role }) => {
|
|
998
|
-
if (isOfferedBYOKModelForRole({
|
|
999
|
-
provider,
|
|
1000
|
-
modelId,
|
|
1001
|
-
role
|
|
1002
|
-
})) return modelId;
|
|
1003
|
-
const fallback = BYOK_DEFAULT_MODELS[provider][role];
|
|
1004
|
-
return isOfferedBYOKModelForRole({
|
|
1005
|
-
provider,
|
|
1006
|
-
modelId: fallback,
|
|
1007
|
-
role
|
|
1008
|
-
}) ? fallback : null;
|
|
1009
|
-
};
|
|
1010
|
-
/**
|
|
1011
|
-
* Anthropic models that use the adaptive-thinking request shape
|
|
1012
|
-
* (`thinking: { type: "adaptive" }`). Newer Claude models reject the
|
|
1013
|
-
* legacy budget-based form, so every Opus 4.6+/Sonnet 4.6/Fable entry
|
|
1014
|
-
* offered above must appear here or it will 400 on the reasoning role.
|
|
929
|
+
* - fast: classification, extraction, short generation
|
|
930
|
+
* - chat: conversational with tool use and streaming
|
|
931
|
+
* - reasoning: complex multi-step legal analysis
|
|
932
|
+
* - pdf: native PDF/image understanding
|
|
1015
933
|
*/
|
|
1016
|
-
const
|
|
1017
|
-
"
|
|
1018
|
-
"
|
|
1019
|
-
"
|
|
1020
|
-
"
|
|
1021
|
-
"claude-opus-4-7",
|
|
1022
|
-
"claude-opus-4-8",
|
|
1023
|
-
"claude-fable-5",
|
|
1024
|
-
"claude-fable-5-1"
|
|
934
|
+
const MODEL_ROLES = [
|
|
935
|
+
"fast",
|
|
936
|
+
"chat",
|
|
937
|
+
"reasoning",
|
|
938
|
+
"pdf"
|
|
1025
939
|
];
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
"
|
|
1034
|
-
"
|
|
1035
|
-
"
|
|
1036
|
-
"
|
|
1037
|
-
"high",
|
|
1038
|
-
"xhigh",
|
|
1039
|
-
"max"
|
|
940
|
+
const TEMPERATURE_POLICIES = ["emit", "omit"];
|
|
941
|
+
const AI_PROVIDERS = [
|
|
942
|
+
"google",
|
|
943
|
+
"openrouter",
|
|
944
|
+
"openai",
|
|
945
|
+
"azure_foundry",
|
|
946
|
+
"anthropic",
|
|
947
|
+
"bedrock",
|
|
948
|
+
"mistral",
|
|
949
|
+
"openai_compatible",
|
|
950
|
+
"huggingface"
|
|
1040
951
|
];
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
openrouter: "openai/gpt-5.6-luna",
|
|
1057
|
-
openai: "gpt-5.6-luna",
|
|
1058
|
-
anthropic: DEFAULT_MODELS.anthropic.fast,
|
|
1059
|
-
bedrock: DEFAULT_MODELS.bedrock.fast,
|
|
1060
|
-
mistral: DEFAULT_MODELS.mistral.fast,
|
|
1061
|
-
azure_foundry: null,
|
|
1062
|
-
openai_compatible: null,
|
|
1063
|
-
huggingface: null
|
|
1064
|
-
};
|
|
1065
|
-
const MODEL_CATALOG_ID_ALIASES = {
|
|
1066
|
-
"gpt-5.6-sol": "gpt-5.6",
|
|
1067
|
-
"claude-opus-4.8": "claude-opus-4-8",
|
|
1068
|
-
"claude-sonnet-4.6": "claude-sonnet-4-6"
|
|
952
|
+
const TANSTACK_AI_PROVIDERS = [
|
|
953
|
+
"google",
|
|
954
|
+
"openrouter",
|
|
955
|
+
"openai",
|
|
956
|
+
"anthropic",
|
|
957
|
+
"bedrock",
|
|
958
|
+
"mistral"
|
|
959
|
+
];
|
|
960
|
+
const MODEL_CATALOG_PROVIDER_KIND = {
|
|
961
|
+
google: "first-party",
|
|
962
|
+
openrouter: "aggregator",
|
|
963
|
+
openai: "first-party",
|
|
964
|
+
anthropic: "first-party",
|
|
965
|
+
bedrock: "platform",
|
|
966
|
+
mistral: "first-party"
|
|
1069
967
|
};
|
|
1070
|
-
const MODEL_CATALOG_ID_ALIAS_TARGET_BY_ID = MODEL_CATALOG_ID_ALIASES;
|
|
1071
|
-
const normalizeModelCatalogId = (modelId) => MODEL_CATALOG_ID_ALIAS_TARGET_BY_ID[modelId] ?? modelId;
|
|
1072
|
-
const MODEL_TEMPERATURE_POLICY_BY_ID = MODEL_TEMPERATURE_POLICIES;
|
|
1073
968
|
/**
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
*
|
|
1077
|
-
* also resolve to `false` (send nothing; provider default). Callers must
|
|
1078
|
-
* never index `MODEL_TEMPERATURE_POLICIES` directly with
|
|
1079
|
-
* a runtime string.
|
|
969
|
+
* Runtime form of the first-party provider union. The conditional annotation
|
|
970
|
+
* makes adding a first-party policy without adding its discovery implementation
|
|
971
|
+
* a compile error.
|
|
1080
972
|
*/
|
|
1081
|
-
const
|
|
1082
|
-
|
|
973
|
+
const FIRST_PARTY_MODEL_PROVIDERS = [
|
|
974
|
+
"google",
|
|
975
|
+
"openai",
|
|
976
|
+
"anthropic",
|
|
977
|
+
"mistral"
|
|
978
|
+
];
|
|
1083
979
|
/**
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
* directly with a runtime string.
|
|
980
|
+
* Per-role default model IDs for the BYOK-capable cloud providers.
|
|
981
|
+
* Shared between the instance default table (`DEFAULT_MODELS`) and the
|
|
982
|
+
* settings-UI default selection, so a default is defined exactly once.
|
|
1088
983
|
*/
|
|
1089
|
-
const
|
|
1090
|
-
|
|
984
|
+
const BYOK_DEFAULT_MODELS = {
|
|
985
|
+
google: {
|
|
986
|
+
fast: "gemini-3.7-flash",
|
|
987
|
+
chat: "gemini-3.7-flash",
|
|
988
|
+
reasoning: "gemini-3.7-flash",
|
|
989
|
+
pdf: "gemini-3.7-flash"
|
|
990
|
+
},
|
|
991
|
+
openrouter: {
|
|
992
|
+
fast: "openai/gpt-5.6-luna",
|
|
993
|
+
chat: "openai/gpt-5.6-terra",
|
|
994
|
+
reasoning: "openai/gpt-5.6-terra",
|
|
995
|
+
pdf: "openai/gpt-5.6-terra"
|
|
996
|
+
},
|
|
997
|
+
openai: {
|
|
998
|
+
fast: "gpt-5.4-nano",
|
|
999
|
+
chat: "gpt-5.4-mini",
|
|
1000
|
+
reasoning: "gpt-5.4",
|
|
1001
|
+
pdf: "gpt-5.4"
|
|
1002
|
+
},
|
|
1003
|
+
anthropic: {
|
|
1004
|
+
fast: "claude-opus-5",
|
|
1005
|
+
chat: "claude-opus-5",
|
|
1006
|
+
reasoning: "claude-opus-5",
|
|
1007
|
+
pdf: "claude-opus-5"
|
|
1008
|
+
},
|
|
1009
|
+
bedrock: {
|
|
1010
|
+
fast: "us.amazon.nova-micro-v1:0",
|
|
1011
|
+
chat: "us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
1012
|
+
reasoning: "us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
1013
|
+
pdf: "us.anthropic.claude-sonnet-4-5-20250929-v1:0"
|
|
1014
|
+
},
|
|
1015
|
+
mistral: {
|
|
1016
|
+
fast: "mistral-small-latest",
|
|
1017
|
+
chat: "mistral-medium-latest",
|
|
1018
|
+
reasoning: "magistral-medium-latest",
|
|
1019
|
+
pdf: "mistral-large-latest"
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1091
1022
|
/**
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1023
|
+
* Instance-level default model IDs per provider. Extends the BYOK
|
|
1024
|
+
* defaults with the providers that only the instance path uses
|
|
1025
|
+
* (custom deployments and OpenAI-compatible endpoints).
|
|
1094
1026
|
*/
|
|
1095
|
-
const
|
|
1096
|
-
|
|
1027
|
+
const DEFAULT_MODELS = {
|
|
1028
|
+
...BYOK_DEFAULT_MODELS,
|
|
1029
|
+
azure_foundry: {
|
|
1030
|
+
fast: "gpt-5.4-nano",
|
|
1031
|
+
chat: "gpt-5.4-mini",
|
|
1032
|
+
reasoning: "gpt-5.4",
|
|
1033
|
+
pdf: "gpt-5.4"
|
|
1034
|
+
},
|
|
1035
|
+
openai_compatible: {
|
|
1036
|
+
fast: "default",
|
|
1037
|
+
chat: "default",
|
|
1038
|
+
reasoning: "default",
|
|
1039
|
+
pdf: "default"
|
|
1040
|
+
},
|
|
1041
|
+
huggingface: {
|
|
1042
|
+
fast: "speakleash/Bielik-1.5B-v3.0-Instruct",
|
|
1043
|
+
chat: "speakleash/Bielik-11B-v2.3-Instruct",
|
|
1044
|
+
reasoning: "speakleash/Bielik-11B-v2.3-Instruct",
|
|
1045
|
+
pdf: "speakleash/Bielik-11B-v2.3-Instruct"
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1097
1048
|
/**
|
|
1098
|
-
*
|
|
1099
|
-
*
|
|
1049
|
+
* BYOK-offered model IDs per provider — the curated catalog users pick
|
|
1050
|
+
* from in org settings, and the server-side allowlist the API enforces.
|
|
1051
|
+
* The frontend list is not a security boundary; this is what the API
|
|
1052
|
+
* accepts.
|
|
1100
1053
|
*
|
|
1101
|
-
*
|
|
1102
|
-
*
|
|
1103
|
-
*
|
|
1104
|
-
* - Otherwise → the supported value nearest on `REASONING_EFFORTS`,
|
|
1105
|
-
* preferring the weaker side on ties, so a "none" request against a
|
|
1106
|
-
* reasoning-mandatory model degrades to its weakest tier instead of
|
|
1107
|
-
* erroring, and requests above the model's ceiling clamp down to it.
|
|
1054
|
+
* Limited to providers the TanStack AI integration supports for BYOK.
|
|
1055
|
+
* Providers without a first-class TanStack adapter path are intentionally
|
|
1056
|
+
* not accepted at this boundary.
|
|
1108
1057
|
*/
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1058
|
+
const BYOK_MODEL_OPTIONS = {
|
|
1059
|
+
google: [
|
|
1060
|
+
"gemini-3.8-flash",
|
|
1061
|
+
"gemini-3.7-flash",
|
|
1062
|
+
"gemini-3.6-flash",
|
|
1063
|
+
"gemini-3.5-flash-lite",
|
|
1064
|
+
"gemini-3.1-pro-preview",
|
|
1065
|
+
"gemini-3.5-flash",
|
|
1066
|
+
"gemini-3.1-flash-lite"
|
|
1067
|
+
],
|
|
1068
|
+
anthropic: [
|
|
1069
|
+
"claude-sonnet-5",
|
|
1070
|
+
"claude-fable-5-1",
|
|
1071
|
+
"claude-fable-5",
|
|
1072
|
+
"claude-opus-5",
|
|
1073
|
+
"claude-opus-4-8",
|
|
1074
|
+
"claude-opus-4-7",
|
|
1075
|
+
"claude-sonnet-4-6",
|
|
1076
|
+
"claude-opus-4-6",
|
|
1077
|
+
"claude-haiku-4-5-20251001"
|
|
1078
|
+
],
|
|
1079
|
+
openai: [
|
|
1080
|
+
"gpt-5.6",
|
|
1081
|
+
"gpt-5.6-terra",
|
|
1082
|
+
"gpt-5.6-luna",
|
|
1083
|
+
"gpt-5.5",
|
|
1084
|
+
"gpt-5.4",
|
|
1085
|
+
"gpt-5.4-mini",
|
|
1086
|
+
"gpt-5.4-nano",
|
|
1087
|
+
"gpt-5.2"
|
|
1088
|
+
],
|
|
1089
|
+
openrouter: [
|
|
1090
|
+
"openai/gpt-5.6-luna",
|
|
1091
|
+
"openai/gpt-5.6-terra",
|
|
1092
|
+
"google/gemini-3.8-flash",
|
|
1093
|
+
"google/gemini-3.7-flash",
|
|
1094
|
+
"google/gemini-3.6-flash",
|
|
1095
|
+
"google/gemini-3.5-flash-lite",
|
|
1096
|
+
"google/gemini-3.1-pro-preview",
|
|
1097
|
+
"google/gemini-3.5-flash",
|
|
1098
|
+
"google/gemini-3.1-flash-lite",
|
|
1099
|
+
"anthropic/claude-sonnet-5",
|
|
1100
|
+
"anthropic/claude-opus-5",
|
|
1101
|
+
"anthropic/claude-opus-4.8",
|
|
1102
|
+
"anthropic/claude-sonnet-4.6",
|
|
1103
|
+
"openai/gpt-5.5",
|
|
1104
|
+
"openai/gpt-5.4-mini"
|
|
1105
|
+
],
|
|
1106
|
+
bedrock: [
|
|
1107
|
+
"us.anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
1108
|
+
"us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
1109
|
+
"us.amazon.nova-pro-v1:0",
|
|
1110
|
+
"us.amazon.nova-lite-v1:0",
|
|
1111
|
+
"us.amazon.nova-micro-v1:0",
|
|
1112
|
+
"openai.gpt-oss-120b-1:0",
|
|
1113
|
+
"openai.gpt-oss-20b-1:0",
|
|
1114
|
+
"us.deepseek.r1-v1:0"
|
|
1115
|
+
],
|
|
1116
|
+
mistral: [
|
|
1117
|
+
"mistral-large-latest",
|
|
1118
|
+
"mistral-medium-latest",
|
|
1119
|
+
"mistral-small-latest",
|
|
1120
|
+
"magistral-medium-latest",
|
|
1121
|
+
"magistral-small",
|
|
1122
|
+
"pixtral-large-latest"
|
|
1123
|
+
]
|
|
1125
1124
|
};
|
|
1126
|
-
const getStandardModelRate = (rate) => rate.kind === "flat" ? rate : rate.standard;
|
|
1127
|
-
const resolveModelRate = (rate, inputTokens) => rate.kind === "input-token-tiered" && inputTokens > rate.inputTokenThreshold ? rate.aboveThreshold : getStandardModelRate(rate);
|
|
1128
1125
|
/**
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
* model IDs or the fallback rate.
|
|
1126
|
+
* Presentation metadata for every offered model. Keeping this exhaustive beside
|
|
1127
|
+
* the allowlist prevents a newly offered model from leaking a raw provider ID
|
|
1128
|
+
* into user-facing pickers. OpenRouter entries deliberately carry their model
|
|
1129
|
+
* creator's icon while their routing provider remains available separately.
|
|
1134
1130
|
*/
|
|
1135
|
-
const
|
|
1136
|
-
"gemini-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
outputPerMTok: 25e4,
|
|
1140
|
-
cachedInputPerMTok: 7500
|
|
1141
|
-
},
|
|
1142
|
-
"gemini-2.5-pro": {
|
|
1143
|
-
kind: "flat",
|
|
1144
|
-
inputPerMTok: 125e3,
|
|
1145
|
-
outputPerMTok: 1e6,
|
|
1146
|
-
cachedInputPerMTok: 31250
|
|
1147
|
-
},
|
|
1148
|
-
"gemini-3.1-flash-lite": {
|
|
1149
|
-
kind: "flat",
|
|
1150
|
-
inputPerMTok: 25e3,
|
|
1151
|
-
outputPerMTok: 15e4,
|
|
1152
|
-
cachedInputPerMTok: 2500
|
|
1153
|
-
},
|
|
1154
|
-
"gemini-3.5-flash": {
|
|
1155
|
-
kind: "flat",
|
|
1156
|
-
inputPerMTok: 15e4,
|
|
1157
|
-
outputPerMTok: 9e5,
|
|
1158
|
-
cachedInputPerMTok: 15e3
|
|
1131
|
+
const MODEL_DISPLAY_METADATA = {
|
|
1132
|
+
"gemini-3.8-flash": {
|
|
1133
|
+
displayName: "Gemini 3.8 Flash",
|
|
1134
|
+
iconProvider: "google"
|
|
1159
1135
|
},
|
|
1160
|
-
"gemini-3.
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
outputPerMTok: 25e4,
|
|
1164
|
-
cachedInputPerMTok: 3e3
|
|
1136
|
+
"gemini-3.7-flash": {
|
|
1137
|
+
displayName: "Gemini 3.7 Flash",
|
|
1138
|
+
iconProvider: "google"
|
|
1165
1139
|
},
|
|
1166
1140
|
"gemini-3.6-flash": {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
outputPerMTok: 375e3,
|
|
1170
|
-
cachedInputPerMTok: 7500
|
|
1141
|
+
displayName: "Gemini 3.6 Flash",
|
|
1142
|
+
iconProvider: "google"
|
|
1171
1143
|
},
|
|
1172
|
-
"gemini-3.
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
outputPerMTok: 375e3,
|
|
1176
|
-
cachedInputPerMTok: 7500
|
|
1144
|
+
"gemini-3.5-flash-lite": {
|
|
1145
|
+
displayName: "Gemini 3.5 Flash Lite",
|
|
1146
|
+
iconProvider: "google"
|
|
1177
1147
|
},
|
|
1178
1148
|
"gemini-3.1-pro-preview": {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
},
|
|
1186
|
-
aboveThreshold: {
|
|
1187
|
-
inputPerMTok: 4e5,
|
|
1188
|
-
outputPerMTok: 18e5,
|
|
1189
|
-
cachedInputPerMTok: 4e4
|
|
1190
|
-
}
|
|
1149
|
+
displayName: "Gemini 3.1 Pro Preview",
|
|
1150
|
+
iconProvider: "google"
|
|
1151
|
+
},
|
|
1152
|
+
"gemini-3.5-flash": {
|
|
1153
|
+
displayName: "Gemini 3.5 Flash",
|
|
1154
|
+
iconProvider: "google"
|
|
1191
1155
|
},
|
|
1192
|
-
"
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
outputPerMTok: 6e4,
|
|
1196
|
-
cachedInputPerMTok: 7500
|
|
1156
|
+
"gemini-3.1-flash-lite": {
|
|
1157
|
+
displayName: "Gemini 3.1 Flash Lite",
|
|
1158
|
+
iconProvider: "google"
|
|
1197
1159
|
},
|
|
1198
|
-
"
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
outputPerMTok: 1e6,
|
|
1202
|
-
cachedInputPerMTok: 125e3
|
|
1160
|
+
"claude-sonnet-5": {
|
|
1161
|
+
displayName: "Claude Sonnet 5",
|
|
1162
|
+
iconProvider: "anthropic"
|
|
1203
1163
|
},
|
|
1204
|
-
"
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
outputPerMTok: 14e5,
|
|
1208
|
-
cachedInputPerMTok: 17500
|
|
1164
|
+
"claude-fable-5-1": {
|
|
1165
|
+
displayName: "Claude Fable 5.1",
|
|
1166
|
+
iconProvider: "anthropic"
|
|
1209
1167
|
},
|
|
1210
|
-
"
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
outputPerMTok: 125e3,
|
|
1214
|
-
cachedInputPerMTok: 2e3
|
|
1168
|
+
"claude-fable-5": {
|
|
1169
|
+
displayName: "Claude Fable 5",
|
|
1170
|
+
iconProvider: "anthropic"
|
|
1215
1171
|
},
|
|
1216
|
-
"
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
outputPerMTok: 45e4,
|
|
1220
|
-
cachedInputPerMTok: 7500
|
|
1172
|
+
"claude-opus-5": {
|
|
1173
|
+
displayName: "Claude Opus 5",
|
|
1174
|
+
iconProvider: "anthropic"
|
|
1221
1175
|
},
|
|
1222
|
-
"
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
standard: {
|
|
1226
|
-
inputPerMTok: 25e4,
|
|
1227
|
-
outputPerMTok: 15e5,
|
|
1228
|
-
cachedInputPerMTok: 25e3
|
|
1229
|
-
},
|
|
1230
|
-
aboveThreshold: {
|
|
1231
|
-
inputPerMTok: 5e5,
|
|
1232
|
-
outputPerMTok: 225e4,
|
|
1233
|
-
cachedInputPerMTok: 5e4
|
|
1234
|
-
}
|
|
1176
|
+
"claude-opus-4-8": {
|
|
1177
|
+
displayName: "Claude Opus 4.8",
|
|
1178
|
+
iconProvider: "anthropic"
|
|
1235
1179
|
},
|
|
1236
|
-
"
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1180
|
+
"claude-opus-4-7": {
|
|
1181
|
+
displayName: "Claude Opus 4.7",
|
|
1182
|
+
iconProvider: "anthropic"
|
|
1183
|
+
},
|
|
1184
|
+
"claude-sonnet-4-6": {
|
|
1185
|
+
displayName: "Claude Sonnet 4.6",
|
|
1186
|
+
iconProvider: "anthropic"
|
|
1187
|
+
},
|
|
1188
|
+
"claude-opus-4-6": {
|
|
1189
|
+
displayName: "Claude Opus 4.6",
|
|
1190
|
+
iconProvider: "anthropic"
|
|
1191
|
+
},
|
|
1192
|
+
"claude-haiku-4-5-20251001": {
|
|
1193
|
+
displayName: "Claude Haiku 4.5",
|
|
1194
|
+
iconProvider: "anthropic"
|
|
1249
1195
|
},
|
|
1250
1196
|
"gpt-5.6": {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
},
|
|
1258
|
-
aboveThreshold: {
|
|
1259
|
-
inputPerMTok: 8e5,
|
|
1260
|
-
outputPerMTok: 3e6,
|
|
1261
|
-
cachedInputPerMTok: 8e4
|
|
1262
|
-
}
|
|
1197
|
+
displayName: "GPT-5.6 Sol",
|
|
1198
|
+
iconProvider: "openai"
|
|
1199
|
+
},
|
|
1200
|
+
"gpt-5.6-terra": {
|
|
1201
|
+
displayName: "GPT-5.6 Terra",
|
|
1202
|
+
iconProvider: "openai"
|
|
1263
1203
|
},
|
|
1264
1204
|
"gpt-5.6-luna": {
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
standard: {
|
|
1268
|
-
inputPerMTok: 2e4,
|
|
1269
|
-
outputPerMTok: 12e4,
|
|
1270
|
-
cachedInputPerMTok: 2e3
|
|
1271
|
-
},
|
|
1272
|
-
aboveThreshold: {
|
|
1273
|
-
inputPerMTok: 4e4,
|
|
1274
|
-
outputPerMTok: 18e4,
|
|
1275
|
-
cachedInputPerMTok: 4e3
|
|
1276
|
-
}
|
|
1205
|
+
displayName: "GPT-5.6 Luna",
|
|
1206
|
+
iconProvider: "openai"
|
|
1277
1207
|
},
|
|
1278
|
-
"gpt-5.
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
standard: {
|
|
1282
|
-
inputPerMTok: 2e5,
|
|
1283
|
-
outputPerMTok: 12e5,
|
|
1284
|
-
cachedInputPerMTok: 2e4
|
|
1285
|
-
},
|
|
1286
|
-
aboveThreshold: {
|
|
1287
|
-
inputPerMTok: 4e5,
|
|
1288
|
-
outputPerMTok: 18e5,
|
|
1289
|
-
cachedInputPerMTok: 4e4
|
|
1290
|
-
}
|
|
1208
|
+
"gpt-5.5": {
|
|
1209
|
+
displayName: "GPT-5.5",
|
|
1210
|
+
iconProvider: "openai"
|
|
1291
1211
|
},
|
|
1292
|
-
"
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
outputPerMTok: 5e5,
|
|
1296
|
-
cachedInputPerMTok: 1e4
|
|
1212
|
+
"gpt-5.4": {
|
|
1213
|
+
displayName: "GPT-5.4",
|
|
1214
|
+
iconProvider: "openai"
|
|
1297
1215
|
},
|
|
1298
|
-
"
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
outputPerMTok: 15e5,
|
|
1302
|
-
cachedInputPerMTok: 3e4
|
|
1216
|
+
"gpt-5.4-mini": {
|
|
1217
|
+
displayName: "GPT-5.4 Mini",
|
|
1218
|
+
iconProvider: "openai"
|
|
1303
1219
|
},
|
|
1304
|
-
"
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
outputPerMTok: 1e6,
|
|
1308
|
-
cachedInputPerMTok: 2e4
|
|
1220
|
+
"gpt-5.4-nano": {
|
|
1221
|
+
displayName: "GPT-5.4 Nano",
|
|
1222
|
+
iconProvider: "openai"
|
|
1309
1223
|
},
|
|
1310
|
-
"
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
outputPerMTok: 25e5,
|
|
1314
|
-
cachedInputPerMTok: 5e4
|
|
1224
|
+
"gpt-5.2": {
|
|
1225
|
+
displayName: "GPT-5.2",
|
|
1226
|
+
iconProvider: "openai"
|
|
1315
1227
|
},
|
|
1316
|
-
"
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
outputPerMTok: 25e5,
|
|
1320
|
-
cachedInputPerMTok: 5e4
|
|
1228
|
+
"openai/gpt-5.6-luna": {
|
|
1229
|
+
displayName: "GPT-5.6 Luna",
|
|
1230
|
+
iconProvider: "openai"
|
|
1321
1231
|
},
|
|
1322
|
-
"
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
outputPerMTok: 25e5,
|
|
1326
|
-
cachedInputPerMTok: 5e4
|
|
1232
|
+
"openai/gpt-5.6-terra": {
|
|
1233
|
+
displayName: "GPT-5.6 Terra",
|
|
1234
|
+
iconProvider: "openai"
|
|
1327
1235
|
},
|
|
1328
|
-
"
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
outputPerMTok: 25e5,
|
|
1332
|
-
cachedInputPerMTok: 5e4
|
|
1236
|
+
"google/gemini-3.8-flash": {
|
|
1237
|
+
displayName: "Gemini 3.8 Flash",
|
|
1238
|
+
iconProvider: "google"
|
|
1333
1239
|
},
|
|
1334
|
-
"
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
outputPerMTok: 5e6,
|
|
1338
|
-
cachedInputPerMTok: 1e5
|
|
1240
|
+
"google/gemini-3.7-flash": {
|
|
1241
|
+
displayName: "Gemini 3.7 Flash",
|
|
1242
|
+
iconProvider: "google"
|
|
1339
1243
|
},
|
|
1340
|
-
"
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
outputPerMTok: 5e6,
|
|
1344
|
-
cachedInputPerMTok: 25e3
|
|
1244
|
+
"google/gemini-3.6-flash": {
|
|
1245
|
+
displayName: "Gemini 3.6 Flash",
|
|
1246
|
+
iconProvider: "google"
|
|
1345
1247
|
},
|
|
1346
|
-
"
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
outputPerMTok: 6e4
|
|
1248
|
+
"google/gemini-3.5-flash-lite": {
|
|
1249
|
+
displayName: "Gemini 3.5 Flash Lite",
|
|
1250
|
+
iconProvider: "google"
|
|
1350
1251
|
},
|
|
1351
|
-
"
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
outputPerMTok: 15e4
|
|
1252
|
+
"google/gemini-3.1-pro-preview": {
|
|
1253
|
+
displayName: "Gemini 3.1 Pro Preview",
|
|
1254
|
+
iconProvider: "google"
|
|
1355
1255
|
},
|
|
1356
|
-
"
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
outputPerMTok: 75e4
|
|
1256
|
+
"google/gemini-3.5-flash": {
|
|
1257
|
+
displayName: "Gemini 3.5 Flash",
|
|
1258
|
+
iconProvider: "google"
|
|
1360
1259
|
},
|
|
1361
|
-
"
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
outputPerMTok: 75e4
|
|
1260
|
+
"google/gemini-3.1-flash-lite": {
|
|
1261
|
+
displayName: "Gemini 3.1 Flash Lite",
|
|
1262
|
+
iconProvider: "google"
|
|
1365
1263
|
},
|
|
1366
|
-
"
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
outputPerMTok: 5e5
|
|
1264
|
+
"anthropic/claude-sonnet-5": {
|
|
1265
|
+
displayName: "Claude Sonnet 5",
|
|
1266
|
+
iconProvider: "anthropic"
|
|
1370
1267
|
},
|
|
1371
|
-
"
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
outputPerMTok: 15e4
|
|
1268
|
+
"anthropic/claude-opus-5": {
|
|
1269
|
+
displayName: "Claude Opus 5",
|
|
1270
|
+
iconProvider: "anthropic"
|
|
1375
1271
|
},
|
|
1376
|
-
"
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
outputPerMTok: 15e4
|
|
1272
|
+
"anthropic/claude-opus-4.8": {
|
|
1273
|
+
displayName: "Claude Opus 4.8",
|
|
1274
|
+
iconProvider: "anthropic"
|
|
1380
1275
|
},
|
|
1381
|
-
"
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1276
|
+
"anthropic/claude-sonnet-4.6": {
|
|
1277
|
+
displayName: "Claude Sonnet 4.6",
|
|
1278
|
+
iconProvider: "anthropic"
|
|
1279
|
+
},
|
|
1280
|
+
"openai/gpt-5.5": {
|
|
1281
|
+
displayName: "GPT-5.5",
|
|
1282
|
+
iconProvider: "openai"
|
|
1283
|
+
},
|
|
1284
|
+
"openai/gpt-5.4-mini": {
|
|
1285
|
+
displayName: "GPT-5.4 Mini",
|
|
1286
|
+
iconProvider: "openai"
|
|
1385
1287
|
},
|
|
1386
1288
|
"us.anthropic.claude-sonnet-4-5-20250929-v1:0": {
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
outputPerMTok: 15e5,
|
|
1390
|
-
cachedInputPerMTok: 3e4
|
|
1289
|
+
displayName: "Claude Sonnet 4.5",
|
|
1290
|
+
iconProvider: "anthropic"
|
|
1391
1291
|
},
|
|
1392
1292
|
"us.anthropic.claude-haiku-4-5-20251001-v1:0": {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
outputPerMTok: 5e5,
|
|
1396
|
-
cachedInputPerMTok: 1e4
|
|
1293
|
+
displayName: "Claude Haiku 4.5",
|
|
1294
|
+
iconProvider: "anthropic"
|
|
1397
1295
|
},
|
|
1398
1296
|
"us.amazon.nova-pro-v1:0": {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
outputPerMTok: 32e4
|
|
1297
|
+
displayName: "Amazon Nova Pro",
|
|
1298
|
+
iconProvider: "bedrock"
|
|
1402
1299
|
},
|
|
1403
1300
|
"us.amazon.nova-lite-v1:0": {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
outputPerMTok: 24e3
|
|
1301
|
+
displayName: "Amazon Nova Lite",
|
|
1302
|
+
iconProvider: "bedrock"
|
|
1407
1303
|
},
|
|
1408
1304
|
"us.amazon.nova-micro-v1:0": {
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
outputPerMTok: 14e3
|
|
1305
|
+
displayName: "Amazon Nova Micro",
|
|
1306
|
+
iconProvider: "bedrock"
|
|
1412
1307
|
},
|
|
1413
1308
|
"openai.gpt-oss-120b-1:0": {
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
outputPerMTok: 6e4
|
|
1309
|
+
displayName: "GPT OSS 120B",
|
|
1310
|
+
iconProvider: "openai"
|
|
1417
1311
|
},
|
|
1418
1312
|
"openai.gpt-oss-20b-1:0": {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
outputPerMTok: 3e4
|
|
1313
|
+
displayName: "GPT OSS 20B",
|
|
1314
|
+
iconProvider: "openai"
|
|
1422
1315
|
},
|
|
1423
1316
|
"us.deepseek.r1-v1:0": {
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1317
|
+
displayName: "DeepSeek R1",
|
|
1318
|
+
iconProvider: "bedrock"
|
|
1319
|
+
},
|
|
1320
|
+
"mistral-large-latest": {
|
|
1321
|
+
displayName: "Mistral Large",
|
|
1322
|
+
iconProvider: "mistral"
|
|
1323
|
+
},
|
|
1324
|
+
"mistral-medium-latest": {
|
|
1325
|
+
displayName: "Mistral Medium",
|
|
1326
|
+
iconProvider: "mistral"
|
|
1327
|
+
},
|
|
1328
|
+
"mistral-small-latest": {
|
|
1329
|
+
displayName: "Mistral Small",
|
|
1330
|
+
iconProvider: "mistral"
|
|
1331
|
+
},
|
|
1332
|
+
"magistral-medium-latest": {
|
|
1333
|
+
displayName: "Magistral Medium",
|
|
1334
|
+
iconProvider: "mistral"
|
|
1335
|
+
},
|
|
1336
|
+
"magistral-small": {
|
|
1337
|
+
displayName: "Magistral Small",
|
|
1338
|
+
iconProvider: "mistral"
|
|
1339
|
+
},
|
|
1340
|
+
"pixtral-large-latest": {
|
|
1341
|
+
displayName: "Pixtral Large",
|
|
1342
|
+
iconProvider: "mistral"
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
const MODEL_DISPLAY_METADATA_BY_ID = MODEL_DISPLAY_METADATA;
|
|
1346
|
+
const getModelDisplayMetadata = (modelId) => MODEL_DISPLAY_METADATA_BY_ID[normalizeModelCatalogId(modelId)] ?? null;
|
|
1347
|
+
/**
|
|
1348
|
+
* Offered models whose provider API accepts PDF/file content. Generated from
|
|
1349
|
+
* live models.dev input modalities plus dated, reviewed source corrections;
|
|
1350
|
+
* the nightly upstream check rejects drift.
|
|
1351
|
+
*/
|
|
1352
|
+
const BYOK_DOCUMENT_INPUT_MODEL_OPTIONS = MODEL_DOCUMENT_INPUT_OPTIONS;
|
|
1353
|
+
const isBYOKProviderRoleSupported = ({ provider, role }) => role !== "pdf" || BYOK_DOCUMENT_INPUT_MODEL_OPTIONS[provider].length > 0;
|
|
1354
|
+
const isBYOKModelRoleSupported = ({ provider, modelId, role }) => {
|
|
1355
|
+
if (role !== "pdf") return true;
|
|
1356
|
+
return BYOK_DOCUMENT_INPUT_MODEL_OPTIONS[provider].includes(modelId);
|
|
1357
|
+
};
|
|
1358
|
+
/**
|
|
1359
|
+
* Models whose provider adapter can receive a PDF `document` content part in a
|
|
1360
|
+
* chat turn without throwing. This is a narrower, runtime question than the
|
|
1361
|
+
* pdf ROLE (`BYOK_DOCUMENT_INPUT_MODEL_OPTIONS`, which curates model selection
|
|
1362
|
+
* for PDF-processing flows): it only asks "will the chat stream survive this
|
|
1363
|
+
* attachment." The Mistral text adapter maps PDF `document` parts to
|
|
1364
|
+
* `document_url`, so its
|
|
1365
|
+
* vision models accept PDF attachments even though Mistral is deliberately not
|
|
1366
|
+
* offered as a pdf-role provider. Mistral's `document_url` takes PDF but NOT
|
|
1367
|
+
* textual documents (docx/txt/csv/md), so those still gate on
|
|
1368
|
+
* `BYOK_DOCUMENT_INPUT_MODEL_OPTIONS` (which excludes Mistral). Superset
|
|
1369
|
+
* invariant: every pdf-role document model also accepts a PDF chat attachment.
|
|
1370
|
+
*/
|
|
1371
|
+
const CHAT_PDF_ATTACHMENT_MODEL_OPTIONS = {
|
|
1372
|
+
...BYOK_DOCUMENT_INPUT_MODEL_OPTIONS,
|
|
1373
|
+
mistral: [
|
|
1374
|
+
"mistral-medium-latest",
|
|
1375
|
+
"mistral-small-latest",
|
|
1376
|
+
"pixtral-large-latest"
|
|
1377
|
+
]
|
|
1378
|
+
};
|
|
1379
|
+
const isChatPdfAttachmentModelSupported = ({ provider, modelId }) => {
|
|
1380
|
+
return CHAT_PDF_ATTACHMENT_MODEL_OPTIONS[provider].includes(modelId);
|
|
1381
|
+
};
|
|
1382
|
+
/**
|
|
1383
|
+
* Whether a model id is currently offered for this provider+role: it
|
|
1384
|
+
* must be in the curated catalog for the provider AND satisfy the
|
|
1385
|
+
* role's input-modality constraint (PDF needs a document-capable
|
|
1386
|
+
* model). This is the runtime allowlist, so a model dropped by a
|
|
1387
|
+
* catalog bump stops being valid here even though it is still a
|
|
1388
|
+
* non-empty string in a stored org config.
|
|
1389
|
+
*/
|
|
1390
|
+
const isOfferedBYOKModelForRole = ({ provider, modelId, role }) => {
|
|
1391
|
+
return BYOK_MODEL_OPTIONS[provider].includes(modelId) && isBYOKModelRoleSupported({
|
|
1392
|
+
provider,
|
|
1393
|
+
modelId,
|
|
1394
|
+
role
|
|
1395
|
+
});
|
|
1396
|
+
};
|
|
1397
|
+
/**
|
|
1398
|
+
* Resolve a model id that will actually work for this provider+role,
|
|
1399
|
+
* keeping the SAME provider. Returns the caller's model unchanged when
|
|
1400
|
+
* it is still offered; otherwise falls back to the provider's per-role
|
|
1401
|
+
* default (`BYOK_DEFAULT_MODELS`). Returns `null` only when the
|
|
1402
|
+
* provider has no valid model for the role at all — the sole case
|
|
1403
|
+
* today is `mistral` + `pdf`, because the TanStack Mistral adapter
|
|
1404
|
+
* exposes no `document` input modality, so no Mistral model (not even
|
|
1405
|
+
* the default) can serve the PDF role.
|
|
1406
|
+
*
|
|
1407
|
+
* Used to auto-heal org AI configs whose pinned model was removed by a
|
|
1408
|
+
* catalog bump, so generation resolves to a supported model instead of
|
|
1409
|
+
* 400-ing (or forwarding a retired id to the provider).
|
|
1410
|
+
*/
|
|
1411
|
+
const resolveWorkingBYOKModelForRole = ({ provider, modelId, role }) => {
|
|
1412
|
+
if (isOfferedBYOKModelForRole({
|
|
1413
|
+
provider,
|
|
1414
|
+
modelId,
|
|
1415
|
+
role
|
|
1416
|
+
})) return modelId;
|
|
1417
|
+
const fallback = BYOK_DEFAULT_MODELS[provider][role];
|
|
1418
|
+
return isOfferedBYOKModelForRole({
|
|
1419
|
+
provider,
|
|
1420
|
+
modelId: fallback,
|
|
1421
|
+
role
|
|
1422
|
+
}) ? fallback : null;
|
|
1423
|
+
};
|
|
1424
|
+
/**
|
|
1425
|
+
* Anthropic models that use the adaptive-thinking request shape
|
|
1426
|
+
* (`thinking: { type: "adaptive" }`). Newer Claude models reject the
|
|
1427
|
+
* legacy budget-based form, so every Opus 4.6+/Sonnet 4.6/Fable entry
|
|
1428
|
+
* offered above must appear here or it will 400 on the reasoning role.
|
|
1429
|
+
*/
|
|
1430
|
+
const ANTHROPIC_ADAPTIVE_THINKING_MODELS = [
|
|
1431
|
+
"claude-sonnet-5",
|
|
1432
|
+
"claude-opus-5",
|
|
1433
|
+
"claude-sonnet-4-6",
|
|
1434
|
+
"claude-opus-4-6",
|
|
1435
|
+
"claude-opus-4-7",
|
|
1436
|
+
"claude-opus-4-8",
|
|
1437
|
+
"claude-fable-5",
|
|
1438
|
+
"claude-fable-5-1"
|
|
1439
|
+
];
|
|
1440
|
+
/**
|
|
1441
|
+
* Canonical reasoning-effort ladder, ordered weakest to strongest.
|
|
1442
|
+
* Union of every effort keyword the offered providers accept; no
|
|
1443
|
+
* single model accepts all of them, which is exactly why the
|
|
1444
|
+
* generated per-model `MODEL_REASONING_EFFORTS` exists.
|
|
1445
|
+
*/
|
|
1446
|
+
const REASONING_EFFORTS = [
|
|
1447
|
+
"none",
|
|
1448
|
+
"minimal",
|
|
1449
|
+
"low",
|
|
1450
|
+
"medium",
|
|
1451
|
+
"high",
|
|
1452
|
+
"xhigh",
|
|
1453
|
+
"max"
|
|
1454
|
+
];
|
|
1455
|
+
const resolvedReasoningEffortSchema = v.pipe(v.picklist(REASONING_EFFORTS), v.brand("ResolvedReasoningEffort"));
|
|
1456
|
+
/**
|
|
1457
|
+
* Per-provider model served when a user's included budget is exhausted
|
|
1458
|
+
* and no explicit selection overrides it. Falls back to each
|
|
1459
|
+
* provider's fast-role default; providers without a first-class
|
|
1460
|
+
* adapter path cannot serve the lane. Total over providers so a new
|
|
1461
|
+
* provider lands with an explicit decision.
|
|
1462
|
+
*/
|
|
1463
|
+
const FALLBACK_CHAT_MODEL_BY_PROVIDER = {
|
|
1464
|
+
google: DEFAULT_MODELS.google.fast,
|
|
1465
|
+
openrouter: "openai/gpt-5.6-luna",
|
|
1466
|
+
openai: "gpt-5.6-luna",
|
|
1467
|
+
anthropic: DEFAULT_MODELS.anthropic.fast,
|
|
1468
|
+
bedrock: DEFAULT_MODELS.bedrock.fast,
|
|
1469
|
+
mistral: DEFAULT_MODELS.mistral.fast,
|
|
1470
|
+
azure_foundry: null,
|
|
1471
|
+
openai_compatible: null,
|
|
1472
|
+
huggingface: null
|
|
1473
|
+
};
|
|
1474
|
+
/**
|
|
1475
|
+
* Provider-native IDs that are exact aliases of an offered catalog ID.
|
|
1476
|
+
* Every metadata lookup normalizes here, so instance/dev overrides cannot
|
|
1477
|
+
* bypass rates or capabilities and duplicated alias rows cannot drift apart.
|
|
1478
|
+
*/
|
|
1479
|
+
const MODEL_CATALOG_ID_ALIASES = {
|
|
1480
|
+
"gpt-5.6-sol": "gpt-5.6",
|
|
1481
|
+
"claude-opus-4.8": "claude-opus-4-8",
|
|
1482
|
+
"claude-sonnet-4.6": "claude-sonnet-4-6"
|
|
1483
|
+
};
|
|
1484
|
+
const MODEL_CATALOG_ID_ALIAS_TARGET_BY_ID = MODEL_CATALOG_ID_ALIASES;
|
|
1485
|
+
const normalizeModelCatalogId = (modelId) => MODEL_CATALOG_ID_ALIAS_TARGET_BY_ID[modelId] ?? modelId;
|
|
1486
|
+
const MODEL_TEMPERATURE_POLICY_BY_ID = MODEL_TEMPERATURE_POLICIES;
|
|
1487
|
+
/**
|
|
1488
|
+
* Whether stella should emit a `temperature` override for this model.
|
|
1489
|
+
* This is deliberately stricter than provider acceptance: deprecated
|
|
1490
|
+
* parameters that are accepted but ignored resolve to `false`. Unknown ids
|
|
1491
|
+
* also resolve to `false` (send nothing; provider default). Callers must
|
|
1492
|
+
* never index `MODEL_TEMPERATURE_POLICIES` directly with
|
|
1493
|
+
* a runtime string.
|
|
1494
|
+
*/
|
|
1495
|
+
const shouldEmitTemperature = (modelId) => MODEL_TEMPERATURE_POLICY_BY_ID[normalizeModelCatalogId(modelId)] === "emit";
|
|
1496
|
+
const MODEL_REASONING_EFFORTS_BY_ID = MODEL_REASONING_EFFORTS;
|
|
1497
|
+
/**
|
|
1498
|
+
* Declared reasoning-effort values for a model ID, or `null` when the
|
|
1499
|
+
* model has no effort control or is not catalogued (custom deployments,
|
|
1500
|
+
* env overrides). Callers must never index `MODEL_REASONING_EFFORTS`
|
|
1501
|
+
* directly with a runtime string.
|
|
1502
|
+
*/
|
|
1503
|
+
const getModelReasoningEfforts = (modelId) => MODEL_REASONING_EFFORTS_BY_ID[normalizeModelCatalogId(modelId)] ?? null;
|
|
1504
|
+
const MODEL_DEFAULT_REASONING_EFFORTS_BY_ID = MODEL_DEFAULT_REASONING_EFFORTS;
|
|
1505
|
+
/**
|
|
1506
|
+
* Concrete provider-default effort published for a model, or null when the
|
|
1507
|
+
* provider exposes no named default. Unknown ids also resolve to null.
|
|
1508
|
+
*/
|
|
1509
|
+
const getModelDefaultReasoningEffort = (modelId) => MODEL_DEFAULT_REASONING_EFFORTS_BY_ID[normalizeModelCatalogId(modelId)] ?? null;
|
|
1510
|
+
const asResolvedReasoningEffort = (effort) => v.parse(resolvedReasoningEffortSchema, effort);
|
|
1511
|
+
/**
|
|
1512
|
+
* Clamp a requested reasoning effort into the target model's declared
|
|
1513
|
+
* capability.
|
|
1514
|
+
*
|
|
1515
|
+
* - Unknown model or no effort control → `null` (send no effort at
|
|
1516
|
+
* all; the provider default is the only universally safe choice).
|
|
1517
|
+
* - Requested value supported → returned unchanged.
|
|
1518
|
+
* - Otherwise → the supported value nearest on `REASONING_EFFORTS`,
|
|
1519
|
+
* preferring the weaker side on ties, so a "none" request against a
|
|
1520
|
+
* reasoning-mandatory model degrades to its weakest tier instead of
|
|
1521
|
+
* erroring, and requests above the model's ceiling clamp down to it.
|
|
1522
|
+
*/
|
|
1523
|
+
const resolveReasoningEffort = ({ modelId, requested }) => {
|
|
1524
|
+
const efforts = getModelReasoningEfforts(modelId);
|
|
1525
|
+
const weakest = efforts?.at(0);
|
|
1526
|
+
if (efforts === null || weakest === void 0) return null;
|
|
1527
|
+
if (efforts.includes(requested)) return asResolvedReasoningEffort(requested);
|
|
1528
|
+
const requestedRank = REASONING_EFFORTS.indexOf(requested);
|
|
1529
|
+
let nearest = weakest;
|
|
1530
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
1531
|
+
for (const effort of efforts) {
|
|
1532
|
+
const distance = Math.abs(REASONING_EFFORTS.indexOf(effort) - requestedRank);
|
|
1533
|
+
if (distance < nearestDistance || distance === nearestDistance && REASONING_EFFORTS.indexOf(effort) < REASONING_EFFORTS.indexOf(nearest)) {
|
|
1534
|
+
nearest = effort;
|
|
1535
|
+
nearestDistance = distance;
|
|
1536
|
+
}
|
|
1427
1537
|
}
|
|
1538
|
+
return asResolvedReasoningEffort(nearest);
|
|
1428
1539
|
};
|
|
1429
1540
|
const MODEL_RATES_BY_ID = MODEL_RATES;
|
|
1430
1541
|
const OPENROUTER_UNDERLYING_MODEL_ID_BY_ID = Object.fromEntries(BYOK_MODEL_OPTIONS.openrouter.map((modelId) => [modelId, modelId.slice(modelId.indexOf("/") + 1)]));
|
|
@@ -1460,6 +1571,7 @@ const CONTEXT_WINDOW_TOKENS = {
|
|
|
1460
1571
|
"gemini-3.5-flash-lite": 1048576,
|
|
1461
1572
|
"gemini-3.6-flash": 1048576,
|
|
1462
1573
|
"gemini-3.7-flash": 1048576,
|
|
1574
|
+
"gemini-3.8-flash": 1048576,
|
|
1463
1575
|
"gemini-3.1-pro-preview": 1048576,
|
|
1464
1576
|
"gpt-4o-mini": 128e3,
|
|
1465
1577
|
"gpt-4o": 128e3,
|
|
@@ -1488,6 +1600,7 @@ const CONTEXT_WINDOW_TOKENS = {
|
|
|
1488
1600
|
"magistral-small-latest": 128e3,
|
|
1489
1601
|
"magistral-small": 128e3,
|
|
1490
1602
|
"pixtral-large-latest": 128e3,
|
|
1603
|
+
"google/gemini-3.8-flash": 1048576,
|
|
1491
1604
|
"google/gemini-3.7-flash": 1048576,
|
|
1492
1605
|
"google/gemini-3.6-flash": 1048576,
|
|
1493
1606
|
"google/gemini-3.5-flash-lite": 1048576,
|
|
@@ -1525,4 +1638,4 @@ const DEFAULT_CONTEXT_WINDOW_TOKENS = 128e3;
|
|
|
1525
1638
|
*/
|
|
1526
1639
|
const getContextWindowTokens = (modelId) => CONTEXT_WINDOW_TOKENS_BY_ID[normalizeModelCatalogId(modelId)] ?? 128e3;
|
|
1527
1640
|
//#endregion
|
|
1528
|
-
export { AI_PROVIDERS, ANTHROPIC_ADAPTIVE_THINKING_MODELS, BYOK_DEFAULT_MODELS, BYOK_DOCUMENT_INPUT_MODEL_OPTIONS, BYOK_MODEL_OPTIONS, CAPABILITY_OVERRIDES, CHAT_PDF_ATTACHMENT_MODEL_OPTIONS, CONTEXT_WINDOW_TOKENS, DEFAULT_CONTEXT_WINDOW_TOKENS, DEFAULT_MODELS, DOCUMENT_INPUT_OVERRIDES, FALLBACK_CHAT_MODEL_BY_PROVIDER, FIRST_PARTY_MODEL_PROVIDERS, MODEL_CATALOG_ID_ALIASES, MODEL_CATALOG_PROVIDER_KIND, MODEL_DEFAULT_REASONING_EFFORTS, MODEL_DISPLAY_METADATA, MODEL_RATES, MODEL_REASONING_EFFORTS, MODEL_ROLES, MODEL_TEMPERATURE_POLICIES, REASONING_EFFORTS, TANSTACK_AI_PROVIDERS, TEMPERATURE_POLICIES, getContextWindowTokens, getModelDefaultReasoningEffort, getModelDisplayMetadata, getModelRate, getModelReasoningEfforts, getStandardModelRate, isBYOKModelRoleSupported, isBYOKProviderRoleSupported, isChatPdfAttachmentModelSupported, normalizeModelCatalogId, resolveModelRate, resolveReasoningEffort, resolveWorkingBYOKModelForRole, shouldEmitTemperature };
|
|
1641
|
+
export { AI_PROVIDERS, ANTHROPIC_ADAPTIVE_THINKING_MODELS, BYOK_DEFAULT_MODELS, BYOK_DOCUMENT_INPUT_MODEL_OPTIONS, BYOK_MODEL_OPTIONS, CAPABILITY_OVERRIDES, CHAT_PDF_ATTACHMENT_MODEL_OPTIONS, CONTEXT_WINDOW_TOKENS, DEFAULT_CONTEXT_WINDOW_TOKENS, DEFAULT_MODELS, DOCUMENT_INPUT_OVERRIDES, FALLBACK_CHAT_MODEL_BY_PROVIDER, FIRST_PARTY_MODEL_PROVIDERS, MODELS_DEV_RATE_PROVIDER_BY_CATALOG_PROVIDER, MODELS_DEV_RATE_SOURCE_ALIASES, MODEL_CATALOG_ID_ALIASES, MODEL_CATALOG_PROVIDER_KIND, MODEL_DEFAULT_REASONING_EFFORTS, MODEL_DISPLAY_METADATA, MODEL_RATES, MODEL_RATE_UNITS_PER_USD, MODEL_REASONING_EFFORTS, MODEL_ROLES, MODEL_TEMPERATURE_POLICIES, REASONING_EFFORTS, RETAINED_MODELS_DEV_RATE_ENTRIES, TANSTACK_AI_PROVIDERS, TEMPERATURE_POLICIES, getContextWindowTokens, getModelDefaultReasoningEffort, getModelDisplayMetadata, getModelRate, getModelReasoningEfforts, getStandardModelRate, isBYOKModelRoleSupported, isBYOKProviderRoleSupported, isChatPdfAttachmentModelSupported, normalizeModelCatalogId, resolveModelRate, resolveReasoningEffort, resolveWorkingBYOKModelForRole, shouldEmitTemperature };
|