hermes - 💡(How to fix) Fix opencode-go: Kimi K2 models fail with HTTP 400 "cannot specify both 'thinking' and 'reasoning_effort

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Kimi K2.5 and K2.6 models on the opencode-go provider fail immediately with a non-retryable BadRequestError:

HTTP 400: Error from provider: cannot specify both 'thinking' and 'reasoning_effort'

Error Message

HTTP 400: Error from provider: cannot specify both 'thinking' and 'reasoning_effort'

Root Cause

In plugins/model-providers/opencode-zen/__init__.py, the OpenCodeGoProfile.build_api_kwargs_extras() method for Kimi K2 models unconditionally sends BOTH:

  • extra_body.thinking = {"type": "enabled"}
  • top_level.reasoning_effort = "<effort>" (from agent config)

Moonshot's backend rejects requests containing both parameters simultaneously.

Fix Action

Fix

When reasoning_effort has a value, skip sending extra_body.thinking to avoid the collision. Only send extra_body.thinking when reasoning_effort is empty/not set.

         if _is_kimi_k2_model(model):
-            # 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).
+            # Kimi K2 on OpenCode Go uses Moonshot's native wire shape.
+            # WARNING: Moonshot rejects requests that include BOTH
+            # extra_body.thinking AND top-level reasoning_effort.
             if not isinstance(reasoning_config, dict):
                 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:
+                extra_body["thinking"] = {"type": "disabled"}
                 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
+
+            # Only send thinking toggle when NOT also sending reasoning_effort
+            if not top_level.get("reasoning_effort"):
+                extra_body["thinking"] = {"type": "enabled"}
+
             return extra_body, top_level

Code Example

HTTP 400: Error from provider: cannot specify both 'thinking' and 'reasoning_effort'

---

if _is_kimi_k2_model(model):
-            # 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).
+            # Kimi K2 on OpenCode Go uses Moonshot's native wire shape.
+            # WARNING: Moonshot rejects requests that include BOTH
+            # extra_body.thinking AND top-level reasoning_effort.
             if not isinstance(reasoning_config, dict):
                 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:
+                extra_body["thinking"] = {"type": "disabled"}
                 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
+
+            # Only send thinking toggle when NOT also sending reasoning_effort
+            if not top_level.get("reasoning_effort"):
+                extra_body["thinking"] = {"type": "enabled"}
+
             return extra_body, top_level
RAW_BUFFERClick to expand / collapse

Description

Kimi K2.5 and K2.6 models on the opencode-go provider fail immediately with a non-retryable BadRequestError:

HTTP 400: Error from provider: cannot specify both 'thinking' and 'reasoning_effort'

Root Cause

In plugins/model-providers/opencode-zen/__init__.py, the OpenCodeGoProfile.build_api_kwargs_extras() method for Kimi K2 models unconditionally sends BOTH:

  • extra_body.thinking = {"type": "enabled"}
  • top_level.reasoning_effort = "<effort>" (from agent config)

Moonshot's backend rejects requests containing both parameters simultaneously.

Steps to Reproduce

  1. Set model.default: deepseek-v4-pro and agent.reasoning_effort: medium in config
  2. Provider: opencode-go
  3. Switch model to kimi-k2.6 via /model kimi-k2.6
  4. Send any message → HTTP 400 on first API call

Fix

When reasoning_effort has a value, skip sending extra_body.thinking to avoid the collision. Only send extra_body.thinking when reasoning_effort is empty/not set.

         if _is_kimi_k2_model(model):
-            # 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).
+            # Kimi K2 on OpenCode Go uses Moonshot's native wire shape.
+            # WARNING: Moonshot rejects requests that include BOTH
+            # extra_body.thinking AND top-level reasoning_effort.
             if not isinstance(reasoning_config, dict):
                 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:
+                extra_body["thinking"] = {"type": "disabled"}
                 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
+
+            # Only send thinking toggle when NOT also sending reasoning_effort
+            if not top_level.get("reasoning_effort"):
+                extra_body["thinking"] = {"type": "enabled"}
+
             return extra_body, top_level

Environment

  • Hermes Agent (latest from main, commit 50aaf0c)
  • Provider: opencode-go (OpenCode Go subscription)
  • Affected models: kimi-k2.5, kimi-k2.6

Additional Notes

The native KimiProfile (plugins/model-providers/kimi-coding/init.py) also sends both parameters but targets api.moonshot.ai/v1 directly — that endpoint may accept both. The OpenCode Go proxy (opencode.ai/zen/go/v1) appears to forward to a Moonshot endpoint with stricter validation.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING