Skip to content

feat(agent): bounded auto and cold fast modes - #89991

Open
100yenadmin wants to merge 4 commits into
NousResearch:mainfrom
100yenadmin:upstream/fast-mode-bounded-auto-cold
Open

feat(agent): bounded auto and cold fast modes#89991
100yenadmin wants to merge 4 commits into
NousResearch:mainfrom
100yenadmin:upstream/fast-mode-bounded-auto-cold

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds two time-bounded fast-mode policies on top of the existing normal/priority modes:

  • auto — fast mode is on for the first N seconds of a session's activity (default 60s), then relaxes;
  • cold — fast mode on for a cold start (no prior session activity), off once the session is warm.

The policy is revalidated at every provider-dispatch boundary, so a mode change (or the window closing) takes effect on the next request and can't leak stale fast-mode settings across turns. It's inert by default: for any service_tier outside {auto, cold} the dispatch path is byte-identical to today.

Stacked PR — read this

This branch has three commits, the first two of which are already open as standalone PRs:

  1. refactor(anthropic): extract idempotent fast-mode kwargs helperrefactor(anthropic): extract idempotent fast-mode kwargs helper #89982
  2. fix(models): fail closed on unverified fast-mode endpointsfix(models): fail closed on unverified fast-mode endpoints #89960
  3. feat(agent): bounded auto and cold fast modes → this PR's actual contribution

The feature needs both (it calls the idempotent helper to apply/revoke per turn, and the endpoint verifier to stay fail-closed). Simplest path: take #89960 and #89982 first (they stand on their own — a fix and a refactor), and this rebases down to the single feature commit. I can rebase it to one commit on request. This is the last piece of the original #74730, split for reviewability.

Related Issue

Completes #64785 / #74730 (minus the user-facing surface — see below).

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made (feature commit only)

  • agent/fast_mode.py (new) — the policy module: normalize_fast_auto_on_seconds (with a bool-is-not-a-float guard), has_prior_session_activity, begin_fast_mode_turn / invalidate_fast_mode_turn, effective_request_overrides, revalidate_fast_mode_request.
  • agent/agent_init.py, run_agent.pyfast_auto_on_seconds param + normalization on the agent.
  • agent/conversation_loop.pybegin_fast_mode_turn at run ingress.
  • agent/chat_completion_helpers.py — revalidate at the provider-dispatch boundaries; build_api_kwargs reads the effective overrides.
  • Tests: 27 unit (tests/agent/test_fast_mode_auto.py) + 5 dispatch-revalidation integration (tests/run_agent/test_run_agent.py).

Now includes the config/CLI surface

Updated: this PR now also exposes the modes on the generic surface (a 4th commit, da7bc56750), so the feature is actually usable, not just wired:

  • agent.service_tier accepts auto/cold (alongside normal/fast/priority) in config, CLI, and the gateway.
  • agent.fast_auto_on_seconds (default 60) is a config key threaded to the agent.
  • /fast [normal|fast|auto|cold|status] works across the CLI, the messaging gateway, and the TUI/desktop backend gateway.

The one piece still deferred is the desktop model-settings menu UI (ui-tui / apps/desktop) — a small follow-up that doesn't affect headless, CLI, or gateway users. Surface tests: tests/cli/test_fast_command.py + tests/gateway/test_fast_command.py + tests/tui_gateway/test_fast_session_scope.py → 36 passed; a 546-test regression sweep across tui_gateway/gateway/cli is green.

How to Test

bash scripts/run_tests.sh tests/agent/test_fast_mode_auto.py tests/run_agent/test_run_agent.py -q
→ 27/27 fast-mode unit + the dispatch-revalidation integration green

(One unrelated red on this machine, test_interruptible_anthropic_interrupt_never_closes_shared_client, is a missing anthropic SDK in the venv — it fails identically at the base commit.)

test_normal_and_fast_modes_remain_backwards_compatible asserts the normal/priority path is unchanged.

Checklist

Code

  • I've read the Contributing Guide
  • Conventional Commits
  • Searched existing PRs
  • My PR contains only changes related to this feature (the two prerequisite commits are their own open PRs)
  • Ran the fast-mode + run_agent suites
  • Added tests
  • Tested on my platform: macOS 15

