From 802daa8fcdebef4f690ef59974756c900387e30c Mon Sep 17 00:00:00 2001 From: kael-odin Date: Tue, 7 Jul 2026 18:13:21 +0800 Subject: [PATCH] fix(openai): recognize MiMo in thinking disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openAIThinkingDisableKind only matched dashscope/qwen/aliyun, deepseek/bigmodel/z.ai/zhipu, and gpt-5.1+/gpt-6. Xiaomi MiMo (api.xiaomimimo.com, model mimo-*) fell through to the default branch, so when a user set reasoning=disabled the adapter wrote no disable field and MiMo kept thinking enabled (extra latency + reasoning token cost contrary to user intent). Add xiaomimimo/mimo to the thinking_type case — MiMo uses the same thinking:{type:"disabled"} shape as deepseek/glm, confirmed in MiMo docs. - openai.go: +2 conditions in openAIThinkingDisableKind - openai_thinking_disable_test.go: cover MiMo (base/model/ultraspeed), regress deepseek/glm/z.ai/qwen/gpt-5.1/gpt-6/unknown, and verify applyOpenAIThinkingDisable writes thinking:{type:disabled} + deletes reasoning_effort for MiMo --- internal/backend/agent/model/openai.go | 5 +- .../model/openai_thinking_disable_test.go | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 internal/backend/agent/model/openai_thinking_disable_test.go diff --git a/internal/backend/agent/model/openai.go b/internal/backend/agent/model/openai.go index 4012831..798aaa6 100644 --- a/internal/backend/agent/model/openai.go +++ b/internal/backend/agent/model/openai.go @@ -1893,10 +1893,13 @@ func openAIThinkingDisableKind(baseURL string, modelID string, endpoint string) strings.Contains(base, "bigmodel") || strings.Contains(base, "z.ai") || strings.Contains(base, "zhipu") || + strings.Contains(base, "xiaomimimo") || + strings.Contains(base, "mimo") || strings.Contains(model, "deepseek") || strings.Contains(model, "glm") || strings.Contains(model, "zai") || - strings.Contains(model, "zhipu"): + strings.Contains(model, "zhipu") || + strings.Contains(model, "mimo"): return "thinking_type" case openAIModelSupportsReasoningNone(model): return "reasoning_none" diff --git a/internal/backend/agent/model/openai_thinking_disable_test.go b/internal/backend/agent/model/openai_thinking_disable_test.go new file mode 100644 index 0000000..f53b775 --- /dev/null +++ b/internal/backend/agent/model/openai_thinking_disable_test.go @@ -0,0 +1,84 @@ +package modeladapter + +import ( + "testing" +) + +// TestOpenAIThinkingDisableKindMiMo 验证小米 MiMo(base_url 含 xiaomimimo/mimo, +// model 含 mimo)被识别为 thinking_type 分支,从而在用户禁用思考时正确写入 +// thinking:{type:"disabled"}。回归覆盖 deepseek/glm/qwen/gpt-5 等既有分支。 +func TestOpenAIThinkingDisableKindMiMo(t *testing.T) { + tests := []struct { + name string + baseURL string + modelID string + endpoint string + want string + }{ + // MiMo —— 修复目标 + {name: "mimo official base + pro model", baseURL: "https://api.xiaomimimo.com/v1", modelID: "mimo-v2.5-pro", endpoint: "/chat/completions", want: "thinking_type"}, + {name: "mimo base by host keyword", baseURL: "https://api.xiaomimimo.com/v1", modelID: "mimo-v2.5", endpoint: "/chat/completions", want: "thinking_type"}, + {name: "mimo model only (custom base)", baseURL: "https://custom.proxy.example.com/v1", modelID: "mimo-v2.5-pro", endpoint: "/chat/completions", want: "thinking_type"}, + {name: "mimo ultraspeed variant", baseURL: "https://api.xiaomimimo.com/v1", modelID: "mimo-v2.5-pro-ultraspeed", endpoint: "/chat/completions", want: "thinking_type"}, + // 回归:既有 thinking_type 分支不受影响 + {name: "deepseek base", baseURL: "https://api.deepseek.com/v1", modelID: "deepseek-chat", endpoint: "/chat/completions", want: "thinking_type"}, + {name: "glm model via zhipu base", baseURL: "https://open.bigmodel.cn/api/paas/v4", modelID: "glm-4.6", endpoint: "/chat/completions", want: "thinking_type"}, + {name: "z.ai base", baseURL: "https://api.z.ai/api/paas/v4", modelID: "glm-4.5", endpoint: "/chat/completions", want: "thinking_type"}, + // 回归:enable_thinking 分支(qwen 系) + {name: "qwen via dashscope", baseURL: "https://dashscope.aliyuncs.com/v1", modelID: "qwen-max", endpoint: "/chat/completions", want: "enable_thinking"}, + {name: "qwen model keyword", baseURL: "https://custom.example.com/v1", modelID: "qwen3-coder", endpoint: "/chat/completions", want: "enable_thinking"}, + // 回归:reasoning_none 分支(gpt-5.1+/gpt-6) + {name: "gpt-5.1", baseURL: "https://api.openai.com/v1", modelID: "gpt-5.1", endpoint: "/chat/completions", want: "reasoning_none"}, + {name: "gpt-6", baseURL: "https://api.openai.com/v1", modelID: "gpt-6", endpoint: "/chat/completions", want: "reasoning_none"}, + // 回归:未知 provider 不做 disable + {name: "unknown provider", baseURL: "https://api.unknown-llm.com/v1", modelID: "some-model", endpoint: "/chat/completions", want: ""}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := openAIThinkingDisableKind(tc.baseURL, tc.modelID, tc.endpoint) + if got != tc.want { + t.Fatalf("openAIThinkingDisableKind(%q, %q, %q) = %q, want %q", tc.baseURL, tc.modelID, tc.endpoint, got, tc.want) + } + }) + } +} + +// TestApplyOpenAIThinkingDisableMiMo 验证当 ThinkingEffort=disabled 且 provider +// 为 MiMo 时,applyOpenAIThinkingDisable 会写入 thinking:{type:"disabled"} 并删除 +// reasoning_effort,与 deepseek/glm 行为一致。 +func TestApplyOpenAIThinkingDisableMiMo(t *testing.T) { + req := StreamRequest{ThinkingEffort: "disabled", RequestKnobs: map[string]any{}} + body := map[string]any{ + "model": "mimo-v2.5-pro", + "messages": []map[string]any{{"role": "user", "content": "hi"}}, + "reasoning_effort": "high", + } + applyOpenAIThinkingDisable(body, req, "https://api.xiaomimimo.com/v1", "mimo-v2.5-pro", "/chat/completions") + + thinking, ok := body["thinking"].(map[string]any) + if !ok { + t.Fatalf("expected body[thinking] to be map[string]any, got %T (%v)", body["thinking"], body["thinking"]) + } + if thinking["type"] != "disabled" { + t.Fatalf("expected thinking.type=disabled, got %v", thinking["type"]) + } + if _, stillPresent := body["reasoning_effort"]; stillPresent { + t.Fatalf("reasoning_effort should be deleted when thinking disabled for mimo, got %v", body["reasoning_effort"]) + } + if got := req.RequestKnobs["thinking_disabled_provider_param"]; got != "thinking.type" { + t.Fatalf("expected request knob thinking_disabled_provider_param=thinking.type, got %v", got) + } +} + +// TestApplyOpenAIThinkingDisableMiMoNotTriggered 验证非 disabled 时不会误写 disable 字段。 +func TestApplyOpenAIThinkingDisableMiMoNotTriggered(t *testing.T) { + req := StreamRequest{ThinkingEffort: "high", RequestKnobs: map[string]any{}} + body := map[string]any{"model": "mimo-v2.5-pro", "reasoning_effort": "high"} + applyOpenAIThinkingDisable(body, req, "https://api.xiaomimimo.com/v1", "mimo-v2.5-pro", "/chat/completions") + if _, present := body["thinking"]; present { + t.Fatalf("thinking should not be injected when ThinkingEffort != disabled, got %v", body["thinking"]) + } + if body["reasoning_effort"] != "high" { + t.Fatalf("reasoning_effort should be preserved when not disabled, got %v", body["reasoning_effort"]) + } +}