This page documents the context compression system in Hermes Agent. Context compression automatically reduces conversation history to fit within model context limits while preserving conversation continuity and task state.
For information about the conversation loop and message handling, see Core Agent For prompt construction and caching, see Core Agent
The context compression system solves the problem of conversations exceeding model context limits. As agent conversations grow through repeated tool calls and responses, the token count can exceed the model's maximum context length. Rather than truncating history or failing requests, Hermes implements surgical compression that:
context_overflow or image_too_large by shrinking base64 image parts or triggering emergency compaction. agent/conversation_compression.py20-23 agent/error_classifier.py51-53The system is primarily implemented in the ContextCompressor class, which handles the logic of summarizing middle turns while protecting the head and tail of the conversation. agent/context_compressor.py3-6
Sources: agent/context_compressor.py1-17 agent/conversation_compression.py1-27 agent/error_classifier.py51-53
Hermes employs a pluggable context engine architecture. While ContextCompressor is the default, the system supports third-party engines via the ContextEngine base class. agent/context_engine.py32-61
The following diagram illustrates how the ContextCompressor bridges the high-level conversation state with the low-level message list and model constraints.
Context Compression Data Flow
Sources: agent/context_compressor.py26-32 agent/context_engine.py32-61 agent/error_classifier.py77-94 agent/conversation_compression.py15-23 agent/agent_init.py33-41
Before compression can occur, the system must determine the model's limits. ContextCompressor initializes these values during setup. agent/context_compressor.py116-120
get_model_context_length to resolve limits based on the model name and provider. agent/context_compressor.py30-31threshold_tokens (trigger point for compression) is calculated as a percentage of the total context_length. agent/context_compressor.py124check_compression_model_feasibility warns at session start if the auxiliary compression model's context window is smaller than the main model's compression threshold. agent/conversation_compression.py5-9gpt-4 on Codex, the threshold is automatically adjusted to maximize the usable window before summarization. agent/chat_completion_helpers.py136-152Sources: agent/context_compressor.py116-124 agent/conversation_compression.py5-9 agent/chat_completion_helpers.py136-152 agent/model_metadata.py30-32
The ContextCompressor uses a "head-middle-tail" strategy to ensure the agent never loses its original instructions or its most recent context. agent/context_compressor.py4-5
Before LLM summarization, the compressor performs an informative pre-pass via _summarize_tool_result. This replaces large tool outputs with descriptive 1-line summaries. agent/context_compressor.py14
| Segment | Logic | Purpose |
|---|---|---|
| Protected Head | First protect_first_n messages | Keeps the system prompt and the initial user exchange. agent/context_compressor.py111 |
| Compacted Middle | Turns between Head and Tail | Summarized into a single structured message. agent/context_compressor.py4-5 |
| Protected Tail | Last protect_last_n messages or tail_token_budget | Keeps the most recent context for immediate continuity. agent/context_compressor.py13 agent/context_compressor.py126 |
To prevent the agent from being "hijacked" by old instructions in the summary, Hermes uses strict framing in SUMMARY_PREFIX. agent/context_compressor.py95-122
HISTORICAL_TASK_HEADING) to avoid being read as active directives. agent/context_compressor.py92-93COMPRESSED_SUMMARY_METADATA_KEY so frontends can filter them. agent/context_compressor.py138-139Hermes implements protections to ensure that compressed state remains consistent across parallel execution paths.
_fresh_compaction_message_copy and _strip_persistence_markers ensure that messages copied into a new compacted transcript don't carry stale database markers (_db_persisted) that would prevent them from being saved to the new session. agent/context_compressor.py154-172_CompressionLockLeaseRefresher) maintains the lock during long-running summarization tasks. agent/conversation_compression.py99-130Sources: agent/context_compressor.py92-139 agent/context_compressor.py154-172 agent/conversation_compression.py55-130 tests/agent/test_compression_concurrent_fork.py1-27
Compression behavior is controlled via parameters passed to the ContextCompressor.
| Parameter | Description |
|---|---|
threshold_percent | Triggers compression when prompt tokens reach this percentage of context. agent/context_compressor.py124 |
protect_first_n | Number of messages to preserve at the start (Head). agent/context_compressor.py111 |
protect_last_n | Minimum number of recent messages to preserve (Tail). agent/context_compressor.py112 |
The ContextCompressor includes logic to defer preflight compression checks (should_defer_preflight_to_real_usage) if recent real usage was significantly below the threshold, avoiding unnecessary overhead. tests/agent/test_context_compressor.py122-130
Sources: agent/context_compressor.py111-124 tests/agent/test_context_compressor.py122-130
Code Entity Relationships
Sources: agent/context_compressor.py17-25 agent/context_engine.py32 agent/agent_init.py33
should_compress(prompt_tokens) agent/context_compressor.py228: Checks if the current token count exceeds threshold_tokens. agent/context_compressor.py228-232_align_boundary_forward agent/context_compressor.py503: Ensures compression boundaries don't split atomic message blocks (e.g., a tool call and its response). agent/context_compressor.py503-519_find_tail_cut_by_tokens agent/context_compressor.py455: Calculates how many messages to keep at the end to stay within the token budget. agent/context_compressor.py455-471update_from_response(usage) agent/context_compressor.py210: Updates internal token tracking based on actual usage reported by the provider. agent/context_compressor.py210-218Sources: agent/context_compressor.py210-232 agent/context_compressor.py455-471 agent/context_compressor.py503-519
Refresh this wiki