FIELD NOTES · 02 · JULY 2026

What My Hermes Token Logs Revealed About Long Agent Conversations

A ¥100 bill sent me digging through my agent’s logs. The surprise wasn’t how much I was asking. It was how much old context each new request carried along.

Claude Code had stopped working for me, so I’d been trying a few Chinese-developed models. After a full day running GLM5.2, I noticed my coding agent’s bill was much higher than I expected: about ¥100.

I wasn’t completely oblivious to context management. I usually watched the context-usage indicator, and I’d used Claude Code enough to expect it to compact a conversation as it grew. Long chats hadn’t felt like something I needed to worry about very much.

Then I opened the Hermes conversation records and token data.

In one conversation containing 239 messages, the database recorded:

The database as a whole showed a similar pattern: about 6.0M input tokens and 80M cache-read tokens.

That ratio does not mean the same context was replayed exactly 39 times. It also does not mean the bill was 39 times larger. It means the cumulative volume of cached tokens read was about 39 times the volume recorded as new input.

Each new message could be quite small. The history travelling behind it was not.

1. Why I didn’t notice sooner

Looking back, three things were working together.

First, I’d brought my Claude Code habits with me. In my usual workflow, I watched the context indicator and expected automatic compaction to step in as the conversation approached its limit. Over time, that became a default assumption: keep an eye on the gauge, and the agent will handle the rest. I carried that assumption into other tools.

Second, agents don’t all manage context in the same way. Claude Code, Codex, and Hermes differed in when they compacted, which thresholds they used, and how much manual intervention they expected. Their commands and interfaces differed too. Moving between CLIs and desktop clients, I never developed a reliable habit for when to compact—or which command to use where.

Third, prompt caching felt like a safety net. Reading cached input is often much cheaper than processing fresh input. I assumed that even if a request carried a lot of history, a good cache hit would keep the bill manageable.

That wasn’t entirely wrong. But I’d underestimated the cumulative volume. Caching lowers the unit cost. If an ever-growing context keeps being reused, the total can still become substantial.

Large files and long tool outputs made this worse. Reading several hundred lines of a file may not be a one-off cost. If that content stays in the conversation, later requests can carry it again and count it as cached input.

The question I needed to ask wasn’t “How many more questions did I ask today?” It was “How much old material is coming along with every request?”

2. What goes into an agent request?

It helps to think of the input in three parts.

A relatively stable prefix. This can include system instructions, operating rules, tool definitions, user memory, project guidance, and a list of available skills. It may not keep growing, but it gives every request a baseline size.

The conversation history. As long as earlier messages are retained, they may appear in later requests. Longer conversations generally mean more history to carry.

Tool results. File contents, search results, terminal output, and error logs all enter the context. A single file read can contribute more text than several rounds of ordinary conversation.

The snowball is mostly in the last two: accumulating history and uncontrolled tool output.

Skills need a little more nuance. A skill list may be part of the stable prefix. Whether detailed instructions, references, and templates remain in context depends on the agent’s loading mechanism. Installing a skill does not automatically mean every file in it is permanently added to every request.

3. Why compaction came too late in this setup

A long conversation doesn’t have to grow forever. An agent can compact older history as it approaches a threshold, replacing earlier exchanges with a shorter summary of the state that matters.

In the Hermes version I inspected, the problem was the number used to make that decision. The active preflight path still passed a rough character-based token estimate into the compaction check, rather than the provider’s actual prompt_tokens. Tracking for the real token count existed elsewhere, but it wasn’t wired into that preflight path.

The rough estimate used a conversion like this:

estimated_tokens = characters / 4

That is only an approximation, and it can be particularly misleading for Chinese text. Under this formula, 1,000 Chinese characters become an estimate of just 250 tokens. The actual count depends on the model and tokenizer; in many Chinese-language cases, it can be substantially higher—sometimes around twice that estimate or more.

So the compaction check could be receiving half the real count, or less. The context was already large, but the estimate still said it hadn’t reached the threshold. The old history stayed, and the next request carried it again.

This was a specific code-path issue in the version I examined. It doesn’t establish that all coding agents have the same defect. It does point to a broader risk:

A fixed characters-to-tokens ratio is a shaky basis for deciding when to compact multilingual context.

4. Cheap cache reads are not context management

Prompt caching lets a repeated prefix be reused at a lower price and with less prefill work. That is useful. It does not replace compaction.

Cache-read and cache-write pricing differ across providers and models. To calculate the input-side cost, you need the applicable rates:

Input cost
= input_tokens × input price
+ cache_write_tokens × cache-write price
+ cache_read_tokens × cache-read price

In this environment, estimated_cost_usd=0 in the Hermes database meant the model’s pricing information hadn’t been matched. It did not mean the calls were free.

Cached content also still belongs to the model’s context. Lower processing costs don’t make it disappear from the context window. A large context can still affect the remaining room, latency, and subsequent reasoning.

Caching and compaction answer different questions:

My mistake was letting the low price of the first distract me from the cumulative effect of neglecting the second.

5. What I’d do differently

Check context management when changing agents

I can’t assume that habits from one agent transfer directly to another. I need to check whether it compacts automatically, whether its threshold uses real token counts or an estimate, and what its manual compaction command actually does.

In the Hermes version I inspected, /compress could trigger compaction manually.

Use task boundaries, not a magic message count

“Compact every 60 messages” is, at best, a reminder. Sixty short exchanges and sixty large file reads can differ enormously in size.

Better moments to pause are when a phase is finished, when I’m about to switch tasks, after a lot of file or terminal output, or when the earlier process no longer needs to be preserved word for word.

Compaction is lossy. If the next task is largely unrelated, I can first create a handoff note with the key conclusions, files, constraints, and unfinished work—then start a new conversation.

Find the relevant part before reading a large file

Use rg, code search, or symbol navigation to locate the function, then read the relevant section. The point isn’t “never read large files.” It’s to avoid repeatedly putting an entire file into context before I even know where the problem is.

Filter long output; don’t just redirect it

Writing a command’s full output to a file doesn’t save tokens by itself. If I then read the whole file back into the conversation, little has changed.

What helps is reading only the error lines, checking the end with tail, extracting a statistical summary, searching for a keyword, or selecting the relevant range.

Watch cumulative usage as well as the context gauge

A context indicator tells me how close the current window is to its limit. It may not tell me how many cache reads have accumulated, or what they have cost.

When usage data is available, I want to look at input_tokens, cache_read_tokens, cache_write_tokens, and output_tokens, along with the number of API calls and how the prompt size changes from request to request.

The cache_read / input ratio isn’t a replay counter. It can still be a useful clue that a long conversation is repeatedly carrying a large amount of old material.

6. The lesson I’m keeping

This wasn’t simply a case of forgetting that context needs managing. Three reasonable assumptions had combined in an unhelpful way:

What I need isn’t one compression command to memorize. It’s a habit of checking how each tool works, tidying context at task boundaries, limiting unnecessary tool output, and looking at both unit prices and total usage.

An agent becoming heavier as a conversation grows doesn’t always mean there’s a bug. It isn’t always user error either. Sometimes it happens in the gap between automatic compaction, caching, and the habits we bring to the tool.

Luckily, this lesson cost me a ¥100 bill—not a long-running task that had truly spiralled out of control.

I’m writing it down partly so I remember, and partly for anyone else approaching these tools from a non-engineering background. I hope it saves you a similar surprise.