diff --git a/internal/registry/model_definitions.go b/internal/registry/model_definitions.go index 7a4bdf0c..ca894ba6 100644 --- a/internal/registry/model_definitions.go +++ b/internal/registry/model_definitions.go @@ -630,6 +630,13 @@ func GetQwenModels() []*ModelInfo { } } +// iFlowThinkingSupport is a shared ThinkingSupport configuration for iFlow models +// that support thinking mode via chat_template_kwargs.enable_thinking (boolean toggle). +// Uses level-based configuration so standard normalization flows apply before conversion. +var iFlowThinkingSupport = &ThinkingSupport{ + Levels: []string{"none", "auto", "minimal", "low", "medium", "high", "xhigh"}, +} + // GetIFlowModels returns supported models for iFlow OAuth accounts. func GetIFlowModels() []*ModelInfo { entries := []struct { @@ -645,9 +652,9 @@ func GetIFlowModels() []*ModelInfo { {ID: "qwen3-vl-plus", DisplayName: "Qwen3-VL-Plus", Description: "Qwen3 multimodal vision-language", Created: 1758672000}, {ID: "qwen3-max-preview", DisplayName: "Qwen3-Max-Preview", Description: "Qwen3 Max preview build", Created: 1757030400}, {ID: "kimi-k2-0905", DisplayName: "Kimi-K2-Instruct-0905", Description: "Moonshot Kimi K2 instruct 0905", Created: 1757030400}, - {ID: "glm-4.6", DisplayName: "GLM-4.6", Description: "Zhipu GLM 4.6 general model", Created: 1759190400}, + {ID: "glm-4.6", DisplayName: "GLM-4.6", Description: "Zhipu GLM 4.6 general model", Created: 1759190400, Thinking: iFlowThinkingSupport}, {ID: "kimi-k2", DisplayName: "Kimi-K2", Description: "Moonshot Kimi K2 general model", Created: 1752192000}, - {ID: "kimi-k2-thinking", DisplayName: "Kimi-K2-Thinking", Description: "Moonshot Kimi K2 thinking model", Created: 1762387200, Thinking: &ThinkingSupport{Levels: []string{"low", "medium", "high"}}}, + {ID: "kimi-k2-thinking", DisplayName: "Kimi-K2-Thinking", Description: "Moonshot Kimi K2 thinking model", Created: 1762387200}, {ID: "deepseek-v3.2-chat", DisplayName: "DeepSeek-V3.2", Description: "DeepSeek V3.2 Chat", Created: 1764576000}, {ID: "deepseek-v3.2-reasoner", DisplayName: "DeepSeek-V3.2", Description: "DeepSeek V3.2 Reasoner", Created: 1764576000}, {ID: "deepseek-v3.2", DisplayName: "DeepSeek-V3.2-Exp", Description: "DeepSeek V3.2 experimental", Created: 1759104000}, @@ -655,10 +662,10 @@ func GetIFlowModels() []*ModelInfo { {ID: "deepseek-r1", DisplayName: "DeepSeek-R1", Description: "DeepSeek reasoning model R1", Created: 1737331200}, {ID: "deepseek-v3", DisplayName: "DeepSeek-V3-671B", Description: "DeepSeek V3 671B", Created: 1734307200}, {ID: "qwen3-32b", DisplayName: "Qwen3-32B", Description: "Qwen3 32B", Created: 1747094400}, - {ID: "qwen3-235b-a22b-thinking-2507", DisplayName: "Qwen3-235B-A22B-Thinking", Description: "Qwen3 235B A22B Thinking (2507)", Created: 1753401600, Thinking: &ThinkingSupport{Levels: []string{"low", "medium", "high"}}}, + {ID: "qwen3-235b-a22b-thinking-2507", DisplayName: "Qwen3-235B-A22B-Thinking", Description: "Qwen3 235B A22B Thinking (2507)", Created: 1753401600}, {ID: "qwen3-235b-a22b-instruct", DisplayName: "Qwen3-235B-A22B-Instruct", Description: "Qwen3 235B A22B Instruct", Created: 1753401600}, {ID: "qwen3-235b", DisplayName: "Qwen3-235B-A22B", Description: "Qwen3 235B A22B", Created: 1753401600}, - {ID: "minimax-m2", DisplayName: "MiniMax-M2", Description: "MiniMax M2", Created: 1758672000, Thinking: &ThinkingSupport{Levels: []string{"low", "medium", "high"}}}, + {ID: "minimax-m2", DisplayName: "MiniMax-M2", Description: "MiniMax M2", Created: 1758672000}, } models := make([]*ModelInfo, 0, len(entries)) for _, entry := range entries { diff --git a/internal/runtime/executor/iflow_executor.go b/internal/runtime/executor/iflow_executor.go index ad0b4d2a..0ed3c111 100644 --- a/internal/runtime/executor/iflow_executor.go +++ b/internal/runtime/executor/iflow_executor.go @@ -66,6 +66,7 @@ func (e *IFlowExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, re if errValidate := ValidateThinkingConfig(body, upstreamModel); errValidate != nil { return resp, errValidate } + body = applyIFlowThinkingConfig(body) body = applyPayloadConfig(e.cfg, req.Model, body) endpoint := strings.TrimSuffix(baseURL, "/") + iflowDefaultEndpoint @@ -157,6 +158,7 @@ func (e *IFlowExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Au if errValidate := ValidateThinkingConfig(body, upstreamModel); errValidate != nil { return nil, errValidate } + body = applyIFlowThinkingConfig(body) // Ensure tools array exists to avoid provider quirks similar to Qwen's behaviour. toolsResult := gjson.GetBytes(body, "tools") if toolsResult.Exists() && toolsResult.IsArray() && len(toolsResult.Array()) == 0 { @@ -442,3 +444,21 @@ func ensureToolsArray(body []byte) []byte { } return updated } + +// applyIFlowThinkingConfig converts normalized reasoning_effort to iFlow chat_template_kwargs.enable_thinking. +// This should be called after NormalizeThinkingConfig has processed the payload. +// iFlow only supports boolean enable_thinking, so any non-"none" effort enables thinking. +func applyIFlowThinkingConfig(body []byte) []byte { + effort := gjson.GetBytes(body, "reasoning_effort") + if !effort.Exists() { + return body + } + + val := strings.ToLower(strings.TrimSpace(effort.String())) + enableThinking := val != "none" && val != "" + + body, _ = sjson.DeleteBytes(body, "reasoning_effort") + body, _ = sjson.SetBytes(body, "chat_template_kwargs.enable_thinking", enableThinking) + + return body +} diff --git a/internal/runtime/executor/payload_helpers.go b/internal/runtime/executor/payload_helpers.go index b0eafbb7..ff2d6ab4 100644 --- a/internal/runtime/executor/payload_helpers.go +++ b/internal/runtime/executor/payload_helpers.go @@ -273,7 +273,7 @@ func StripThinkingFields(payload []byte, effortOnly bool) []byte { "reasoning.effort", } if !effortOnly { - fieldsToRemove = append([]string{"reasoning"}, fieldsToRemove...) + fieldsToRemove = append([]string{"reasoning", "thinking"}, fieldsToRemove...) } out := payload for _, field := range fieldsToRemove {