Skip to content

Cap adaptive-thinking effort per model's supported levels#55

Merged
pufit merged 1 commit into
ClickHouse:mainfrom
neomnezia:fix/cap-thinking-effort
Apr 30, 2026
Merged

Cap adaptive-thinking effort per model's supported levels#55
pufit merged 1 commit into
ClickHouse:mainfrom
neomnezia:fix/cap-thinking-effort

Conversation

@neomnezia
Copy link
Copy Markdown
Contributor

@neomnezia neomnezia commented Apr 27, 2026

Summary

Global agent.effort (e.g. max) is shared between the main agent and auxiliary models (cron_model, memU recall/memorize). Sonnet/Haiku tiers only advertise {low, medium, high}; forwarding max triggers a 400 from CLIProxyAPI tier validation:

thinking: validation failed | provider=claude model=claude-sonnet-4-6
  error=level "max" not supported, valid levels: low, medium, high

Same shape on Opus 4.6 with xhigh, and on any auxiliary model the user configures below their main Opus 4.7.

Fix

Add _effective_effort(value, model) — a small table of known Claude models with their advertised effort levels, plus a step-down lookup that caps the requested effort to the highest level the target model supports. Unknown models pass through unchanged (backward compatible).

Preserves max for the Opus 4.7 main agent while letting Sonnet cron/memU calls succeed with the tier-appropriate level.

Symmetric with the existing _parse_thinking_config(value, model) which is already model-aware.

Notes

  • _MODEL_EFFORT_LEVELS keys use substring form (opus-4-7, opus-4-6, sonnet-4-6) iterated against the full model name so dated Anthropic aliases like claude-opus-4-7-20260416 resolve. Mirrors the MODEL_PRICING pattern in nerve/db/usage.py and _model_supports_legacy_enabled_thinking in the same file.
  • logger.debug when capping so users can trace why a configured effort: max was forwarded as high to Sonnet.
  • New tests/test_engine.py covers the cap table — dated aliases, unknown models, None/empty model, invalid effort string.

Test plan

  • pytest tests/test_engine.py — new cap-table tests pass
  • Manual: effort: max configured globally; main Opus 4.7 receives max, Sonnet cron/memU receive high (no more 400 from CLIProxyAPI)

🤖 Generated with Claude Code

Global `agent.effort` (e.g. "max") is shared across the main agent and
auxiliary models (`cron_model`, memU recall/memorize). Sonnet/Haiku tiers
only advertise {low, medium, high}; forwarding "max" triggers a 400 from
CLIProxyAPI tier validation (`internal/thinking/validate.go:125`):

    thinking: validation failed | provider=claude model=claude-sonnet-4-6
      error=level "max" not supported, valid levels: low, medium, high

Same shape on Opus 4.6 with "xhigh" (supports max but not xhigh), and on
any auxiliary model the user configures below their main Opus 4.7.

Add `_effective_effort(value, model)` — a small table of known Claude
models with their advertised effort levels, and a step-down lookup that
caps the requested effort to the highest level the target model supports.
Unknown models pass through unchanged (backward compatible).

Preserves "max" for Opus 4.7 main agent while letting Sonnet cron/memU
calls succeed with the tier-appropriate level.

Symmetric with existing `_parse_thinking_config(value, model)` which is
already model-aware.

Implementation notes:
- `_MODEL_EFFORT_LEVELS` keys use substring form (`opus-4-7`, `opus-4-6`,
  `sonnet-4-6`) iterated against the full model name so dated Anthropic
  aliases like `claude-opus-4-7-20260416` resolve. Mirrors the
  MODEL_PRICING pattern in nerve/db/usage.py and
  `_model_supports_legacy_enabled_thinking` in the same file.
- `_effective_effort(value, model=None)` — default matches the sibling
  `_parse_thinking_config(value, model=None)`.
- `logger.debug` when capping happens so users can trace why a configured
  `effort: max` was forwarded as `high` to Sonnet.
- New `tests/test_engine.py` covers the cap table (incl. dated aliases,
  unknown models, None/empty model, invalid effort string).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pufit pufit merged commit 81f0583 into ClickHouse:main Apr 30, 2026
neomnezia added a commit to neomnezia/nerve that referenced this pull request Apr 30, 2026
Resolves conflict in nerve/channels/telegram.py by taking upstream version
(fork's pre-squash drafts of PRs ClickHouse#55 and ClickHouse#56 superseded by upstream squash-merges).

Brings in:
- PR ClickHouse#60 — optional Langfuse observability
- PR ClickHouse#56 — send_file Telegram delivery + cross-channel hardening
- PR ClickHouse#55 — adaptive-thinking effort cap per model

Drops fork-unique tests/test_telegram_send.py: imported symbols
(FLOODWAIT_GAP_S, PREVIEW_FOOTER) that upstream squash-refactored away;
upstream's tests/test_send_file.py provides equivalent coverage.
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.

2 participants