Skip to content

Cron/hook thinking-effort: downgrade only under OAuth proxy#153

Open
constkolesnyak wants to merge 1 commit into
ClickHouse:mainfrom
constkolesnyak:upstream/cron-effort-oauth-only-v2
Open

Cron/hook thinking-effort: downgrade only under OAuth proxy#153
constkolesnyak wants to merge 1 commit into
ClickHouse:mainfrom
constkolesnyak:upstream/cron-effort-oauth-only-v2

Conversation

@constkolesnyak

Copy link
Copy Markdown
Contributor

Problem

Every cron run on Claude OAuth (subscription) fails with:

API Error: 400 level "max" not supported, valid levels: low, medium, high

Root cause: the global agent.thinking=max / agent.effort=max defaults are applied to every session, including cron and hook sessions that run on cron_model (Sonnet by default). Claude OAuth caps non-flagship models at high and rejects max. With a persistent cron session this also poisons every subsequent run on the same sdk_session_id.

The main interactive model (Opus) accepts max, so just lowering the global default would degrade the interactive experience to fix cron. API users (direct ANTHROPIC_API_KEY) accept max on every model and shouldn't be downgraded at all.

Fix

Detect OAuth via config.proxy.enabled — the local cli-proxy-api that wraps Claude Code OAuth credentials is the single source of truth for "running under OAuth subscription" in nerve. Cap thinking and effort to high only when:

  • source in ("cron", "hook"), AND
  • config.proxy.enabled is True

API users (no proxy) keep their configured value untouched for every source, and interactive sessions keep it under OAuth too — only the narrow OAuth+cron path is downgraded.

Implementation lives in a small _select_thinking_effort(config, source) helper at the session-start path in nerve/agent/engine.py. It composes cleanly with the existing model-aware _effective_effort(value, model) (which already caps Sonnet's effort at high) — this layer also handles the thinking side (which the CLI otherwise rejects as a string-level max) and makes the OAuth trigger explicit.

No new config knobs.

Tests

tests/test_engine_options.py (new, 21 tests, all passing):

  • OAuth ON + cron / hook + max,max("high","high") (the exact bug being fixed).
  • OAuth ON + cron / hook + lower values → unchanged (cap, not force).
  • OAuth ON + cron / hook + mixed → each knob capped independently.
  • OAuth ON + interactive sources (web / telegram / discord / api / "") + max,max → unchanged (Opus accepts max under OAuth).
  • OAuth OFF + every source + max,max → unchanged (Artem's exact requirement).
  • OAuth OFF + cron + lower values → unchanged.
  • AgentConfig.from_dict({"cron_thinking": "high", "cron_effort": "high"}) silently ignores those keys (backwards-compat for anyone whose config had them).

Files

  • nerve/agent/engine.py_select_thinking_effort helper + single call site update
  • tests/test_engine_options.py — new

History

Supersedes #129 — addresses @pufit's review feedback:

This will change the behavior for API users. We should keep it max by default and switch to high when OAuth subscription is used.

The previous PR introduced two config knobs (agent.cron_thinking, agent.cron_effort) defaulting to high and applied them unconditionally — silently downgrading API users. This version detects OAuth automatically via config.proxy.enabled with no new config surface.

🤖 Generated with Claude Code

Problem: every cron run on Claude OAuth (subscription) fails with

    API Error: 400 level "max" not supported, valid levels: low, medium, high

because the global agent.thinking=max / agent.effort=max defaults are
applied to every session, including cron/hook sessions that run on
cron_model (Sonnet by default). Claude OAuth caps non-flagship models
at "high" and rejects "max".

The main interactive model (Opus) accepts "max", so lowering the global
default would degrade the interactive experience to fix cron. API users
(direct ANTHROPIC_API_KEY) accept "max" on every model and shouldn't
be downgraded at all.

Fix: detect OAuth via config.proxy.enabled — the local cli-proxy-api
that wraps Claude Code OAuth credentials. _select_thinking_effort()
caps thinking/effort to "high" only when source is cron/hook AND the
proxy is enabled. API users keep their configured value untouched
for every source, and interactive sessions keep it under OAuth too —
only the narrow OAuth+cron path is downgraded.

Composes with the existing model-aware _effective_effort() (which
already caps Sonnet's effort at "high"); this layer also handles the
thinking side (which the CLI otherwise rejects as a string-level
"max") and makes the OAuth trigger explicit.

Tests: tests/test_engine_options.py — 21 tests covering OAuth on/off
× cron/hook/interactive sources × max/lower values, plus from_dict
backwards-compat (legacy cron_thinking/cron_effort keys are silently
ignored — no schema break for users who had them in config.yaml).

History: supersedes ClickHouse#129. The previous version added cron_thinking
and cron_effort config knobs defaulting to "high", applied
unconditionally to every cron/hook session. @pufit's review there
asked to keep "max" by default and switch to "high" only under
OAuth — this PR does exactly that with no new config knobs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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