@oh-my-pi/pi-catalog 16.3.15 → 16.4.0
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/effort.d.ts +2 -1
- package/dist/types/model-thinking.d.ts +0 -15
- package/dist/types/provider-models/descriptors.d.ts +10 -0
- package/dist/types/provider-models/openai-compat.d.ts +8 -0
- package/dist/types/types.d.ts +2 -0
- package/dist/types/wire/codex.d.ts +9 -0
- package/package.json +3 -3
- package/src/compat/openai.ts +5 -28
- package/src/discovery/codex.ts +3 -0
- package/src/effort.ts +2 -0
- package/src/model-thinking.ts +138 -139
- package/src/models.json +3690 -2151
- package/src/provider-models/descriptors.ts +9 -0
- package/src/provider-models/ollama.ts +1 -2
- package/src/provider-models/openai-compat.ts +107 -18
- package/src/types.ts +2 -0
- package/src/variant-collapse.ts +79 -123
- package/src/wire/codex.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.4.0] - 2026-07-10
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Redesigned reasoning effort ladders to be wire-exact, removing the shifted five-tier effort mapping. Models now expose exactly the effort tiers their upstream APIs accept, mapped 1:1. Removed SHIFTED_FIVE_TIER_EFFORT_MAP, ANTHROPIC_ADAPTIVE_EFFORT_MAP_4_TIER, and per-host xhigh-to-max alias maps. Selecting an unsupported tier now automatically clamps down via clampThinkingLevelForModel. Devin effort routing is now mapped 1:1 onto per-tier siblings.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added support for new models: Grok 4.5 family, Dolphin Mistral 24b Venice Edition, GLM5.2-Fast, and Zenmux variants for GPT-5.6 (Luna, Sol, and Terra).
|
|
14
|
+
- Added Novita as a model provider, including public catalog discovery, pricing, limits, modality, reasoning, and tool metadata.
|
|
15
|
+
- Added useResponsesLite to Model and ModelSpec to support the Responses Lite transport, enabled by default for the GPT-5.6 family.
|
|
16
|
+
- Added Effort.Max ("max") as a first-class user-facing thinking level above xhigh.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Enabled reasoning effort controls for Grok 4.5 and updated support flags for additional Grok variants
|
|
21
|
+
- Standardized reasoning effort levels to use a wire-exact max tier across all model providers, including Devin routing and Ollama configurations.
|
|
22
|
+
- Updated costs and context windows for various models in the catalog.
|
|
23
|
+
|
|
5
24
|
## [16.3.15] - 2026-07-09
|
|
6
25
|
|
|
7
26
|
### Added
|
package/dist/types/effort.d.ts
CHANGED
|
@@ -13,21 +13,6 @@ import type { Api, CompatOf, Model, ModelSpec, ThinkingConfig } from "./types.js
|
|
|
13
13
|
* specs and built models.
|
|
14
14
|
*/
|
|
15
15
|
type ApiModel<TApi extends Api = Api> = ModelSpec<TApi> | Model<TApi>;
|
|
16
|
-
/**
|
|
17
|
-
* Effort → wire-value map for a shifted five-tier scale (`low..max`):
|
|
18
|
-
* user-facing efforts shift up one notch so the top tier reaches the genuine
|
|
19
|
-
* "max" and "high" lands on the recommended "xhigh" coding/agentic default.
|
|
20
|
-
* Used by Anthropic adaptive models with a real xhigh tier (Opus 4.7+ and
|
|
21
|
-
* Fable/Mythos 5 on the Messages API) and by GPT-5.6+ wire-effort models,
|
|
22
|
-
* which expose the same genuine `max` tier above `xhigh`.
|
|
23
|
-
*/
|
|
24
|
-
export declare const SHIFTED_FIVE_TIER_EFFORT_MAP: Readonly<Partial<Record<Effort, string>>>;
|
|
25
|
-
/**
|
|
26
|
-
* Effort → wire-value map for the legacy 4-tier adaptive scale (Opus 4.6,
|
|
27
|
-
* Sonnet 4.6+, and every adaptive model on Bedrock Converse). `low..high` pass
|
|
28
|
-
* through verbatim; there is no real "xhigh", so it aliases the top "max" tier.
|
|
29
|
-
*/
|
|
30
|
-
export declare const ANTHROPIC_ADAPTIVE_EFFORT_MAP_4_TIER: Readonly<Partial<Record<Effort, string>>>;
|
|
31
16
|
/**
|
|
32
17
|
* Resolve the canonical thinking metadata for a spec. Called exactly once per
|
|
33
18
|
* model by `buildModel`, after compat resolution.
|
|
@@ -224,6 +224,16 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
224
224
|
readonly catalogDiscovery: {
|
|
225
225
|
readonly label: "NVIDIA";
|
|
226
226
|
};
|
|
227
|
+
}, {
|
|
228
|
+
readonly id: "novita";
|
|
229
|
+
readonly defaultModel: "moonshotai/kimi-k2.7-code";
|
|
230
|
+
readonly envVars: readonly ["NOVITA_API_KEY"];
|
|
231
|
+
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
232
|
+
readonly dynamicModelsAuthoritative: true;
|
|
233
|
+
readonly catalogDiscovery: {
|
|
234
|
+
readonly label: "Novita";
|
|
235
|
+
readonly allowUnauthenticated: true;
|
|
236
|
+
};
|
|
227
237
|
}, {
|
|
228
238
|
readonly id: "ollama";
|
|
229
239
|
readonly defaultModel: "gpt-oss:20b";
|
|
@@ -90,6 +90,14 @@ export interface NvidiaModelManagerConfig {
|
|
|
90
90
|
fetch?: FetchImpl;
|
|
91
91
|
}
|
|
92
92
|
export declare function nvidiaModelManagerOptions(config?: NvidiaModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
93
|
+
/** Novita OpenAI-compatible discovery configuration. */
|
|
94
|
+
export interface NovitaModelManagerConfig {
|
|
95
|
+
apiKey?: string;
|
|
96
|
+
baseUrl?: string;
|
|
97
|
+
fetch?: FetchImpl;
|
|
98
|
+
}
|
|
99
|
+
/** Builds Novita's public model-discovery manager. */
|
|
100
|
+
export declare function novitaModelManagerOptions(config?: NovitaModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
93
101
|
export interface XaiModelManagerConfig {
|
|
94
102
|
apiKey?: string;
|
|
95
103
|
baseUrl?: string;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -630,6 +630,8 @@ export interface Model<TApi extends Api = Api> {
|
|
|
630
630
|
transport?: "pi-native";
|
|
631
631
|
/** Hint that websocket transport should be preferred when supported by the provider implementation. */
|
|
632
632
|
preferWebsockets?: boolean;
|
|
633
|
+
/** Codex Responses Lite transport: send the lite marker and carry instructions/tools as input items (mirrors codex-rs `use_responses_lite`). */
|
|
634
|
+
useResponsesLite?: boolean;
|
|
633
635
|
/** Preferred model to switch to when context promotion is triggered (model id or provider/id). */
|
|
634
636
|
contextPromotionTarget?: string;
|
|
635
637
|
/** Preferred model to use only for compaction (model id or provider/id); the active session model is unchanged. */
|
|
@@ -8,6 +8,15 @@ export declare const OPENAI_HEADERS: {
|
|
|
8
8
|
readonly ORIGINATOR: "originator";
|
|
9
9
|
readonly SESSION_ID: "session_id";
|
|
10
10
|
readonly CONVERSATION_ID: "conversation_id";
|
|
11
|
+
readonly SCOPED_SESSION_ID: "session-id";
|
|
12
|
+
readonly THREAD_ID: "thread-id";
|
|
13
|
+
readonly INSTALLATION_ID: "x-codex-installation-id";
|
|
14
|
+
readonly WINDOW_ID: "x-codex-window-id";
|
|
15
|
+
readonly TURN_METADATA: "x-codex-turn-metadata";
|
|
16
|
+
readonly PARENT_THREAD_ID: "x-codex-parent-thread-id";
|
|
17
|
+
readonly SUBAGENT: "x-openai-subagent";
|
|
18
|
+
/** Responses Lite transport marker (codex-rs `add_responses_lite_header`); value is always `"true"`. */
|
|
19
|
+
readonly RESPONSES_LITE: "x-openai-internal-codex-responses-lite";
|
|
11
20
|
};
|
|
12
21
|
export declare const OPENAI_HEADER_VALUES: {
|
|
13
22
|
readonly BETA_RESPONSES: "responses=experimental";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-catalog",
|
|
4
|
-
"version": "16.
|
|
4
|
+
"version": "16.4.0",
|
|
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.0",
|
|
37
|
-
"@oh-my-pi/pi-utils": "16.
|
|
37
|
+
"@oh-my-pi/pi-utils": "16.4.0",
|
|
38
38
|
"arktype": "^2.2.0",
|
|
39
39
|
"zod": "^4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@oh-my-pi/pi-ai": "16.
|
|
42
|
+
"@oh-my-pi/pi-ai": "16.4.0",
|
|
43
43
|
"@types/bun": "^1.3.14"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
package/src/compat/openai.ts
CHANGED
|
@@ -71,31 +71,11 @@ const DSML_HEALING_PROVIDERS = new Set([
|
|
|
71
71
|
"openrouter",
|
|
72
72
|
]);
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
* builder (not only at discovery) so stale-cached and custom `ollama`-provider
|
|
80
|
-
* specs are backfilled on every `buildModel`, not just on a fresh
|
|
81
|
-
* `omp models refresh`. Custom OpenAI-compatible providers pointed at a local
|
|
82
|
-
* Ollama port under a different provider id are not covered — they must set
|
|
83
|
-
* `compat.reasoningEffortMap` themselves.
|
|
84
|
-
*/
|
|
85
|
-
const OLLAMA_REASONING_EFFORT_MAP: ResolvedOpenAISharedCompat["reasoningEffortMap"] = { minimal: "low", xhigh: "max" };
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Merge the Ollama default effort map under any explicit overrides (overrides
|
|
89
|
-
* win). No-op off the local `ollama` provider or for non-reasoning models.
|
|
90
|
-
*/
|
|
91
|
-
function mergeOllamaReasoningEffortMap(
|
|
92
|
-
compat: ResolvedOpenAISharedCompat,
|
|
93
|
-
provider: string,
|
|
94
|
-
reasoning: boolean | undefined,
|
|
95
|
-
): void {
|
|
96
|
-
if (provider !== "ollama" || !reasoning) return;
|
|
97
|
-
compat.reasoningEffortMap = { ...OLLAMA_REASONING_EFFORT_MAP, ...compat.reasoningEffortMap };
|
|
98
|
-
}
|
|
74
|
+
// Ollama's OpenAI-compatible `reasoning.effort` accepts `high|medium|low|max|none`;
|
|
75
|
+
// `ollama`-provider reasoning models carry the wire-exact `low..max` effort
|
|
76
|
+
// ladder (see getModelDefinedEfforts), so no compat-level remapping is needed.
|
|
77
|
+
// Custom OpenAI-compatible providers pointed at a local Ollama port under a
|
|
78
|
+
// different provider id must set `compat.reasoningEffortMap` themselves.
|
|
99
79
|
|
|
100
80
|
function resolveReasoningDisableMode(
|
|
101
81
|
thinkingFormat: ResolvedOpenAISharedCompat["thinkingFormat"],
|
|
@@ -554,7 +534,6 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
|
|
|
554
534
|
if (spec.compat?.omitReasoningEffort === undefined && !compat.supportsReasoningEffort) {
|
|
555
535
|
compat.omitReasoningEffort = true;
|
|
556
536
|
}
|
|
557
|
-
mergeOllamaReasoningEffortMap(compat, provider, spec.reasoning);
|
|
558
537
|
mergeMimoReasoningEffortMap(compat, isMimoReasoningEffortModel);
|
|
559
538
|
|
|
560
539
|
const whenThinkingPolicy =
|
|
@@ -568,7 +547,6 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
|
|
|
568
547
|
if (whenThinkingPolicy.omitReasoningEffort === undefined && !variant.supportsReasoningEffort) {
|
|
569
548
|
variant.omitReasoningEffort = true;
|
|
570
549
|
}
|
|
571
|
-
mergeOllamaReasoningEffortMap(variant, provider, spec.reasoning);
|
|
572
550
|
mergeMimoReasoningEffortMap(variant, isMimoReasoningEffortModel);
|
|
573
551
|
compat.whenThinking = variant;
|
|
574
552
|
}
|
|
@@ -678,7 +656,6 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
|
|
|
678
656
|
if (spec.compat?.omitReasoningEffort === undefined && !compat.supportsReasoningEffort) {
|
|
679
657
|
compat.omitReasoningEffort = true;
|
|
680
658
|
}
|
|
681
|
-
mergeOllamaReasoningEffortMap(compat, spec.provider, spec.reasoning);
|
|
682
659
|
return compat;
|
|
683
660
|
}
|
|
684
661
|
|
package/src/discovery/codex.ts
CHANGED
|
@@ -30,6 +30,7 @@ const codexModelEntrySchema = type({
|
|
|
30
30
|
"supported_in_api?": "unknown",
|
|
31
31
|
"priority?": "unknown",
|
|
32
32
|
"prefer_websockets?": "unknown",
|
|
33
|
+
"use_responses_lite?": "unknown",
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
const codexModelsResponseSchema = type({
|
|
@@ -262,6 +263,7 @@ function normalizeCodexModelEntry(entry: unknown, baseUrl: string): NormalizedCo
|
|
|
262
263
|
const reasoning = supportsReasoning(payload.default_reasoning_level, payload.supported_reasoning_levels);
|
|
263
264
|
const input = normalizeInputModalities(payload.input_modalities);
|
|
264
265
|
const preferWebsockets = toBoolean(payload.prefer_websockets) === true;
|
|
266
|
+
const useResponsesLite = toBoolean(payload.use_responses_lite) === true;
|
|
265
267
|
const priority = toFiniteNumber(payload.priority) ?? Number.MAX_SAFE_INTEGER;
|
|
266
268
|
|
|
267
269
|
return {
|
|
@@ -279,6 +281,7 @@ function normalizeCodexModelEntry(entry: unknown, baseUrl: string): NormalizedCo
|
|
|
279
281
|
contextWindow,
|
|
280
282
|
maxTokens,
|
|
281
283
|
...(preferWebsockets ? { preferWebsockets: true } : {}),
|
|
284
|
+
...(useResponsesLite ? { useResponsesLite: true } : {}),
|
|
282
285
|
...(priority !== Number.MAX_SAFE_INTEGER ? { priority } : {}),
|
|
283
286
|
},
|
|
284
287
|
};
|
package/src/effort.ts
CHANGED
|
@@ -5,6 +5,7 @@ export const enum Effort {
|
|
|
5
5
|
Medium = "medium",
|
|
6
6
|
High = "high",
|
|
7
7
|
XHigh = "xhigh",
|
|
8
|
+
Max = "max",
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export const THINKING_EFFORTS: readonly Effort[] = [
|
|
@@ -13,4 +14,5 @@ export const THINKING_EFFORTS: readonly Effort[] = [
|
|
|
13
14
|
Effort.Medium,
|
|
14
15
|
Effort.High,
|
|
15
16
|
Effort.XHigh,
|
|
17
|
+
Effort.Max,
|
|
16
18
|
];
|
package/src/model-thinking.ts
CHANGED
|
@@ -61,12 +61,34 @@ const GEMINI_3_FLASH_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, E
|
|
|
61
61
|
const GPT_5_2_PLUS_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh];
|
|
62
62
|
const GPT_5_1_CODEX_MINI_EFFORTS: readonly Effort[] = [Effort.Medium, Effort.High];
|
|
63
63
|
const LOW_MEDIUM_HIGH_REASONING_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
/** Wire-exact two-tier scale (`high`/`max`): GLM-5.2 on Z.ai/Umans/Ollama Cloud/Baseten, Sakana Fugu, DeepSeek. */
|
|
65
|
+
const HIGH_MAX_REASONING_EFFORTS: readonly Effort[] = [Effort.High, Effort.Max];
|
|
66
|
+
/** OpenRouter's DeepSeek route accepts only `high`. */
|
|
67
|
+
const HIGH_ONLY_REASONING_EFFORTS: readonly Effort[] = [Effort.High];
|
|
68
|
+
/**
|
|
69
|
+
* Five wire tiers with a `low` floor: GPT-5.6+, Anthropic adaptive models
|
|
70
|
+
* with the real xhigh tier (Opus 4.7+, Sonnet 5+, Fable/Mythos 5), and the
|
|
71
|
+
* Fire Pass Kimi router (distinct xhigh and max budgets).
|
|
72
|
+
*/
|
|
73
|
+
const FIVE_TIER_EFFORTS_LOW_TO_MAX: readonly Effort[] = [
|
|
74
|
+
Effort.Low,
|
|
75
|
+
Effort.Medium,
|
|
76
|
+
Effort.High,
|
|
77
|
+
Effort.XHigh,
|
|
78
|
+
Effort.Max,
|
|
79
|
+
];
|
|
80
|
+
/** Legacy adaptive scale (Opus/Sonnet 4.6, every Bedrock adaptive model): four wire tiers, no xhigh. */
|
|
81
|
+
const FOUR_TIER_EFFORTS_LOW_TO_MAX: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.Max];
|
|
82
|
+
/** GLM-5.2 resellers that pass the default lower tiers verbatim and expose the genuine `max` top tier. */
|
|
83
|
+
const DEFAULT_REASONING_EFFORTS_WITH_MAX: readonly Effort[] = [
|
|
84
|
+
Effort.Minimal,
|
|
85
|
+
Effort.Low,
|
|
86
|
+
Effort.Medium,
|
|
87
|
+
Effort.High,
|
|
88
|
+
Effort.Max,
|
|
89
|
+
];
|
|
90
|
+
/** Local Ollama wire vocabulary (`low`/`medium`/`high`/`max`; `none` is thinking-off). */
|
|
91
|
+
const OLLAMA_REASONING_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.Max];
|
|
70
92
|
type EffortMap = Partial<Record<Effort, string>>;
|
|
71
93
|
|
|
72
94
|
const GROQ_QWEN3_32B_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
|
|
@@ -76,57 +98,14 @@ const GROQ_QWEN3_32B_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
|
|
|
76
98
|
[Effort.High]: "default",
|
|
77
99
|
[Effort.XHigh]: "default",
|
|
78
100
|
};
|
|
79
|
-
const DEEPSEEK_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
|
|
80
|
-
[Effort.Minimal]: "high",
|
|
81
|
-
[Effort.Low]: "high",
|
|
82
|
-
[Effort.Medium]: "high",
|
|
83
|
-
[Effort.High]: "high",
|
|
84
|
-
[Effort.XHigh]: "max",
|
|
85
|
-
};
|
|
86
101
|
const FIREWORKS_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
|
|
87
102
|
[Effort.Minimal]: "none",
|
|
88
103
|
};
|
|
89
|
-
const ZAI_GLM_52_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
|
|
90
|
-
[Effort.Minimal]: "none",
|
|
91
|
-
[Effort.Low]: "high",
|
|
92
|
-
[Effort.Medium]: "high",
|
|
93
|
-
[Effort.High]: "high",
|
|
94
|
-
[Effort.XHigh]: "max",
|
|
95
|
-
};
|
|
96
|
-
const GLM_52_XHIGH_MAX_EFFORT_MAP: Readonly<EffortMap> = {
|
|
97
|
-
[Effort.XHigh]: "max",
|
|
98
|
-
};
|
|
99
104
|
const MIMO_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
|
|
100
105
|
[Effort.Minimal]: "low",
|
|
101
106
|
[Effort.XHigh]: "high",
|
|
102
107
|
};
|
|
103
108
|
|
|
104
|
-
/**
|
|
105
|
-
* Effort → wire-value map for a shifted five-tier scale (`low..max`):
|
|
106
|
-
* user-facing efforts shift up one notch so the top tier reaches the genuine
|
|
107
|
-
* "max" and "high" lands on the recommended "xhigh" coding/agentic default.
|
|
108
|
-
* Used by Anthropic adaptive models with a real xhigh tier (Opus 4.7+ and
|
|
109
|
-
* Fable/Mythos 5 on the Messages API) and by GPT-5.6+ wire-effort models,
|
|
110
|
-
* which expose the same genuine `max` tier above `xhigh`.
|
|
111
|
-
*/
|
|
112
|
-
export const SHIFTED_FIVE_TIER_EFFORT_MAP: Readonly<Partial<Record<Effort, string>>> = {
|
|
113
|
-
[Effort.Minimal]: "low",
|
|
114
|
-
[Effort.Low]: "medium",
|
|
115
|
-
[Effort.Medium]: "high",
|
|
116
|
-
[Effort.High]: "xhigh",
|
|
117
|
-
[Effort.XHigh]: "max",
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Effort → wire-value map for the legacy 4-tier adaptive scale (Opus 4.6,
|
|
122
|
-
* Sonnet 4.6+, and every adaptive model on Bedrock Converse). `low..high` pass
|
|
123
|
-
* through verbatim; there is no real "xhigh", so it aliases the top "max" tier.
|
|
124
|
-
*/
|
|
125
|
-
export const ANTHROPIC_ADAPTIVE_EFFORT_MAP_4_TIER: Readonly<Partial<Record<Effort, string>>> = {
|
|
126
|
-
[Effort.Minimal]: "low",
|
|
127
|
-
[Effort.XHigh]: "max",
|
|
128
|
-
};
|
|
129
|
-
|
|
130
109
|
const MINIMAX_ANTHROPIC_ADAPTIVE_EFFORT_MAP: Readonly<EffortMap> = {
|
|
131
110
|
[Effort.Low]: "adaptive",
|
|
132
111
|
[Effort.Medium]: "adaptive",
|
|
@@ -172,8 +151,10 @@ export function resolveModelThinking<TApi extends Api>(
|
|
|
172
151
|
/**
|
|
173
152
|
* Backfill identity-derived wire facts onto explicit thinking metadata.
|
|
174
153
|
* Explicit `effortMap` / `supportsDisplay` (including `false`) win, except
|
|
175
|
-
* model-defined effort
|
|
176
|
-
*
|
|
154
|
+
* when the model-defined effort ladder disagrees with the cached surface:
|
|
155
|
+
* then both the ladder AND the wire map are re-derived from identity, so
|
|
156
|
+
* stale cached metadata from before a wire-truth change (e.g. the retired
|
|
157
|
+
* shifted five-tier maps) cannot survive normalization.
|
|
177
158
|
*/
|
|
178
159
|
function fillThinkingWireDefaults<TApi extends Api>(
|
|
179
160
|
spec: ModelSpec<TApi>,
|
|
@@ -184,11 +165,9 @@ function fillThinkingWireDefaults<TApi extends Api>(
|
|
|
184
165
|
const normalizedEfforts = getModelDefinedEfforts(spec, compat) ?? thinking.efforts;
|
|
185
166
|
const effortsChanged = !sameEffortList(normalizedEfforts, thinking.efforts);
|
|
186
167
|
const effortMap =
|
|
187
|
-
thinking.effortMap === undefined
|
|
188
|
-
? inferEffortMap(spec, compat,
|
|
189
|
-
:
|
|
190
|
-
? filterEffortMapToSupportedEfforts(thinking.effortMap, normalizedEfforts)
|
|
191
|
-
: undefined;
|
|
168
|
+
thinking.effortMap === undefined || effortsChanged
|
|
169
|
+
? inferEffortMap(spec, compat, thinking.mode, normalizedEfforts)
|
|
170
|
+
: undefined;
|
|
192
171
|
const shouldReplaceEffortMap = thinking.effortMap === undefined ? effortMap !== undefined : effortsChanged;
|
|
193
172
|
const needsDisplay =
|
|
194
173
|
thinking.supportsDisplay === undefined &&
|
|
@@ -229,7 +208,7 @@ export function deriveThinking<TApi extends Api>(spec: ModelSpec<TApi>, compat:
|
|
|
229
208
|
mode: inferThinkingControlMode(spec, parsed),
|
|
230
209
|
efforts,
|
|
231
210
|
};
|
|
232
|
-
const effortMap = inferEffortMap(spec, compat,
|
|
211
|
+
const effortMap = inferEffortMap(spec, compat, config.mode, config.efforts);
|
|
233
212
|
if (effortMap !== undefined) {
|
|
234
213
|
config.effortMap = effortMap;
|
|
235
214
|
}
|
|
@@ -264,11 +243,10 @@ function omitsWireReasoningEffort(api: Api, compat: CompatOf<Api>): boolean {
|
|
|
264
243
|
function inferEffortMap<TApi extends Api>(
|
|
265
244
|
spec: ModelSpec<TApi>,
|
|
266
245
|
compat: CompatOf<TApi>,
|
|
267
|
-
parsedModel: ParsedModel,
|
|
268
246
|
mode: ThinkingConfig["mode"],
|
|
269
247
|
efforts: readonly Effort[],
|
|
270
248
|
): EffortMap | undefined {
|
|
271
|
-
const detected = inferDetectedEffortMap(spec, compat,
|
|
249
|
+
const detected = inferDetectedEffortMap(spec, compat, mode);
|
|
272
250
|
const configured = readCompatEffortMap(compat);
|
|
273
251
|
const merged =
|
|
274
252
|
detected === undefined ? configured : configured === undefined ? detected : { ...detected, ...configured };
|
|
@@ -300,9 +278,9 @@ function isOpenAICompatReasoningApi(api: Api): boolean {
|
|
|
300
278
|
|
|
301
279
|
/**
|
|
302
280
|
* GPT-5.6+ addressed through a wire `reasoning.effort`/`reasoning_effort`
|
|
303
|
-
* field, where the
|
|
304
|
-
* selects effort by routing to per-tier sibling model ids
|
|
305
|
-
* stay unmapped.
|
|
281
|
+
* field, where the five-tier `low..max` wire scale applies. Devin
|
|
282
|
+
* (`devin-agent`) selects effort by routing to per-tier sibling model ids
|
|
283
|
+
* instead and must stay unmapped.
|
|
306
284
|
*/
|
|
307
285
|
function isGpt56PlusWireEffortModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
308
286
|
switch (spec.api) {
|
|
@@ -324,24 +302,64 @@ function getModelDefinedEfforts<TApi extends Api>(
|
|
|
324
302
|
compat: CompatOf<TApi>,
|
|
325
303
|
): readonly Effort[] | undefined {
|
|
326
304
|
if (isGlm52ReasoningEffortModelId(spec.id)) {
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
// expose only high/max
|
|
330
|
-
|
|
305
|
+
// GLM-5.2's reasoning_effort dialect is host-specific (verified against
|
|
306
|
+
// live endpoints):
|
|
307
|
+
// - Z.ai/Zhipu ("zai" dialect) expose only high/max ("none" is the
|
|
308
|
+
// thinking-off state, not a user tier).
|
|
309
|
+
// - Umans, Ollama Cloud, and Baseten serve the same two-tier
|
|
310
|
+
// high/max scale on their GLM-5.2 routes.
|
|
311
|
+
// - OpenRouter rejects `max` — `xhigh` IS its top tier.
|
|
312
|
+
// - Other openai-compat hosts (Fireworks, resellers) pass the
|
|
313
|
+
// default lower tiers through verbatim and expose the genuine
|
|
314
|
+
// `max` above `high` (host quirks like Fireworks' minimal→none
|
|
315
|
+
// stay in the host maps).
|
|
316
|
+
if (isOpenRouterThinkingFormat(compat)) {
|
|
331
317
|
return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
|
|
332
318
|
}
|
|
333
|
-
if (
|
|
334
|
-
|
|
319
|
+
if (
|
|
320
|
+
isZaiThinkingFormat(compat) ||
|
|
321
|
+
isUmansGlm52ReasoningEffortModel(spec) ||
|
|
322
|
+
isOllamaCloudGlm52ReasoningEffortModel(spec) ||
|
|
323
|
+
spec.provider === "baseten"
|
|
324
|
+
) {
|
|
325
|
+
return HIGH_MAX_REASONING_EFFORTS;
|
|
326
|
+
}
|
|
327
|
+
if (isOpenAICompatReasoningApi(spec.api)) {
|
|
328
|
+
return DEFAULT_REASONING_EFFORTS_WITH_MAX;
|
|
335
329
|
}
|
|
336
330
|
}
|
|
337
331
|
if (isSakanaFuguReasoningModel(spec)) {
|
|
338
|
-
return
|
|
332
|
+
return HIGH_MAX_REASONING_EFFORTS;
|
|
339
333
|
}
|
|
340
334
|
if (isGpt56PlusWireEffortModel(spec)) {
|
|
341
|
-
// Normalize stale baked/discovered `low..xhigh` surfaces to the
|
|
342
|
-
// five-tier
|
|
343
|
-
|
|
344
|
-
|
|
335
|
+
// Normalize stale baked/discovered `low..xhigh` surfaces to the
|
|
336
|
+
// wire-exact five-tier `low..max` ladder.
|
|
337
|
+
return FIVE_TIER_EFFORTS_LOW_TO_MAX;
|
|
338
|
+
}
|
|
339
|
+
const anthropicAdaptive = getAnthropicAdaptiveEfforts(spec);
|
|
340
|
+
if (anthropicAdaptive !== undefined) {
|
|
341
|
+
return anthropicAdaptive;
|
|
342
|
+
}
|
|
343
|
+
// Fire Pass's Kimi router accepts low..max with distinct xhigh and max
|
|
344
|
+
// budgets; user minimal has no wire tier there.
|
|
345
|
+
if (spec.provider === "firepass") {
|
|
346
|
+
return FIVE_TIER_EFFORTS_LOW_TO_MAX;
|
|
347
|
+
}
|
|
348
|
+
// Local Ollama's effort vocabulary is low/medium/high/max regardless of
|
|
349
|
+
// model. Custom OpenAI-compatible providers pointed at an Ollama port
|
|
350
|
+
// under a different provider id must set `compat.reasoningEffortMap`
|
|
351
|
+
// themselves.
|
|
352
|
+
if (spec.provider === "ollama") {
|
|
353
|
+
return OLLAMA_REASONING_EFFORTS;
|
|
354
|
+
}
|
|
355
|
+
if (isOpenAICompatReasoningApi(spec.api) && isDeepseekReasoningModel(spec)) {
|
|
356
|
+
// DeepSeek's reasoning_effort accepts only high/max; OpenRouter's
|
|
357
|
+
// DeepSeek route tops out at high.
|
|
358
|
+
return isOpenRouterThinkingFormat(compat) ? HIGH_ONLY_REASONING_EFFORTS : HIGH_MAX_REASONING_EFFORTS;
|
|
359
|
+
}
|
|
360
|
+
if (spec.provider === "baseten" && isOpenAIGptOssModelId(spec.id)) {
|
|
361
|
+
// Baseten's gpt-oss router mirrors its GLM route: high/max only.
|
|
362
|
+
return HIGH_MAX_REASONING_EFFORTS;
|
|
345
363
|
}
|
|
346
364
|
return isOpenAICompatReasoningApi(spec.api) &&
|
|
347
365
|
(isMinimaxM2FamilyModelId(spec.id) ||
|
|
@@ -351,6 +369,27 @@ function getModelDefinedEfforts<TApi extends Api>(
|
|
|
351
369
|
: undefined;
|
|
352
370
|
}
|
|
353
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Wire-exact effort ladders for Anthropic adaptive models (4.6+). Model-defined
|
|
374
|
+
* so stale cached surfaces normalize on every build: Messages-API models with
|
|
375
|
+
* the real xhigh tier (4.7+) expose the full five-tier `low..max` scale;
|
|
376
|
+
* Opus/Sonnet 4.6 and every Bedrock adaptive model stay on the four-tier
|
|
377
|
+
* `low/medium/high/max` scale.
|
|
378
|
+
*/
|
|
379
|
+
function getAnthropicAdaptiveEfforts<TApi extends Api>(spec: ModelSpec<TApi>): readonly Effort[] | undefined {
|
|
380
|
+
const parsed = parseAnthropicModel(bareModelId(spec.id));
|
|
381
|
+
if (!parsed || !isAnthropicAdaptiveGenAtLeast(parsed, "4.6")) return undefined;
|
|
382
|
+
if (spec.api === "anthropic-messages" || spec.api === "bedrock-converse-stream") {
|
|
383
|
+
return anthropicModelHasRealXHighEffort(spec, parsed)
|
|
384
|
+
? FIVE_TIER_EFFORTS_LOW_TO_MAX
|
|
385
|
+
: FOUR_TIER_EFFORTS_LOW_TO_MAX;
|
|
386
|
+
}
|
|
387
|
+
if (isOpenRouterAnthropicAdaptiveReasoningModel(parsed, spec)) {
|
|
388
|
+
return isAnthropicAdaptiveGenAtLeast(parsed, "4.7") ? FIVE_TIER_EFFORTS_LOW_TO_MAX : FOUR_TIER_EFFORTS_LOW_TO_MAX;
|
|
389
|
+
}
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
|
|
354
393
|
function isOllamaCloudGlm52ReasoningEffortModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
355
394
|
return spec.api === "ollama-chat" && spec.provider === "ollama-cloud" && isGlm52ReasoningEffortModelId(spec.id);
|
|
356
395
|
}
|
|
@@ -395,62 +434,31 @@ function isZaiThinkingFormat(compat: CompatOf<Api>): boolean {
|
|
|
395
434
|
function inferDetectedEffortMap<TApi extends Api>(
|
|
396
435
|
spec: ModelSpec<TApi>,
|
|
397
436
|
compat: CompatOf<TApi>,
|
|
398
|
-
parsedModel: ParsedModel,
|
|
399
437
|
mode: ThinkingConfig["mode"],
|
|
400
438
|
): EffortMap | undefined {
|
|
401
439
|
if (mode === "anthropic-adaptive") {
|
|
402
440
|
if (isMinimaxReasoningModelOnAnthropicEndpoint(spec)) {
|
|
403
441
|
return MINIMAX_ANTHROPIC_ADAPTIVE_EFFORT_MAP;
|
|
404
442
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
// GLM-5.2 coding SKUs accept `reasoning_effort`, but the effort dialect is
|
|
410
|
-
// host-specific (verified against live endpoints):
|
|
411
|
-
// - Z.ai/Zhipu ("zai" dialect): the model exposes only none/high/max, so
|
|
412
|
-
// `xhigh` 400s — collapse minimal->none, low/medium/high->high, xhigh->max.
|
|
413
|
-
// - OpenRouter: `max` 400s and `xhigh` IS its max tier, so it passes `xhigh`
|
|
414
|
-
// through literally (no map; the tier is exposed via getModelDefinedEfforts).
|
|
415
|
-
// - Umans and Ollama Cloud expose only high/max on their GLM-5.2 routes.
|
|
416
|
-
// - Other openai-compat hosts (Fireworks, resellers) keep their distinct
|
|
417
|
-
// lower tiers and host quirks (e.g. Fireworks rejects `minimal`, so
|
|
418
|
-
// `minimal->none` stays) and only remap the top `xhigh` UI tier onto the
|
|
419
|
-
// genuine `max` budget. Filtered to supported efforts later.
|
|
420
|
-
const isGlm52 = isGlm52ReasoningEffortModelId(spec.id);
|
|
421
|
-
if (isGlm52 && isZaiThinkingFormat(compat)) {
|
|
422
|
-
return ZAI_GLM_52_REASONING_EFFORT_MAP;
|
|
423
|
-
}
|
|
424
|
-
if (isUmansGlm52ReasoningEffortModel(spec) || isOllamaCloudGlm52ReasoningEffortModel(spec)) {
|
|
425
|
-
return GLM_52_XHIGH_MAX_EFFORT_MAP;
|
|
426
|
-
}
|
|
427
|
-
if (isSakanaFuguReasoningModel(spec)) {
|
|
428
|
-
return FUGU_REASONING_EFFORT_MAP;
|
|
429
|
-
}
|
|
430
|
-
if (isGpt56PlusWireEffortModel(spec)) {
|
|
431
|
-
return SHIFTED_FIVE_TIER_EFFORT_MAP;
|
|
443
|
+
// Adaptive effort ladders are wire-exact (see
|
|
444
|
+
// getAnthropicAdaptiveEfforts) — no mapping needed.
|
|
445
|
+
return undefined;
|
|
432
446
|
}
|
|
433
447
|
if (!isOpenAICompatReasoningApi(spec.api)) {
|
|
434
448
|
return undefined;
|
|
435
449
|
}
|
|
436
|
-
let map: EffortMap | undefined;
|
|
437
450
|
if (spec.provider === "groq" && spec.id === "qwen/qwen3-32b") {
|
|
438
|
-
|
|
439
|
-
} else if (isDeepseekReasoningModel(spec)) {
|
|
440
|
-
map = DEEPSEEK_REASONING_EFFORT_MAP;
|
|
441
|
-
} else if (isOpenAICompatMimoReasoningEffortModel(spec, compat)) {
|
|
442
|
-
map = MIMO_REASONING_EFFORT_MAP;
|
|
443
|
-
} else if (modelMatchesHost(spec, "openrouter")) {
|
|
444
|
-
map = getOpenRouterAnthropicReasoningEffortMap(spec.id);
|
|
445
|
-
} else if (modelMatchesHost(spec, "fireworks")) {
|
|
446
|
-
map = FIREWORKS_REASONING_EFFORT_MAP;
|
|
451
|
+
return GROQ_QWEN3_32B_REASONING_EFFORT_MAP;
|
|
447
452
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if (isGlm52 && !isOpenRouterThinkingFormat(compat)) {
|
|
451
|
-
map = { ...map, ...GLM_52_XHIGH_MAX_EFFORT_MAP };
|
|
453
|
+
if (isOpenAICompatMimoReasoningEffortModel(spec, compat)) {
|
|
454
|
+
return MIMO_REASONING_EFFORT_MAP;
|
|
452
455
|
}
|
|
453
|
-
|
|
456
|
+
// Host quirk: Fireworks rejects `minimal` (maps to `none`) on ladders
|
|
457
|
+
// that genuinely include it. Filtered to supported efforts later.
|
|
458
|
+
if (modelMatchesHost(spec, "fireworks")) {
|
|
459
|
+
return FIREWORKS_REASONING_EFFORT_MAP;
|
|
460
|
+
}
|
|
461
|
+
return undefined;
|
|
454
462
|
}
|
|
455
463
|
|
|
456
464
|
function isSakanaFuguReasoningModel<TApi extends Api>(spec: ModelSpec<TApi>): boolean {
|
|
@@ -471,17 +479,6 @@ function isDeepseekReasoningModel<TApi extends Api>(spec: ModelSpec<TApi>): bool
|
|
|
471
479
|
);
|
|
472
480
|
}
|
|
473
481
|
|
|
474
|
-
function getOpenRouterAnthropicReasoningEffortMap(modelId: string): EffortMap | undefined {
|
|
475
|
-
const parsed = parseAnthropicModel(bareModelId(modelId));
|
|
476
|
-
if (!parsed) return undefined;
|
|
477
|
-
// Adaptive efforts on OpenRouter's completions front: Fable/Mythos, Sonnet 5+,
|
|
478
|
-
// and Opus 4.6+ only — older Sonnet versions stay on the plain effort vocabulary there.
|
|
479
|
-
if (!isAnthropicAdaptiveGenAtLeast(parsed, "4.6")) return undefined;
|
|
480
|
-
|
|
481
|
-
const hasRealXHigh = isAnthropicAdaptiveGenAtLeast(parsed, "4.7");
|
|
482
|
-
return hasRealXHigh ? SHIFTED_FIVE_TIER_EFFORT_MAP : ANTHROPIC_ADAPTIVE_EFFORT_MAP_4_TIER;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
482
|
function inferSupportedEfforts<TApi extends Api>(
|
|
486
483
|
parsedModel: ParsedModel,
|
|
487
484
|
spec: ModelSpec<TApi>,
|
|
@@ -507,10 +504,9 @@ function inferOpenAISupportedEfforts(model: OpenAIModel): readonly Effort[] {
|
|
|
507
504
|
if (model.variant === "codex-mini" && semverEqual(model.version, "5.1")) {
|
|
508
505
|
return GPT_5_1_CODEX_MINI_EFFORTS;
|
|
509
506
|
}
|
|
510
|
-
// 5.6+ exposes the
|
|
511
|
-
// low..max, with user `minimal` reaching the native `low` tier.
|
|
507
|
+
// 5.6+ exposes the wire-exact five-tier ladder low..max.
|
|
512
508
|
if (semverGte(model.version, "5.6")) {
|
|
513
|
-
return
|
|
509
|
+
return FIVE_TIER_EFFORTS_LOW_TO_MAX;
|
|
514
510
|
}
|
|
515
511
|
if (semverGte(model.version, "5.2")) {
|
|
516
512
|
return GPT_5_2_PLUS_EFFORTS;
|
|
@@ -554,16 +550,18 @@ function inferAnthropicSupportedEfforts<TApi extends Api>(
|
|
|
554
550
|
spec: ModelSpec<TApi>,
|
|
555
551
|
compat: CompatOf<TApi>,
|
|
556
552
|
): readonly Effort[] {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
553
|
+
// Ladders for adaptive-generation models (Opus 4.6+, Sonnet 5+,
|
|
554
|
+
// Fable/Mythos) are model-defined and already resolved by
|
|
555
|
+
// getAnthropicAdaptiveEfforts. Every other 4.6+ model on the Messages
|
|
556
|
+
// API (Sonnet/Haiku 4.6) still runs adaptive mode with the three-tier
|
|
557
|
+
// low/medium/high wire scale — no minimal, no max.
|
|
558
|
+
if (spec.api === "anthropic-messages" && semverGte(parsedModel.version, "4.6")) {
|
|
559
|
+
return LOW_MEDIUM_HIGH_REASONING_EFFORTS;
|
|
564
560
|
}
|
|
565
|
-
|
|
566
|
-
|
|
561
|
+
// Non-adaptive 4.6 models on Bedrock stay budget-mode, where minimal is
|
|
562
|
+
// a legitimate synthetic budget tier.
|
|
563
|
+
if (spec.api === "bedrock-converse-stream" && semverGte(parsedModel.version, "4.6")) {
|
|
564
|
+
return DEFAULT_REASONING_EFFORTS;
|
|
567
565
|
}
|
|
568
566
|
return inferFallbackEfforts(spec, compat);
|
|
569
567
|
}
|
|
@@ -752,6 +750,7 @@ export function mapEffortToGoogleThinkingLevel(effort: Effort): "MINIMAL" | "LOW
|
|
|
752
750
|
return "MEDIUM";
|
|
753
751
|
case Effort.High:
|
|
754
752
|
case Effort.XHigh:
|
|
753
|
+
case Effort.Max:
|
|
755
754
|
return "HIGH";
|
|
756
755
|
}
|
|
757
756
|
}
|