The plan
Everything from this module, in the working agent. Four changes, in order of what they buy
you.
1. Caching (biggest win, smallest change)
Move anything volatile out of the system prompt, then turn caching on:
SYSTEM_PROMPT = """You are Rover, a coding assistant working in a project folder.
Prefer search_files before reading whole files.
Always read a file before editing it.""" # nothing dynamic in here
reply = llm.send(messages, TOOLS, system=SYSTEM_PROMPT)
Then switch caching on the way your provider wants it (Lesson 6.2) — or, on OpenAI, simply
benefit from it now that the prefix is stable.
Dynamic things — the date, the folder, the user — go into the first user message.
Check: by turn three, cache_read_input_tokens should be most of your input.
2. Clearing
if turn > 0 and turn % 5 == 0:
messages = clear_old_tool_results(messages, keep_last=6)
Every fifth turn, not every turn — clearing invalidates the cache from that point, so batching
it keeps both features working together.
Check: total input tokens on a fifteen-turn task should drop noticeably.
3. Memory
MEMORY = Path("MEMORY.md")
if MEMORY.exists():
SYSTEM_PROMPT += f"\n\nFrom earlier sessions:\n{MEMORY.read_text()}"
Plus the remember tool from 6.5, with the durable-facts description.
Check: run three sessions. Session three should know something from session one without
being told.
Note where it goes: in the system prompt, which is cached. Memory is stable content, so it
belongs in the stable part. Putting it in the last message would work and would waste the
cache.
4. The handover summariser
def handover(messages):
messages = messages + [{"role": "user", "content":
"Summarise for a fresh session: the task, files changed and how, "
"what failed and why, and any constraints the user gave. "
"Be specific about file names and error messages."}]
return llm.send(messages).text
Wire it to a turn threshold or a key press:
if turn == 20:
summary = handover(messages)
messages = [
{"role": "user", "content": f"Earlier work on this task:\n\n{summary}"},
*messages[-4:],
]
Check: run past turn twenty and confirm it still knows the task.
Measure the whole thing
Run one realistic task — say fifteen turns of real work — three times:
| Configuration | Total input tokens | Cost | Still correct? |
|---|---|---|---|
| Module 5’s Rover | |||
| Caching only | |||
| All four |
Fill it in with your own numbers. Two things usually come out of this table.
The caching row is a much bigger jump than people expect, for four lines of code.
And the third row must keep the “still correct?” column honest. Every technique here trades
information for room. If the answers got worse, you cleared too aggressively or summarised
away something that mattered — and finding that out is the point of the column.
Caching first, clearing second, memory third, summarising last. Measure after each, and
keep checking whether the answers are still right.
Try this before the next module
Take the numbers from your table into Module 7.
You have just made four changes and formed opinions about them from a handful of runs. Module
7 is about whether those opinions are true — and the “still correct?” column is exactly the
thing you are about to learn to measure properly.