@oh-my-pi/pi-catalog 17.1.5 → 17.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/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [17.1.7] - 2026-07-27
6
+
7
+ ### Added
8
+
9
+ - Added support for moonshotai/Kimi-K3 and kimi-k3-fast models
10
+ - Added umans-kimi-k3 prerelease model configuration
11
+
12
+ ### Changed
13
+
14
+ - Updated pricing and token limits for selected models
15
+
16
+ ## [17.1.6] - 2026-07-27
17
+
18
+ ### Added
19
+
20
+ - Added SiliconFlow providers (`siliconflow`, `siliconflow-cn`) with dynamic-only OpenAI-compatible model discovery: no bundled catalog — the model list is fetched live from each region's `/v1/models` endpoint, with non-chat entries (embedding, reranker, image, audio, video) filtered out. Discovery hydrates pricing, context/output limits, and reasoning metadata from the provider's models.dev catalog at runtime (with bundled upstream references as a reasoning-only fallback for ids models.dev has not indexed), so reasoning models keep thinking enabled and sessions compact against real context windows. `SILICONFLOW_API_KEY` / `SILICONFLOW_CN_API_KEY` environment variables are wired into `getEnvApiKey`.
21
+
5
22
  ## [17.1.5] - 2026-07-27
6
23
 
7
24
  ### Fixed
