home/roleplay/effort-routing

Effort Routing

GPTClaudeGemini··1,277 copies·updated 2026-07-14
effort-routing.prompt
# Effort routing — turn classification rules

Companion to `verbosity_steering.md`. Classifies each turn before the model
generates, so we can route mechanical continuations to lower effort and
keep full effort for new asks and error recovery.

In upstream Headroom, this runs in the proxy and clamps
`output_config.effort` (Anthropic) or `thinking.budget_tokens` (legacy
models) on mechanical turns. In the portable skill, the agent itself
applies the classification before deciding how much reasoning to do.

## The classification

Look at the **last message** in the conversation (the one the model is
about to respond to). Classify based on its content:

| Last message contains…                                       | Classification            | Verbosity | Effort  |
|--------------------------------------------------------------|---------------------------|-----------|---------|
| A new question or instruction (text, image, document block)  | `NEW_USER_ASK`            | L2        | full    |
| Only `tool_result`, all `is_error: false`                    | `MECHANICAL_CONTINUATION` | L3        | low     |
| Any `tool_result` with `is_error: true`                      | `ERROR_CONTINUATION`      | L2        | full    |
| Anything else                                                | `UNKNOWN`                 | L2        | full    |

## Why this works

In an agentic loop, most API calls are mechanical continuations: the model
just read a file (no errors), or ran a test (it passed), or did a search
(got results). The model is just resuming. Harnesses like Claude Code pin
`output_config.effort` at `xhigh` for *every* turn, including these — and
effort drives thinking depth, which bills as output tokens.

Lowering effort on mechanical turns cuts output tokens by ~30% on those
turns, with no measurable accuracy loss on standard benchmarks.

## Concrete rules

### `NEW_USER_ASK`
The user asked a new question or gave a new instruction. The model needs
full reasoning. Verbosity L2, effort full.

Detection: the last message has `role: user` AND contains any text/image/
document block.

### `MECHANICAL_CONTINUATION`
The previous turn was a tool call, the tool succeeded, and there's no new
user input. The model is resuming. Lower effort to `low`, drop verbosity
to L3.

Detection: the last message has `role: tool` (or contains a `tool_result`
block) AND no `is_error: true` AND there's no new user message after it.

### `ERROR_CONTINUATION`
The previous turn was a tool call, the tool failed (`is_error: true`). The
model needs to reason about the failure. Keep effort at full, verbosity L2.

Detection: the last message has `role: tool` (or contains a `tool_result`
block) AND at least one block has `is_error: true`.

### `UNKNOWN`
Anything else (e.g. an assistant message with no following user/tool
message — shouldn't happen in normal flow). Default to L2 + full effort.

## What "lower effort" means per provider

### Anthropic (Claude)
- Lower `output_config.effort` from `xhigh`/`high` to `low` on mechanical
  turns.
- Never inject `output_config.effort` where the client didn't send it —
  models without effort support 400 on it. Lowering an already-present
  value is always valid; its presence proves the model accepts the param.
- On legacy models with `thinking: {type: "enabled", budget_tokens: N}`,
  clamp `N` to the API floor (1024) on mechanical turns.
- **Never toggle `thinking.type`.** Disabling thinking while history
  carries thinking blocks 400s on some models.

### OpenAI (GPT-4o, o1, etc.)
- Lower `reasoning.effort` from `high` to `low` on mechanical turns (o1/o3
  models).
- For GPT-4o and below, no equivalent param — rely on verbosity steering
  alone.

### Gemini
- Lower `thinkingConfig.thinkingBudget` on mechanical turns (Gemini 2.5+).
- Keep `0` as the floor (the model can still answer).

### Open-source / local
- Most local runtimes don't expose effort. Rely on verbosity steering
  alone.

## Safety rules (each prevents a concrete failure)

1. **Never inject `effort` where the client didn't send it.** Models
   without effort support return 400 on it. Lowering an already-present
   value is always valid — its presence proves the target model accepts
   the param.
2. **Never toggle `thinking.type`.** Disabling thinking while history
   carries thinking blocks 400s on some models, and the toggle busts the
   messages cache tier.
3. **Byte-stable, idempotent steering.** Repeated requests keep an
   identical prefix; cache stays warm.
4. **Respect `x-headroom-bypass`.** Sub-agent calls that opt out of
   compression also opt out of shaping. (In the portable skill: respect
   the user's "don't compress this" instructions.)

## Implementation example (Python, for agent authors)

fill the variables

This prompt has 1 variable. Pro fills them into a ready-to-paste prompt for you — no manual find-and-replace.

{type: "enabled", budget_tokens: N}
Unlock with Pro →

when to use it

Community prompt sourced from the open-source GitHub repo roman-ryzenadvanced/headroom-skill (Apache-2.0). A "Effort Routing" style prompt — adapt the placeholders and specifics to your task. Imported as-is and not independently retested here, so check the output before relying on it.

tags

roleplaycommunitygeneral

source

roman-ryzenadvanced/headroom-skill · Apache-2.0