Skip to content

[Bug] Variant body-level fields (e.g. chat_template_kwargs) are dropped before the request #42876

Closed as not planned

Description

@d9beuD

Description

Body-level fields declared in a model's variants entry never reach the HTTP request. The variant is merged into options correctly inside opencode, but the fields are lost before the wire.

I verified this with a logging reverse proxy between opencode and the server, so this is the actual request body, not an inference.

Config declares a variant carrying chat_template_kwargs (needed to enable thinking on Qwen3.8 via its chat template):

"variants": {
  "low": {
    "temperature": 1.0, "top_p": 0.95, "top_k": 20,
    "chat_template_kwargs": { "enable_thinking": true, "reasoning_effort": "low" }
  }
}

Agent uses "variant": "low". Captured request body:

{
  "model": "Qwen3.8-27B-oQ6e-mtp",
  "max_tokens": 32000,
  "top_p": 1,
  "stream": true
}

chat_template_kwargs, temperature and top_k are all gone; top_p is the hardcoded value from ProviderTransform.topP(), not the variant's.

Sending the same chat_template_kwargs straight to the same endpoint with curl works, so the server accepts it:

POST /v1/messages  {"chat_template_kwargs":{"enable_thinking":true,"reasoning_effort":"banana"}}
-> {"error":{"message":"Chat template error: Unexpected reasoning effort banana. ..."}}

As far as I can tell the loss happens at packages/opencode/src/provider/transform.ts:1405:

const key = sdkKey(model.api.npm) ?? (usesDotSplitOptions ? model.providerID.split(".")[0] : model.providerID)
return { [key]: normalized }

Options are handed to the AI SDK as providerOptions[key], and the adapter validates that object against its own schema, so keys it does not know are dropped. mergeOptions at session/llm/request.ts:91 does include the variant, so this is not a merge bug.

This may affect shipped functionality, not just custom providers. ProviderTransform.variants() (transform.ts:729) returns chat_template_kwargs for MiniMax-M3 on @ai-sdk/anthropic and @ai-sdk/openai-compatible:

return {
  none:     { chat_template_kwargs: { thinking_mode: "disabled" } },
  thinking: { chat_template_kwargs: { thinking_mode: "enabled"  } },
}

If the analysis above is right those built-in variants go the same way. I have not tested MiniMax-M3 myself, so I am flagging it rather than asserting it.

Previously reported in #42300 for @ai-sdk/openai-compatible; that issue was auto-closed for template non-compliance rather than on merit. This report adds a second adapter and a captured request body.

specs/v2/config.md:265 mentions agent-local options carrying body overrides, which would be a natural place to fix this.

Plugins

none (reproduced with a minimal standalone config)

OpenCode version

1.18.18

Steps to reproduce

  1. Start any OpenAI/Anthropic-compatible server that accepts extra body fields. I used oMLX serving Qwen3.8-27B on 127.0.0.1:8001.

  2. Put a logging proxy in front of it that dumps the request body and forwards to the server (any tiny HTTP proxy will do), listening on 127.0.0.1:8009.

  3. Minimal config pointing at the proxy:

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "px": {
      "npm": "@ai-sdk/anthropic",
      "options": { "baseURL": "http://127.0.0.1:8009/v1", "apiKey": "x" },
      "models": {
        "Qwen3.8-27B-oQ6e-mtp": {
          "reasoning": true,
          "limit": { "context": 262144, "output": 262144 },
          "variants": {
            "low": { "chat_template_kwargs": { "enable_thinking": true, "reasoning_effort": "low" } }
          }
        }
      }
    }
  },
  "model": "px/Qwen3.8-27B-oQ6e-mtp",
  "agent": { "probe": { "model": "px/Qwen3.8-27B-oQ6e-mtp", "variant": "low" } }
}
  1. OPENCODE_CONFIG=<that file> opencode run --agent probe "hi"

  2. Look at the proxy log: the body has no chat_template_kwargs.

Screenshot and/or share link

n/a — captured request bodies are inline above.

Operating System

macOS (Darwin 25.5.0), Apple Silicon

Terminal

n/a — reproduced headless with opencode run

Activity

  1. github-actions commented on Aug 16, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of, or closely related to, existing issues. Please check:

    If these are considered the same underlying issue, it may be worth reopening or linking #42300 rather than tracking it separately.

  2. AnshulJ999 commented on Aug 30, 2026

    @AnshulJ999

    Encountered the same issue (#46314) and is breaking effort levels for me. Effort levels are basically a no-op until this gets fixed; every model defaults to provider-set default effort.

  3. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

  4. huornlmj commented on Oct 27, 2026

    @huornlmj

    But v2 is a hugely sub-par compared to v1. I've tried v2 and it's a show stopper in the new bugs it brings, so moving to v2 isn't a solution to this.

    Using opencode 1.18.35 and local qwen3.8:27b, trying to control reasoning via variant yields:

    "body": {
      "chat_template_kwargs": {
        "enable_thinking": false
      }
    }
    

    but it needs to actually be the following for qwen3.8:27b:

    "chat_template_kwargs": {
      "enable_thinking": false
    }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions