Objective
Why agents "forget" — they don't, you overflow
There's no forgetting mechanism in the API. What actually happens: every model has a maximum context window (how many tokens of conversation it can process at once). Once your accumulated messages list exceeds that, the API call fails outright — or, on some setups, older messages silently get truncated by whatever's calling the API, and the agent behaves as if it "forgot" something it clearly said three steps ago. Neither is graceful.
Tokens, not characters, and not "messages"
Context limits are measured in tokens (roughly 4 characters of English per token, but code and non-English text vary a lot). A single fetch_url result you didn't truncate can be tens of thousands of tokens by itself. This is exactly why Lesson 2's fetch_url caps output at 5000 characters — that wasn't an arbitrary limit, it was context management you'd already started doing without a name for it yet.
The fix: summarize before you overflow, not after you crash
You don't need a sophisticated memory architecture for this course — you need one working idea: track how large messages is getting, and when it crosses a threshold, replace the older tool-call/result pairs with a short text summary before continuing the loop.
def rough_token_estimate(messages: list) -> int:
text = json.dumps(messages)
return len(text) // 4 # ~4 chars per token, good enough for a guard rail
if rough_token_estimate(messages) > 6000:
messages = compress_history(messages)
This is deliberately a rough heuristic, not a real tokenizer — good enough to trigger compression before you're anywhere near the model's actual limit, which is the only thing that matters for a safety guard. A precise token count is an easy upgrade later; a working rough guard today beats a precise one you never get around to building.
What actually gets compressed
Not everything is equally safe to summarize. The current task and the most recent 2-3 exchanges should stay verbatim — that's what the model is actively reasoning about. Older tool results (a full webpage fetch from 5 steps ago) are the safest thing to compress into "searched for X, found Y" one-liners, because by the time they're old, the agent has already extracted what it needed from them into its own reasoning.
Your agent is 6 steps into a long research task. You compress the message history, but you accidentally summarize away the ORIGINAL task description from message 1, replacing it with a vague "user asked a research question." What breaks?
The model only knows what's in its current context — it has no separate persistent memory of the original task once that text is gone. This is why the original task/user request is one of the things you should almost never compress away, even as you aggressively compress old tool results.
What you're building
A message-history guard that estimates size, and a compress_history function that keeps the original task and the last few exchanges verbatim while collapsing older tool results into one-line summaries — wired into Lesson 3's loop so it runs automatically before each API call.
Unlock the full lesson
You've read the first 2 sections. The rest of this lesson covers The Problem, The Concept, Build, Check Yourself, Key Terms & Next — plus a hands-on lab, quiz, and project artifact.
Create a free account — the opening phases of 29 of 35 courses are free, no credit card.