minimax-reasoning
v0.1.0
Published
OpenCode plugin that fixes MiniMax M3 <think> tag leakage in the TUI by injecting reasoning_split into the chat params. Also works for any OpenAI-compatible provider that uses the same pattern.
Downloads
37
Maintainers
Readme
minimax-reasoning
OpenCode plugin that fixes the <think> tag leakage in the TUI for MiniMax M3 and other OpenAI-compatible reasoning models.
Without this plugin, the model's chain-of-thought shows up as raw text in your TUI:
<think>The user is asking me to calculate 17 * 23. Let me compute...391.</think> 391With this plugin, the thinking is split into a separate part and rendered as a collapsible thinking block:
▼ [Thinking] The user is asking me to calculate 17 * 23... 391
Why this exists
OpenAI's Chat Completions spec predates reasoning models — it has no field for chain-of-thought. When MiniMax exposes M3's reasoning through that spec, it embeds the thinking inside the normal content field wrapped in <think>...</think> tags.
OpenCode's TUI does not parse <think> tags inside text. It only renders a collapsible thinking block when the reasoning arrives on a dedicated reasoning_content field (which is the shape Anthropic, OpenAI Responses, and DeepSeek use natively).
This plugin bridges the gap by injecting the official MiniMax reasoning_split: true flag into the LLM request. The server then returns the same thinking in a separate message.reasoning_content field, which OpenCode renders correctly.
Even better: MiniMax also offers an Anthropic-compatible API at
/anthropic/v1. If you can switch to that, you don't need this plugin at all — see When to use this plugin below.
Quick install
Edit ~/.config/opencode/opencode.json and add the plugin:
{
"plugin": [
"oh-my-openagent@latest",
"minimax-reasoning@latest"
]
}OpenCode will install the plugin on next startup. Restart any active TUI session.
Local install (development / offline)
{
"plugin": [
"./local-plugins/minimax-reasoning"
]
}When to use this plugin
Use this plugin only when you need to keep using MiniMax's OpenAI-compatible Chat Completions endpoint (baseURL: https://api.minimaxi.com/v1, npm: @ai-sdk/openai-compatible).
If you can switch endpoints, the cleaner fix is to use the Anthropic-compatible API natively:
{
"provider": {
"minimax": {
"npm": "@ai-sdk/anthropic",
"options": {
"apiKey": "...",
"baseURL": "https://api.minimaxi.com/anthropic/v1"
}
}
}
}The Anthropic endpoint returns reasoning as native thinking content blocks, so OpenCode's TUI handles them out of the box — no plugin needed.
How it works
OpenCode exposes a chat.params plugin hook that fires just before the LLM call. The hook receives a mutable output.options object; whatever you set there gets routed through OpenCode's Oo.providerOptions() translation layer into the AI SDK's providerOptions[<sdk-key>], which the openai-compatible provider's getArgs() spreads into the HTTP request body.
This plugin sets output.options.reasoning_split = true, which the MiniMax server reads and uses to move thinking out of content and into reasoning_content in the response.
The AI SDK's openai-compatible provider already parses delta.reasoning_content natively, emitting reasoning-start / reasoning-delta / reasoning-end events. OpenCode's event adapter then creates a separate reasoning part in the database, which the TUI renders as a collapsible block.
Zero custom rendering code in this plugin. All the reasoning-block UI is OpenCode's native behavior, just unlocked by the right request flag.
Configuration
| Env var | Values | Default | Effect |
|---|---|---|---|
| OPENCODE_REASONING_SPLIT_MODE | split / disable / off | split | Operating mode |
split(default): injectreasoning_split: true→ thinking stays on, just split into a separate fielddisable: injectthinking: { type: "disabled" }→ model skips emitting thinking tags (faster, cheaper, no thinking shown)off: plugin does nothing (effectively disabled)
Adding more providers
Edit PROVIDERS in src/index.ts:
const PROVIDERS: Record<string, Partial<Record<Mode, Record<string, unknown>>>> = {
minimax: {
split: { reasoning_split: true },
disable: { thinking: { type: "disabled" } },
},
myProvider: {
split: { some_flag: true },
disable: { another_flag: "off" },
},
}Then rebuild: npm run build.
Verify it works
# 1. Run a simple prompt
opencode run "Reply: 17 * 23 = ? Just the answer." --model minimax/MiniMax-M3
# Expected: no `<think>` block in visible output
# 2. Inspect DB to confirm reasoning is a separate part
SID=$(sqlite3 ~/.local/share/opencode/opencode.db \
"SELECT id FROM session ORDER BY time_created DESC LIMIT 1")
sqlite3 ~/.local/share/opencode/opencode.db \
"SELECT json_extract(p.data, '\$.type'), length(json_extract(p.data, '\$.text'))
FROM part p JOIN message m ON p.message_id = m.id
WHERE m.session_id = '$SID'
AND json_extract(p.data, '\$.type') IN ('text', 'reasoning')"
# Expected output: two rows — one 'reasoning' and one 'text'Caveats
- Multi-turn thinking continuity: MiniMax's docs require the entire
response_message(includingreasoning_details) to be preserved in message history for the model's chain-of-thought to stay coherent across turns. This plugin preserves the thinking text in a separate DB part, but OpenCode's OpenAI-compatible path may not replay the fullreasoning_detailsarray on subsequent turns. If you see thinking quality degrade over long agentic sessions, switch to the Anthropic endpoint or setOPENCODE_REASONING_SPLIT_MODE=disable. - M2.x models: According to MiniMax's docs,
thinking: { type: "disabled" }is a soft hint — M2.x models continue to reason even with this flag set, but the response is just cleaner.
Related ecosystem
- OpenCode PR #31426 — merged: enables MiniMax M3 thinking on the Anthropic interface
- OpenCode PR #26233 — open: would add
provider.options.extraBodyas a config-only solution (no plugin needed) once merged - Pi Agent's MiniMax provider — uses the Anthropic-compatible endpoint natively
Development
# Clone
git clone https://github.com/openopencode/minimax-reasoning.git
cd minimax-reasoning
# Install deps
npm install
# Build
npm run build
# Test locally — link into OpenCode's plugin dir
ln -s "$PWD" ~/.config/opencode/plugins/minimax-reasoning
# Or reference as file path in opencode.json:
# "plugin": ["/absolute/path/to/minimax-reasoning"]License
MIT — see LICENSE.
