@openclaw/chutes-provider 0.0.0 → 2026.6.9

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/dist/models.js ADDED
@@ -0,0 +1,766 @@
1
+ import { isChutesModelDiscoveryTestEnvironment } from "./model-discovery-env.js";
2
+ import { asPositiveSafeInteger, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { LiveModelCatalogHttpError, clearLiveCatalogCacheForTests, getCachedLiveProviderModelRows } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
4
+ import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
5
+ import { ssrfPolicyFromHttpBaseUrlAllowedHostname } from "openclaw/plugin-sdk/ssrf-runtime";
6
+ //#region extensions/chutes/models.ts
7
+ /**
8
+ * Chutes model catalog, static model definitions, and dynamic model discovery.
9
+ */
10
+ const log = createSubsystemLogger("chutes-models");
11
+ /** Base URL for Chutes OpenAI-compatible inference. */
12
+ const CHUTES_BASE_URL = "https://llm.chutes.ai/v1";
13
+ /** Default Chutes model id used for onboarding. */
14
+ const CHUTES_DEFAULT_MODEL_ID = "zai-org/GLM-4.7-TEE";
15
+ /** Default Chutes model ref used for onboarding. */
16
+ const CHUTES_DEFAULT_MODEL_REF = `chutes/${CHUTES_DEFAULT_MODEL_ID}`;
17
+ const CHUTES_DEFAULT_CONTEXT_WINDOW = 128e3;
18
+ const CHUTES_DEFAULT_MAX_TOKENS = 4096;
19
+ /** Bundled fallback Chutes model catalog. */
20
+ const CHUTES_MODEL_CATALOG = [
21
+ {
22
+ id: "Qwen/Qwen3-32B",
23
+ name: "Qwen/Qwen3-32B",
24
+ reasoning: true,
25
+ input: ["text"],
26
+ contextWindow: 40960,
27
+ maxTokens: 40960,
28
+ cost: {
29
+ input: .08,
30
+ output: .24,
31
+ cacheRead: 0,
32
+ cacheWrite: 0
33
+ }
34
+ },
35
+ {
36
+ id: "unsloth/Mistral-Nemo-Instruct-2407",
37
+ name: "unsloth/Mistral-Nemo-Instruct-2407",
38
+ reasoning: false,
39
+ input: ["text"],
40
+ contextWindow: 131072,
41
+ maxTokens: 131072,
42
+ cost: {
43
+ input: .02,
44
+ output: .04,
45
+ cacheRead: 0,
46
+ cacheWrite: 0
47
+ }
48
+ },
49
+ {
50
+ id: "deepseek-ai/DeepSeek-V3-0324-TEE",
51
+ name: "deepseek-ai/DeepSeek-V3-0324-TEE",
52
+ reasoning: true,
53
+ input: ["text"],
54
+ contextWindow: 163840,
55
+ maxTokens: 65536,
56
+ cost: {
57
+ input: .25,
58
+ output: 1,
59
+ cacheRead: 0,
60
+ cacheWrite: 0
61
+ }
62
+ },
63
+ {
64
+ id: "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE",
65
+ name: "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE",
66
+ reasoning: true,
67
+ input: ["text"],
68
+ contextWindow: 262144,
69
+ maxTokens: 65536,
70
+ cost: {
71
+ input: .08,
72
+ output: .55,
73
+ cacheRead: 0,
74
+ cacheWrite: 0
75
+ }
76
+ },
77
+ {
78
+ id: "openai/gpt-oss-120b-TEE",
79
+ name: "openai/gpt-oss-120b-TEE",
80
+ reasoning: true,
81
+ input: ["text"],
82
+ contextWindow: 131072,
83
+ maxTokens: 65536,
84
+ cost: {
85
+ input: .05,
86
+ output: .45,
87
+ cacheRead: 0,
88
+ cacheWrite: 0
89
+ }
90
+ },
91
+ {
92
+ id: "chutesai/Mistral-Small-3.1-24B-Instruct-2503",
93
+ name: "chutesai/Mistral-Small-3.1-24B-Instruct-2503",
94
+ reasoning: false,
95
+ input: ["text", "image"],
96
+ contextWindow: 131072,
97
+ maxTokens: 131072,
98
+ cost: {
99
+ input: .03,
100
+ output: .11,
101
+ cacheRead: 0,
102
+ cacheWrite: 0
103
+ }
104
+ },
105
+ {
106
+ id: "deepseek-ai/DeepSeek-V3.2-TEE",
107
+ name: "deepseek-ai/DeepSeek-V3.2-TEE",
108
+ reasoning: true,
109
+ input: ["text"],
110
+ contextWindow: 131072,
111
+ maxTokens: 65536,
112
+ cost: {
113
+ input: .28,
114
+ output: .42,
115
+ cacheRead: 0,
116
+ cacheWrite: 0
117
+ }
118
+ },
119
+ {
120
+ id: "zai-org/GLM-4.7-TEE",
121
+ name: "zai-org/GLM-4.7-TEE",
122
+ reasoning: true,
123
+ input: ["text"],
124
+ contextWindow: 202752,
125
+ maxTokens: 65535,
126
+ cost: {
127
+ input: .4,
128
+ output: 2,
129
+ cacheRead: 0,
130
+ cacheWrite: 0
131
+ }
132
+ },
133
+ {
134
+ id: "moonshotai/Kimi-K2.5-TEE",
135
+ name: "moonshotai/Kimi-K2.5-TEE",
136
+ reasoning: true,
137
+ input: ["text", "image"],
138
+ contextWindow: 262144,
139
+ maxTokens: 65535,
140
+ cost: {
141
+ input: .45,
142
+ output: 2.2,
143
+ cacheRead: 0,
144
+ cacheWrite: 0
145
+ }
146
+ },
147
+ {
148
+ id: "unsloth/gemma-3-27b-it",
149
+ name: "unsloth/gemma-3-27b-it",
150
+ reasoning: false,
151
+ input: ["text", "image"],
152
+ contextWindow: 128e3,
153
+ maxTokens: 65536,
154
+ cost: {
155
+ input: .04,
156
+ output: .15,
157
+ cacheRead: 0,
158
+ cacheWrite: 0
159
+ }
160
+ },
161
+ {
162
+ id: "XiaomiMiMo/MiMo-V2-Flash-TEE",
163
+ name: "XiaomiMiMo/MiMo-V2-Flash-TEE",
164
+ reasoning: true,
165
+ input: ["text"],
166
+ contextWindow: 262144,
167
+ maxTokens: 65536,
168
+ cost: {
169
+ input: .09,
170
+ output: .29,
171
+ cacheRead: 0,
172
+ cacheWrite: 0
173
+ }
174
+ },
175
+ {
176
+ id: "chutesai/Mistral-Small-3.2-24B-Instruct-2506",
177
+ name: "chutesai/Mistral-Small-3.2-24B-Instruct-2506",
178
+ reasoning: false,
179
+ input: ["text", "image"],
180
+ contextWindow: 131072,
181
+ maxTokens: 131072,
182
+ cost: {
183
+ input: .06,
184
+ output: .18,
185
+ cacheRead: 0,
186
+ cacheWrite: 0
187
+ }
188
+ },
189
+ {
190
+ id: "deepseek-ai/DeepSeek-R1-0528-TEE",
191
+ name: "deepseek-ai/DeepSeek-R1-0528-TEE",
192
+ reasoning: true,
193
+ input: ["text"],
194
+ contextWindow: 163840,
195
+ maxTokens: 65536,
196
+ cost: {
197
+ input: .45,
198
+ output: 2.15,
199
+ cacheRead: 0,
200
+ cacheWrite: 0
201
+ }
202
+ },
203
+ {
204
+ id: "zai-org/GLM-5-TEE",
205
+ name: "zai-org/GLM-5-TEE",
206
+ reasoning: true,
207
+ input: ["text"],
208
+ contextWindow: 202752,
209
+ maxTokens: 65535,
210
+ cost: {
211
+ input: .95,
212
+ output: 3.15,
213
+ cacheRead: 0,
214
+ cacheWrite: 0
215
+ }
216
+ },
217
+ {
218
+ id: "deepseek-ai/DeepSeek-V3.1-TEE",
219
+ name: "deepseek-ai/DeepSeek-V3.1-TEE",
220
+ reasoning: true,
221
+ input: ["text"],
222
+ contextWindow: 163840,
223
+ maxTokens: 65536,
224
+ cost: {
225
+ input: .2,
226
+ output: .8,
227
+ cacheRead: 0,
228
+ cacheWrite: 0
229
+ }
230
+ },
231
+ {
232
+ id: "deepseek-ai/DeepSeek-V3.1-Terminus-TEE",
233
+ name: "deepseek-ai/DeepSeek-V3.1-Terminus-TEE",
234
+ reasoning: true,
235
+ input: ["text"],
236
+ contextWindow: 163840,
237
+ maxTokens: 65536,
238
+ cost: {
239
+ input: .23,
240
+ output: .9,
241
+ cacheRead: 0,
242
+ cacheWrite: 0
243
+ }
244
+ },
245
+ {
246
+ id: "unsloth/gemma-3-4b-it",
247
+ name: "unsloth/gemma-3-4b-it",
248
+ reasoning: false,
249
+ input: ["text", "image"],
250
+ contextWindow: 96e3,
251
+ maxTokens: 96e3,
252
+ cost: {
253
+ input: .01,
254
+ output: .03,
255
+ cacheRead: 0,
256
+ cacheWrite: 0
257
+ }
258
+ },
259
+ {
260
+ id: "MiniMaxAI/MiniMax-M2.5-TEE",
261
+ name: "MiniMaxAI/MiniMax-M2.5-TEE",
262
+ reasoning: true,
263
+ input: ["text"],
264
+ contextWindow: 196608,
265
+ maxTokens: 65536,
266
+ cost: {
267
+ input: .3,
268
+ output: 1.1,
269
+ cacheRead: 0,
270
+ cacheWrite: 0
271
+ }
272
+ },
273
+ {
274
+ id: "tngtech/DeepSeek-TNG-R1T2-Chimera",
275
+ name: "tngtech/DeepSeek-TNG-R1T2-Chimera",
276
+ reasoning: true,
277
+ input: ["text"],
278
+ contextWindow: 163840,
279
+ maxTokens: 163840,
280
+ cost: {
281
+ input: .25,
282
+ output: .85,
283
+ cacheRead: 0,
284
+ cacheWrite: 0
285
+ }
286
+ },
287
+ {
288
+ id: "Qwen/Qwen3-Coder-Next-TEE",
289
+ name: "Qwen/Qwen3-Coder-Next-TEE",
290
+ reasoning: true,
291
+ input: ["text"],
292
+ contextWindow: 262144,
293
+ maxTokens: 65536,
294
+ cost: {
295
+ input: .12,
296
+ output: .75,
297
+ cacheRead: 0,
298
+ cacheWrite: 0
299
+ }
300
+ },
301
+ {
302
+ id: "NousResearch/Hermes-4-405B-FP8-TEE",
303
+ name: "NousResearch/Hermes-4-405B-FP8-TEE",
304
+ reasoning: true,
305
+ input: ["text"],
306
+ contextWindow: 131072,
307
+ maxTokens: 65536,
308
+ cost: {
309
+ input: .3,
310
+ output: 1.2,
311
+ cacheRead: 0,
312
+ cacheWrite: 0
313
+ }
314
+ },
315
+ {
316
+ id: "deepseek-ai/DeepSeek-V3",
317
+ name: "deepseek-ai/DeepSeek-V3",
318
+ reasoning: false,
319
+ input: ["text"],
320
+ contextWindow: 163840,
321
+ maxTokens: 163840,
322
+ cost: {
323
+ input: .3,
324
+ output: 1.2,
325
+ cacheRead: 0,
326
+ cacheWrite: 0
327
+ }
328
+ },
329
+ {
330
+ id: "openai/gpt-oss-20b",
331
+ name: "openai/gpt-oss-20b",
332
+ reasoning: true,
333
+ input: ["text"],
334
+ contextWindow: 131072,
335
+ maxTokens: 131072,
336
+ cost: {
337
+ input: .04,
338
+ output: .15,
339
+ cacheRead: 0,
340
+ cacheWrite: 0
341
+ }
342
+ },
343
+ {
344
+ id: "unsloth/Llama-3.2-3B-Instruct",
345
+ name: "unsloth/Llama-3.2-3B-Instruct",
346
+ reasoning: false,
347
+ input: ["text"],
348
+ contextWindow: 128e3,
349
+ maxTokens: 4096,
350
+ cost: {
351
+ input: .01,
352
+ output: .01,
353
+ cacheRead: 0,
354
+ cacheWrite: 0
355
+ }
356
+ },
357
+ {
358
+ id: "unsloth/Mistral-Small-24B-Instruct-2501",
359
+ name: "unsloth/Mistral-Small-24B-Instruct-2501",
360
+ reasoning: false,
361
+ input: ["text", "image"],
362
+ contextWindow: 32768,
363
+ maxTokens: 32768,
364
+ cost: {
365
+ input: .07,
366
+ output: .3,
367
+ cacheRead: 0,
368
+ cacheWrite: 0
369
+ }
370
+ },
371
+ {
372
+ id: "zai-org/GLM-4.7-FP8",
373
+ name: "zai-org/GLM-4.7-FP8",
374
+ reasoning: true,
375
+ input: ["text"],
376
+ contextWindow: 202752,
377
+ maxTokens: 65535,
378
+ cost: {
379
+ input: .3,
380
+ output: 1.2,
381
+ cacheRead: 0,
382
+ cacheWrite: 0
383
+ }
384
+ },
385
+ {
386
+ id: "zai-org/GLM-4.6-TEE",
387
+ name: "zai-org/GLM-4.6-TEE",
388
+ reasoning: true,
389
+ input: ["text"],
390
+ contextWindow: 202752,
391
+ maxTokens: 65536,
392
+ cost: {
393
+ input: .4,
394
+ output: 1.7,
395
+ cacheRead: 0,
396
+ cacheWrite: 0
397
+ }
398
+ },
399
+ {
400
+ id: "Qwen/Qwen3.5-397B-A17B-TEE",
401
+ name: "Qwen/Qwen3.5-397B-A17B-TEE",
402
+ reasoning: true,
403
+ input: ["text", "image"],
404
+ contextWindow: 262144,
405
+ maxTokens: 65536,
406
+ cost: {
407
+ input: .55,
408
+ output: 3.5,
409
+ cacheRead: 0,
410
+ cacheWrite: 0
411
+ }
412
+ },
413
+ {
414
+ id: "Qwen/Qwen2.5-72B-Instruct",
415
+ name: "Qwen/Qwen2.5-72B-Instruct",
416
+ reasoning: false,
417
+ input: ["text"],
418
+ contextWindow: 32768,
419
+ maxTokens: 32768,
420
+ cost: {
421
+ input: .3,
422
+ output: 1.2,
423
+ cacheRead: 0,
424
+ cacheWrite: 0
425
+ }
426
+ },
427
+ {
428
+ id: "NousResearch/DeepHermes-3-Mistral-24B-Preview",
429
+ name: "NousResearch/DeepHermes-3-Mistral-24B-Preview",
430
+ reasoning: false,
431
+ input: ["text"],
432
+ contextWindow: 32768,
433
+ maxTokens: 32768,
434
+ cost: {
435
+ input: .02,
436
+ output: .1,
437
+ cacheRead: 0,
438
+ cacheWrite: 0
439
+ }
440
+ },
441
+ {
442
+ id: "Qwen/Qwen3-Next-80B-A3B-Instruct",
443
+ name: "Qwen/Qwen3-Next-80B-A3B-Instruct",
444
+ reasoning: false,
445
+ input: ["text"],
446
+ contextWindow: 262144,
447
+ maxTokens: 262144,
448
+ cost: {
449
+ input: .1,
450
+ output: .8,
451
+ cacheRead: 0,
452
+ cacheWrite: 0
453
+ }
454
+ },
455
+ {
456
+ id: "zai-org/GLM-4.6-FP8",
457
+ name: "zai-org/GLM-4.6-FP8",
458
+ reasoning: true,
459
+ input: ["text"],
460
+ contextWindow: 202752,
461
+ maxTokens: 65535,
462
+ cost: {
463
+ input: .3,
464
+ output: 1.2,
465
+ cacheRead: 0,
466
+ cacheWrite: 0
467
+ }
468
+ },
469
+ {
470
+ id: "Qwen/Qwen3-235B-A22B-Thinking-2507",
471
+ name: "Qwen/Qwen3-235B-A22B-Thinking-2507",
472
+ reasoning: true,
473
+ input: ["text"],
474
+ contextWindow: 262144,
475
+ maxTokens: 262144,
476
+ cost: {
477
+ input: .11,
478
+ output: .6,
479
+ cacheRead: 0,
480
+ cacheWrite: 0
481
+ }
482
+ },
483
+ {
484
+ id: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
485
+ name: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
486
+ reasoning: true,
487
+ input: ["text"],
488
+ contextWindow: 131072,
489
+ maxTokens: 131072,
490
+ cost: {
491
+ input: .03,
492
+ output: .11,
493
+ cacheRead: 0,
494
+ cacheWrite: 0
495
+ }
496
+ },
497
+ {
498
+ id: "tngtech/R1T2-Chimera-Speed",
499
+ name: "tngtech/R1T2-Chimera-Speed",
500
+ reasoning: true,
501
+ input: ["text"],
502
+ contextWindow: 131072,
503
+ maxTokens: 65536,
504
+ cost: {
505
+ input: .22,
506
+ output: .6,
507
+ cacheRead: 0,
508
+ cacheWrite: 0
509
+ }
510
+ },
511
+ {
512
+ id: "zai-org/GLM-4.6V",
513
+ name: "zai-org/GLM-4.6V",
514
+ reasoning: true,
515
+ input: ["text", "image"],
516
+ contextWindow: 131072,
517
+ maxTokens: 65536,
518
+ cost: {
519
+ input: .3,
520
+ output: .9,
521
+ cacheRead: 0,
522
+ cacheWrite: 0
523
+ }
524
+ },
525
+ {
526
+ id: "Qwen/Qwen2.5-VL-32B-Instruct",
527
+ name: "Qwen/Qwen2.5-VL-32B-Instruct",
528
+ reasoning: false,
529
+ input: ["text", "image"],
530
+ mediaInput: { image: {
531
+ maxPixels: 12845056,
532
+ preferredSidePx: 2048,
533
+ tokenMode: "provider"
534
+ } },
535
+ contextWindow: 16384,
536
+ maxTokens: 16384,
537
+ cost: {
538
+ input: .05,
539
+ output: .22,
540
+ cacheRead: 0,
541
+ cacheWrite: 0
542
+ }
543
+ },
544
+ {
545
+ id: "Qwen/Qwen3-VL-235B-A22B-Instruct",
546
+ name: "Qwen/Qwen3-VL-235B-A22B-Instruct",
547
+ reasoning: false,
548
+ input: ["text", "image"],
549
+ mediaInput: { image: {
550
+ maxPixels: 12845056,
551
+ preferredSidePx: 2048,
552
+ tokenMode: "provider"
553
+ } },
554
+ contextWindow: 262144,
555
+ maxTokens: 262144,
556
+ cost: {
557
+ input: .3,
558
+ output: 1.2,
559
+ cacheRead: 0,
560
+ cacheWrite: 0
561
+ }
562
+ },
563
+ {
564
+ id: "Qwen/Qwen3-14B",
565
+ name: "Qwen/Qwen3-14B",
566
+ reasoning: true,
567
+ input: ["text"],
568
+ contextWindow: 40960,
569
+ maxTokens: 40960,
570
+ cost: {
571
+ input: .05,
572
+ output: .22,
573
+ cacheRead: 0,
574
+ cacheWrite: 0
575
+ }
576
+ },
577
+ {
578
+ id: "Qwen/Qwen2.5-Coder-32B-Instruct",
579
+ name: "Qwen/Qwen2.5-Coder-32B-Instruct",
580
+ reasoning: false,
581
+ input: ["text"],
582
+ contextWindow: 32768,
583
+ maxTokens: 32768,
584
+ cost: {
585
+ input: .03,
586
+ output: .11,
587
+ cacheRead: 0,
588
+ cacheWrite: 0
589
+ }
590
+ },
591
+ {
592
+ id: "Qwen/Qwen3-30B-A3B",
593
+ name: "Qwen/Qwen3-30B-A3B",
594
+ reasoning: true,
595
+ input: ["text"],
596
+ contextWindow: 40960,
597
+ maxTokens: 40960,
598
+ cost: {
599
+ input: .06,
600
+ output: .22,
601
+ cacheRead: 0,
602
+ cacheWrite: 0
603
+ }
604
+ },
605
+ {
606
+ id: "unsloth/gemma-3-12b-it",
607
+ name: "unsloth/gemma-3-12b-it",
608
+ reasoning: false,
609
+ input: ["text", "image"],
610
+ contextWindow: 131072,
611
+ maxTokens: 131072,
612
+ cost: {
613
+ input: .03,
614
+ output: .1,
615
+ cacheRead: 0,
616
+ cacheWrite: 0
617
+ }
618
+ },
619
+ {
620
+ id: "unsloth/Llama-3.2-1B-Instruct",
621
+ name: "unsloth/Llama-3.2-1B-Instruct",
622
+ reasoning: false,
623
+ input: ["text"],
624
+ contextWindow: 128e3,
625
+ maxTokens: 4096,
626
+ cost: {
627
+ input: .01,
628
+ output: .01,
629
+ cacheRead: 0,
630
+ cacheWrite: 0
631
+ }
632
+ },
633
+ {
634
+ id: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16-TEE",
635
+ name: "nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16-TEE",
636
+ reasoning: true,
637
+ input: ["text"],
638
+ contextWindow: 128e3,
639
+ maxTokens: 4096,
640
+ cost: {
641
+ input: .3,
642
+ output: 1.2,
643
+ cacheRead: 0,
644
+ cacheWrite: 0
645
+ }
646
+ },
647
+ {
648
+ id: "NousResearch/Hermes-4-14B",
649
+ name: "NousResearch/Hermes-4-14B",
650
+ reasoning: true,
651
+ input: ["text"],
652
+ contextWindow: 40960,
653
+ maxTokens: 40960,
654
+ cost: {
655
+ input: .01,
656
+ output: .05,
657
+ cacheRead: 0,
658
+ cacheWrite: 0
659
+ }
660
+ },
661
+ {
662
+ id: "Qwen/Qwen3Guard-Gen-0.6B",
663
+ name: "Qwen/Qwen3Guard-Gen-0.6B",
664
+ reasoning: false,
665
+ input: ["text"],
666
+ contextWindow: 128e3,
667
+ maxTokens: 4096,
668
+ cost: {
669
+ input: .01,
670
+ output: .01,
671
+ cacheRead: 0,
672
+ cacheWrite: 0
673
+ }
674
+ },
675
+ {
676
+ id: "rednote-hilab/dots.ocr",
677
+ name: "rednote-hilab/dots.ocr",
678
+ reasoning: false,
679
+ input: ["text", "image"],
680
+ contextWindow: 131072,
681
+ maxTokens: 131072,
682
+ cost: {
683
+ input: .01,
684
+ output: .01,
685
+ cacheRead: 0,
686
+ cacheWrite: 0
687
+ }
688
+ }
689
+ ];
690
+ /** Adds Chutes provider compat metadata to one model catalog entry. */
691
+ function buildChutesModelDefinition(model) {
692
+ return {
693
+ ...model,
694
+ compat: { supportsUsageInStreaming: false }
695
+ };
696
+ }
697
+ const CACHE_TTL = 300 * 1e3;
698
+ /** Clears the dynamic Chutes model discovery cache for tests. */
699
+ function clearChutesModelCacheForTests() {
700
+ clearLiveCatalogCacheForTests();
701
+ }
702
+ async function fetchChutesModelRows(accessToken) {
703
+ return await getCachedLiveProviderModelRows({
704
+ providerId: "chutes",
705
+ endpoint: `${CHUTES_BASE_URL}/models`,
706
+ discoveryApiKey: accessToken,
707
+ timeoutMs: 1e4,
708
+ ttlMs: CACHE_TTL,
709
+ buildRequestHeaders: ({ discoveryApiKey }) => ({
710
+ Accept: "application/json",
711
+ ...discoveryApiKey ? { Authorization: `Bearer ${discoveryApiKey}` } : {}
712
+ }),
713
+ policy: ssrfPolicyFromHttpBaseUrlAllowedHostname(CHUTES_BASE_URL),
714
+ auditContext: "chutes-model-discovery"
715
+ });
716
+ }
717
+ /** Discovers Chutes models dynamically, falling back to the bundled static catalog. */
718
+ async function discoverChutesModels(accessToken) {
719
+ const trimmedKey = normalizeOptionalString(accessToken) ?? "";
720
+ if (isChutesModelDiscoveryTestEnvironment()) return CHUTES_MODEL_CATALOG.map(buildChutesModelDefinition);
721
+ const staticCatalog = () => CHUTES_MODEL_CATALOG.map(buildChutesModelDefinition);
722
+ try {
723
+ const data = await fetchChutesModelRows(trimmedKey || void 0);
724
+ if (data.length === 0) {
725
+ log.warn("No models in response, using static catalog");
726
+ return staticCatalog();
727
+ }
728
+ const seen = /* @__PURE__ */ new Set();
729
+ const models = [];
730
+ for (const entry of data) {
731
+ const id = normalizeOptionalString(entry?.id) ?? "";
732
+ if (!id || seen.has(id)) continue;
733
+ seen.add(id);
734
+ const lowerId = normalizeLowercaseStringOrEmpty(id);
735
+ const isReasoning = entry.supported_features?.includes("reasoning") || lowerId.includes("r1") || lowerId.includes("thinking") || lowerId.includes("reason") || lowerId.includes("tee");
736
+ const input = (entry.input_modalities || ["text"]).filter((i) => i === "text" || i === "image");
737
+ models.push({
738
+ id,
739
+ name: id,
740
+ reasoning: isReasoning,
741
+ input,
742
+ cost: {
743
+ input: entry.pricing?.prompt || 0,
744
+ output: entry.pricing?.completion || 0,
745
+ cacheRead: 0,
746
+ cacheWrite: 0
747
+ },
748
+ contextWindow: asPositiveSafeInteger(entry.context_length) ?? CHUTES_DEFAULT_CONTEXT_WINDOW,
749
+ maxTokens: asPositiveSafeInteger(entry.max_output_length) ?? CHUTES_DEFAULT_MAX_TOKENS,
750
+ compat: { supportsUsageInStreaming: false }
751
+ });
752
+ }
753
+ if (models.length === 0) return staticCatalog();
754
+ return models;
755
+ } catch (error) {
756
+ if (error instanceof LiveModelCatalogHttpError && error.status === 401 && trimmedKey) return await discoverChutesModels(void 0);
757
+ if (error instanceof LiveModelCatalogHttpError && error.status !== 401 && error.status !== 503) {
758
+ log.warn(`GET /v1/models failed: HTTP ${error.status}, using static catalog`);
759
+ return staticCatalog();
760
+ }
761
+ log.warn(`Discovery failed: ${String(error)}, using static catalog`);
762
+ return staticCatalog();
763
+ }
764
+ }
765
+ //#endregion
766
+ export { CHUTES_BASE_URL, CHUTES_DEFAULT_MODEL_ID, CHUTES_DEFAULT_MODEL_REF, CHUTES_MODEL_CATALOG, buildChutesModelDefinition, clearChutesModelCacheForTests, discoverChutesModels };