Skip to content

th-1cc9fa: model-output ceiling clamp + raise starvation defaults (Python server parity)#194

Open
brentrager wants to merge 1 commit into
localflavor-hardeningfrom
th-1cc9fa-py-ceiling
Open

th-1cc9fa: model-output ceiling clamp + raise starvation defaults (Python server parity)#194
brentrager wants to merge 1 commit into
localflavor-hardeningfrom
th-1cc9fa-py-ceiling

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Problem

The server's per-turn sizing (max_tokens=512, max_iterations=6) is chat-widget sizing that starves reasoning models — they exhaust the token budget on reasoning and return empty, or run out of loop iterations mid-tool-use. And a budget max_tokens can exceed what a model can physically emit. Rust parity for th-1cc9fa (raise defaults) + th-562b6d (clamp chat max_tokens to the /model/info ceiling).

Change (mirrors rust/smooth-operator-server/src/{config,admin,handler,runner}.rs)

  • Raise the starvation defaults the turn runner applies: DEFAULT_MAX_TOKENS 512→8192, DEFAULT_MAX_ITERATIONS 6→20.
  • New model_info.py — best-effort per-model output ceiling from the gateway's /model/info (map_model_info + model_output_ceiling), the Python analog of admin.rs. Cached once per process, stdlib urllib fetch (no new deps). No gateway key / any transport error / unknown model / missing ceiling ⇒ None ⇒ engine leaves max_tokens unclamped.
  • Thread the resolved ceiling into AgentOptions.model_max_output (from the core parity PR) so the engine clamps max_tokens to what the model can emit — the raised 8192 default is then safe.

Release-ordering (important)

The server pins the published smooai-smooth-operator-core (currently 1.3.1, which predates the clamp field). The ceiling threading is feature-detected (_CORE_SUPPORTS_CEILING) so this PR is green on the pinned core today and the clamp auto-activates once core ≥ 1.3.2 (the paired core PR) is published and the pin bumped. Until then: the raised defaults are live; the clamp is wired but dormant.

Paired core PR: SmooAI/smooth-operator-core#73 (publish core 1.3.2, then bump this repo's smooai-smooth-operator-core pin).

Tests

  • test_model_info.pymap_model_info (positive/skip/garbage payloads) + model_output_ceiling (clamp lookup, unknown model, no-key skips fetch, error→None uncached, success cached once, /model/info URL).
  • test_starvation_defaults.py — raised constants, runner sends 8192, iteration cap is 20 (behavioral), + a forward-compat end-to-end clamp test that skips on the pre-clamp core (verified: passes when run against the local core-parity build).

Full server suite: 47 passed, 1 skipped; ruff clean.

EPIC th-1cc9fa.

🤖 Generated with Claude Code

…thon server parity)

Python-server parity for the Rust server hardening (th-1cc9fa / th-562b6d):

- Raise the anti-starvation turn sizing the runner applies: max_tokens 512 -> 8192
  (DEFAULT_MAX_TOKENS), max_iterations 6 -> 20 (DEFAULT_MAX_ITERATIONS). The old
  chat-widget sizing starves reasoning models (empty replies / truncated tool loops).
- New model_info.py: best-effort per-model output ceiling from the gateway's
  /model/info (map_model_info + model_output_ceiling), cached once per process,
  stdlib fetch, no extra deps. No key / any error / unknown model -> None -> unclamped.
- Thread the resolved ceiling into AgentOptions.model_max_output so the engine
  clamps max_tokens to what the model can emit. Feature-detected against the pinned
  published core (which predates the field) so this stays green now and activates
  automatically once a core >= 1.3.2 is pinned.

Tests: test_model_info.py (map + ceiling lookup: clamp/unknown/no-key/error/cache/url)
and test_starvation_defaults.py (raised constants, runner sends 8192, iteration cap 20,
+ a forward-compat clamp test that skips on the pre-clamp core). 47 passed, 1 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: f556862

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

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