@oh-my-pi/pi-catalog 18.0.3 → 18.0.5
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/model-thinking.d.ts +11 -0
- package/dist/types/models.d.ts +5 -2
- package/dist/types/provider-models/descriptors.d.ts +20 -1
- package/dist/types/provider-models/openai-compat.d.ts +41 -0
- package/dist/types/types.d.ts +8 -5
- package/dist/types/variant-collapse.d.ts +9 -0
- package/package.json +4 -4
- package/src/compat/openai.ts +2 -0
- package/src/identity/priority.ts +1 -0
- package/src/model-manager.ts +9 -1
- package/src/model-thinking.ts +44 -7
- package/src/models.json +15095 -7488
- package/src/models.ts +15 -6
- package/src/provider-models/cache-provider-id.ts +4 -3
- package/src/provider-models/descriptors.ts +19 -1
- package/src/provider-models/openai-compat.ts +364 -0
- package/src/types.ts +16 -5
- package/src/variant-collapse.ts +75 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.0.5] - 2026-08-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added built-in DeepInfra provider support (`deepinfra`, `DEEPINFRA_API_KEY`) with live model discovery, including chat models, context windows, pricing, cache-read pricing, vision input, and reasoning-effort capabilities.
|
|
10
|
+
- Added built-in Yolo-Auto provider support with the flat-rate `deepseek-flash-v4` model and live model discovery.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Fixed the Synthetic provider’s default model to use `hf:zai-org/GLM-5.2` instead of the retired `hf:zai-org/GLM-5.1`.
|
|
15
|
+
|
|
16
|
+
## [18.0.4] - 2026-08-24
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Fixed default reasoning effort for `cursor/cursor-grok-4.5` and `cursor/cursor-grok-4.6` so requests without an explicit effort setting default to `-medium` instead of `-low`, preventing rate limit rejections on Cursor's Start plan ([#9478](https://github.com/can1357/oh-my-pi/issues/9478)).
|
|
21
|
+
- Fixed aliased OpenCode Zen Ox Alpha models exposing incorrect effort levels, ensuring the gateway's native `low`, `high`, and `max` tiers are correctly mapped and reachable ([#9349](https://github.com/can1357/oh-my-pi/issues/9349)).
|
|
22
|
+
- Fixed missing rate card tier for public xAI and SuperGrok models with prompt lengths exceeding 200K tokens ([#9512](https://github.com/can1357/oh-my-pi/issues/9512)).
|
|
23
|
+
|
|
5
24
|
## [18.0.2] - 2026-08-23
|
|
6
25
|
|
|
7
26
|
### Fixed
|
|
@@ -67,4 +67,15 @@ export declare function resolveWireModelId<TApi extends Api>(model: ApiModel<TAp
|
|
|
67
67
|
* thinking-off requests on `thinking.requiresEffort` models.
|
|
68
68
|
*/
|
|
69
69
|
export declare function minimumSupportedEffort<TApi extends Api>(model: ApiModel<TApi>): Effort | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Clamp target for effort-less requests on `thinking.requiresEffort` models:
|
|
72
|
+
* the effort whose wire route equals the model's default wire id
|
|
73
|
+
* (`requestModelId`), so a collapsed row clamps to the tier it already
|
|
74
|
+
* advertises as its default rather than the numerically lowest supported tier
|
|
75
|
+
* (e.g. Cursor Grok 4.5/4.6 default to `medium`, the only tier the Start plan
|
|
76
|
+
* serves). Falls back to {@link minimumSupportedEffort} when no route matches
|
|
77
|
+
* the default id — families whose default already is the minimum, or that
|
|
78
|
+
* expose no routing, are unaffected.
|
|
79
|
+
*/
|
|
80
|
+
export declare function defaultSupportedEffort<TApi extends Api>(model: ApiModel<TApi>): Effort | undefined;
|
|
70
81
|
export {};
|
package/dist/types/models.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import MODELS from "./models.json";
|
|
2
|
-
import type { Api, KnownProvider, Model, Usage } from "./types.js";
|
|
2
|
+
import type { Api, KnownProvider, Model, ModelCost, Usage } from "./types.js";
|
|
3
3
|
export type GeneratedProvider = keyof typeof MODELS;
|
|
4
4
|
export declare function getBundledModel<TApi extends Api = Api>(provider: GeneratedProvider, modelId: string): Model<TApi>;
|
|
5
5
|
export declare function getBundledProviders(): KnownProvider[];
|
|
6
6
|
export declare function getBundledModels(provider: GeneratedProvider): Model<Api>[];
|
|
7
7
|
/** Price a prompt as fully uncached input under its active context-length tier. */
|
|
8
|
-
export declare function calculateUncachedInputCost(cost:
|
|
8
|
+
export declare function calculateUncachedInputCost(cost: ModelCost, promptInputTokens: number): number;
|
|
9
|
+
/** Price one usage record from a token rate card, including active context tiers. */
|
|
10
|
+
export declare function calculateUsageCost(cost: ModelCost, usage: Usage): Usage["cost"];
|
|
11
|
+
/** Price one usage record from its model's token rate card. */
|
|
9
12
|
export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage["cost"];
|
|
10
13
|
/**
|
|
11
14
|
* Check if two models are equal by comparing both their id and provider.
|
|
@@ -97,6 +97,16 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
97
97
|
readonly envVars: readonly ["CURSOR_API_KEY"];
|
|
98
98
|
readonly oauthProvider: "cursor";
|
|
99
99
|
};
|
|
100
|
+
}, {
|
|
101
|
+
readonly id: "deepinfra";
|
|
102
|
+
readonly defaultModel: "deepseek-ai/DeepSeek-V4-Flash-0731";
|
|
103
|
+
readonly envVars: readonly ["DEEPINFRA_API_KEY"];
|
|
104
|
+
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
105
|
+
readonly dynamicModelsAuthoritative: true;
|
|
106
|
+
readonly catalogDiscovery: {
|
|
107
|
+
readonly label: "DeepInfra";
|
|
108
|
+
readonly allowUnauthenticated: true;
|
|
109
|
+
};
|
|
100
110
|
}, {
|
|
101
111
|
readonly id: "deepseek";
|
|
102
112
|
readonly defaultModel: "deepseek-v4-pro";
|
|
@@ -361,7 +371,7 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
361
371
|
readonly dynamicModelsAuthoritative: true;
|
|
362
372
|
}, {
|
|
363
373
|
readonly id: "synthetic";
|
|
364
|
-
readonly defaultModel: "hf:zai-org/GLM-5.
|
|
374
|
+
readonly defaultModel: "hf:zai-org/GLM-5.2";
|
|
365
375
|
readonly envVars: readonly ["SYNTHETIC_API_KEY"];
|
|
366
376
|
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
367
377
|
readonly dynamicModelsAuthoritative: true;
|
|
@@ -469,6 +479,15 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
469
479
|
readonly defaultModel: "mimo-v2.5";
|
|
470
480
|
readonly envVars: readonly ["XIAOMI_TOKEN_PLAN_SGP_API_KEY"];
|
|
471
481
|
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
482
|
+
}, {
|
|
483
|
+
readonly id: "yolo-auto";
|
|
484
|
+
readonly defaultModel: "deepseek-flash-v4";
|
|
485
|
+
readonly envVars: readonly ["YOLO_AUTO_API_KEY"];
|
|
486
|
+
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
487
|
+
readonly dynamicModelsAuthoritative: true;
|
|
488
|
+
readonly catalogDiscovery: {
|
|
489
|
+
readonly label: "Yolo-Auto";
|
|
490
|
+
};
|
|
472
491
|
}, {
|
|
473
492
|
readonly id: "zai";
|
|
474
493
|
readonly defaultModel: "glm-5.3";
|
|
@@ -161,11 +161,29 @@ export interface NovitaModelManagerConfig {
|
|
|
161
161
|
}
|
|
162
162
|
/** Builds Novita's public model-discovery manager. */
|
|
163
163
|
export declare function novitaModelManagerOptions(config?: NovitaModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
164
|
+
export declare const DEEPINFRA_BASE_URL = "https://api.deepinfra.com/v1/openai";
|
|
165
|
+
/** DeepInfra OpenAI-compatible discovery configuration. */
|
|
166
|
+
export interface DeepinfraModelManagerConfig {
|
|
167
|
+
apiKey?: string;
|
|
168
|
+
baseUrl?: string;
|
|
169
|
+
fetch?: FetchImpl;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Builds DeepInfra's model-discovery manager. The catalog endpoint is public,
|
|
173
|
+
* so discovery (and keyless `gen:models` generation) works without an API key;
|
|
174
|
+
* model availability at runtime is still gated on credentials by the registry.
|
|
175
|
+
*/
|
|
176
|
+
export declare function deepinfraModelManagerOptions(config?: DeepinfraModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
164
177
|
export interface XaiModelManagerConfig {
|
|
165
178
|
apiKey?: string;
|
|
166
179
|
baseUrl?: string;
|
|
167
180
|
fetch?: FetchImpl;
|
|
168
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Applies xAI's long-context rate card and mirrors exact public-model prices
|
|
184
|
+
* onto matching SuperGrok catalog rows.
|
|
185
|
+
*/
|
|
186
|
+
export declare function applyXaiCatalogPricing(models: readonly ModelSpec[]): ModelSpec[];
|
|
169
187
|
export declare function xaiModelManagerOptions(config?: XaiModelManagerConfig): ModelManagerOptions<"openai-responses">;
|
|
170
188
|
export interface XaiOAuthModelManagerConfig {
|
|
171
189
|
apiKey?: string;
|
|
@@ -523,6 +541,29 @@ export interface AiandModelManagerConfig {
|
|
|
523
541
|
* pricing metadata, so discovery is authoritative over the bundled seed.
|
|
524
542
|
*/
|
|
525
543
|
export declare function aiandModelManagerOptions(config?: AiandModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
544
|
+
/**
|
|
545
|
+
* Documented Yolo-Auto catalog (yolo-auto.com/docs, 2026-08) bundled so the
|
|
546
|
+
* provider is usable when generation and first boot have no live key. The
|
|
547
|
+
* flat-rate `/v1/models` response is authoritative once discovery runs.
|
|
548
|
+
* The compat block mirrors the provider's documented wire surface: the API
|
|
549
|
+
* speaks the generic chat template with `reasoning_effort` support and rejects
|
|
550
|
+
* the `developer` role and `store` param.
|
|
551
|
+
*/
|
|
552
|
+
export declare const YOLO_AUTO_STATIC_MODELS: readonly ModelSpec<"openai-completions">[];
|
|
553
|
+
export interface YoloAutoModelManagerConfig {
|
|
554
|
+
apiKey?: string;
|
|
555
|
+
baseUrl?: string;
|
|
556
|
+
fetch?: FetchImpl;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Yolo-Auto model manager: OpenAI-compatible chat completions at the
|
|
560
|
+
* flat-rate `deepseek-flash-v4` endpoint. Live `/v1/models` discovery replaces the
|
|
561
|
+
* bundled seed once a key is stored or present in `YOLO_AUTO_API_KEY`. Models
|
|
562
|
+
* the provider adds later inherit metadata (reasoning, thinking, context)
|
|
563
|
+
* from the global bundled reference index, so new ids work without a per-id
|
|
564
|
+
* code change.
|
|
565
|
+
*/
|
|
566
|
+
export declare function yoloAutoModelManagerOptions(config?: YoloAutoModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
526
567
|
export interface QwenPortalModelManagerConfig {
|
|
527
568
|
apiKey?: string;
|
|
528
569
|
baseUrl?: string;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -121,8 +121,8 @@ export interface Usage {
|
|
|
121
121
|
total: number;
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
export type OpenAIReasoningFormat = "openai" | "openrouter" | "zai" | "kimi" | "qwen" | "qwen-chat-template";
|
|
125
|
-
export type OpenAIReasoningDisableMode = "omit" | "lowest-effort" | "none-effort" | "openrouter-enabled-false" | "venice-disable-thinking" | "zai-thinking-disabled" | "qwen-enable-thinking-false" | "qwen-template-false";
|
|
124
|
+
export type OpenAIReasoningFormat = "openai" | "openrouter" | "zai" | "kimi" | "qwen" | "qwen-chat-template" | "chat-template";
|
|
125
|
+
export type OpenAIReasoningDisableMode = "omit" | "lowest-effort" | "none-effort" | "openrouter-enabled-false" | "venice-disable-thinking" | "zai-thinking-disabled" | "qwen-enable-thinking-false" | "qwen-template-false" | "chat-template-thinking-false";
|
|
126
126
|
export type OpenAIStreamMarkupHealingPattern = "kimi" | "dsml" | "qwen" | "thinking";
|
|
127
127
|
/**
|
|
128
128
|
* Compatibility settings for openai-completions API.
|
|
@@ -705,12 +705,15 @@ export interface TokenCost {
|
|
|
705
705
|
cacheWrite: number;
|
|
706
706
|
}
|
|
707
707
|
/**
|
|
708
|
-
* Rates applied to the full request when its prompt exceeds `inputThreshold
|
|
709
|
-
*
|
|
710
|
-
* provider-orchestration input
|
|
708
|
+
* Rates applied to the full request when its prompt exceeds `inputThreshold`,
|
|
709
|
+
* or reaches it when `inputThresholdInclusive` is true. Prompt input is the
|
|
710
|
+
* sum of uncached, cached-read, cache-write, and provider-orchestration input
|
|
711
|
+
* tokens.
|
|
711
712
|
*/
|
|
712
713
|
export interface LongContextTokenCost extends TokenCost {
|
|
713
714
|
inputThreshold: number;
|
|
715
|
+
/** Whether the long-context tier starts exactly at `inputThreshold`. */
|
|
716
|
+
inputThresholdInclusive?: boolean;
|
|
714
717
|
}
|
|
715
718
|
/** Base token rates plus an optional long-context tier. */
|
|
716
719
|
export interface ModelCost extends TokenCost {
|
|
@@ -21,6 +21,15 @@ export interface EffortVariantFamily {
|
|
|
21
21
|
* when it equals the logical id).
|
|
22
22
|
*/
|
|
23
23
|
members: readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* Preferred default wire id: overrides the member-order default for the
|
|
26
|
+
* collapsed spec's `requestModelId` when this member is live. Lets a
|
|
27
|
+
* mandatory-reasoning family advertise a canonical tier that is not its
|
|
28
|
+
* numeric floor (Cursor Grok 4.5/4.6 default to `-medium`, the only tier the
|
|
29
|
+
* Start plan serves; the `-low` floor is refused). Ignored when absent from
|
|
30
|
+
* the input or retired.
|
|
31
|
+
*/
|
|
32
|
+
defaultMember?: string;
|
|
24
33
|
/**
|
|
25
34
|
* Wire ids upstream no longer serves (e.g. a deployment killed while
|
|
26
35
|
* discovery still advertises it). Fresh collapsing never routes to them,
|
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.5",
|
|
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.5",
|
|
38
|
+
"@oh-my-pi/pi-utils": "18.0.5"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@oh-my-pi/pi-ai": "18.0.
|
|
41
|
+
"@oh-my-pi/pi-ai": "18.0.5",
|
|
42
42
|
"@types/bun": "^1.3.14"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
package/src/compat/openai.ts
CHANGED
package/src/identity/priority.ts
CHANGED
package/src/model-manager.ts
CHANGED
|
@@ -492,9 +492,17 @@ function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamic
|
|
|
492
492
|
// dynamic discovery also pre-applies the correct image fallback for omitted
|
|
493
493
|
// `supports.vision`, so its explicit `false` must not be OR-upgraded by the
|
|
494
494
|
// canonical bundled model.
|
|
495
|
+
// DeepInfra's discovery is authoritative (`dynamicModelsAuthoritative`) and
|
|
496
|
+
// its `vision`/`vlm` tags are the catalog's whole truth for modality. Every
|
|
497
|
+
// row shares the single DeepInfra endpoint, so `endpointChanged` never fires
|
|
498
|
+
// there: without this carve-out a model that dropped those tags would keep
|
|
499
|
+
// the bundled reference's image support and the agent would go on sending
|
|
500
|
+
// images to a now text-only route.
|
|
495
501
|
const endpointChanged = existingModel.baseUrl !== dynamicModel.baseUrl;
|
|
496
502
|
const dynamicInputAuthoritative =
|
|
497
|
-
endpointChanged ||
|
|
503
|
+
endpointChanged ||
|
|
504
|
+
(existingModel.provider === "github-copilot" && dynamicModel.provider === "github-copilot") ||
|
|
505
|
+
(existingModel.provider === "deepinfra" && dynamicModel.provider === "deepinfra");
|
|
498
506
|
const supportsImage = dynamicInputAuthoritative
|
|
499
507
|
? dynamicModel.input.includes("image")
|
|
500
508
|
: existingModel.input.includes("image") || dynamicModel.input.includes("image");
|
package/src/model-thinking.ts
CHANGED
|
@@ -329,6 +329,14 @@ function getModelDefinedEfforts<TApi extends Api>(
|
|
|
329
329
|
spec: ModelSpec<TApi>,
|
|
330
330
|
compat: CompatOf<TApi>,
|
|
331
331
|
): readonly Effort[] | undefined {
|
|
332
|
+
if (
|
|
333
|
+
isOpenAICompatReasoningApi(spec.api) &&
|
|
334
|
+
isChatTemplateThinkingFormat(compat) &&
|
|
335
|
+
spec.thinking?.mode === "effort" &&
|
|
336
|
+
spec.thinking.efforts.length > 0
|
|
337
|
+
) {
|
|
338
|
+
return spec.thinking.efforts;
|
|
339
|
+
}
|
|
332
340
|
if (isGlm53ReasoningEffortModelId(spec.id)) {
|
|
333
341
|
// GLM-5.3+ exposes a uniform wire-exact low/high/max ladder on every
|
|
334
342
|
// host — unlike GLM-5.2, whose reasoning_effort dialect is
|
|
@@ -519,6 +527,9 @@ function isQwenTemplateReasoningEffortCompat(compat: CompatOf<Api>): boolean {
|
|
|
519
527
|
compat !== undefined && "qwenTemplateReasoningEffort" in compat && compat.qwenTemplateReasoningEffort === true
|
|
520
528
|
);
|
|
521
529
|
}
|
|
530
|
+
function isChatTemplateThinkingFormat(compat: CompatOf<Api>): boolean {
|
|
531
|
+
return compat !== undefined && "thinkingFormat" in compat && compat.thinkingFormat === "chat-template";
|
|
532
|
+
}
|
|
522
533
|
|
|
523
534
|
function inferDetectedEffortMap<TApi extends Api>(
|
|
524
535
|
spec: ModelSpec<TApi>,
|
|
@@ -559,15 +570,19 @@ function isSakanaFuguReasoningModel<TApi extends Api>(spec: ModelSpec<TApi>): bo
|
|
|
559
570
|
* `opencode-zen`) reason through the wire-exact `low`/`high`/`max` ladder with
|
|
560
571
|
* mandatory thinking: the gateway rejects `minimal`/`medium`/`xhigh`
|
|
561
572
|
* (`[1210] ... please use low, high, or max`), the same dialect it already
|
|
562
|
-
* serves for GLM-5.3 and Kimi K3.
|
|
563
|
-
* (
|
|
564
|
-
*
|
|
573
|
+
* serves for GLM-5.3 and Kimi K3. The SKU also ships under unrelated aliased
|
|
574
|
+
* ids (`opencode-zen/x-preview-f-free`), so the stencil display name is
|
|
575
|
+
* matched as well. Other hosts proxying an `ox-alpha` SKU (Kilo, NanoGPT,
|
|
576
|
+
* Venice, OpenRouter) expose their own vocabularies and are left untouched.
|
|
577
|
+
* See issue #9349.
|
|
565
578
|
*/
|
|
566
579
|
function isOpenCodeGatewayOxAlphaModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
567
|
-
return
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
)
|
|
580
|
+
if (spec.provider !== "opencode-go" && spec.provider !== "opencode-zen") return false;
|
|
581
|
+
if (/(?:^|\/)ox-alpha(?:-|$)/i.test(bareModelId(spec.id))) return true;
|
|
582
|
+
// Aliased gateway ids surface the same SKU under an unrelated id; the
|
|
583
|
+
// display name ("Ox Alpha …") is the stable cross-id signal. Anchored on
|
|
584
|
+
// both sides so "Box Alpha"/"Ox Alphabet" cannot false-positive.
|
|
585
|
+
return /\box[ _-]?alpha\b/i.test(spec.name ?? "");
|
|
571
586
|
}
|
|
572
587
|
|
|
573
588
|
function isDeepseekReasoningModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
@@ -923,3 +938,25 @@ export function minimumSupportedEffort<TApi extends Api>(model: ApiModel<TApi>):
|
|
|
923
938
|
}
|
|
924
939
|
return efforts[0];
|
|
925
940
|
}
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* Clamp target for effort-less requests on `thinking.requiresEffort` models:
|
|
944
|
+
* the effort whose wire route equals the model's default wire id
|
|
945
|
+
* (`requestModelId`), so a collapsed row clamps to the tier it already
|
|
946
|
+
* advertises as its default rather than the numerically lowest supported tier
|
|
947
|
+
* (e.g. Cursor Grok 4.5/4.6 default to `medium`, the only tier the Start plan
|
|
948
|
+
* serves). Falls back to {@link minimumSupportedEffort} when no route matches
|
|
949
|
+
* the default id — families whose default already is the minimum, or that
|
|
950
|
+
* expose no routing, are unaffected.
|
|
951
|
+
*/
|
|
952
|
+
export function defaultSupportedEffort<TApi extends Api>(model: ApiModel<TApi>): Effort | undefined {
|
|
953
|
+
const routing = model.thinking?.effortRouting;
|
|
954
|
+
const defaultWireId = model.requestModelId;
|
|
955
|
+
if (routing !== undefined && defaultWireId !== undefined) {
|
|
956
|
+
const efforts = model.thinking?.efforts;
|
|
957
|
+
for (const effort of THINKING_EFFORTS) {
|
|
958
|
+
if (efforts?.includes(effort) && routing[effort] === defaultWireId) return effort;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return minimumSupportedEffort(model);
|
|
962
|
+
}
|