Managing the Context25 of 37
In [Compaction in Code](compaction-in-code) you saw the cheaper way to shorten an agent's history: drop the oldest turns and keep the rest word for word. It has one rule that must never break. A tool_use and the tool_result that answers it go together, or the API refuses the request. Here you'll write that trim.
## The input
The first line is the budget. Then one line per message, oldest first: its role, how many tokens it has, and what kind of message it is (task, text, tool_use or tool_result):
``text
budget 10000
user 1200 task
assistant 300 tool_use
user 4000 tool_result
assistant 200 tool_use
user 2500 tool_result
assistant 250 tool_use
user 3000 tool_result
assistant 150 tool_use
user 900 tool_result
`
Message 0 is the task. After it, the history is made of **turns**: an assistant message, then the user message that answers it. Messages 1 and 2 are one turn, 3 and 4 the next, and so on. The list always ends with a user message: the newest turn's answer, which the model is about to read.
## What to write
Fill in trim(messages, budget). It returns the indices of the messages to keep, or None:
1. **Always keep message 0**, the task.
2. **Always keep the newest turn**, the last two messages.
3. **Drop turns from the oldest**, a whole turn at a time: messages 1 and 2 first, then 3 and 4, and so on.
4. **Stop as soon as the kept messages fit**: their tokens add up to the budget or less. Don't drop more than you need to.
5. **If even message 0 and the newest turn are over the budget**, return None.
For the example, the whole history is 12,500 tokens. Dropping the oldest turn (messages 1 and 2) brings it to 8,200, which fits, so the output is:
`text
dropped: 1 2
kept: 0 3 4 5 6 7 8 (8,200 tokens)
`
main prints this from the list you return, and prints cannot fit for None.
<details>
<summary>A hint, if you're stuck</summary>
Start with kept = list(range(len(messages))). While the kept messages are over the budget and there's still an old turn to drop (more than three messages kept), delete the two indices right after the task: del kept[1:3].
</details>
Notice why dropping whole turns is enough to keep the history valid. Every tool_result sits in the user message right after the assistant message with its tool_use`, so removing both together can never leave one without the other, and the roles still take turns: user, assistant, user.
Sign in to try this exercise.