Skip to content

feat(models): add claude-opus-5 + fix interactive /effort on Anthropic#746

Merged
ericleepi314 merged 1 commit into
mainfrom
feat/opus-5-support
Jul 25, 2026
Merged

feat(models): add claude-opus-5 + fix interactive /effort on Anthropic#746
ericleepi314 merged 1 commit into
mainfrom
feat/opus-5-support

Conversation

@ericleepi314

Copy link
Copy Markdown
Collaborator

Makes clawcodex --model claude-opus-5 --effort xhigh work on a Claude subscription — interactively, not just headless. Three separate defects stood in the way.

1. claude-opus-5 was unregistered

_model_supports_extended_thinking already matches opus-5 by regex, so the loop fell through to the budget_tokens branch — removed on Opus 5, so every request 400'd. Quieter side effects: --effort was dropped (opus-5 was off the effort allowlist) and the context window resolved to the 200K default instead of 1M, the early-compaction handicap #730 removed for opus-4-8.

Registered in MODEL_CONFIGS (1M context, 5/25 per MTok), pricing.py, both provider model lists, and the three query.py gates.

Wire-probed 2026-07-25 over subscription OAuth: claude-opus-5 + adaptive thinking accepts effort: xhigh and max (200, end_turn). The xhigh entry is measured, not inferred; the "unprobed" comments now scope that to fable-5 only.

2. Interactive /effort was broken on Anthropic

  • _do_set_effort validated against a hardcoded (minimal|low|medium|high) — so /effort xhigh and /effort max were rejected in the TUI while the same values worked via --effort and every other surface. Meanwhile minimal (a GPT-5 level) was accepted, and because it isn't in VALID_THINKING_EFFORT_LEVELS, resolve_thinking_effort treated it as "nothing requested" and substituted settings.effort/effort minimal could emit max while the TUI echoed "minimal". The ladder is now VALID_EFFORT_VALUES.
  • Every provider got extra_body={"reasoning_effort": …}, which is the OpenAI-compat shape. The Anthropic wire rejects it: 400 — reasoning_effort: Extra inputs are not permitted (probed). One /effort broke every following request in an interactive Anthropic session. New _turn_effort_routing routes Anthropic through thinking_effortoutput_config.effort (per-model gating intact, so xhigh still clamps to high where unsupported) and keeps _EffortProvider for OpenAI-compat.

Not wrapping Anthropic providers also un-breaks the isinstance(provider, AnthropicProvider) checks that agent_loop_compat worked around and advisor.py did not.

3. --effort didn't apply interactively at all

Plumbed only into HeadlessOptions, so the interactive path parsed and discarded it. Now: cli/launcher → backend argv → AgentServerConfig → the session's /effort level, across all four entry paths (clawcodex, clawcodex tui, --print-connect, agent-server --stdio). Validated and lowercased at the seed as well as via argparse choices=, because --stdio callers reach the config without a parser.

Also

  • is_anthropic_wire() in src/providers replaces a predicate copy-pasted at three sites that all had to agree.
  • _EffortProvider.__getattr__ guards _inner: copy.copy built an uninitialized instance and recursed to RecursionError, which two live callers swallowed as except Exception — silently running subagents on the session model instead of their override.
  • /effort and /thinking off each now warn that the other discards effort.
  • The TUI advertised [minimal|low|medium|high|auto|ultracode]; it now advertises the real ladder, and the effort badge beside the model name has a producer for the first time.

Verification

  • 8827 passed, 0 failed (1 deselected: test_connection_error_re_raises, a pre-existing hang confirmed on clean main).
  • ui-tui tsc --noEmit clean; ui-tui tests at their 8-failed pre-existing baseline, no new failures.
  • Live: headless --model claude-opus-5 --effort xhigh on subscription returns a real answer; the interactive control path accepts /effort xhigh and routes it as thinking_effort='xhigh' with the provider unwrapped.
  • Every hop of the flag chain and both halves of the routing split are individually revert-sensitive — verified by deleting each line and confirming exactly the intended test fails.
  • Critic-reviewed over three rounds.

Known follow-ups (not in scope here)

  • claude-sonnet-5 has the identical budget_tokens 400 today — same defect class, unregistered.
  • src/utils/advisor.py's advisor allowlist is opus-4-6/sonnet-4-6 only; the TS reference is two models ahead and carries @[MODEL LAUNCH] markers the port lacks.
  • src/models/aliases.py's opus alias still resolves to Opus 4, so Agent(model="opus") subagents don't follow the session model.
  • Interactive /effort doesn't persist to settings.effort, so subagents don't inherit it — now consistent with --effort on both paths, but a product decision worth making.

🤖 Generated with Claude Code

Register `claude-opus-5` and make `--effort` / `/effort` actually work on
the interactive path, so `clawcodex --model claude-opus-5 --effort xhigh`
runs at xhigh on a Claude subscription.

## claude-opus-5 registration

`_model_supports_extended_thinking` already matched opus-5 by regex, so
without a registration the loop fell through to the `budget_tokens`
branch — REMOVED on Opus 5, i.e. a 400 on every request. Two quieter
consequences: `--effort` was dropped (opus-5 was off the effort
allowlist) and the context window resolved to the 200K default instead
of 1M, the early-compaction handicap #730 removed for opus-4-8.

* MODEL_CONFIGS row (1M context, 5/25 per MTok, 32K first-attempt wire
  max_tokens per the existing convention) + pricing tier and family
  prefix + both provider available-model lists.
* The three query.py gates: adaptive thinking, effort, xhigh.

Wire-probed 2026-07-25 over subscription OAuth: `claude-opus-5` with
adaptive thinking accepts `effort: xhigh` AND `max` (200, end_turn), so
the xhigh allowlist entry is measured, not documentation-derived. The
comments that said "unprobed" now say so only of fable-5.

## Interactive /effort was broken on Anthropic

Two independent defects, both invisible at runtime:

1. `_do_set_effort` validated against a hardcoded
   `(minimal|low|medium|high)`, so `/effort xhigh` and `/effort max` were
   REJECTED in the TUI while the same values worked via `--effort`,
   `/effort` on the other surfaces, and settings.effort. `minimal` was
   accepted despite being a GPT-5 level absent from every other surface —
   and actively harmful here: it is not in VALID_THINKING_EFFORT_LEVELS,
   so resolve_thinking_effort treats it as "nothing requested" and
   substitutes settings.effort, i.e. `/effort minimal` could emit `max`
   while the TUI echoed "minimal". The ladder is now VALID_EFFORT_VALUES.

2. Every provider got `extra_body={"reasoning_effort": …}`. That is the
   OpenAI-compat shape; the Anthropic wire rejects it outright (probed:
   `400 — reasoning_effort: Extra inputs are not permitted`), so a single
   `/effort` broke every following request in an interactive Anthropic
   session. New `_turn_effort_routing` sends Anthropic down
   `thinking_effort` → `output_config.effort` (with the per-model gating,
   so xhigh still clamps to high where unsupported) and keeps
   `_EffortProvider` for OpenAI-compat. Not wrapping Anthropic providers
   also un-breaks the `isinstance(provider, AnthropicProvider)` checks
   that agent_loop_compat worked around and advisor.py did not.

## --effort now applies interactively

The flag was plumbed only into HeadlessOptions, so the interactive path
parsed and discarded it. It now rides cli/launcher → backend argv →
AgentServerConfig → the session's /effort level, on all four entry paths
(`clawcodex`, `clawcodex tui`, `--print-connect`, `agent-server --stdio`).
Validated and lowercased at the seed as well as via argparse `choices=`,
because --stdio callers reach the config without a parser.

## Also

* `is_anthropic_wire()` in src/providers replaces a predicate that was
  copy-pasted at three call sites and had to agree at all of them.
* `_EffortProvider.__getattr__` guards `_inner`: `copy.copy` built an
  uninitialized instance and recursed to RecursionError, which two live
  callers swallowed as `except Exception` — silently running subagents on
  the session model instead of their override.
* `/effort` and `/thinking off` now each warn that the other discards
  effort (it rides inside the thinking block on this wire).
* The TUI advertised `[minimal|low|medium|high|auto|ultracode]`; it now
  advertises the real ladder, and the effort badge next to the model name
  has a producer for the first time (backend emits `reasoning_effort`).

Tests: 8827 passed. Every hop of the flag chain and both halves of the
routing split are individually revert-sensitive (verified by deleting
each line and confirming exactly the intended test fails).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ericleepi314
ericleepi314 merged commit bac2ae9 into main Jul 25, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant