Here is the intuition to kill: a 40-step agent run costs about twice a 20-step run. Twice the steps, twice the work, twice the bill. That feels obvious, and it is wrong by a factor that grows with how long your agent runs.

The real curve is quadratic. A 40-step run costs roughly four times a 20-step run, not two, because the expensive resource isn’t the number of steps — it’s the number of tokens each step re-reads, and that number climbs every single step. The retry-budgets post showed how failures inflate this curve. This post is about the curve itself, the one you pay even when nothing fails.

Where the square comes from

An agent step is a model call. The model is stateless, so every call re-sends the entire conversation so far as prefill: the system prompt, the task, and every prior step’s model output and tool result. That’s the whole point of treating the context window as a cache rather than a memory — the model doesn’t remember anything; you re-pay to remind it each turn.

So at step k, the prefill you send is roughly proportional to k — everything the first k−1 steps accumulated. Sum that across N steps and you get the classic triangular number:

1 + 2 + 3 + ... + N  ≈  N² / 2

The total input tokens for the run scale with , not N. The output tokens are linear (each step emits about the same amount), but on most agent workloads prefill dominates the token count by a wide margin, so the run’s cost tracks the quadratic term.

Let’s measure it instead of trusting the algebra.

A cost model you can run

SYS      = 1500     # system prompt + task, re-sent every call
OUT      = 300      # tokens the model emits per step
RESULT   = 600      # tool result appended to the transcript per step
IN_COST  = 3.0 / 1e6
OUT_COST = 15.0 / 1e6

def run_cost(N, per_step_context):
    """per_step_context(k) -> tokens of transcript visible at step k."""
    total_in = total_out = 0
    for k in range(1, N + 1):
        prefill = SYS + per_step_context(k)
        total_in  += prefill
        total_out += OUT
    return total_in * IN_COST + total_out * OUT_COST

# Naive: everything every prior step produced stays in the window forever.
def naive(k):
    return (k - 1) * (OUT + RESULT)

for N in (10, 20, 40, 80):
    print(f"N={N:3d}  ${run_cost(N, naive):.4f}")

Output:

N= 10  $0.2115
N= 20  $0.6930
N= 40  $2.4660
N= 80  $9.2520

Double the steps from 20 to 40 and the cost goes up 3.6×. From 40 to 80, another 3.8×. Each doubling of run length roughly quadruples the bill — and the ratio creeps closer to a clean 4× the longer the run gets, as the fixed system prompt and the linear output term wash out and the quadratic prefill term takes over. A demo that runs 8 steps hides this completely; the term is small when N is small. It only bites once your agent runs long enough to matter — the overnight batch, the deep research task, the multi-hour coding session — which is exactly when you stopped watching.

Flattening the curve

The fix is not “make the agent take fewer steps.” It’s to stop letting the visible transcript grow linearly with step count. Four structural moves, roughly in order of how much they buy you.

1. Truncate tool results, don’t carry them whole. The biggest single contributor above is RESULT = 600 re-sent every subsequent step. A tool that returns a 600-token blob — a full API response, a file, a search result — usually mattered once, at the step that called it. Summarize it to the 40 tokens the agent will actually reference later and drop the rest. Swap RESULT for something small after the step that consumed it and the quadratic constant collapses.

def summarize_results(k, kept=40):
    # each prior step keeps a short digest, not the full result
    return (k - 1) * (OUT + kept)

That single change takes the N=80 run from $9.25 to about $3.94 — more than halved, no information the agent needs lost, because a digest of “the API returned 200, order #4471, status shipped” is all step 60 ever needed from step 12’s call. It’s not a full 4× cut because the model’s own output still accumulates in the transcript; truncating results kills the largest growing term, not the only one. To flatten the rest, you have to stop the reasoning itself from piling up — which is the next two moves.

2. Externalize state to a scratchpad. The agent doesn’t need the transcript of how it learned something; it needs the something. Keep a compact running state — a file, a structured note, a task list — that the agent reads and rewrites, and let the raw back-and-forth fall out of the window. This is compaction done deliberately and continuously instead of in a panic at the context limit. The scratchpad is bounded by the complexity of the task, not by the number of steps taken — which is the whole game.

3. Scope sub-agents with fresh windows. A sub-task that takes 15 steps and returns one answer should run in its own context and hand back only the answer. The parent pays for 15 steps once, as a single result, instead of dragging all 15 steps’ transcript through every remaining parent step. This is the strongest argument for the orchestrator/sub-agent shape that isn’t about capability at all — it’s about keeping each window’s N small so nobody pays the square on the whole job.

4. Exploit the prefix cache — but don’t rely on it to save you. Providers cache identical prefixes, so re-sending an unchanged system prompt is cheap on a cache hit. That helps the constant, but the transcript’s tail changes every step, so the growing part is exactly the part that never caches. Prefix caching flattens the floor, not the slope. It’s a discount on the quadratic, not a fix for it.

The one-line version

Your agent’s token bill scales with the square of its run length because every step re-reads a transcript every prior step grew. The steps aren’t the cost; the re-reading is. So the lever isn’t “fewer steps” — it’s “keep what each step leaves behind small.” Truncate results to digests, keep state in a scratchpad instead of the transcript, run sub-tasks in their own windows, and treat prefix caching as a discount rather than a cure.

Measure it on your own workload: log the prefill token count per step and plot it against step number. If that line slopes up, you’re paying the square. A well-engineered long-running agent’s per-step prefill is roughly flat — and a flat per-step cost is the difference between an agent you can run for an hour and one you can’t afford to run for ten minutes.