My agent kept hitting context limits. This one function fixed it. A developer created `agent-message-trim`, a Python library that solves context window limits in AI agents by intelligently trimming conversation history while preserving paired tool_use and tool_result messages. The function ensures trimmed message histories remain valid for Anthropic's API, preventing request rejections that occur when tool calls are separated from their results. The library supports multiple trimming strategies, including dropping oldest messages or removing from the middle of conversations. This is a submission for the Hermes Agent Challenge. My Hermes research agent was failing after about 40 turns. The cause: conversation history growing past the context window. The fix everyone reaches for is "just drop old messages" — but if you drop a tool use without its matching tool result , Anthropic's API rejects the whole request. I needed something smarter. That's agent-message-trim . python from agent message trim import trim messages result = trim messages messages, max tokens=4000 Send result.messages to the model — it's safe. response = client.messages.create model="claude-sonnet-4-5", messages=result.messages, ... print f"Dropped {result.dropped count} messages to fit" This is the part that matters. If your history looks like this: {"role": "user", "content": "search for X"}, {"role": "assistant", "content": {"type": "tool use", "id": "call 001", ...} }, {"role": "user", "content": {"type": "tool result", "tool use id": "call 001", ...} }, {"role": "assistant", "content": "Here is what I found."}, trim messages never drops the tool use without also dropping its tool result . They move as a unit. The conversation you get back is always API-valid. result = trim messages messages, max tokens=4000, keep system=True system-role messages are pinned — never dropped, not counted toward drop candidates Default: drop from the front oldest messages go first result = trim messages messages, max tokens=4000, strategy="drop oldest" Keep first + last, remove from the middle result = trim messages messages, max tokens=4000, strategy="drop middle" drop middle is useful when you want to keep the original task context AND the most recent exchange, but can sacrifice the middle of a long conversation. The built-in estimator is max 1, len text +3 //4 . Plug in your own: python import tiktoken enc = tiktoken.encoding for model "gpt-4o" result = trim messages messages, max tokens=4000, count tokens=lambda text: len enc.encode text , result = trim messages messages, max tokens=4000 result.messages trimmed list result.token count estimated tokens used result.original count how many messages came in result.dropped count how many were removed result.ok True if nothing was dropped result.kept count len result.messages python from agent message trim import trim to fit trimmed = trim to fit messages, max tokens=4000 returns the list directly Standard library only: json , dataclasses . Nothing else. pip install agent-message-trim