FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

thinking levels: `max` is never offered (shift+tab stops at `high`), and `minimal` is offered but 400s · Issue #1 · CommandCodeAI/pi-commandcode-provider · GitHub

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

  1. changed the title [-]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[/+] on Sep 24, 2026
  2. changed the title [-]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[/+] on Sep 24, 2026
  3. km-tr commented on Sep 24, 2026

    Author

    Workaround without waiting for a release

    No fork or local checkout needed. models.json modelOverrides is applied on top of extension-provided models, and it merges thinkingLevelMap key 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 /model reloads the file.

    Verified on pi 0.87.1 by reading the thinking_level_change entry the session writes:

    request before after
    --model command-code/deepseek/deepseek-v4.1-flash:max clamped to high max
    --model command-code/deepseek/deepseek-v4.1-flash:minimal 400 reasoning_effort clamped to low, no error

    max also appears in shift+tab / /thinking once 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.json entry 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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


      Back | FazBrowse Home | New Git URL