1313 */
1414
1515import type { ThinkingLevel } from "@/common/types/thinking" ;
16+ import { getReasoningConfig } from "@/common/constants/reasoning-config" ;
1617import modelsData from "@/common/utils/tokens/models.json" ;
1718
1819/**
@@ -48,53 +49,33 @@ function getModelMetadata(modelString: string): Record<string, unknown> | null {
4849 * Returns the thinking policy for a given model.
4950 *
5051 * Rules:
51- * - openai:gpt-5-pro → ["high"] (only supported level)
52- * - Models without supports_reasoning in models.json → ["off"]
53- * - xAI Grok-[1-9]* → ["off", "high"] (binary reasoning)
54- * - Gemini 3 → ["low", "high"]
55- * - default → ["off", "low", "medium", "high"] (all levels selectable)
56- *
57- * Tolerates version suffixes (e.g., gpt-5-pro-2025-10-06).
58- * Does NOT match gpt-5-pro-mini (uses negative lookahead).
52+ * 1. Check reasoning-config.ts for explicit model policies
53+ * 2. Check models.json for supports_reasoning: false → ["off"]
54+ * 3. Default → ["off", "low", "medium", "high"]
5955 */
6056export function getThinkingPolicyForModel ( modelString : string ) : ThinkingPolicy {
61- // Match "openai:" followed by optional whitespace and "gpt-5-pro"
62- // Allow version suffixes like "-2025-10-06" but NOT "-mini" or other text suffixes
63- if ( / ^ o p e n a i : \s * g p t - 5 - p r o (? ! - [ a - z ] ) / . test ( modelString ) ) {
64- return [ "high" ] ;
65- }
66-
67- // Gemini 3 Pro only supports "low" and "high" reasoning levels
68- if ( modelString . includes ( "gemini-3" ) ) {
69- return [ "low" , "high" ] ;
57+ // Check explicit config first
58+ const config = getReasoningConfig ( modelString ) ;
59+ if ( config ) {
60+ return config ;
7061 }
7162
72- // xAI Grok-[1-9]* models only support binary on/off reasoning (no gradual levels)
73- // Use "high" to represent "reasoning enabled" for consistency with backend logic
74- // Note: grok-code does not match this pattern
75- if ( modelString . startsWith ( "xai:" ) && / g r o k - [ 1 - 9 ] / . test ( modelString ) ) {
76- return [ "off" , "high" ] ;
77- }
78-
79- // Check models.json for supports_reasoning
63+ // Check models.json for models that don't support reasoning
8064 const metadata = getModelMetadata ( modelString ) ;
8165 if ( metadata ?. supports_reasoning === false ) {
8266 return [ "off" ] ;
8367 }
8468
85- // Default policy : all levels selectable (for models with supports_reasoning: true or unknown models)
69+ // Default: all levels selectable
8670 return [ "off" , "low" , "medium" , "high" ] ;
8771}
8872
8973/**
9074 * Enforce thinking policy by clamping requested level to allowed set.
9175 *
92- * Fallback strategy:
93- * 1. If requested level is allowed, use it
94- * 2. If requested level is non-"off" but not allowed, map to highest allowed non-"off" level
95- * (preserves user intent to have reasoning enabled for binary models like Grok)
96- * 3. If "medium" is allowed, use it (reasonable default)
97- * 4. Otherwise use first allowed level
76+ * If the requested level isn't allowed:
77+ * - If user wanted reasoning (non-"off"), pick the highest available non-"off" level
78+ * - Otherwise return the first allowed level
9879 */
9980export function enforceThinkingPolicy (
10081 modelString : string ,
@@ -106,18 +87,12 @@ export function enforceThinkingPolicy(
10687 return requested ;
10788 }
10889
109- // If user requested a non-"off" level but it's not allowed, preserve reasoning intent
110- // by mapping to the highest non-"off" level available (e.g., "medium" → "high" for Grok)
90+ // If user wanted reasoning, keep it on with the best available level
11191 if ( requested !== "off" ) {
112- const nonOffLevels = allowed . filter ( ( level ) => level !== "off" ) ;
113- if ( nonOffLevels . length > 0 ) {
114- // Return highest available: prefer high > medium > low
115- if ( nonOffLevels . includes ( "high" ) ) return "high" ;
116- if ( nonOffLevels . includes ( "medium" ) ) return "medium" ;
117- if ( nonOffLevels . includes ( "low" ) ) return "low" ;
118- }
92+ if ( allowed . includes ( "high" ) ) return "high" ;
93+ if ( allowed . includes ( "medium" ) ) return "medium" ;
94+ if ( allowed . includes ( "low" ) ) return "low" ;
11995 }
12096
121- // Fallback: prefer "medium" if allowed, else use first allowed level
122- return allowed . includes ( "medium" ) ? "medium" : allowed [ 0 ] ;
97+ return allowed [ 0 ] ;
12398}
0 commit comments