@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 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
@@ -4,6 +4,7 @@ export declare const enum Effort {
4
4
  Low = "low",
5
5
  Medium = "medium",
6
6
  High = "high",
7
- XHigh = "xhigh"
7
+ XHigh = "xhigh",
8
+ Max = "max"
8
9
  }
9
10
  export declare const THINKING_EFFORTS: readonly Effort[];
@@ -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;
@@ -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.3.15",
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.3.15",
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.3.15",
42
+ "@oh-my-pi/pi-ai": "16.4.0",
43
43
  "@types/bun": "^1.3.14"
44
44
  },
45
45
  "engines": {
@@ -71,31 +71,11 @@ const DSML_HEALING_PROVIDERS = new Set([
71
71
  "openrouter",
72
72
  ]);
73
73
 
74
- /**
75
- * Ollama's OpenAI-compatible `reasoning.effort` only accepts
76
- * `high|medium|low|max|none`; OMP's `minimal`/`xhigh` levels make the server
77
- * reject the turn with HTTP 400 `invalid reasoning value`. Map the two
78
- * unsupported levels onto the closest accepted ones. Stamped in the compat
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
 
@@ -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
  ];
@@ -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
- const GLM_52_HIGH_MAX_REASONING_EFFORTS: readonly Effort[] = [Effort.High, Effort.XHigh];
65
-
66
- const FUGU_REASONING_EFFORTS: readonly Effort[] = [Effort.High, Effort.XHigh];
67
- const FUGU_REASONING_EFFORT_MAP: Readonly<EffortMap> = {
68
- [Effort.XHigh]: "max",
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 restrictions still normalize stale cached capability
176
- * surfaces before request-time code can observe them.
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, parsed, thinking.mode, normalizedEfforts)
189
- : effortsChanged
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, parsed, config.mode, config.efforts);
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, parsedModel, mode);
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 shifted five-tier map applies. Devin (`devin-agent`)
304
- * selects effort by routing to per-tier sibling model ids instead and must
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
- // Z.ai/Zhipu and OpenRouter both surface GLM-5.2's full effort ladder,
328
- // including the top `xhigh` (= "max") tier; Umans and Ollama Cloud
329
- // expose only high/max.
330
- if (isZaiThinkingFormat(compat) || isOpenRouterThinkingFormat(compat)) {
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 (isUmansGlm52ReasoningEffortModel(spec) || isOllamaCloudGlm52ReasoningEffortModel(spec)) {
334
- return GLM_52_HIGH_MAX_REASONING_EFFORTS;
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 FUGU_REASONING_EFFORTS;
332
+ return HIGH_MAX_REASONING_EFFORTS;
339
333
  }
340
334
  if (isGpt56PlusWireEffortModel(spec)) {
341
- // Normalize stale baked/discovered `low..xhigh` surfaces to the full
342
- // five-tier ladder so the shifted map keeps the native `low` tier
343
- // reachable (user `minimal`).
344
- return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
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
- return anthropicModelHasRealXHighEffort(spec, parsedModel)
406
- ? SHIFTED_FIVE_TIER_EFFORT_MAP
407
- : ANTHROPIC_ADAPTIVE_EFFORT_MAP_4_TIER;
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
- map = GROQ_QWEN3_32B_REASONING_EFFORT_MAP;
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
- // Overlay GLM-5.2's top-tier `xhigh -> max` on the host base map, except on
449
- // OpenRouter (xhigh IS its max tier; `max` 400s there).
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
- return map;
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 full five-tier ladder: the shifted wire map spans
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 DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
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
- if (
558
- (spec.api === "anthropic-messages" || spec.api === "bedrock-converse-stream") &&
559
- semverGte(parsedModel.version, "4.6")
560
- ) {
561
- return isAnthropicAdaptiveGenAtLeast(parsedModel, "4.6")
562
- ? DEFAULT_REASONING_EFFORTS_WITH_XHIGH
563
- : DEFAULT_REASONING_EFFORTS;
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
- if (isOpenRouterAnthropicAdaptiveReasoningModel(parsedModel, spec)) {
566
- return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
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
  }