@@ -323,6 +323,18 @@ export declare const CATALOG_PROVIDERS: readonly [{
323
323
  readonly catalogDiscovery: {
324
324
  readonly label: "Sakana AI";
325
325
  };
326
+ }, {
327
+ readonly id: "siliconflow";
328
+ readonly defaultModel: "zai-org/GLM-5.1";
329
+ readonly envVars: readonly ["SILICONFLOW_API_KEY"];
330
+ readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
331
+ readonly dynamicModelsAuthoritative: true;
332
+ }, {
333
+ readonly id: "siliconflow-cn";
334
+ readonly defaultModel: "deepseek-ai/DeepSeek-V4-Pro";
335
+ readonly envVars: readonly ["SILICONFLOW_CN_API_KEY"];
336
+ readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
337
+ readonly dynamicModelsAuthoritative: true;
326
338
  }, {
327
339
  readonly id: "synthetic";
328
340
  readonly defaultModel: "hf:zai-org/GLM-5.1";
@@ -166,6 +166,14 @@ export interface DeepSeekModelManagerConfig {
166
166
  fetch?: FetchImpl;
167
167
  }
168
168
  export declare function deepseekModelManagerOptions(config?: DeepSeekModelManagerConfig): ModelManagerOptions<"openai-completions">;
169
+ export interface SiliconFlowModelManagerConfig {
170
+ apiKey?: string;
171
+ baseUrl?: string;
172
+ fetch?: FetchImpl;
173
+ }
174
+ export declare function isLikelySiliconFlowChatModelId(id: string): boolean;
175
+ export declare function siliconflowModelManagerOptions(config?: SiliconFlowModelManagerConfig): ModelManagerOptions<"openai-completions">;
176
+ export declare function siliconflowCnModelManagerOptions(config?: SiliconFlowModelManagerConfig): ModelManagerOptions<"openai-completions">;
169
177
  export interface ZhipuCodingPlanModelManagerConfig {
170
178
  apiKey?: string;
171
179
  baseUrl?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-catalog",
4
- "version": "17.1.5",
4
+ "version": "17.1.7",
5
5
  "description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -34,12 +34,12 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@bufbuild/protobuf": "^2.12.1",
37
- "@oh-my-pi/pi-utils": "17.1.5",
37
+ "@oh-my-pi/pi-utils": "17.1.7",
38
38
  "arktype": "2.2.3",
39
39
  "zod": "^4"
40
40
  },
41
41
  "devDependencies": {
42
- "@oh-my-pi/pi-ai": "17.1.5",
42
+ "@oh-my-pi/pi-ai": "17.1.7",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
package/src/models.json CHANGED
@@ -13155,6 +13155,27 @@
13155
13155
  "supportsComputerUse": false,
13156
13156
  "supportsComputerUseConfig": false
13157
13157
  },
13158
+ "moonshotai/Kimi-K3": {
13159
+ "id": "moonshotai/Kimi-K3",
13160
+ "name": "Kimi K3",
13161
+ "api": "openai-completions",
13162
+ "provider": "baseten",
13163
+ "baseUrl": "https://inference.baseten.co/v1",
13164
+ "reasoning": false,
13165
+ "input": [
13166
+ "text",
13167
+ "image"
13168
+ ],
13169
+ "cost": {
13170
+ "input": 3,
13171
+ "output": 15,
13172
+ "cacheRead": 0.3,
13173
+ "cacheWrite": 0
13174
+ },
13175
+ "contextWindow": 1048576,
13176
+ "maxTokens": 1048576,
13177
+ "supportsComputerUse": false
13178
+ },
13158
13179
  "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B": {
13159
13180
  "id": "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
13160
13181
  "name": "Nemotron Ultra",
@@ -17111,6 +17132,40 @@
17111
17132
  "supportsComputerUse": false,
17112
17133
  "supportsComputerUseConfig": false
17113
17134
  },
17135
+ "kimi-k3": {
17136
+ "id": "kimi-k3",
17137
+ "name": "Kimi K3",
17138
+ "api": "openai-completions",
17139
+ "provider": "fireworks",
17140
+ "baseUrl": "https://api.fireworks.ai/inference/v1",
17141
+ "reasoning": true,
17142
+ "input": [
17143
+ "text",
17144
+ "image"
17145
+ ],
17146
+ "cost": {
17147
+ "input": 3,
17148
+ "output": 15,
17149
+ "cacheRead": 0.3,
17150
+ "cacheWrite": 0
17151
+ },
17152
+ "contextWindow": 1048576,
17153
+ "maxTokens": 131072,
17154
+ "thinking": {
17155
+ "mode": "effort",
17156
+ "efforts": [
17157
+ "low",
17158
+ "high",
17159
+ "max"
17160
+ ],
17161
+ "defaultLevel": "max",
17162
+ "effortMap": {
17163
+ "max": "max"
17164
+ },
17165
+ "requiresEffort": true
17166
+ },
17167
+ "supportsComputerUse": false
17168
+ },
17114
17169
  "minimax-m2.5": {
17115
17170
  "id": "minimax-m2.5",
17116
17171
  "name": "MiniMax-M2.5",
@@ -27541,7 +27596,8 @@
27541
27596
  },
27542
27597
  "contextWindow": null,
27543
27598
  "maxTokens": null,
27544
- "supportsComputerUse": false
27599
+ "supportsComputerUse": false,
27600
+ "supportsComputerUseConfig": false
27545
27601
  },
27546
27602
  "liquid/lfm-2-24b-a2b": {
27547
27603
  "id": "liquid/lfm-2-24b-a2b",
@@ -30167,7 +30223,8 @@
30167
30223
  },
30168
30224
  "contextWindow": null,
30169
30225
  "maxTokens": null,
30170
- "supportsComputerUse": false
30226
+ "supportsComputerUse": false,
30227
+ "supportsComputerUseConfig": false
30171
30228
  },
30172
30229
  "openai/gpt-4o:extended": {
30173
30230
  "id": "openai/gpt-4o:extended",
@@ -64047,6 +64104,38 @@
64047
64104
  ]
64048
64105
  }
64049
64106
  },
64107
+ "kimi-k3": {
64108
+ "id": "kimi-k3",
64109
+ "name": "Kimi K3",
64110
+ "api": "ollama-chat",
64111
+ "provider": "ollama-cloud",
64112
+ "baseUrl": "https://ollama.com",
64113
+ "reasoning": true,
64114
+ "thinking": {
64115
+ "mode": "effort",
64116
+ "efforts": [
64117
+ "low",
64118
+ "high",
64119
+ "max"
64120
+ ],
64121
+ "defaultLevel": "max",
64122
+ "requiresEffort": true
64123
+ },
64124
+ "input": [
64125
+ "text",
64126
+ "image"
64127
+ ],
64128
+ "cost": {
64129
+ "input": 3,
64130
+ "output": 15,
64131
+ "cacheRead": 0.3,
64132
+ "cacheWrite": 0
64133
+ },
64134
+ "contextWindow": 1048576,
64135
+ "maxTokens": 8192,
64136
+ "omitMaxOutputTokens": true,
64137
+ "supportsComputerUse": false
64138
+ },
64050
64139
  "minimax-m2": {
64051
64140
  "id": "minimax-m2",
64052
64141
  "name": "minimax-m2",
@@ -68713,6 +68802,39 @@
68713
68802
  ]
68714
68803
  }
68715
68804
  },
68805
+ "kimi-k3": {
68806
+ "id": "kimi-k3",
68807
+ "name": "Kimi K3",
68808
+ "api": "openai-completions",
68809
+ "provider": "opencode-zen",
68810
+ "baseUrl": "https://opencode.ai/zen/v1",
68811
+ "reasoning": true,
68812
+ "input": [
68813
+ "text",
68814
+ "image"
68815
+ ],
68816
+ "cost": {
68817
+ "input": 3,
68818
+ "output": 15,
68819
+ "cacheRead": 0.3,
68820
+ "cacheWrite": 0
68821
+ },
68822
+ "contextWindow": 1048576,
68823
+ "maxTokens": 131072,
68824
+ "thinking": {
68825
+ "mode": "effort",
68826
+ "efforts": [
68827
+ "low",
68828
+ "high",
68829
+ "max"
68830
+ ],
68831
+ "defaultLevel": "max",
68832
+ "effortMap": {
68833
+ "max": "max"
68834
+ },
68835
+ "requiresEffort": true
68836
+ }
68837
+ },
68716
68838
  "laguna-s-2.1-free": {
68717
68839
  "id": "laguna-s-2.1-free",
68718
68840
  "name": "Laguna S 2.1 Free",
@@ -72047,8 +72169,8 @@
72047
72169
  "image"
72048
72170
  ],
72049
72171
  "cost": {
72050
- "input": 0.12,
72051
- "output": 0.35,
72172
+ "input": 0.14,
72173
+ "output": 0.42,
72052
72174
  "cacheRead": 0.049999999999999996,
72053
72175
  "cacheWrite": 0
72054
72176
  },
@@ -74224,9 +74346,9 @@
74224
74346
  "text"
74225
74347
  ],
74226
74348
  "cost": {
74227
- "input": 0.6,
74228
- "output": 3.5999999999999996,
74229
- "cacheRead": 0.19999999999999998,
74349
+ "input": 0.5,
74350
+ "output": 2.2,
74351
+ "cacheRead": 0.09999999999999999,
74230
74352
  "cacheWrite": 0
74231
74353
  },
74232
74354
  "contextWindow": 512288,
@@ -75036,11 +75158,11 @@
75036
75158
  "cost": {
75037
75159
  "input": 1.25,
75038
75160
  "output": 10,
75039
- "cacheRead": 0.125,
75161
+ "cacheRead": 0.13,
75040
75162
  "cacheWrite": 0
75041
75163
  },
75042
75164
  "contextWindow": 128000,
75043
- "maxTokens": 16384,
75165
+ "maxTokens": 32000,
75044
75166
  "supportsComputerUse": false,
75045
75167
  "supportsComputerUseConfig": false
75046
75168
  },
@@ -75503,10 +75625,10 @@
75503
75625
  "image"
75504
75626
  ],
75505
75627
  "cost": {
75506
- "input": 1,
75507
- "output": 6,
75508
- "cacheRead": 0.09999999999999999,
75509
- "cacheWrite": 1.25
75628
+ "input": 0.5,
75629
+ "output": 3,
75630
+ "cacheRead": 0.049999999999999996,
75631
+ "cacheWrite": 0.625
75510
75632
  },
75511
75633
  "contextWindow": 1050000,
75512
75634
  "maxTokens": 128000,
@@ -75535,10 +75657,10 @@
75535
75657
  "image"
75536
75658
  ],
75537
75659
  "cost": {
75538
- "input": 1,
75539
- "output": 6,
75540
- "cacheRead": 0.09999999999999999,
75541
- "cacheWrite": 1.25
75660
+ "input": 0.5,
75661
+ "output": 3,
75662
+ "cacheRead": 0.049999999999999996,
75663
+ "cacheWrite": 0.625
75542
75664
  },