Documentation & Housekeeping

  • Docs — deferred with the user-facing surface (nothing user-visible in this PR)
  • cli-config.yaml.example — deferred (no config key exposed yet)
  • CONTRIBUTING.md/AGENTS.md — N/A
  • Cross-platform — N/A
  • Tool descriptions/schemas — N/A

Salvage note: the feature is one commit (ec09a3af98) on top of #89960 + #89982 — cherry-pick the prerequisites, then this.

Pure refactor: lift the inline Anthropic Fast Mode block in
build_anthropic_kwargs into a dedicated _apply_fast_mode_to_kwargs
helper. The helper is idempotent and revocable — it strips any prior
extra_body["speed"] and the fast-mode beta token from anthropic-beta
before deciding, so applying it twice is stable and applying it with
enabled=False cleanly reverts a prior application. This is needed
because a later slice toggles fast mode per-turn on already-built
kwargs; the strip-first design keeps that safe.

No behavior change when enabled: the enabled path is byte-identical to
the pre-refactor inline block (verified by test), and disabled on fresh
kwargs is a no-op.

Second slice of the bounded-fast-modes series (T1 = NousResearch#89960).

Receipts:
  tests/agent/test_anthropic_adapter.py: 96 passed, 0 failed
  new test: test_apply_fast_mode_helper_idempotent_revocable_and_byte_identical
  built on pin 13ce0c5
Add keyword-only provider/api_mode/base_url to resolve_fast_mode_overrides
so that, when a caller supplies the runtime endpoint identity, service_tier:
priority is granted only for allow-listed first-party origins: native OpenAI
(openai/openai-api @ api.openai.com), ChatGPT-Codex (openai-codex @
chatgpt.com), and xAI Grok 4.6 (xai/xai-oauth @ api.x.ai). A gpt- or
grok-shaped model name on an OpenAI-compatible proxy no longer earns the
field — it fails closed to None. Anthropic speed=fast is likewise gated to
the anthropic_messages transport.

This gate is INERT until a caller actually passes identity (a later slice in
this series wires it through). All three params default to None, so every
existing zero-arg call site is byte-identical and the legacy static `fast`
path is unchanged: this is hardening-in-advance, not a live user-visible
change. The xAI Grok branch closes a gap where the upstream whitelist (which
predated Grok fast-mode support) would have silently returned None for a
model the resolver already routes into fast mode.

First slice of a bounded-fast-modes series split from a larger PR for
single-concern review.
Add a provider-neutral, turn-local fast-mode policy on top of the existing
normal/priority (fast) tiers. Two dynamic modes:

- auto: opens a time-bounded fast window (default 60s, configurable via
  fast_auto_on_seconds) on every user turn.
- cold: opens the same window, but only for the first logical-session turn.

The window is resolved at each user-turn boundary (begin_fast_mode_turn at
run_conversation ingress) and re-validated immediately before every provider
dispatch (revalidate_fast_mode_request at the non-streaming, streaming,
Anthropic, Bedrock, and codex-summary boundaries). Re-validating per dispatch
means an expired window drops fast metadata even when relay/middleware
finalizes kwargs after the cutoff, so a fast turn can never leak across
turns. The policy touches request metadata only: conversation messages,
prompts, tools, and persisted overrides stay stable.

The new policy is inert for the existing normal and priority modes — their
dispatch path stays byte-identical to today. Only service_tier in
{auto, cold} activates the window.

Stacks on NousResearch#89960 (fail-closed fast-mode endpoints; resolve_fast_mode_overrides
identity kwargs) and NousResearch#89982 (idempotent _apply_fast_mode_to_kwargs helper),
both of which this policy calls.

The user-facing config/CLI/UI surface that exposes auto/cold to users
(service_tier: auto/cold across the CLI, gateway, tui, and desktop app) is a
deferred follow-up; this change wires the policy internally so it is exercised
by the default agent path and its unit + integration tests.
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard labels Aug 19, 2026
@100yenadmin

Copy link
Copy Markdown
Contributor Author

