@oh-my-pi/pi-catalog 18.0.7 → 18.0.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/CHANGELOG.md +19 -0
- package/dist/types/identity/family.d.ts +15 -11
- package/dist/types/wire/cloudflare-ai-gateway.d.ts +18 -0
- package/package.json +4 -4
- package/src/identity/family.ts +43 -24
- package/src/model-thinking.ts +8 -0
- package/src/models.json +53 -36
- package/src/provider-models/cache-provider-id.ts +4 -1
- package/src/provider-models/openai-compat.ts +33 -13
- package/src/variant-collapse.ts +1 -1
- package/src/wire/cloudflare-ai-gateway.ts +44 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.0.9] - 2026-08-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added Z.AI GLM-5.3-Flash to the bundled GLM Coding Plan catalog, with a 1M-token context window, 131,072-token output limit, native image input, and low/high/max thinking levels. It is now available through model discovery and the model picker.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed Google Antigravity Gemini 3.7 Flash tiered models failing with HTTP 400 errors at minimal or disabled thinking levels; those tiers now use the compatible Gemini 3.7 Flash model routing.
|
|
14
|
+
- Fixed OpenCode Go and Zen GLM-5.3 Flash models exposing an unsupported extra-high reasoning level; they now use the supported low/high/max reasoning levels.
|
|
15
|
+
- Fixed Cloudflare AI Gateway credential handling so stored credentials and routing metadata are parsed and used correctly.
|
|
16
|
+
|
|
17
|
+
## [18.0.8] - 2026-08-27
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixed the thinking control mode for OpenAI models served over Bedrock Converse (`global.openai.gpt-5.6-luna`, `-sol`, `-terra`), which are now classified as `effort` rather than `budget` so requests use OpenAI's reasoning schema.
|
|
22
|
+
- Fixed LiteLLM discovery leaking a colliding bundled model's provider-specific transport onto custom endpoints: a discovered alias (e.g. `kimi-k3`) matching a bundled Fireworks model no longer inherits that model's wire-id transform, which had caused requests to POST a model id the endpoint never advertised and return HTTP 400 ([#9938](https://github.com/can1357/oh-my-pi/issues/9938)).
|
|
23
|
+
|
|
5
24
|
## [18.0.7] - 2026-08-26
|
|
6
25
|
|
|
7
26
|
### Added
|
|
@@ -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
|
|
@@ -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": "@oh-my-pi/pi-catalog",
|
|
4
|
-
"version": "18.0.
|
|
4
|
+
"version": "18.0.9",
|
|
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": "Stencil Labs, Inc.",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"gen:proto": "bun scripts/generate-protocols.ts"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@oh-my-pi/omptype": "18.0.
|
|
38
|
-
"@oh-my-pi/pi-utils": "18.0.
|
|
37
|
+
"@oh-my-pi/omptype": "18.0.9",
|
|
38
|
+
"@oh-my-pi/pi-utils": "18.0.9"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@oh-my-pi/pi-ai": "18.0.
|
|
41
|
+
"@oh-my-pi/pi-ai": "18.0.9",
|
|
42
42
|
"@types/bun": "^1.3.14"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
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
|
/**
|
package/src/model-thinking.ts
CHANGED
|
@@ -777,6 +777,14 @@ function inferThinkingControlMode<TApi extends Api>(
|
|
|
777
777
|
return "anthropic-budget-effort";
|
|
778
778
|
}
|
|
779
779
|
}
|
|
780
|
+
// Bedrock serves the GPT-5.x models through OpenAI's own request
|
|
781
|
+
// schema, which rejects Anthropic's budget block outright:
|
|
782
|
+
// `unknown_parameter: 'thinking'`. It takes `reasoning.effort`
|
|
783
|
+
// instead. gpt-oss parses as `unknown` (no `gpt-<digits>`), so it
|
|
784
|
+
// keeps the budget path it ships with today.
|
|
785
|
+
if (parsedModel.family === "openai") {
|
|
786
|
+
return "effort";
|
|
787
|
+
}
|
|
780
788
|
return "budget";
|
|
781
789
|
|
|
782
790
|
default:
|
package/src/models.json
CHANGED
|
@@ -28688,7 +28688,7 @@
|
|
|
28688
28688
|
"contextWindow": 1050000,
|
|
28689
28689
|
"maxTokens": 128000,
|
|
28690
28690
|
"thinking": {
|
|
28691
|
-
"mode": "
|
|
28691
|
+
"mode": "effort",
|
|
28692
28692
|
"efforts": [
|
|
28693
28693
|
"low",
|
|
28694
28694
|
"medium",
|
|
@@ -28727,7 +28727,7 @@
|
|
|
28727
28727
|
"contextWindow": 1050000,
|
|
28728
28728
|
"maxTokens": 128000,
|
|
28729
28729
|
"thinking": {
|
|
28730
|
-
"mode": "
|
|
28730
|
+
"mode": "effort",
|
|
28731
28731
|
"efforts": [
|
|
28732
28732
|
"low",
|
|
28733
28733
|
"medium",
|
|
@@ -28766,7 +28766,7 @@
|
|
|
28766
28766
|
"contextWindow": 1050000,
|
|
28767
28767
|
"maxTokens": 128000,
|
|
28768
28768
|
"thinking": {
|
|
28769
|
-
"mode": "
|
|
28769
|
+
"mode": "effort",
|
|
28770
28770
|
"efforts": [
|
|
28771
28771
|
"low",
|
|
28772
28772
|
"medium",
|
|
@@ -64887,38 +64887,6 @@
|
|
|
64887
64887
|
"requiresGlyphTokenization": false,
|
|
64888
64888
|
"supportsComputerUse": false
|
|
64889
64889
|
},
|
|
64890
|
-
"gemini-3.7-flash-tiered": {
|
|
64891
|
-
"id": "gemini-3.7-flash-tiered",
|
|
64892
|
-
"name": "gemini-3.7-flash-tiered",
|
|
64893
|
-
"api": "google-gemini-cli",
|
|
64894
|
-
"provider": "google-antigravity",
|
|
64895
|
-
"baseUrl": "https://daily-cloudcode-pa.googleapis.com",
|
|
64896
|
-
"reasoning": true,
|
|
64897
|
-
"input": [
|
|
64898
|
-
"text",
|
|
64899
|
-
"image"
|
|
64900
|
-
],
|
|
64901
|
-
"cost": {
|
|
64902
|
-
"input": 0,
|
|
64903
|
-
"output": 0,
|
|
64904
|
-
"cacheRead": 0,
|
|
64905
|
-
"cacheWrite": 0
|
|
64906
|
-
},
|
|
64907
|
-
"contextWindow": 1048576,
|
|
64908
|
-
"maxTokens": 65536,
|
|
64909
|
-
"thinking": {
|
|
64910
|
-
"mode": "google-level",
|
|
64911
|
-
"efforts": [
|
|
64912
|
-
"minimal",
|
|
64913
|
-
"low",
|
|
64914
|
-
"medium",
|
|
64915
|
-
"high"
|
|
64916
|
-
],
|
|
64917
|
-
"requiresEffort": true
|
|
64918
|
-
},
|
|
64919
|
-
"requiresGlyphTokenization": false,
|
|
64920
|
-
"supportsComputerUse": false
|
|
64921
|
-
},
|
|
64922
64890
|
"gpt-oss-120b": {
|
|
64923
64891
|
"id": "gpt-oss-120b",
|
|
64924
64892
|
"name": "GPT OSS 120B",
|
|
@@ -294589,6 +294557,55 @@
|
|
|
294589
294557
|
},
|
|
294590
294558
|
"supportsComputerUseConfig": false
|
|
294591
294559
|
},
|
|
294560
|
+
"glm-5.3-flash": {
|
|
294561
|
+
"id": "glm-5.3-flash",
|
|
294562
|
+
"name": "GLM-5.3-Flash",
|
|
294563
|
+
"api": "anthropic-messages",
|
|
294564
|
+
"provider": "zai",
|
|
294565
|
+
"baseUrl": "https://api.z.ai/api/anthropic",
|
|
294566
|
+
"reasoning": true,
|
|
294567
|
+
"input": [
|
|
294568
|
+
"text",
|
|
294569
|
+
"image"
|
|
294570
|
+
],
|
|
294571
|
+
"cost": {
|
|
294572
|
+
"input": 0.15,
|
|
294573
|
+
"output": 0.5,
|
|
294574
|
+
"cacheRead": 0.03,
|
|
294575
|
+
"cacheWrite": 0
|
|
294576
|
+
},
|
|
294577
|
+
"contextWindow": 1000000,
|
|
294578
|
+
"maxTokens": 131072,
|
|
294579
|
+
"thinking": {
|
|
294580
|
+
"mode": "anthropic-budget-effort",
|
|
294581
|
+
"efforts": [
|
|
294582
|
+
"low",
|
|
294583
|
+
"high",
|
|
294584
|
+
"max"
|
|
294585
|
+
],
|
|
294586
|
+
"defaultLevel": "max",
|
|
294587
|
+
"requiresEffort": true
|
|
294588
|
+
},
|
|
294589
|
+
"requiresGlyphTokenization": false,
|
|
294590
|
+
"tokenizer": "glm5",
|
|
294591
|
+
"supportsComputerUse": false,
|
|
294592
|
+
"compat": {
|
|
294593
|
+
"officialEndpoint": false,
|
|
294594
|
+
"signingEndpoint": false,
|
|
294595
|
+
"disableStrictTools": false,
|
|
294596
|
+
"disableAdaptiveThinking": false,
|
|
294597
|
+
"allowAnthropicHeaderOverrides": false,
|
|
294598
|
+
"supportsEagerToolInputStreaming": false,
|
|
294599
|
+
"supportsLongCacheRetention": false,
|
|
294600
|
+
"supportsMidConversationSystem": false,
|
|
294601
|
+
"supportsForcedToolChoice": true,
|
|
294602
|
+
"supportsSamplingParams": true,
|
|
294603
|
+
"requiresToolResultId": true,
|
|
294604
|
+
"requiresThinkingEnabled": false,
|
|
294605
|
+
"replayUnsignedThinking": true,
|
|
294606
|
+
"escapeBuiltinToolNames": false
|
|
294607
|
+
}
|
|
294608
|
+
},
|
|
294592
294609
|
"glm-5v-turbo": {
|
|
294593
294610
|
"id": "glm-5v-turbo",
|
|
294594
294611
|
"name": "GLM-5V-Turbo",
|
|
@@ -312261,4 +312278,4 @@
|
|
|
312261
312278
|
}
|
|
312262
312279
|
}
|
|
312263
312280
|
}
|
|
312264
|
-
}
|
|
312281
|
+
}
|
|
@@ -60,7 +60,10 @@ export function resolveModelCacheProviderId(providerId: string, options: ModelCa
|
|
|
60
60
|
return "cursor:default-effort-v4";
|
|
61
61
|
case "litellm": {
|
|
62
62
|
const baseUrl = options.baseUrl ?? getDefaultModelDiscoveryBaseUrl(providerId)!;
|
|
63
|
-
|
|
63
|
+
// rich-v8 invalidates rows whose `compatConfig` retained a colliding
|
|
64
|
+
// bundled model's provider-specific transport (e.g. Fireworks
|
|
65
|
+
// `wireModelIdMode`) before that leak was fixed (issue #9938).
|
|
66
|
+
return `litellm:rich-v8:${Bun.hash(baseUrl).toString(36)}`;
|
|
64
67
|
}
|
|
65
68
|
case "opencode-go":
|
|
66
69
|
case "opencode-zen": {
|
|
@@ -2823,6 +2823,9 @@ const OPENCODE_GO_API_ID_OVERRIDES: Readonly<Record<string, Api>> = {
|
|
|
2823
2823
|
"qwen3.5-plus": "openai-completions",
|
|
2824
2824
|
"qwen3.6-plus": "openai-completions",
|
|
2825
2825
|
};
|
|
2826
|
+
// Runtime-discovered rows cached before model-identity corrections retain
|
|
2827
|
+
// stale capability metadata until the authoritative catalog TTL expires.
|
|
2828
|
+
const OPENCODE_CACHE_MIGRATION_MODEL_IDS = ["glm-5.3-flash"] as const;
|
|
2826
2829
|
|
|
2827
2830
|
// Billing-variant suffixes the OpenCode gateways append to a base model id
|
|
2828
2831
|
// without changing its transport (`deepseek-v4-flash-free`,
|
|
@@ -2883,12 +2886,10 @@ function openCodeModelManagerOptions(
|
|
|
2883
2886
|
providerId,
|
|
2884
2887
|
cacheProviderId: resolveModelCacheProviderId(providerId, { apiKey, baseUrl: discoveryBaseUrl }),
|
|
2885
2888
|
dynamicModelsAuthoritative: true,
|
|
2886
|
-
//
|
|
2887
|
-
// before a
|
|
2888
|
-
//
|
|
2889
|
-
|
|
2890
|
-
// by the 2h cache TTL instead.
|
|
2891
|
-
dropCachedModelIdsOnStaticMismatch: Object.keys(apiOverrides),
|
|
2889
|
+
// Per-id route pins and capability migrations are cache identity:
|
|
2890
|
+
// without this, rows cached before a correction keep the stale route or
|
|
2891
|
+
// thinking surface until TTL expiry (#8957, #9960).
|
|
2892
|
+
dropCachedModelIdsOnStaticMismatch: [...Object.keys(apiOverrides), ...OPENCODE_CACHE_MIGRATION_MODEL_IDS],
|
|
2892
2893
|
modelsDev: {
|
|
2893
2894
|
fetch: () => fetchRevalidatedWellKnownModelsWithTimeout(config?.fetch),
|
|
2894
2895
|
map: payload => {
|
|
@@ -5397,12 +5398,29 @@ function mapLiteLLMRichEntry<TApi extends Api>(
|
|
|
5397
5398
|
["tools", "tool_choice", "functions", "function_call"].includes(param),
|
|
5398
5399
|
)
|
|
5399
5400
|
: reference?.supportsTools;
|
|
5401
|
+
// Enrich from the bundled reference with provider-INDEPENDENT reasoning
|
|
5402
|
+
// hints only. The reference is resolved against the global bundled catalog,
|
|
5403
|
+
// so a custom endpoint exposing an alias that collides with a bundled model
|
|
5404
|
+
// (a LiteLLM proxy serving `kimi-k3`, which matches Fireworks' bundled
|
|
5405
|
+
// `kimi-k3`) must not inherit that provider's transport compat. Spreading
|
|
5406
|
+
// the resolved `reference.compat` wholesale leaked `wireModelIdMode`,
|
|
5407
|
+
// `toolSchemaFlavor`, `thinkingFormat`, etc. across the provider boundary —
|
|
5408
|
+
// rewriting the wire id to `accounts/fireworks/models/kimi-k3` for a
|
|
5409
|
+
// non-Fireworks endpoint (issue #9938). `buildModel` re-derives every
|
|
5410
|
+
// transport field from the discovered provider and model id, so only the
|
|
5411
|
+
// effort vocabulary flows through here. Mirrors `discoverOpenAIModelsList`.
|
|
5412
|
+
const referenceCompat = reference?.compat as OpenAICompat | undefined;
|
|
5400
5413
|
const compat: OpenAICompat = {
|
|
5401
|
-
...(reference?.compat ?? {}),
|
|
5402
5414
|
supportsStore: false,
|
|
5403
5415
|
supportsDeveloperRole: false,
|
|
5404
5416
|
...(supportedOpenAIParams !== undefined
|
|
5405
5417
|
? { supportsReasoningEffort: supportedOpenAIParams.includes("reasoning_effort") }
|
|
5418
|
+
: referenceCompat?.supportsReasoningEffort !== undefined
|
|
5419
|
+
? { supportsReasoningEffort: referenceCompat.supportsReasoningEffort }
|
|
5420
|
+
: {}),
|
|
5421
|
+
...(referenceCompat?.reasoningEffortMap ? { reasoningEffortMap: referenceCompat.reasoningEffortMap } : {}),
|
|
5422
|
+
...(referenceCompat?.omitReasoningEffort !== undefined
|
|
5423
|
+
? { omitReasoningEffort: referenceCompat.omitReasoningEffort }
|
|
5406
5424
|
: {}),
|
|
5407
5425
|
};
|
|
5408
5426
|
return {
|
|
@@ -5628,12 +5646,14 @@ export function litellmModelManagerOptions(config?: LiteLLMModelManagerConfig):
|
|
|
5628
5646
|
const baseUrl = config?.baseUrl ?? getDefaultModelDiscoveryBaseUrl("litellm")!;
|
|
5629
5647
|
return {
|
|
5630
5648
|
providerId: "litellm",
|
|
5631
|
-
// rich-
|
|
5632
|
-
//
|
|
5633
|
-
//
|
|
5634
|
-
//
|
|
5635
|
-
//
|
|
5636
|
-
//
|
|
5649
|
+
// rich-v8 invalidates rows whose `compatConfig` retained a colliding
|
|
5650
|
+
// bundled model's provider-specific transport (e.g. Fireworks
|
|
5651
|
+
// `wireModelIdMode`) before that leak was fixed. Earlier versions added
|
|
5652
|
+
// bundled reference fallback, moved OpenAI models to Responses, continued
|
|
5653
|
+
// past incomplete vision/API metadata and endpoints omitting cache
|
|
5654
|
+
// pricing, stripped reseller usage suffixes, filtered placeholder rows,
|
|
5655
|
+
// and mapped rich pricing. Bump the version whenever these mappers change,
|
|
5656
|
+
// or warm authoritative caches keep serving pre-change rows for the full TTL.
|
|
5637
5657
|
cacheProviderId: resolveModelCacheProviderId("litellm", { baseUrl }),
|
|
5638
5658
|
// litellm is a local-only proxy and is never bundled in models.json (that
|
|
5639
5659
|
// would leak the machine's localhost catalog). Prefer the proxy's richer
|
package/src/variant-collapse.ts
CHANGED
|
@@ -307,7 +307,7 @@ function geminiLevelFlashFamily(version: "3.6" | "3.7", ...additionalMembers: st
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
const GEMINI_36_FLASH_FAMILY = geminiLevelFlashFamily("3.6", "gemini-3.6-flash-tiered");
|
|
310
|
-
const GEMINI_37_FLASH_FAMILY = geminiLevelFlashFamily("3.7");
|
|
310
|
+
const GEMINI_37_FLASH_FAMILY = geminiLevelFlashFamily("3.7", "gemini-3.7-flash-tiered");
|
|
311
311
|
|
|
312
312
|
function geminiProFamily(mode: "budget" | "google-level"): EffortVariantFamily {
|
|
313
313
|
const budget = mode === "budget";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isRecord } from "../utils";
|
|
2
|
+
|
|
3
|
+
/** Provider-native AI Gateway prefix before the upstream route segment. */
|
|
4
|
+
export const CLOUDFLARE_AI_GATEWAY_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>";
|
|
5
|
+
/** Anthropic Messages passthrough endpoint. */
|
|
6
|
+
export const CLOUDFLARE_AI_GATEWAY_ANTHROPIC_BASE_URL = `${CLOUDFLARE_AI_GATEWAY_BASE_URL}/anthropic`;
|
|
7
|
+
/** OpenAI Responses passthrough endpoint. */
|
|
8
|
+
export const CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL = `${CLOUDFLARE_AI_GATEWAY_BASE_URL}/openai`;
|
|
9
|
+
/** OpenAI-compatible Workers AI endpoint. */
|
|
10
|
+
export const CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL = `${CLOUDFLARE_AI_GATEWAY_BASE_URL}/compat`;
|
|
11
|
+
|
|
12
|
+
/** Opaque API-key credential payload persisted by Cloudflare AI Gateway login. */
|
|
13
|
+
export interface CloudflareAiGatewayCredential {
|
|
14
|
+
token: string;
|
|
15
|
+
accountId?: string;
|
|
16
|
+
gatewayId?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Parse both structured login credentials and legacy plain gateway tokens. */
|
|
20
|
+
export function parseCloudflareAiGatewayCredential(value: string): CloudflareAiGatewayCredential | null {
|
|
21
|
+
const trimmed = value.trim();
|
|
22
|
+
if (!trimmed) return null;
|
|
23
|
+
if (!trimmed.startsWith("{")) return { token: trimmed };
|
|
24
|
+
try {
|
|
25
|
+
const parsed: unknown = JSON.parse(trimmed);
|
|
26
|
+
if (!isRecord(parsed)) return null;
|
|
27
|
+
if (typeof parsed.token !== "string" || !parsed.token.trim()) return null;
|
|
28
|
+
if (parsed.accountId !== undefined && typeof parsed.accountId !== "string") return null;
|
|
29
|
+
if (parsed.gatewayId !== undefined && typeof parsed.gatewayId !== "string") return null;
|
|
30
|
+
const credential: CloudflareAiGatewayCredential = { token: parsed.token.trim() };
|
|
31
|
+
const accountId = parsed.accountId?.trim();
|
|
32
|
+
const gatewayId = parsed.gatewayId?.trim();
|
|
33
|
+
if (accountId) credential.accountId = accountId;
|
|
34
|
+
if (gatewayId) credential.gatewayId = gatewayId;
|
|
35
|
+
return credential;
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Serialize the gateway token with the routing identifiers collected during login. */
|
|
42
|
+
export function serializeCloudflareAiGatewayCredential(token: string, accountId: string, gatewayId: string): string {
|
|
43
|
+
return JSON.stringify({ token: token.trim(), accountId: accountId.trim(), gatewayId: gatewayId.trim() });
|
|
44
|
+
}
|