| 1 | # Reasoning controls by provider |
| 2 | |
| 3 | Reasonix exposes a single `/effort` knob (and the per-provider `effort` / |
| 4 | `thinking` config fields), but OpenAI-compatible backends disagree on *how* |
| 5 | chain-of-thought is requested on the wire. The `openai` provider adapts the |
| 6 | request shape per backend; this table is the reference for which protocol each |
| 7 | known backend uses and which parameters it honours or ignores. |
| 8 | |
| 9 | ## Auto-detected backends |
| 10 | |
| 11 | These are recognised by base URL (see `internal/provider/openai/host.go`) and |
| 12 | get a tailored request shape automatically — no extra config needed. |
| 13 | |
| 14 | | Provider | Base URL | Reasoning control | `/effort` levels | Notes | |
| 15 | |----------|----------|-------------------|------------------|-------| |
| 16 | | DeepSeek V4 Flash | `api.deepseek.com`, `*.deepseek.com` | `thinking.type` + `reasoning_effort` (depth) | `auto`, `disabled`, `low`, `high`, `max` | Thinking on by default; `disabled` turns it off via `thinking.type=disabled`. Compatibility input `medium` normalizes to `high`, while `xhigh` normalizes to `high`. | |
| 17 | | DeepSeek V4 Pro | `api.deepseek.com`, `*.deepseek.com` | `thinking.type` + `reasoning_effort` (depth) | `auto`, `disabled`, `high`, `max` | Thinking on by default; `disabled` turns it off via `thinking.type=disabled`. Compatibility inputs `low`/`medium` normalize to `high`, while `xhigh` normalizes to `max`. | |
| 18 | | MiniMax M3 | `api.minimaxi.com`, `*.minimaxi.com` | `thinking.type` (`adaptive`\|`disabled`) | `auto`, `adaptive`, `disabled` | No depth scale; `reasoning_effort` is omitted. | |
| 19 | | Zhipu GLM | `open.bigmodel.cn` / `*.bigmodel.cn`, `api.z.ai` / `*.z.ai` | `thinking.type` (`enabled`\|`disabled`) | `auto`, `enabled`, `disabled` | **`reasoning_effort` is silently ignored** by the endpoint, so reasoning is driven purely through `thinking.type`. | |
| 20 | |
| 21 | ## Explicit per-model scales |
| 22 | |
| 23 | | Provider/model | Base URL | Reasoning control | `/effort` levels | Notes | |
| 24 | |----------------|----------|-------------------|------------------|-------| |
| 25 | | Kimi CN/Global `kimi-k3` | `api.moonshot.cn/v1`, `api.moonshot.ai/v1` | `reasoning_effort` | `low`, `high`, `max` | Always thinks; defaults to `max`. Reasonix replays the complete assistant message, uses `max_completion_tokens`, and omits K3's fixed sampling fields. | |
| 26 | | OpenCode Go `kimi-k3` | `opencode.ai/zen/go/v1` | `reasoning_effort` | `high`, `max` | Relay-specific scale; defaults to `max` and keeps the relay's standard OpenAI-compatible request shape. | |
| 27 | | Token Rhythm DeepSeek V4 | `tokenrhythm.studio/v1` | DeepSeek `thinking.type` + `reasoning_effort` | Model-specific DeepSeek scale | Selected through the preset's model override, independent of the gateway host. | |
| 28 | | Token Rhythm GLM 5/5.1/5.2 | `tokenrhythm.studio/v1` | GLM `thinking.type` (`enabled`\|`disabled`) | `auto`, `enabled`, `disabled` | Selected through the preset's model override; `reasoning_effort` is omitted. | |
| 29 | |
| 30 | On the Token Rhythm endpoint, exact GLM model IDs (`glm-5`, `glm-5.1`, and |
| 31 | `glm-5.2`) automatically select the official GLM request shape even when an |
| 32 | existing configuration has no `reasoning_protocol` field. The endpoint check |
| 33 | keeps unrelated mixed-model gateways backward-compatible. A `model_overrides` |
| 34 | entry with explicit `reasoning_protocol = "glm"` remains available for aliases |
| 35 | and custom model IDs. While GLM thinking is enabled, Reasonix retains and |
| 36 | returns the original `reasoning_content` unchanged in later history, as required |
| 37 | by GLM interleaved and preserved thinking. |
| 38 | |
| 39 | ## DeepSeek Anthropic-compatible endpoint |
| 40 | |
| 41 | The optional `deepseek-anthropic` preset targets |
| 42 | `https://api.deepseek.com/anthropic`. It keeps the official Chat Completions |
| 43 | provider as Reasonix's default, but provides a native Messages API path for |
| 44 | compatibility testing and Anthropic-oriented clients. Reasonix emits |
| 45 | `thinking.type=enabled|disabled` with `output_config.effort`, replays unsigned |
| 46 | DeepSeek thinking blocks from historical tool-call turns, omits unsupported |
| 47 | images, and relies on DeepSeek's automatic prefix cache instead of ignored |
| 48 | `cache_control` markers. |
| 49 | |
| 50 | The preset exposes the current model-specific effort scales: Flash supports |
| 51 | `auto`, `disabled`, `low`, `high`, and `max`, while Pro exposes `auto`, |
| 52 | `disabled`, `high`, and `max` because its current `low` input maps to `high`. |
| 53 | The Anthropic-compatible endpoint accepts `low|high|max` on the wire. Legacy |
| 54 | `medium` normalizes to `high`; legacy `xhigh` normalizes to `high` for Flash and |
| 55 | `max` for Pro. Claude Opus aliases use the Pro mapping, while Sonnet/Haiku and |
| 56 | unsupported model names follow DeepSeek's documented Flash fallback. |
| 57 | |
| 58 | ## Everything else (standard `reasoning_effort`) |
| 59 | |
| 60 | Any other OpenAI-compatible backend falls through to the standard |
| 61 | `reasoning_effort` scale (`low`\|`medium`\|`high`). A resolved provider/model |
| 62 | entry may explicitly advertise a different supported scale; in that case |
| 63 | Reasonix preserves those declared values instead of applying the generic |
| 64 | ceiling. Curated per-model capability metadata can opt into another scale as |
| 65 | shown above. |
| 66 | |
| 67 | Surveyed popular providers that need **no special handling** because they |
| 68 | already follow the standard convention: |
| 69 | |
| 70 | Qwen (`dashscope.aliyuncs.com`), Yi |
| 71 | (`api.01.ai`), SiliconFlow (`api.siliconflow.cn`), Stepfun (`api.stepfun.com`), |
| 72 | Groq (`api.groq.com`), Together (`api.together.xyz`), OpenRouter |
| 73 | (`openrouter.ai`), Perplexity (`api.perplexity.ai`), xAI (`api.x.ai`). |
| 74 | |
| 75 | For a backend that uses a binary `thinking.type` toggle but is **not** |
| 76 | auto-detected, set the vendor-agnostic `thinking` field on the provider entry: |
| 77 | |
| 78 | ```toml |
| 79 | [[providers]] |
| 80 | name = "my-glm-proxy" |
| 81 | kind = "openai" |
| 82 | base_url = "https://my-gateway.example.com/v1" |
| 83 | model = "glm-4.6" |
| 84 | api_key_env = "MY_API_KEY" |
| 85 | thinking = "disabled" # enabled | disabled — emits thinking.type |
| 86 | ``` |
| 87 | |
| 88 | ## Troubleshooting |
| 89 | |
| 90 | If a model keeps thinking when you asked it not to (or vice versa): |
| 91 | |
| 92 | 1. Check the table above — a backend may **ignore** the parameter you set |
| 93 | (e.g. Zhipu ignores `reasoning_effort`; use `thinking`/`/effort` instead). |
| 94 | 2. If the backend isn't auto-detected, set the explicit `thinking` field. |
| 95 | 3. If the backend uses a non-OpenAI protocol entirely (e.g. Baidu Wenxin), the |
| 96 | `openai` kind cannot drive its thinking mode — that needs a dedicated |
| 97 | provider kind. |
| 98 | |
| 99 | Distinguishing "provider ignores the field" from a Reasonix bug starts here: |
| 100 | the request shape Reasonix emits is fixed per the table, so a mismatch between |
| 101 | the table and observed behaviour is the provider's, not Reasonix's. |
| 102 |