From 70aaa774be92d8c9ffb6b9745f5c47bb69b8198c Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Sat, 23 May 2026 01:49:26 -0700 Subject: [PATCH] fix(opencode-go): emit Kimi reasoning_effort, match KimiProfile shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Kimi K2 branch added in the prior commit only emitted extra_body.thinking and dropped reasoning_effort entirely. KimiProfile (api.moonshot.ai/v1) sends both fields, and OpenCode Go proxies to the same Moonshot backend. Mirror that shape on the Go path so /reasoning effort actually reaches Kimi. - low/medium/high pass through verbatim - xhigh/max clamp to high (Moonshot's max supported value) - minimal / unknown effort → omit reasoning_effort, keep thinking on - disabled / no config → unchanged - DeepSeek branch unchanged --- .../model-providers/opencode-zen/__init__.py | 25 +++++++++++----- .../test_opencode_go_profile.py | 29 ++++++++++++------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/plugins/model-providers/opencode-zen/__init__.py b/plugins/model-providers/opencode-zen/__init__.py index 6f5cda9f15d..385741f09a1 100644 --- a/plugins/model-providers/opencode-zen/__init__.py +++ b/plugins/model-providers/opencode-zen/__init__.py @@ -41,13 +41,24 @@ class OpenCodeGoProfile(ProviderProfile): top_level: dict[str, Any] = {} if _is_kimi_k2_model(model): - # Kimi K2 uses Moonshot's native binary thinking switch here, not - # OpenRouter's normalized extra_body.reasoning object. - if isinstance(reasoning_config, dict): - enabled = reasoning_config.get("enabled") is not False - extra_body["thinking"] = { - "type": "enabled" if enabled else "disabled" - } + # Kimi K2 on OpenCode Go uses Moonshot's native wire shape: + # extra_body.thinking (binary toggle) + top-level reasoning_effort + # (low|medium|high). Mirrors the KimiProfile (api.moonshot.ai/v1). + if not isinstance(reasoning_config, dict): + # No config → leave server defaults alone. + return extra_body, top_level + + enabled = reasoning_config.get("enabled") is not False + extra_body["thinking"] = {"type": "enabled" if enabled else "disabled"} + + if not enabled: + return extra_body, top_level + + effort = (reasoning_config.get("effort") or "").strip().lower() + if effort in {"xhigh", "max"}: + top_level["reasoning_effort"] = "high" + elif effort in {"low", "medium", "high"}: + top_level["reasoning_effort"] = effort return extra_body, top_level if not _is_deepseek_thinking_model(model): diff --git a/tests/plugins/model_providers/test_opencode_go_profile.py b/tests/plugins/model_providers/test_opencode_go_profile.py index 5e4c3f2b29d..7e6b5c8f64c 100644 --- a/tests/plugins/model_providers/test_opencode_go_profile.py +++ b/tests/plugins/model_providers/test_opencode_go_profile.py @@ -17,17 +17,17 @@ def opencode_go_profile(): class TestOpenCodeGoKimiReasoning: - """Kimi K2 models use binary thinking controls on OpenCode Go.""" + """Kimi K2 models use Moonshot's thinking + reasoning_effort shape on OpenCode Go.""" - def test_high_effort_enables_thinking_without_effort(self, opencode_go_profile): + def test_high_effort_emits_thinking_and_effort(self, opencode_go_profile): extra_body, top_level = opencode_go_profile.build_api_kwargs_extras( reasoning_config={"enabled": True, "effort": "high"}, model="kimi-k2.6", ) assert extra_body == {"thinking": {"type": "enabled"}} - assert top_level == {} + assert top_level == {"reasoning_effort": "high"} - def test_disabled_emits_thinking_disabled(self, opencode_go_profile): + def test_disabled_emits_thinking_disabled_without_effort(self, opencode_go_profile): extra_body, top_level = opencode_go_profile.build_api_kwargs_extras( reasoning_config={"enabled": False}, model="kimi-k2.6", @@ -36,6 +36,7 @@ class TestOpenCodeGoKimiReasoning: assert top_level == {} def test_minimal_effort_enables_thinking_without_effort(self, opencode_go_profile): + # "minimal" is not a Moonshot-supported value — drop it, keep thinking on. extra_body, top_level = opencode_go_profile.build_api_kwargs_extras( reasoning_config={"enabled": True, "effort": "minimal"}, model="kimi-k2.6", @@ -50,14 +51,22 @@ class TestOpenCodeGoKimiReasoning: "max", ], ) - def test_strong_efforts_enable_thinking_without_effort( - self, opencode_go_profile, effort - ): - extra_body, _ = opencode_go_profile.build_api_kwargs_extras( + def test_strong_efforts_clamp_to_high(self, opencode_go_profile, effort): + extra_body, top_level = opencode_go_profile.build_api_kwargs_extras( reasoning_config={"enabled": True, "effort": effort}, model="moonshotai/kimi-k2.6", ) assert extra_body == {"thinking": {"type": "enabled"}} + assert top_level == {"reasoning_effort": "high"} + + def test_low_and_medium_pass_through(self, opencode_go_profile): + for effort in ("low", "medium"): + extra_body, top_level = opencode_go_profile.build_api_kwargs_extras( + reasoning_config={"enabled": True, "effort": effort}, + model="kimi-k2.5", + ) + assert extra_body == {"thinking": {"type": "enabled"}} + assert top_level == {"reasoning_effort": effort} def test_no_config_preserves_server_default(self, opencode_go_profile): extra_body, top_level = opencode_go_profile.build_api_kwargs_extras( @@ -140,7 +149,7 @@ class TestOpenCodeGoModelGating: class TestOpenCodeGoFullKwargsIntegration: """End-to-end transport kwargs include the profile-provided controls.""" - def test_kimi_reasoning_reaches_extra_body(self, opencode_go_profile): + def test_kimi_reasoning_reaches_extra_body_and_top_level(self, opencode_go_profile): from agent.transports.chat_completions import ChatCompletionsTransport kwargs = ChatCompletionsTransport().build_kwargs( @@ -152,7 +161,7 @@ class TestOpenCodeGoFullKwargsIntegration: base_url="https://opencode.ai/zen/go/v1", ) assert kwargs["extra_body"] == {"thinking": {"type": "enabled"}} - assert "reasoning_effort" not in kwargs + assert kwargs["reasoning_effort"] == "high" def test_deepseek_thinking_reaches_extra_body_and_top_level( self, opencode_go_profile