Skip to content

Use lower thinking/effort for cron and hook sessions under OAuth#129

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

Use lower thinking/effort for cron and hook sessions under OAuth#129
constkolesnyak wants to merge 1 commit into
ClickHouse:mainfrom
constkolesnyak:upstream/cron-effort-oauth

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.

Fix

Add dedicated agent.cron_thinking and agent.cron_effort settings (default high) and a small _select_thinking_effort(agent_config, source) helper that returns the right pair for the session source:

  • source in {"cron", "hook"}cron_thinking / cron_effort
  • everything else → thinking / effort (unchanged)

Defaults match what works under OAuth on Sonnet (high). Users with a provider that accepts max for Sonnet can lift the defaults.

Composes cleanly with the existing model-aware _parse_thinking_config(value, model) / _effective_effort(value, model) helpers — _select_thinking_effort only picks the source-appropriate input, the model-aware step still gates per-model legality.

Tests

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

  • _select_thinking_effort returns cron_* for cron and hook, defaults for everything else
  • explicit override + None handling
  • defaults of high for cron_thinking / cron_effort

Full suite: 1164 passed, 2 skipped (excluding pre-existing tests/test_cron.py::TestMaybeRotateContext rotate_at failures unrelated to this change — present on main too).

Files

  • nerve/config.py — add cron_thinking / cron_effort to AgentConfig with "high" defaults
  • nerve/agent/engine.py_select_thinking_effort helper, used at session-start path
  • nerve/bootstrap.py — surface in bootstrap defaults
  • config.example.yaml, docs/config.md — document the two new keys
  • tests/test_engine_options.py — new

History

Previously opened as #53, closed in error against the wrong target. This is the recreated version against upstream, rebased onto current main with the model-aware _parse_thinking_config / _effective_effort API.

Generated with Claude Code

Every cron run was failing with `API Error: 400 level "max" not
supported, valid levels: low, medium, high` because the global
`agent.effort=max` and `agent.thinking=max` were applied to cron
sessions too. Cron sessions run on `cron_model` (Sonnet by default),
which under Claude OAuth (subscription) 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.

Add dedicated `agent.cron_thinking` / `agent.cron_effort` settings
(default `high`) and a `_select_thinking_effort` helper that picks
the right pair based on session source. `cron` and `hook` get the
overrides; everything else keeps the main settings, so interactive
sessions still get the full thinking budget on the flagship model.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread config.example.yaml
# level "max" not supported, valid levels: low, medium, high
# Keep these at "high" unless your provider accepts "max" for the
# cron model.
cron_thinking: high

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

constkolesnyak added a commit to constkolesnyak/nerve that referenced this pull request Jun 25, 2026
Previous version added `agent.cron_thinking` and `agent.cron_effort`
config fields, both defaulting to `high`, applied to every cron/hook
session regardless of provider. That changed behavior for API users
who configure `effort=max` / `thinking=max` and accept it on every
model — they got silently downgraded.

Artem's review on ClickHouse#129: keep `max` by default and
switch to `high` only when OAuth subscription is in use.

OAuth in nerve is gated by the local cli-proxy-api wrapping the
user's subscription credentials — i.e. `config.proxy.enabled`. The
helper now reads that flag and only downgrades when source is
cron/hook AND proxy is enabled. API users (no proxy) keep their
configured value untouched, even for cron sessions.

Changes:
* `nerve/config.py`: remove `cron_thinking` / `cron_effort` fields
  and from_dict entries. Defaults stay at `max` / `max`.
* `nerve/agent/engine.py`: rewrite `_select_thinking_effort` to take
  the full Config (not just agent_config) and cap `max` -> `high`
  for cron/hook only when `config.proxy.enabled`. Update the single
  call site.
* `nerve/bootstrap.py`: remove the two SetupWizard defaults.
* `config.example.yaml`: drop the two keys, replace comment with a
  note that the cap is automatic under OAuth.
* `docs/config.md`: drop the two doc rows, fold the OAuth+cron note
  into the existing `thinking` / `effort` rows.
* `tests/test_engine_options.py`: rewrite around the new OAuth gate.
  21 tests covering OAuth on/off × cron/hook/interactive × max/lower
  values, plus the from_dict backwards-compat (legacy cron_thinking/
  cron_effort keys are silently ignored).

Tests: 21/21 in tests/test_engine_options.py. Full suite: 1306 passed,
2 skipped, 0 failed.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@constkolesnyak

Copy link
Copy Markdown
Contributor Author

Superseded by #153 — does exactly what you asked: keeps max by default and switches to high only when OAuth subscription is in use (detected via config.proxy.enabled). The agent.cron_thinking / agent.cron_effort config knobs introduced here are removed in #153 in favor of the implicit OAuth gate.

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