75543
75665
  "contextWindow": 1050000,
75544
75666
  "maxTokens": 128000,
@@ -75631,10 +75753,10 @@
75631
75753
  "image"
75632
75754
  ],
75633
75755
  "cost": {
75634
- "input": 2.5,
75635
- "output": 15,
75636
- "cacheRead": 0.25,
75637
- "cacheWrite": 3.125
75756
+ "input": 1.25,
75757
+ "output": 7.5,
75758
+ "cacheRead": 0.125,
75759
+ "cacheWrite": 1.5625
75638
75760
  },
75639
75761
  "contextWindow": 1050000,
75640
75762
  "maxTokens": 128000,
@@ -75663,10 +75785,10 @@
75663
75785
  "image"
75664
75786
  ],
75665
75787
  "cost": {
75666
- "input": 2.5,
75667
- "output": 15,
75668
- "cacheRead": 0.25,
75669
- "cacheWrite": 3.125
75788
+ "input": 1.25,
75789
+ "output": 7.5,
75790
+ "cacheRead": 0.125,
75791
+ "cacheWrite": 1.5625
75670
75792
  },
75671
75793
  "contextWindow": 1050000,
75672
75794
  "maxTokens": 128000,
@@ -79676,9 +79798,9 @@
79676
79798
  "text"
79677
79799
  ],
79678
79800
  "cost": {
79679
- "input": 0.6692,
79680
- "output": 2.1032,
79681
- "cacheRead": 0.12428,
79801
+ "input": 0.7714000000000001,
79802
+ "output": 2.4244,
79803
+ "cacheRead": 0.14326,
79682
79804
  "cacheWrite": 0
79683
79805
  },
79684
79806
  "contextWindow": 1048576,
@@ -81152,6 +81274,40 @@
81152
81274
  "escapeBuiltinToolNames": true
81153
81275
  }
81154
81276
  },
81277
+ "umans-kimi-k3": {
81278
+ "id": "umans-kimi-k3",
81279
+ "name": "Umans Kimi K3 (prerelease)",
81280
+ "api": "anthropic-messages",
81281
+ "provider": "umans",
81282
+ "baseUrl": "https://api.code.umans.ai",
81283
+ "reasoning": true,
81284
+ "thinking": {
81285
+ "mode": "budget",
81286
+ "efforts": [
81287
+ "minimal",
81288
+ "low",
81289
+ "medium",
81290
+ "high",
81291
+ "xhigh"
81292
+ ]
81293
+ },
81294
+ "input": [
81295
+ "text",
81296
+ "image"
81297
+ ],
81298
+ "cost": {
81299
+ "input": 0,
81300
+ "output": 0,
81301
+ "cacheRead": 0,
81302
+ "cacheWrite": 0
81303
+ },
81304
+ "contextWindow": 1048576,
81305
+ "maxTokens": 131071,
81306
+ "supportsComputerUse": false,
81307
+ "compat": {
81308
+ "escapeBuiltinToolNames": true
81309
+ }
81310
+ },
81155
81311
  "umans-qwen3.6-35b-a3b": {
81156
81312
  "id": "umans-qwen3.6-35b-a3b",
81157
81313
  "name": "Umans Qwen3.6 35B A3B",
@@ -88444,6 +88600,37 @@
88444
88600
  },
88445
88601
  "supportsComputerUse": false
88446
88602
  },
88603
+ "moonshotai/kimi-k3-fast": {
88604
+ "id": "moonshotai/kimi-k3-fast",
88605
+ "name": "Kimi K3 Fast",
88606
+ "api": "anthropic-messages",
88607
+ "provider": "vercel-ai-gateway",
88608
+ "baseUrl": "https://ai-gateway.vercel.sh",
88609
+ "reasoning": true,
88610
+ "input": [
88611
+ "text",
88612
+ "image"
88613
+ ],
88614
+ "cost": {
88615
+ "input": 4.5,
88616
+ "output": 22.5,
88617
+ "cacheRead": 0.44999999999999996,
88618
+ "cacheWrite": 0
88619
+ },
88620
+ "contextWindow": 1000000,
88621
+ "maxTokens": 131072,
88622
+ "thinking": {
88623
+ "mode": "budget",
88624
+ "efforts": [
88625
+ "low",
88626
+ "high",
88627
+ "max"
88628
+ ],
88629
+ "defaultLevel": "max",
88630
+ "requiresEffort": true
88631
+ },
88632
+ "supportsComputerUse": false
88633
+ },
88447
88634
  "nvidia/nemotron-3-nano-30b-a3b": {
88448
88635
  "id": "nvidia/nemotron-3-nano-30b-a3b",
88449
88636
  "name": "Nemotron 3 Nano 30B A3B",
@@ -91404,9 +91591,9 @@
91404
91591
  "text"
91405
91592
  ],
