Repository navigation
thinking levels: max is never offered (shift+tab stops at high), and minimal is offered but 400s #1
Description
Versions — pi 0.87.1 (macOS), @commandcode/pi-commandcode-provider 0.3.0.
Problem
pi's thinking levels for every Command Code model stop at high. max never shows up when cycling with shift+tab or in /thinking, and asking for it on the command line is silently clamped back to high:
$ pi -p --model command-code/deepseek/deepseek-v4.1-flash:max "reply with exactly: ok"
ok
$ # the session log records the level that was actually used:
$ grep thinking_level_change ~/.pi/agent/sessions/**/*.jsonl
{"type":"thinking_level_change","thinkingLevel":"high"}
PI_REASONING_LEVEL=max behaves the same way, and nothing warns that the request was downgraded. This applies to all 81 models in the catalog, not just DeepSeek, and no configuration reaches max — modelThinkingLevels and defaultThinkingLevel are clamped the same way.
max is a value the gateway accepts (POST /provider/v1/chat/completions, deepseek/deepseek-v4.1-flash, max_tokens: 16):
reasoning_effort |
gateway |
|---|---|
low / medium / high / max |
200 |
minimal |
400 (see below) |
Why
getSupportedThinkingLevels() in @earendil-works/pi-ai:
const EXTENDED_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
export function getSupportedThinkingLevels(model) {
if (!model.reasoning) return ["off"];
return EXTENDED_THINKING_LEVELS.filter((level) => {
const mapped = model.thinkingLevelMap?.[level];
if (mapped === null) return false;
if (level === "xhigh" || level === "max") return mapped !== undefined; // opt-in
return true;
});
}xhigh and max are opt-in — pi only offers them when thinkingLevelMap names them, and docs/rpc-commands.md:278 describes them as levels "exposed only when supported by the selected model". toModel never sets thinkingLevelMap, so the offered set is off | minimal | low | medium | high, and clampThinkingLevel() pulls anything above high back down to it.
The mirror image: minimal is offered but rejected
The same missing map makes the fallback "every level that is not opt-in is supported", so pi offers minimal and the gateway answers 400:
$ pi -p --model command-code/deepseek/deepseek-v4.1-flash:minimal "reply with exactly: ok"
400: {"message":"Invalid option: expected one of \"low\"|\"medium\"|\"high\"|\"xhigh\"|\"max\"","type":"invalid_request_error","param":"reasoning_effort"}
Reproduced against 12 models on the /chat/completions route — deepseek/deepseek-v4.1-flash, deepseek/deepseek-v4-pro, Qwen/Qwen3.8-Max, MiniMaxAI/MiniMax-M3, moonshotai/Kimi-K3, zai-org/GLM-5.3, google/gemini-3.8-flash, xai/grok-4.7, meta/muse-spark-1.3, xiaomi/mimo-v2.6-pro, sakana/fugu-ultra, gpt-6-astra — all return that same message. off is unaffected: pi omits the field entirely and the request returns 200. The /messages route (Claude) is untested here, plan-limited on this key.
Fix
Only minimal is a clear-cut bug — the gateway rejects it, so it should not be offered:
model.thinkingLevelMap = { minimal: null };Adding max: "max" on top of that puts max back into shift+tab for the /chat/completions models, which is what this report is about:
model.thinkingLevelMap = { minimal: null, max: "max" };Whether max deserves a place on every open model, and whether xhigh belongs anywhere here, is a call for the maintainer — xhigh is an OpenAI-style value that pi treats as a per-model opt-in, and nothing in the catalog currently claims it. /provider/v1/models returns no capability fields today (id, object, created, owned_by, name, context_length, supported_endpoints), so a per-model reasoning_efforts list there would let toModel derive the whole map instead of hardcoding one, the same way pricing, max_output_tokens, modalities and reasoning are already read when the API sends them.
Activity
[-]thinking level "minimal" 400s on the Chat Completions route (`reasoning_effort` rejects it)[/-][+]thinking levels: `xhigh`/`max` are never offered (shift+tab stops at `high`), and `minimal` is offered but 400s[/+][-]thinking levels: `xhigh`/`max` are never offered (shift+tab stops at `high`), and `minimal` is offered but 400s[/-][+]thinking levels: `max` is never offered (shift+tab stops at `high`), and `minimal` is offered but 400s[/+]km-tr commentedon Sep 24, 2026
Workaround without waiting for a release
No fork or local checkout needed.
models.jsonmodelOverridesis applied on top of extension-provided models, and it mergesthinkingLevelMapkey by key, so the missing map can be supplied from user config:~/.pi/agent/models.json{ "providers": { "command-code": { "modelOverrides": { "deepseek/deepseek-v4.1-flash": { "thinkingLevelMap": { "minimal": null, "max": "max" } } } } } }Keys are the bare model ids, so any other model in the catalog can be added the same way. Opening
/modelreloads the file.Verified on pi 0.87.1 by reading the
thinking_level_changeentry the session writes:--model command-code/deepseek/deepseek-v4.1-flash:maxhighmax--model command-code/deepseek/deepseek-v4.1-flash:minimalreasoning_effortlow, no errormaxalso appears inshift+tab//thinkingonce the map names it, since the offered levels are derived from the same map.This is a stopgap — once the provider ships a map of its own, the
models.jsonentry can be dropped. It is only a user-side patch; it does not fix the other 80 models for anyone who does not write the file.