Leadership has asked what the new pull-request review agent will cost, and they want a number to approve. You price one model call, multiply by the 14 steps the agent takes on a typical PR, and get about $0.06. The real figure for that run is about $0.29, nearly five times higher, and the provider dashboard will only tell you so after the agent is live.

The gap comes from what each call carries. Every step resends the whole history, so the last call of a run sends about ten times the input of the first. Nobody sees that in a per-call price.

This post wraps the model call in about 25 lines, prints one row per step in tokens and dollars, and turns that into a per-run cost and a monthly range you can defend. Every number below comes from an illustrative run, described in full so you can see how it was built. Run the meter on your own agent before you trust any of them.

The running example

The agent reviews pull requests. It has three tools: read_file, run_tests and post_comment. Given a PR that touches 12 files, it reads them one at a time, runs the tests, and posts a review. That is 14 model calls, and we will call each call a step.

A token is the unit a model reads and writes, roughly a short word or word fragment, and providers bill by it. Input tokens are everything you send in a call; output tokens are what the model writes back. The two have separate prices.

The illustrative setup: the system prompt and tool list come to about 1,500 tokens, the PR description adds 200, and each file read adds about 1,000 to 1,200 tokens to the conversation. One file is much bigger than the rest. The review the agent posts at the end is about 950 tokens of output.

The meter: wrap the model call

The meter is one function. It calls the model, reads the usage counts off the response, prices them, and appends a row to a list. Here it is against the Anthropic Python SDK, with the usage read isolated in one function so you can swap it.

import anthropic

client = anthropic.Anthropic()

MODEL = "your-model-id"   # placeholder
INPUT_PER_M = 2.00        # placeholder: USD per million input tokens
OUTPUT_PER_M = 10.00      # placeholder: USD per million output tokens
log = []                  # one (review_id, step, input, output, dollars) row per call

def read_usage(response):
    """The only provider-specific line. Swap it for another SDK."""
    return response.usage.input_tokens, response.usage.output_tokens

def metered_call(review_id, **request):
    response = client.messages.create(model=MODEL, **request)
    tokens_in, tokens_out = read_usage(response)
    dollars = (tokens_in * INPUT_PER_M + tokens_out * OUTPUT_PER_M) / 1_000_000
    step = sum(1 for row in log if row[0] == review_id) + 1
    log.append((review_id, step, tokens_in, tokens_out, dollars))
    return response

def print_table(review_id):
    total = 0.0
    for rid, step, tin, tout, usd in log:
        if rid != review_id:
            continue
        total += usd
        print(f"{step:>4} {tin:>8,} {tout:>7,} {usd:>8.4f} {total:>10.4f}")

review_id is whatever you already generate per PR review: a UUID, the PR number, a request ID. It tags each row so two reviews writing to the same log at once stay attributable to the right run; it does not make log.append itself safe under real concurrency (see the callout below the loop).

The agent loop calls metered_call where it used to call the API directly. Nothing else in it changes.

def run_agent(review_id, task):
    messages = [{"role": "user", "content": task}]
    while True:
        response = metered_call(review_id, max_tokens=1024, system=SYSTEM, tools=TOOLS, messages=messages)
        if response.stop_reason != "tool_use":
            break
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "user", "content": run_tools(response.content)})

That is about 25 lines, counting the loop. SYSTEM, TOOLS and run_tools are your existing agent.

If multiple reviews can run in threads, log.append is not safe as written: wrap it in a lock, or give each thread its own list.

The prices are placeholders. They are not any provider's price list, and the model name is a stand-in. Put in the two per-million prices for the model you plan to use, and write down the date you read them.

One assumption sits under every dollar figure: each input token is billed at one flat input price. Check your provider's billing page for anything that departs from that.

Using another provider? In practice, most report the same two counts somewhere on the response, usually in an object called usage, under names that differ. Find them in the response reference for your SDK and change read_usage. That is the only line that moves.

Read the table

Run the agent on the 12-file PR and call print_table(). This is the illustrative run, priced at the placeholder prices above.

Step

Tool called

Input tokens

Output tokens

Dollars

Cumulative

1

read_file

1,700

120

0.0046

0.0046

2

read_file

2,700

80

0.0062

0.0108

3

read_file

3,800

80

0.0084

0.0192

4

read_file

4,800

80

0.0104

0.0296

5

read_file

5,900

80

0.0126

0.0422

6

read_file

7,000

80

0.0148

0.0570

7

read_file

8,000

80

0.0168

0.0738

8

read_file (large file)

9,000

80

0.0188

0.0926

9

read_file

12,500

80

0.0258

0.1184

10

read_file

13,500

80

0.0278

0.1462

11

read_file

14,600

80

0.0300

0.1762

12

read_file

15,600

80

0.0320

0.2082

13

run_tests

16,600

70

0.0339

0.2421

14

post_comment

17,800

950

0.0451

0.2872

Total

133,500

2,020

$0.29

Illustrative run of a 12-file PR at placeholder prices ($2 per million input tokens, $10 per million output tokens). Not measured on a real agent.

Three things stand out from this run: input tokens rise on every step, from 1,700 at step 1 to 17,800 at step 14. Nothing in the agent got more expensive to run; each call just carries more.

Output tokens stay small. The agent writes about 80 tokens to ask for the next file, and only the last call writes anything long, the 950-token review. The whole run writes about 2,000 tokens and reads about 133,500.

So input dominates. It is 98.5% of the tokens and, even with output priced five times higher in these placeholders, 93% of the dollars. Your ratio will differ, because it depends on your tool results and your prices.

Look at step 9. The input jumps by 3,500 tokens, where the other steps add about 1,000. That is the large file read at step 8, and every later step pays for it again.

Why the tenth step costs more than the first

A model call has no memory. To answer at step 10, the model needs the system prompt, the tool list, the PR description, and every earlier message and tool result, so your loop sends all of it again. That is the messages list in run_agent, passed in full on each pass. Its size is limited by the model's context window, the maximum number of tokens it accepts in one call.

This is the Resend Tax: each step pays again for everything that came before it. The tax is why the run total outgrows the step count. If every step adds tokens, the average step gets bigger as the run gets longer, and the total is steps times that average.

You can estimate a longer run from the table without running it. Input grew from 1,700 to 17,800 over 13 additions, about 1,240 tokens per step, big file included. A 30-step run would end near 1,700 + 29 x 1,240, about 37,700 tokens at step 30. The average step is the midpoint of first and last, so the total is roughly 30 x (1,700 + 37,700) / 2, about 590,000 input tokens.

Check the method on the run you have: the same formula gives 136,500 for 14 steps against the 133,500 in the table, 2% high. Good enough to plan with.

Now compare the two runs. The 30-step run has 2.1 times the steps of the 14-step run and 4.4 times the input. Double the length of a run and you more than double its cost.

This holds for a loop that resends the whole history, which is what the code above does. Some frameworks trim or summarise old messages before sending, and if yours does, your growth will be flatter. Check what your framework puts in the request, and let the meter confirm it. It also assumes each step adds tokens; a step that added nothing would cost the same as the one before.

From one run to a number for leadership

One run is an anecdote. Leadership needs a figure that covers the PRs you will actually get, so meter three: a small one, a typical one, and a large one. Here they are, from the same illustrative setup.

PR size

Model calls

Input tokens

Output tokens

Cost per run

Small (3 files)

5

19,000

950

$0.048

Typical (12 files)

14

133,500

2,020

$0.29

Large (28 files)

30

about 590,000

about 3,300

about $1.21

Illustrative, at placeholder prices. The large row is the extrapolation from the previous section; in practice, meter a real large PR.

The large run costs about 25 times the small one, though it has only six times the calls. That spread is why a single number misleads.

Now multiply by volume, and give leadership a range. Assume 300 PRs a month, and three ways they might split by size:

Scenario

Small

Typical

Large

Month

Low

210

75

15

about $50

Expected

150

120

30

about $78

High

90

120

90

about $148

Write the assumptions next to the table, where the reader cannot miss them:

  • 300 PRs a month, in the splits above.

  • Runs like the illustrative agent: 1,700-token starting context, about 1,000 tokens added per step.

  • One model, priced at the placeholder rates, as of the date you read them.

  • Cost only; no retries, no failed runs, no other tools.

Then say what would move it: longer runs, bigger files, more PRs, or a different model. In the high scenario, the 90 large PRs are about three quarters of the bill, so the share of large PRs is the number to pin down first.

This is a range built on assumptions, not a forecast. It is only as good as those assumptions. Once the agent has real traffic, meter that and replace this table.

A budget alert

A meter that only prints a table after the run is a post-mortem. A token budget makes it a smoke detector: a limit on the total tokens one run may use, checked after each call. This version warns at 80% of the budget and again when the budget is passed, and the loop carries on.

TOKEN_BUDGET = 110_000    # per run, illustrative
warned = {}                # review_id -> set of labels already warned

def check_budget(review_id):
    rows = [row for row in log if row[0] == review_id]
    used = sum(tin + tout for _, _, tin, tout, _ in rows)
    seen = warned.setdefault(review_id, set())
    for label, limit in (("80%", 0.8 * TOKEN_BUDGET), ("100%", TOKEN_BUDGET)):
        if used >= limit and label not in seen:
            seen.add(label)
            print(f"WARNING review {review_id} step {len(rows)}: {used:,} tokens, {label} of budget")

Call check_budget(review_id) in metered_call, right after the log.append line, using the same review_id the call already has.

Run the typical PR against it. The cumulative total is 84,420 tokens after step 11, so nothing fires. After step 12 it is 100,100, past the 88,000 mark, and the first warning prints. After step 13 it is 116,770, and the second prints. The run finishes at 135,520 tokens. We guessed 110,000 before we had metered anything, and the meter says the guess was low for a run this ordinary.

The 80% and 100% thresholds are illustrative. Set yours from your own metered runs, and expect to change them.

The alert does not stop a runaway run, and it does not make a run cheaper. It prints a line. That is deliberate here, but it means a warn-only alert only helps if someone is watching, or the line goes somewhere that pages a person. Shrinking the history is a separate problem, and this post stops at measuring it.

Takeaway

  • A per-call price times the step count comes out low, because every step resends the whole history: about $0.06 by that method against about $0.29 metered, for the same 14-step run.

  • Input tokens dominate an agent run. In the illustrative run, input was 98.5% of the tokens and 93% of the dollars, so watch what goes into the context before you watch what comes out.

  • Late steps cost the most, and run cost grows faster than run length: 2.1 times the steps meant 4.4 times the input.

  • A metered wrapper is about 25 lines, and the only provider-specific part is one function that reads the usage counts.

  • Give leadership a range, not a point: meter a small, a typical and a large run, multiply by an assumed volume, and write the assumptions beside it.

  • Three numbers go in the summary: the cost of the typical run ($0.29 here), the share of input in the total (93% of dollars here), and the high-case monthly figure ($148 here). Every one of them is illustrative until you run the meter on your own agent.