91406
91593
  "cost": {
91407
- "input": 1.75,
91408
- "output": 5.5,
91409
- "cacheRead": 0.325,
91594
+ "input": 1.575,
91595
+ "output": 4.95,
91596
+ "cacheRead": 0.2875,
91410
91597
  "cacheWrite": 0
91411
91598
  },
91412
91599
  "contextWindow": 1048576,
@@ -41,6 +41,8 @@ import {
41
41
  qianfanModelManagerOptions,
42
42
  qwenPortalModelManagerOptions,
43
43
  sakanaModelManagerOptions,
44
+ siliconflowCnModelManagerOptions,
45
+ siliconflowModelManagerOptions,
44
46
  syntheticModelManagerOptions,
45
47
  togetherModelManagerOptions,
46
48
  umansModelManagerOptions,
@@ -369,6 +371,20 @@ export const CATALOG_PROVIDERS = [
369
371
  dynamicModelsAuthoritative: true,
370
372
  catalogDiscovery: { label: "Sakana AI" },
371
373
  },
374
+ {
375
+ id: "siliconflow",
376
+ defaultModel: "zai-org/GLM-5.1",
377
+ envVars: ["SILICONFLOW_API_KEY"],
378
+ createModelManagerOptions: (config: ModelManagerConfig) => siliconflowModelManagerOptions(config),
379
+ dynamicModelsAuthoritative: true,
380
+ },
381
+ {
382
+ id: "siliconflow-cn",
383
+ defaultModel: "deepseek-ai/DeepSeek-V4-Pro",
384
+ envVars: ["SILICONFLOW_CN_API_KEY"],
385
+ createModelManagerOptions: (config: ModelManagerConfig) => siliconflowCnModelManagerOptions(config),
386
+ dynamicModelsAuthoritative: true,
387
+ },
372
388
  {
373
389
  id: "synthetic",
374
390
  defaultModel: "hf:zai-org/GLM-5.1",
@@ -6,6 +6,7 @@ import {
6
6
  } from "../discovery/openai-compatible";
7
7
  import { Effort, THINKING_EFFORTS } from "../effort";
8
8
  import { FIREWORKS_FAST_SUFFIX, toFireworksPublicModelId } from "../fireworks-model-id";
9
+ import { getBundledModelReferenceIndex } from "../identity/bundled";
9
10
  import {
10
11
  anthropicModelSupportsThinking,
11
12
  isGlmVisionModelId,
@@ -14,6 +15,7 @@ import {
14
15
  isKimiModelId,
15
16
  isReasoningGlmModelId,
16
17
  } from "../identity/family";
18
+ import { resolveModelReference } from "../identity/reference";
17
19
  import type { ModelManagerOptions } from "../model-manager";
18
20
  import { getBundledModels } from "../models";
19
21
  import type { Api, FetchImpl, Model, ModelSpec, OpenAICompat, Provider, ThinkingConfig } from "../types";
@@ -91,10 +93,11 @@ function toInputCapabilities(value: unknown): ("text" | "image")[] {
91
93
  return supportsImage ? ["text", "image"] : ["text"];
92
94
  }
93
95
 
94
- async function fetchModelsDevPayload(fetchImpl: FetchImpl = discoveryFetch()): Promise<unknown> {
96
+ async function fetchModelsDevPayload(fetchImpl: FetchImpl = discoveryFetch(), signal?: AbortSignal): Promise<unknown> {
95
97
  const response = await fetchImpl(MODELS_DEV_URL, {
96
98
  method: "GET",
97
99
  headers: { Accept: "application/json" },
100
+ signal,
98
101
  });
99
102
  if (!response.ok) {
100
103
  throw new Error(`models.dev fetch failed: ${response.status}`);
@@ -1436,6 +1439,166 @@ export function deepseekModelManagerOptions(
1436
1439
  ): ModelManagerOptions<"openai-completions"> {
1437
1440
  return createSimpleOpenAICompletionsOptions("deepseek", "https://api.deepseek.com", config);
1438
1441
  }
1442
+
1443
+ // ---------------------------------------------------------------------------
1444
+ // 6.6 SiliconFlow
1445
+ // ---------------------------------------------------------------------------
1446
+
1447
+ export interface SiliconFlowModelManagerConfig {
1448
+ apiKey?: string;
1449
+ baseUrl?: string;
1450
+ fetch?: FetchImpl;
1451
+ }
1452
+
1453
+ /**
1454
+ * SiliconFlow's `/v1/models` lists every served model — including embeddings,
1455
+ * rerankers, image, audio, and video generators that cannot serve chat
1456
+ * completions — and carries no per-model type field, so non-chat entries are
1457
+ * dropped by id to keep the picker usable.
1458
+ */
1459
+ const SILICONFLOW_NON_CHAT_MODEL_TOKENS = [
1460
+ "embedding",
1461
+ "reranker",
1462
+ "bge-",
1463
+ "bce-",
1464
+ "stable-diffusion",
1465
+ "image",
1466
+ "flux",
1467
+ "kolors",
1468
+ "sensevoice",
1469
+ "cosyvoice",
1470
+ "fish-speech",
1471
+ "indextts",
1472
+ "sovits",
1473
+ "whisper",
1474
+ "hunyuanvideo",
1475
+ "wan2",
1476
+ "ltx-video",
1477
+ "speech",
1478
+ "moderator",
1479
+ "tts",
1480
+ ] as const;
1481
+
1482
+ export function isLikelySiliconFlowChatModelId(id: string): boolean {
1483
+ const normalized = id.trim().toLowerCase();
1484
+ if (!normalized) {
1485
+ return false;
1486
+ }
1487
+ return !SILICONFLOW_NON_CHAT_MODEL_TOKENS.some(token => normalized.includes(token));
1488
+ }
1489
+
1490
+ /**
1491
+ * models.dev mappings consulted ONLY as a runtime metadata reference during
1492
+ * dynamic discovery. They are deliberately absent from
1493
+ * `MODELS_DEV_PROVIDER_DESCRIPTORS` so `generate-models.ts` never bundles
1494
+ * SiliconFlow models — the live endpoint decides which models exist, while
1495
+ * these entries hydrate the pricing, limits, and reasoning metadata that the
1496
+ * endpoint's bare `{id}` rows do not carry. No filter: the join against live
1497
+ * discovered ids already restricts hydration to chat models.
1498
+ */
1499
+ const SILICONFLOW_MODELS_DEV_DESCRIPTORS: readonly ModelsDevProviderDescriptor[] = [
1500
+ openAiCompletionsDescriptor("siliconflow", "siliconflow", "https://api.siliconflow.com/v1", {
1501
+ filterModel: () => true,
1502
+ }),
1503
+ openAiCompletionsDescriptor("siliconflow-cn", "siliconflow-cn", "https://api.siliconflow.cn/v1", {
1504
+ filterModel: () => true,
1505
+ }),
1506
+ ];
1507
+
1508
+ const SILICONFLOW_MODELS_DEV_REFERENCE_TIMEOUT_MS = 5_000;
1509
+
1510
+ async function loadSiliconFlowModelsDevReferences(
1511
+ providerId: "siliconflow" | "siliconflow-cn",
1512
+ fetchImpl?: FetchImpl,
1513
+ ): Promise<Map<string, ModelSpec<"openai-completions">>> {
1514
+ const descriptor = SILICONFLOW_MODELS_DEV_DESCRIPTORS.find(d => d.providerId === providerId);
1515
+ if (!descriptor) {
1516
+ return new Map();
1517
+ }
1518
+ try {
1519
+ // Bounded: this enrichment is optional, so a stalled models.dev must not
1520
+ // hold back the authoritative endpoint request that runs after it.
1521
+ const payload = await withCatalogDiscoveryTimeout(SILICONFLOW_MODELS_DEV_REFERENCE_TIMEOUT_MS, signal =>
1522
+ fetchModelsDevPayload(fetchImpl, signal),
1523
+ );
1524
+ return createModelsDevReferenceMap<"openai-completions">(
1525
+ mapModelsDevToModels(payload as Record<string, unknown>, [descriptor]),
1526
+ );
1527
+ } catch {
1528
+ return new Map();
1529
+ }
1530
+ }
1531
+
1532
+ function createSiliconFlowModelManagerOptions(
1533
+ providerId: "siliconflow" | "siliconflow-cn",
1534
+ defaultBaseUrl: string,
1535
+ config?: SiliconFlowModelManagerConfig,
1536
+ ): ModelManagerOptions<"openai-completions"> {
1537
+ const apiKey = config?.apiKey;
1538
+ const baseUrl = config?.baseUrl ?? defaultBaseUrl;
1539
+ return {
1540
+ providerId,
1541
+ dynamicModelsAuthoritative: true,
1542
+ ...(apiKey && {
1543
+ fetchDynamicModels: async () => {
1544
+ const modelsDevReferences = await loadSiliconFlowModelsDevReferences(providerId, config?.fetch);
1545
+ // Resolved here, not at options construction: walking the bundled
1546
+ // reference index is only worth paying for when dynamic discovery
1547
+ // actually runs, keeping the ModelManager cache fast path cheap.
1548
+ const canonicalReferences = getBundledModelReferenceIndex();
1549
+ return fetchOpenAICompatibleModels({
1550
+ api: "openai-completions",
1551
+ provider: providerId,
1552
+ baseUrl,
1553
+ apiKey,
1554
+ filterModel: (_entry, model) => isLikelySiliconFlowChatModelId(model.id),
1555
+ mapModel: (entry, defaults) => {
1556
+ const modelsDevReference = modelsDevReferences.get(defaults.id);
1557
+ if (modelsDevReference) {
1558
+ return mapWithBundledReference(entry, defaults, modelsDevReference);
1559
+ }
1560
+ // ids missing from models.dev (new launches) still recover intrinsic
1561
+ // capabilities and canonical limits from any bundled upstream/reseller
1562
+ // entry — but never its pricing, which is provider-specific.
1563
+ const canonical = resolveModelReference(defaults.id, canonicalReferences) as
1564
+ | ModelSpec<"openai-completions">
1565
+ | undefined;
1566
+ if (!canonical) {
1567
+ return defaults;
1568
+ }
1569
+ const contextWindow = canonical.contextWindow ?? defaults.contextWindow;
1570
+ const maxTokens =
1571
+ canonical.maxTokens != null && contextWindow != null
1572
+ ? Math.min(canonical.maxTokens, contextWindow)
1573
+ : (canonical.maxTokens ?? defaults.maxTokens);
1574
+ return {
1575
+ ...defaults,
1576
+ name: toModelName(entry.name, canonical.name ?? defaults.name),
1577
+ reasoning: canonical.reasoning,
1578
+ input: canonical.input,
1579
+ contextWindow,
1580
+ maxTokens,
1581
+ };
1582
+ },
1583
+ fetch: config?.fetch,
1584
+ });
1585
+ },
1586
+ }),
1587
+ };
1588
+ }
1589
+
1590
+ export function siliconflowModelManagerOptions(
1591
+ config?: SiliconFlowModelManagerConfig,
1592
+ ): ModelManagerOptions<"openai-completions"> {
1593
+ return createSiliconFlowModelManagerOptions("siliconflow", "https://api.siliconflow.com/v1", config);
1594
+ }
1595
+
1596
+ export function siliconflowCnModelManagerOptions(
1597
+ config?: SiliconFlowModelManagerConfig,
1598
+ ): ModelManagerOptions<"openai-completions"> {
1599
+ return createSiliconFlowModelManagerOptions("siliconflow-cn", "https://api.siliconflow.cn/v1", config);
1600
+ }
1601
+
1439
1602
  // ---------------------------------------------------------------------------
1440
1603
  // 6.7 Zhipu Coding Plan
1441
1604
  // ---------------------------------------------------------------------------