@linxiraos/pi-catalog 1.1.5 → 1.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 +8 -0
- package/dist/types/discovery/cursor.d.ts +6 -0
- package/dist/types/identity/family.d.ts +15 -11
- package/dist/types/model-manager.d.ts +20 -4
- package/dist/types/provider-models/models-dev-policies.d.ts +8 -0
- package/dist/types/provider-models/openai-compat.d.ts +20 -4
- package/dist/types/wire/cloudflare-ai-gateway.d.ts +18 -0
- package/package.json +4 -4
- package/src/discovery/cursor.ts +26 -11
- package/src/identity/family.ts +43 -24
- package/src/model-manager.ts +112 -71
- package/src/model-thinking.ts +13 -2
- package/src/models.json +40109 -29220
- package/src/provider-models/cache-provider-id.ts +4 -1
- package/src/provider-models/models-dev-policies.ts +38 -0
- package/src/provider-models/openai-compat.ts +221 -72
- package/src/variant-collapse.ts +1 -1
- package/src/wire/cloudflare-ai-gateway.ts +44 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.1.7] - 2026-09-01
|
|
6
|
+
|
|
7
|
+
- 同步上游 OMP v18.0.11(`b8ce33a58911c26bed1d84f0db9a5e2e727c49a2`)。
|
|
8
|
+
|
|
9
|
+
## [1.1.6] - 2026-08-30
|
|
10
|
+
|
|
11
|
+
- 同步上游 OMP v18.0.9(`cc14e04f075d`)。
|
|
12
|
+
|
|
5
13
|
## [1.1.5] - 2026-08-26
|
|
6
14
|
|
|
7
15
|
- 同步上游 OMP v18.0.5 / v18.0.6:新增 DeepInfra / Yolo-Auto 提供商标识。
|
|
@@ -21,3 +21,9 @@ export interface CursorModelDiscoveryOptions {
|
|
|
21
21
|
* Returns `[]` only when the endpoint responds successfully with no usable models.
|
|
22
22
|
*/
|
|
23
23
|
export declare function fetchCursorUsableModels(options: CursorModelDiscoveryOptions): Promise<ModelSpec<"cursor-agent">[] | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolves input modalities from a bundled reference when available, except
|
|
26
|
+
* for Cursor-only families whose image support is known independently. Without
|
|
27
|
+
* a reference, native multimodal families fall back to id classification.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveCursorInput(id: string, referenceInput?: ("text" | "image")[]): ("text" | "image")[];
|
|
@@ -145,24 +145,28 @@ export declare const supportsCodexReasoningSummary: (modelId: string) => boolean
|
|
|
145
145
|
export declare const isOpenAISamplingRestrictedModelId: (modelId: string) => boolean;
|
|
146
146
|
/**
|
|
147
147
|
* Reasoning-capable GLM coding SKUs: glm-4.5 and up on the base / `-air` /
|
|
148
|
-
* `-turbo` lines
|
|
149
|
-
* `-
|
|
150
|
-
* keeps newly-bumped integers (`glm-5.
|
|
151
|
-
* allowlist.
|
|
148
|
+
* `-turbo` lines, plus `-flash` from GLM-5.3-Flash on. Excludes the vision
|
|
149
|
+
* (`…v`) shape, the non-reasoning `-flashx`/`-preview` variants, and pre-4.5
|
|
150
|
+
* ids. Matching the family keeps newly-bumped integers (`glm-5.4`, `glm-6`, …)
|
|
151
|
+
* covered without a per-id allowlist.
|
|
152
152
|
*/
|
|
153
153
|
export declare const isReasoningGlmModelId: (modelId: string) => boolean;
|
|
154
154
|
/** GLM-5.2+ coding SKUs accept `reasoning_effort` in addition to binary thinking. */
|
|
155
155
|
export declare const isGlm52ReasoningEffortModelId: (modelId: string) => boolean;
|
|
156
156
|
/**
|
|
157
|
-
* GLM-5.3+
|
|
158
|
-
* host-specific),
|
|
159
|
-
* ladder on every host, and thinking can
|
|
160
|
-
* `thinking.type` must always be `enabled`. Matching
|
|
161
|
-
* bumps (`glm-5.4`, `glm-6`, …) covered while excluding
|
|
162
|
-
* shape and the non-reasoning `-
|
|
157
|
+
* GLM-5.3+ reasoning-effort SKUs. Unlike GLM-5.2 (whose dialect is
|
|
158
|
+
* host-specific), the base, `-air`, `-turbo`, and `-flash` variants expose a
|
|
159
|
+
* uniform wire-exact `low`/`high`/`max` ladder on every host, and thinking can
|
|
160
|
+
* no longer be disabled — `thinking.type` must always be `enabled`. Matching
|
|
161
|
+
* the family keeps future bumps (`glm-5.4`, `glm-6`, …) covered while excluding
|
|
162
|
+
* the vision (`…v`) shape and the non-reasoning `-flashx`/`-preview` variants.
|
|
163
163
|
*/
|
|
164
164
|
export declare const isGlm53ReasoningEffortModelId: (modelId: string) => boolean;
|
|
165
|
-
/**
|
|
165
|
+
/**
|
|
166
|
+
* GLM SKUs that accept image input: the `v` that attaches to the version
|
|
167
|
+
* (`glm-4v`, `glm-4.5v`) and the natively multimodal `-flash` line from
|
|
168
|
+
* GLM-5.3-Flash on, whose id carries no `v` marker.
|
|
169
|
+
*/
|
|
166
170
|
export declare const isGlmVisionModelId: (modelId: string) => boolean;
|
|
167
171
|
/**
|
|
168
172
|
* Coarse vendor-lineage token for "are two models the same family?" checks
|
|
@@ -11,6 +11,8 @@ export interface ModelsDevFallback<TApi extends Api = Api, TPayload = unknown> {
|
|
|
11
11
|
fetch(): Promise<TPayload>;
|
|
12
12
|
/** Maps payload into provider models. */
|
|
13
13
|
map(payload: TPayload, providerId: Provider): readonly ModelSpec<TApi>[];
|
|
14
|
+
/** When true, mapped rows can add model ids but cannot replace static metadata. */
|
|
15
|
+
additiveOnly?: boolean;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Configuration for provider model resolution.
|
|
@@ -45,18 +47,25 @@ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload =
|
|
|
45
47
|
/** Clock override for deterministic tests. */
|
|
46
48
|
now?: () => number;
|
|
47
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Catalog source that most recently refreshed the resolved provider snapshot.
|
|
52
|
+
*/
|
|
53
|
+
export type ModelResolutionSource = "bundled" | "cache" | "models.dev" | "provider";
|
|
48
54
|
/**
|
|
49
55
|
* Resolution result.
|
|
50
56
|
*
|
|
51
57
|
* `stale` is false when the resolved catalog is authoritative for the selected provider:
|
|
52
|
-
* - a
|
|
58
|
+
* - a provider endpoint fetch succeeded in this call (an empty catalog is still
|
|
53
59
|
* authoritative for the cycle, so downstream pruning of removed models runs),
|
|
60
|
+
* - a models.dev fetch succeeded for a provider without endpoint discovery,
|
|
54
61
|
* - a still-fresh authoritative cache was reused in `online-if-uncached` mode, or
|
|
55
|
-
* - the provider has no
|
|
62
|
+
* - the provider has no remote fetcher configured.
|
|
56
63
|
*/
|
|
57
64
|
export interface ModelResolutionResult<TApi extends Api = Api> {
|
|
58
65
|
models: Model<TApi>[];
|
|
59
66
|
stale: boolean;
|
|
67
|
+
source: ModelResolutionSource;
|
|
68
|
+
updatedAt?: number;
|
|
60
69
|
}
|
|
61
70
|
/**
|
|
62
71
|
* Stateful facade over provider model resolution.
|
|
@@ -70,8 +79,15 @@ export interface ModelManager<TApi extends Api = Api> {
|
|
|
70
79
|
export declare function createModelManager<TApi extends Api = Api, TModelsDevPayload = unknown>(options: ModelManagerOptions<TApi, TModelsDevPayload>): ModelManager<TApi>;
|
|
71
80
|
/**
|
|
72
81
|
* Resolves provider models with source precedence:
|
|
73
|
-
* static -> stencil.so ->
|
|
82
|
+
* static -> cached fallback -> stencil.so -> dynamic.
|
|
74
83
|
*
|
|
75
|
-
* Later sources override earlier ones by model id.
|
|
84
|
+
* Later sources override earlier ones by model id. Cached rows participate only
|
|
85
|
+
* when at least one configured remote source did not refresh successfully.
|
|
76
86
|
*/
|
|
77
87
|
export declare function resolveProviderModels<TApi extends Api = Api, TModelsDevPayload = unknown>(options: ModelManagerOptions<TApi, TModelsDevPayload>, strategy?: ModelRefreshStrategy): Promise<ModelResolutionResult<TApi>>;
|
|
88
|
+
/**
|
|
89
|
+
* Return the versioned, low-collision model-cache identity for a static provider
|
|
90
|
+
* slice. Results are cached by array reference so repeat cold-start paths skip
|
|
91
|
+
* the JSON serialization and hash.
|
|
92
|
+
*/
|
|
93
|
+
export declare function fingerprintStaticModels<TApi extends Api>(models: readonly (ModelSpec<TApi> | Model<TApi>)[], dynamicModelsAuthoritative?: boolean): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Api, ModelSpec } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Remove models.dev rows that OMP cannot route successfully.
|
|
4
|
+
*
|
|
5
|
+
* Generation and runtime refresh share this policy so a live catalog cannot
|
|
6
|
+
* reintroduce selectors deliberately excluded from the bundled catalog.
|
|
7
|
+
*/
|
|
8
|
+
export declare function filterModelsDevCatalogRows<TApi extends Api>(models: readonly ModelSpec<TApi>[]): ModelSpec<TApi>[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ModelManagerOptions } from "../model-manager.js";
|
|
1
|
+
import type { ModelManagerOptions, ModelsDevFallback } from "../model-manager.js";
|
|
2
2
|
import { getBundledModels } from "../models.js";
|
|
3
3
|
import type { Api, FetchImpl, ModelSpec, Provider } from "../types.js";
|
|
4
4
|
import { ALIBABA_TOKEN_PLAN_BASE_URL } from "../wire/alibaba-token-plan.js";
|
|
@@ -32,9 +32,12 @@ export interface ModelsDevModel {
|
|
|
32
32
|
* The frame magic is sniffed rather than trusting content-type so plain-JSON
|
|
33
33
|
* responses (test stubs, fallback mirrors) parse identically.
|
|
34
34
|
*
|
|
35
|
-
* Fetched fully once per
|
|
36
|
-
* request, repeat callers send a
|
|
37
|
-
*
|
|
35
|
+
* Fetched fully once per fetch context: concurrent callers sharing a fetch
|
|
36
|
+
* implementation reuse one transport request, while repeat callers send a
|
|
37
|
+
* conditional GET that the server answers with `304`. Each subscriber may stop
|
|
38
|
+
* waiting independently; the shared transport retains its own hard deadline.
|
|
39
|
+
* Transient failures reuse the last in-memory payload for callers that only
|
|
40
|
+
* need best-effort metadata.
|
|
38
41
|
*/
|
|
39
42
|
export declare function fetchWellKnownModels(fetchImpl?: FetchImpl, signal?: AbortSignal): Promise<unknown>;
|
|
40
43
|
/**
|
|
@@ -685,3 +688,16 @@ export interface ModelsDevProviderDescriptor {
|
|
|
685
688
|
export declare function mapModelsDevToModels(data: Record<string, unknown>, descriptors: readonly ModelsDevProviderDescriptor[]): ModelSpec<Api>[];
|
|
686
689
|
/** All provider descriptors for models.dev data mapping in generate-models.ts. */
|
|
687
690
|
export declare const MODELS_DEV_PROVIDER_DESCRIPTORS: readonly ModelsDevProviderDescriptor[];
|
|
691
|
+
/** Providers whose bundled catalog can receive additive models.dev updates at runtime. */
|
|
692
|
+
export declare const MODELS_DEV_CATALOG_PROVIDER_IDS: readonly string[];
|
|
693
|
+
/**
|
|
694
|
+
* Build the shared models.dev fallback for one known provider.
|
|
695
|
+
*
|
|
696
|
+
* Provider managers sharing one fetch implementation reuse its conditional
|
|
697
|
+
* catalog session. Each mapped provider slice is persisted independently so
|
|
698
|
+
* startup can restore it without parsing the full catalog.
|
|
699
|
+
*
|
|
700
|
+
* `timeoutMs` bounds the catalog request. It is configurable for callers with a
|
|
701
|
+
* stricter startup budget and for deterministic timeout tests.
|
|
702
|
+
*/
|
|
703
|
+
export declare function modelsDevCatalogFallback(providerId: string, fetchImpl?: FetchImpl, timeoutMs?: number): ModelsDevFallback<Api> | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Provider-native AI Gateway prefix before the upstream route segment. */
|
|
2
|
+
export declare const CLOUDFLARE_AI_GATEWAY_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>";
|
|
3
|
+
/** Anthropic Messages passthrough endpoint. */
|
|
4
|
+
export declare const CLOUDFLARE_AI_GATEWAY_ANTHROPIC_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/anthropic";
|
|
5
|
+
/** OpenAI Responses passthrough endpoint. */
|
|
6
|
+
export declare const CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/openai";
|
|
7
|
+
/** OpenAI-compatible Workers AI endpoint. */
|
|
8
|
+
export declare const CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/compat";
|
|
9
|
+
/** Opaque API-key credential payload persisted by Cloudflare AI Gateway login. */
|
|
10
|
+
export interface CloudflareAiGatewayCredential {
|
|
11
|
+
token: string;
|
|
12
|
+
accountId?: string;
|
|
13
|
+
gatewayId?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Parse both structured login credentials and legacy plain gateway tokens. */
|
|
16
|
+
export declare function parseCloudflareAiGatewayCredential(value: string): CloudflareAiGatewayCredential | null;
|
|
17
|
+
/** Serialize the gateway token with the routing identifiers collected during login. */
|
|
18
|
+
export declare function serializeCloudflareAiGatewayCredential(token: string, accountId: string, gatewayId: string): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@linxiraos/pi-catalog",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.7",
|
|
5
5
|
"description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
|
|
6
6
|
"homepage": "https://linxira-os.github.io/zeta/",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"gen:proto": "bun scripts/generate-protocols.ts"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@linxiraos/pi-omptype": "1.1.
|
|
38
|
-
"@linxiraos/pi-utils": "1.1.
|
|
37
|
+
"@linxiraos/pi-omptype": "1.1.7",
|
|
38
|
+
"@linxiraos/pi-utils": "1.1.7"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@linxiraos/pi-ai": "1.1.
|
|
41
|
+
"@linxiraos/pi-ai": "1.1.7",
|
|
42
42
|
"@types/bun": "^1.3.14"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
package/src/discovery/cursor.ts
CHANGED
|
@@ -33,14 +33,20 @@ const CURSOR_KIMI_K3_BARE_ID_PATTERN = /(^|\/)k3$/i;
|
|
|
33
33
|
* reasoning models whose effort is carried in the per-tier sibling id.
|
|
34
34
|
* `GetUsableModels` ships no `thinkingDetails` and the bundled references read
|
|
35
35
|
* `reasoning: false`, so classification falls back to the id. The non-reasoning
|
|
36
|
-
* `grok-code-*`
|
|
36
|
+
* `grok-code-fast-*` family deliberately stays out.
|
|
37
37
|
*/
|
|
38
38
|
const CURSOR_GROK_REASONING_ID_PATTERN = /^cursor-grok-\d/i;
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Cursor-only families verified to accept `selectedImages` even though
|
|
42
|
+
* `GetUsableModels` does not advertise input modalities.
|
|
43
|
+
*/
|
|
44
|
+
const CURSOR_GROK_4_MULTIMODAL_ID_PATTERN = /^cursor-grok-4(?:[.:_-]|$)/i;
|
|
45
|
+
const CURSOR_COMPOSER_25_MULTIMODAL_ID_PATTERN = /^composer-2\.5(?:[.:_-]|$)/i;
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* Model-id families whose native catalogs (anthropic, openai/openai-codex,
|
|
42
|
-
* google) are multimodal. Cursor-only
|
|
43
|
-
* `grok-code-*`) intentionally stay outside this pattern.
|
|
49
|
+
* google) are multimodal. Cursor-only verified families are handled separately.
|
|
44
50
|
*/
|
|
45
51
|
const CURSOR_MULTIMODAL_ID_PATTERN = /claude|gemini|gpt-|codex/;
|
|
46
52
|
|
|
@@ -319,6 +325,7 @@ function normalizeCursorModel(
|
|
|
319
325
|
name,
|
|
320
326
|
baseUrl: baseUrlOverride ?? reference.baseUrl,
|
|
321
327
|
reasoning,
|
|
328
|
+
input: resolveCursorInput(id, reference.input),
|
|
322
329
|
contextWindow: resolveCursorContextWindow(details, id, reference.contextWindow),
|
|
323
330
|
cursorMaxMode: details.maxMode,
|
|
324
331
|
};
|
|
@@ -330,7 +337,7 @@ function normalizeCursorModel(
|
|
|
330
337
|
provider: "cursor",
|
|
331
338
|
baseUrl: baseUrlOverride ?? CURSOR_DEFAULT_BASE_URL,
|
|
332
339
|
reasoning,
|
|
333
|
-
input:
|
|
340
|
+
input: resolveCursorInput(id),
|
|
334
341
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
335
342
|
contextWindow: resolveCursorContextWindow(details, id, DEFAULT_CONTEXT_WINDOW),
|
|
336
343
|
maxTokens: DEFAULT_MAX_TOKENS,
|
|
@@ -394,14 +401,22 @@ function pickModelDisplayName(model: CursorModelDetailsValue, fallbackId: string
|
|
|
394
401
|
}
|
|
395
402
|
|
|
396
403
|
/**
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
* falls back to the model family: families that are multimodal in OMP's own
|
|
401
|
-
* native catalogs accept images, everything else stays text-only. Mirrors
|
|
402
|
-
* `inferInputFromGeminiId` in ./gemini.ts.
|
|
404
|
+
* Resolves input modalities from a bundled reference when available, except
|
|
405
|
+
* for Cursor-only families whose image support is known independently. Without
|
|
406
|
+
* a reference, native multimodal families fall back to id classification.
|
|
403
407
|
*/
|
|
404
|
-
function
|
|
408
|
+
export function resolveCursorInput(id: string, referenceInput?: ("text" | "image")[]): ("text" | "image")[] {
|
|
409
|
+
if (
|
|
410
|
+
isKimiK3ModelId(id) ||
|
|
411
|
+
CURSOR_KIMI_K3_BARE_ID_PATTERN.test(id) ||
|
|
412
|
+
CURSOR_GROK_4_MULTIMODAL_ID_PATTERN.test(id) ||
|
|
413
|
+
CURSOR_COMPOSER_25_MULTIMODAL_ID_PATTERN.test(id)
|
|
414
|
+
) {
|
|
415
|
+
return ["text", "image"];
|
|
416
|
+
}
|
|
417
|
+
if (referenceInput) {
|
|
418
|
+
return referenceInput;
|
|
419
|
+
}
|
|
405
420
|
if (CURSOR_MULTIMODAL_ID_PATTERN.test(id.toLowerCase())) {
|
|
406
421
|
return ["text", "image"];
|
|
407
422
|
}
|
package/src/identity/family.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
bareModelId,
|
|
12
|
+
type GlmModel,
|
|
12
13
|
isAnthropicAdaptiveGenAtLeast,
|
|
13
14
|
isFableOrMythos,
|
|
14
15
|
parseAnthropicModel,
|
|
@@ -283,19 +284,35 @@ export const isOpenAISamplingRestrictedModelId = memo((modelId: string): boolean
|
|
|
283
284
|
return isOpenAIWireGen5Plus(modelId) || O_SERIES_REASONING_RE.test(bare);
|
|
284
285
|
});
|
|
285
286
|
|
|
287
|
+
/**
|
|
288
|
+
* GLM SKU shapes that carry the reasoning ladders. `base`/`air`/`turbo` have
|
|
289
|
+
* always been reasoning lines; `flash` joins at GLM-5.3-Flash, the first flash
|
|
290
|
+
* SKU whose thinking is mandatory (pre-5.3 `-flash` SKUs are non-reasoning).
|
|
291
|
+
* `flashx` and `preview` stay out.
|
|
292
|
+
*/
|
|
293
|
+
function isGlmReasoningVariant(glm: GlmModel): boolean {
|
|
294
|
+
switch (glm.variant) {
|
|
295
|
+
case "base":
|
|
296
|
+
case "air":
|
|
297
|
+
case "turbo":
|
|
298
|
+
return true;
|
|
299
|
+
case "flash":
|
|
300
|
+
return semverGte(glm.version, "5.3");
|
|
301
|
+
default:
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
286
306
|
/**
|
|
287
307
|
* Reasoning-capable GLM coding SKUs: glm-4.5 and up on the base / `-air` /
|
|
288
|
-
* `-turbo` lines
|
|
289
|
-
* `-
|
|
290
|
-
* keeps newly-bumped integers (`glm-5.
|
|
291
|
-
* allowlist.
|
|
308
|
+
* `-turbo` lines, plus `-flash` from GLM-5.3-Flash on. Excludes the vision
|
|
309
|
+
* (`…v`) shape, the non-reasoning `-flashx`/`-preview` variants, and pre-4.5
|
|
310
|
+
* ids. Matching the family keeps newly-bumped integers (`glm-5.4`, `glm-6`, …)
|
|
311
|
+
* covered without a per-id allowlist.
|
|
292
312
|
*/
|
|
293
313
|
export const isReasoningGlmModelId = memo((modelId: string): boolean => {
|
|
294
314
|
const glm = parseGlmModel(bareModelId(modelId));
|
|
295
|
-
if (!glm || glm.vision) {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
|
-
if (glm.variant !== "base" && glm.variant !== "air" && glm.variant !== "turbo") {
|
|
315
|
+
if (!glm || glm.vision || !isGlmReasoningVariant(glm)) {
|
|
299
316
|
return false;
|
|
300
317
|
}
|
|
301
318
|
return semverGte(glm.version, "4.5");
|
|
@@ -304,37 +321,39 @@ export const isReasoningGlmModelId = memo((modelId: string): boolean => {
|
|
|
304
321
|
/** GLM-5.2+ coding SKUs accept `reasoning_effort` in addition to binary thinking. */
|
|
305
322
|
export const isGlm52ReasoningEffortModelId = memo((modelId: string): boolean => {
|
|
306
323
|
const glm = parseGlmModel(bareModelId(modelId));
|
|
307
|
-
if (!glm || glm.vision) {
|
|
308
|
-
return false;
|
|
309
|
-
}
|
|
310
|
-
if (glm.variant !== "base" && glm.variant !== "air" && glm.variant !== "turbo") {
|
|
324
|
+
if (!glm || glm.vision || !isGlmReasoningVariant(glm)) {
|
|
311
325
|
return false;
|
|
312
326
|
}
|
|
313
327
|
return semverGte(glm.version, "5.2");
|
|
314
328
|
});
|
|
315
329
|
|
|
316
330
|
/**
|
|
317
|
-
* GLM-5.3+
|
|
318
|
-
* host-specific),
|
|
319
|
-
* ladder on every host, and thinking can
|
|
320
|
-
* `thinking.type` must always be `enabled`. Matching
|
|
321
|
-
* bumps (`glm-5.4`, `glm-6`, …) covered while excluding
|
|
322
|
-
* shape and the non-reasoning `-
|
|
331
|
+
* GLM-5.3+ reasoning-effort SKUs. Unlike GLM-5.2 (whose dialect is
|
|
332
|
+
* host-specific), the base, `-air`, `-turbo`, and `-flash` variants expose a
|
|
333
|
+
* uniform wire-exact `low`/`high`/`max` ladder on every host, and thinking can
|
|
334
|
+
* no longer be disabled — `thinking.type` must always be `enabled`. Matching
|
|
335
|
+
* the family keeps future bumps (`glm-5.4`, `glm-6`, …) covered while excluding
|
|
336
|
+
* the vision (`…v`) shape and the non-reasoning `-flashx`/`-preview` variants.
|
|
323
337
|
*/
|
|
324
338
|
export const isGlm53ReasoningEffortModelId = memo((modelId: string): boolean => {
|
|
325
339
|
const glm = parseGlmModel(bareModelId(modelId));
|
|
326
|
-
if (!glm || glm.vision) {
|
|
327
|
-
return false;
|
|
328
|
-
}
|
|
329
|
-
if (glm.variant !== "base" && glm.variant !== "air" && glm.variant !== "turbo") {
|
|
340
|
+
if (!glm || glm.vision || !isGlmReasoningVariant(glm)) {
|
|
330
341
|
return false;
|
|
331
342
|
}
|
|
332
343
|
return semverGte(glm.version, "5.3");
|
|
333
344
|
});
|
|
334
345
|
|
|
335
|
-
/**
|
|
346
|
+
/**
|
|
347
|
+
* GLM SKUs that accept image input: the `v` that attaches to the version
|
|
348
|
+
* (`glm-4v`, `glm-4.5v`) and the natively multimodal `-flash` line from
|
|
349
|
+
* GLM-5.3-Flash on, whose id carries no `v` marker.
|
|
350
|
+
*/
|
|
336
351
|
export const isGlmVisionModelId = memo((modelId: string): boolean => {
|
|
337
|
-
|
|
352
|
+
const glm = parseGlmModel(bareModelId(modelId));
|
|
353
|
+
if (!glm) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
return glm.vision || (glm.variant === "flash" && semverGte(glm.version, "5.3"));
|
|
338
357
|
});
|
|
339
358
|
|
|
340
359
|
/**
|