@oh-my-pi/pi-catalog 17.1.5 → 17.1.6
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,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.1.6] - 2026-07-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- 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`.
|
|
10
|
+
|
|
5
11
|
## [17.1.5] - 2026-07-27
|
|
6
12
|
|
|
7
13
|
### 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.
|
|
4
|
+
"version": "17.1.6",
|
|
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.
|
|
37
|
+
"@oh-my-pi/pi-utils": "17.1.6",
|
|
38
38
|
"arktype": "2.2.3",
|
|
39
39
|
"zod": "^4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@oh-my-pi/pi-ai": "17.1.
|
|
42
|
+
"@oh-my-pi/pi-ai": "17.1.6",
|
|
43
43
|
"@types/bun": "^1.3.14"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
@@ -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
|
// ---------------------------------------------------------------------------
|