Folded the config/CLI surface into this PR (commit da7bc56750) so the feature is complete and usable rather than wired-but-unreachable: service_tier: auto/cold and fast_auto_on_seconds are now settable via config, the CLI, and the gateway /fast command, all with tests. Only the desktop model-settings menu UI remains a follow-up. The PR is now 4 commits — the two prerequisites (#89960, #89982), the policy+wiring, and this surface.

Expose the NousResearch#89991 bounded-auto/cold fast-mode feature on the generic
config, CLI, and gateway surface (headless / CLI / gateway users), so
`service_tier: auto` / `cold` and `fast_auto_on_seconds` are settable via
config.yaml and selectable via the `/fast` command across the CLI,
messaging gateway, and TUI/desktop backend gateway.

- config_defaults.py / cli.py / cli-config.yaml.example: default
  fast_auto_on_seconds=60; parse+persist normal/fast/auto/cold.
- cli_agent_setup_mixin / cli_commands_mixin / commands / web_server:
  thread fast_auto_on_seconds into the agent; /fast accepts auto/cold.
- gateway/run.py / session_state.py / slash_commands.py: thread
  fast_auto_on_seconds; defer dynamic modes to the agent; persist
  "priority"/"auto"/"cold" session overrides.
- tui_gateway/server.py / methods_session.py / methods_config.py:
  accept + persist auto/cold via session.create and config.set/get,
  invalidating the fast-mode turn clock on live mode changes.

Reuses the feature's normalize_fast_auto_on_seconds and the fail-closed
resolve_fast_mode_overrides; existing normal/priority paths unchanged.

The desktop model-settings UI (ui-tui/*, apps/desktop/*) is deliberately
excluded and remains a separate follow-up.

Stacks on NousResearch#89991.
@100yenadmin

Copy link
Copy Markdown
Contributor Author

Fixed both real CI failures here (87914a66dd):

  1. NameError: CLI_CONFIG — the surface commit read CLI_CONFIG in _init_agent without the function-local import that file uses elsewhere, so agent init failed whenever that path ran (surfaced as test_runtime_resolution_failure_is_not_sticky). Now behind a small _fast_auto_on_seconds_setting() helper that does the local import and falls back to the default.
  2. test_bare_fast_sends_picker_when_adapter_supports_it — that test pins the /fast picker to ["fast", "normal"]; this PR intentionally adds auto and cold, so the assertion is updated to match the new choice list. Behavior change is the point of the PR, not a regression.

Green after the fix: 55 passed across test_choice_picker.py, test_cli_provider_resolution.py, test_fast_command.py (cli + gateway), and test_fast_session_scope.py.

The remaining red check (test_image_generation.py::test_upscale_defaults_are_all_off) is the current main-is-red issue #90013 — unrelated to this PR and already has fixes in flight.

100yenadmin added a commit to electricsheephq/evaOS-hermes-desktop-app-adapter that referenced this pull request Aug 20, 2026
Expose the NousResearch#89991 bounded-auto/cold fast-mode feature on the generic
config, CLI, and gateway surface (headless / CLI / gateway users), so
`service_tier: auto` / `cold` and `fast_auto_on_seconds` are settable via
config.yaml and selectable via the `/fast` command across the CLI,
messaging gateway, and TUI/desktop backend gateway.

- config_defaults.py / cli.py / cli-config.yaml.example: default
  fast_auto_on_seconds=60; parse+persist normal/fast/auto/cold.
- cli_agent_setup_mixin / cli_commands_mixin / commands / web_server:
  thread fast_auto_on_seconds into the agent; /fast accepts auto/cold.
- gateway/run.py / session_state.py / slash_commands.py: thread
  fast_auto_on_seconds; defer dynamic modes to the agent; persist
  "priority"/"auto"/"cold" session overrides.
- tui_gateway/server.py / methods_session.py / methods_config.py:
  accept + persist auto/cold via session.create and config.set/get,
  invalidating the fast-mode turn clock on live mode changes.

Reuses the feature's normalize_fast_auto_on_seconds and the fail-closed
resolve_fast_mode_overrides; existing normal/priority paths unchanged.

The desktop model-settings UI (ui-tui/*, apps/desktop/*) is deliberately
excluded and remains a separate follow-up.

Stacks on NousResearch#89991.

(cherry picked from commit 87914a6)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants