Skip to content

claude-sonnet-5 capped at effort 'high' — Anthropic docs confirm xhigh/max are supported #3913

Description

@chulmin-dev

Summary

claude-sonnet-5 is hardcoded to maxLevel: "high" in the bundled model catalog (packages/ai/src/models.json), so --thinking xhigh / --thinking max silently clamp to high on this model. Per Anthropic's current public docs, Sonnet 5 supports xhigh and max effort at the API level, same as Opus 5 and Fable 5.

Evidence (current official Anthropic docs, checked 2026-08-06)

docs.claude.com/en/docs/build-with-claude/effort — Compatibility section:

Supported models: claude-fable-5, claude-mythos-5, claude-mythos-preview, claude-opus-5, claude-opus-4-8, claude-opus-4-7, claude-opus-4-6, claude-sonnet-5, claude-sonnet-4-6, claude-opus-4-5-20251101

Per-level "Available on" lists in the same page:

  • xhigh: "Available on Claude Fable 5, Claude Mythos 5, Claude Opus 5, Claude Opus 4.8, Claude Opus 4.7, and Claude Sonnet 5."
  • max: "Available on Claude Fable 5, Claude Mythos 5, Claude Opus 5, Claude Opus 4.8, Claude Mythos Preview, Claude Opus 4.7, Claude Opus 4.6, Claude Sonnet 5, and Claude Sonnet 4.6."

The page also has a dedicated "Recommended effort levels for Claude Sonnet 5" section that explicitly documents xhigh ("For the hardest coding and agentic tasks") and max ("For tasks requiring the absolute highest capability with no constraints on token spending") as first-class supported levels for this model — not fallback/undocumented behavior.

docs.claude.com/en/docs/build-with-claude/thinking-troubleshooting — per-model thinking-type table confirms Sonnet 5 runs Adaptive only thinking (same family as Opus 5, not the older extended-thinking-only models), so there's no protocol-level reason it should be capped differently from Opus 5's effort ladder.

Current GJC behavior

packages/ai/src/models.json:

"claude-sonnet-5": {
  ...
  "thinking": {
    "mode": "anthropic-adaptive",
    "minLevel": "minimal",
    "maxLevel": "high"
  }
}

vs. claude-opus-5 / claude-fable-5 which get max / xhigh respectively.

packages/ai/src/model-thinking.ts, inferAnthropicSupportedEfforts():

if (parsedModel.kind === "fable") {
  return model.api === "anthropic-messages" ? DEFAULT_REASONING_EFFORTS_WITH_XHIGH : DEFAULT_REASONING_EFFORTS;
}
if (parsedModel.kind !== "opus") return DEFAULT_REASONING_EFFORTS; // <- Sonnet falls through here, capped at "high"
return anthropicModelHasRealXHighEffort(model)
  ? DEFAULT_REASONING_EFFORTS_WITH_XHIGH_AND_MAX
  : DEFAULT_REASONING_EFFORTS_WITH_MAX;

and anthropicModelHasRealXHighEffort():

function anthropicModelHasRealXHighEffort<TApi extends Api>(model): boolean {
  if (model.api !== "anthropic-messages") return false;
  const parsedModel = parseKnownModel(model.id);
  if (parsedModel.family !== "anthropic" || parsedModel.kind !== "opus") return false; // Sonnet excluded
  return semverGte(parsedModel.version, "4.7");
}

Both the static catalog entry and the runtime inference function special-case kind === "opus" (with Fable getting a separate xhigh-only branch), leaving Sonnet on the old DEFAULT_REASONING_EFFORTS (minimal/low/medium/high) ceiling regardless of version.

Repro

gjc --model anthropic/claude-sonnet-5 --thinking xhigh -p "reply OK"
# effort silently clamps to "high" (clampThinkingLevelForModel in model-thinking.ts)

models.yml modelOverrides also can't work around this from user config — the documented overridable fields are name, reasoning, input, cost, contextWindow, maxTokens, headers, compat, contextPromotionTarget (per docs/models.md); thinking isn't in that list, so there's no user-side escape hatch either.

Expected

claude-sonnet-5 should expose xhigh and max effort, matching current Anthropic API support:

"thinking": {
  "mode": "anthropic-adaptive",
  "minLevel": "minimal",
  "maxLevel": "max",
  "levels": ["minimal", "low", "medium", "high", "xhigh", "max"]
}

and inferAnthropicSupportedEfforts() / anthropicModelHasRealXHighEffort() should stop gating xhigh/max on kind === "opus" only — Sonnet 5 (and presumably any future non-Opus model Anthropic ships with the same effort ladder) needs the same branch Opus/Fable get, ideally driven by an explicit per-model capability check rather than a kind allowlist that has to be manually extended every time Anthropic widens support.

Environment

  • gjc version: 0.12.12
  • @gajae-code/ai version: 0.12.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions