Chapter 05: Cost & Context Awareness
Track model pricing, usage, and context window. Display cost after every turn so you never blow your API budget.
TUTOR WITH THEFOCUS.AI
Copy this prompt into Claude, ChatGPT, or any external AI assistant. It points the assistant to the course instructions and links it to your student profile to track your progress and customize observations.
You are not enrolled yet. Enroll to generate a Student ID to track lesson completions and store learning notes.
Chapter 05: Cost & Context Awareness
What We’re Building
Right now your agent has no idea how much it’s costing you. We’ll add:
- Model stats lookup — Fetch pricing from OpenRouter on startup
- Per-turn cost tracking — Show cost after every response
- Session accumulation — Running total for the whole conversation
- Context size awareness — How many tokens we’re using and when we’re getting close to the limit
Step 1: Add Model Stats and Cost Tracking
Paste this prompt into your agent:
Look up the model stats on startup, including name and cost. Log cost stats from the responses. Calculate message length, context size, and current cost. Display status after each message.
Step 2: The Implementation
Model Stats Lookup
The agent will create a fetchModelStats function in src/lib/api.ts:
export interface ModelStats {
name: string;
cost: {
prompt: number; // Cost per token for input
completion: number; // Cost per token for output
};
}
let cachedStats: ModelStats | null = null;
export async function fetchModelStats(): Promise<ModelStats | null> {
if (cachedStats) return cachedStats;
const response = await fetch("https://openrouter.ai/api/v1/models");
const data = await response.json();
const models = (data as any).data;
const modelInfo = models.find((m: any) => m.id === MODEL);
if (modelInfo) {
cachedStats = {
name: modelInfo.name,
cost: {
prompt: parseFloat(modelInfo.pricing.prompt) || 0,
completion: parseFloat(modelInfo.pricing.completion) || 0,
},
};
return cachedStats;
}
return null;
}
This fetches the full model list from OpenRouter, finds your model, extracts the pricing, and caches it. The cost values are in dollars per token. You’ll see prices like:
Model: Google Gemini 3 Pro Preview
Cost: $1.25 per 1M input tokens, $10.00 per 1M output tokens
The Startup Display
In src/index.ts, the startup sequence shows model info:
const stats = await fetchModelStats();
if (stats) {
console.log(`Model: ${stats.name}`);
console.log(
`Cost: $${stats.cost.prompt * 1000000} per 1M input tokens, ` +
`$${stats.cost.completion * 1000000} per 1M output tokens`,
);
} else {
console.log(`Model: ${MODEL} (Stats not found)`);
}
Per-Turn Cost Calculation
After each agent turn, calculate and display the cost:
let turnCost = 0;
if (stats) {
turnCost =
usage.prompt_tokens * stats.cost.prompt +
usage.completion_tokens * stats.cost.completion;
sessionUsage.cost += turnCost;
}
console.log(
`\n[Turn Usage] Input: ${usage.prompt_tokens} | ` +
`Output: ${usage.completion_tokens} | Cost: $${turnCost.toFixed(6)}`,
);
console.log(
`[Session Total] Input: ${sessionUsage.prompt_tokens} | ` +
`Output: ${sessionUsage.completion_tokens} | Cost: $${sessionUsage.cost.toFixed(6)}`,
);
Context Awareness
The agent accumulates usage across the session. As the context window fills up (128K–200K tokens for most models), things get expensive and potentially dumb. The session totals help you know when it’s time to compact (which we’ll add in Chapter 11).
Step 3: The Revenue Question
Paste this follow-up:
Print the usage right after each of the responses, not before.
This ensures the cost display follows the output you care about. You’ll see something like:
Assistant: Here's the test you asked for...
[Turn Usage] Input: 2,450 | Output: 850 | Cost: $0.011562
[Session Total] Input: 45,200 | Output: 12,400 | Cost: $0.180500
Step 4: Update the Prompt to Auto-Verify
Add this improvement:
update the prompt to always run linting and testing after each work unit, and make sure that everything currently is tested
This adds a verification step to the agent’s workflow: after every code change, run mise run check. The run_check tool now becomes the default finale for any code editing cycle.
Step 5: Test It
Start your agent and issue a few commands:
read src/agent.ts and explain what runTurn does
search for "cost" in the src directory
Check the cost display after each turn. For a typical coding session, you’ll see costs like:
- Simple file reads: $0.001–0.005 per turn
- Complex edits with tool calls: $0.01–0.05 per turn
- Full-feature builds: $0.10–0.50 per session
At these rates, you can build a lot for a few dollars. But it adds up — which is why tracking is essential.
Step 6: Understand the Numbers
| Operation | Typical Input Tokens | Typical Output Tokens | Approximate Cost |
|---|---|---|---|
| Simple question | 500 | 200 | $0.001 |
| File read + analysis | 1,500 | 400 | $0.004 |
| Complex edit (3 tools) | 3,000 | 800 | $0.010 |
| Full feature (10+ turns) | 50,000 | 15,000 | $0.150 |
| Full session (1 hour) | 200,000 | 60,000 | $0.600 |
Note: These are estimates with Gemini 3 Pro Preview. Opus 4.5 is about 10–15× more expensive. Choose your model accordingly!
Key Source File
src/lib/api.ts contains both the model stats fetcher and the LLM caller:
import { TOOLS } from "../tools/index";
import type { CompletionResponse, Message } from "./types";
const API_URL = "https://openrouter.ai/api/v1/chat/completions";
export const MODEL = process.env.AGENT_MODEL || "anthropic/claude-opus-4.5";
export async function callLLM(
messages: Message[],
tools: any[] = TOOLS,
): Promise<CompletionResponse> {
const apiKey = process.env.OPENROUTER_API_KEY;
const response = await fetch(API_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: MODEL,
messages: messages,
tools: tools,
reasoning: { max_tokens: 5000 },
include_reasoning: true,
}),
});
return await response.json();
}
Note the reasoning and include_reasoning fields — these enable the model’s thinking/reasoning output, which you can see with Gemini (OpenRouter surfaces this as reasoning_details).