Skip to main content

LRU-based intelligent context manager for LLM agents. Keeps hot context, evicts cold.

Project description

๐Ÿ”ฅ hot-context

LRU-based intelligent context manager for LLM agents. Keeps hot context, evicts cold.

Most conversation managers use a naive sliding window โ€” drop the oldest messages when context fills up. hot-context treats your context window like an intelligent cache: every chunk is scored by relevance, recency, and access frequency, and only the highest-value context survives.

PyPI version License arXiv


Key Features

  • Relevance-aware trimming โ€” trims tool results to only the lines the LLM actually used, instead of evicting entire entries
  • Adaptive token calibration โ€” learns the real chars-per-token ratio from actual LLM feedback, self-corrects over time
  • Entity echo feedback loop โ€” uses the LLM's own response as a proxy for attention weights, zero extra API calls
  • Turn-aware eviction โ€” never evicts during a turn (LLM needs full context to reason), only trims between turns
  • Framework-agnostic core with drop-in adapters for Strands, LangChain, and OpenAI

How It Works

Turn N:
  User query โ†’ Tools return data โ†’ LLM sees FULL context โ†’ Answers
                                                              โ†“
                                          Entity echo: what did the LLM use?
                                          Trimmer: keep only relevant lines from tool results
                                          Calibrator: learn real token ratio from Bedrock
                                                              โ†“
Turn N+1:
  Context has trimmed tool results (5k instead of 80k) + all assistant answers preserved

Scoring formula (no LLM needed):

score = ฮฑยทsimilarity(chunk, query) + ฮฒยทrecency(chunk) + ฮณยทaccess_frequency(chunk) - ฮดยทsize_penalty(chunk)
  • Similarity: Jaccard overlap on extracted entities (BM25-inspired, zero API calls)
  • Recency: Exponential decay by turn distance
  • Access frequency: Time-decayed count of how often the LLM actually used this chunk
  • Size penalty: Large tool results are penalized proportionally to budget

Topic shift detection: When the user changes topics, similarity weight increases and frequency weight decreases โ€” preventing stale popular chunks from dominating.


Results

Tested against Strands SlidingWindowConversationManager on a real multi-turn agent with MCP tools (SQL queries, knowledge base lookups):

Metric SlidingWindow hot-context
Q3 (heavy query) CRASHED โ€” context overflow โœ… Answered (2831 chars)
Peak context Q2 Unbounded (168k+) 105k (trimmed)
Peak context Q3 Overflow (>200k) 113k (controlled)
Queries completed 2.5 of 3 3 of 3

Peak context went DOWN from Q1โ†’Q2 (128kโ†’105k) โ€” the trimmer removed irrelevant lines from Q1's tool result.


Quick Start

Installation

# Core โ€” no dependencies
pip install hot-context

# With AWS Strands adapter
pip install hot-context[strands]

# With embedding-based similarity (recommended for production)
pip install hot-context[embeddings]

# Everything
pip install hot-context[all]

Strands (drop-in replacement)

from strands import Agent
from strands.models.bedrock import BedrockModel
from hot_context.adapters.strands import StrandsHotContextManager
from hot_context import ScoringWeights

agent = Agent(
    model=BedrockModel(model_id="us.anthropic.claude-sonnet-4-5-20250929-v1:0"),
    conversation_manager=StrandsHotContextManager(
        token_budget=100_000,
        weights=ScoringWeights.tool_agent(),
    ),
)

Framework-agnostic core

from hot_context import HotContextManager, ScoringWeights

manager = HotContextManager(
    token_budget=100_000,
    weights=ScoringWeights.tool_agent(),
    pin_last_n=2,
)

# Before each query
manager.on_query(user_input)

# After LLM responds
manager.on_response(str(result))

Adaptive calibration (Strands)

# Token estimator self-calibrates from actual Bedrock token counts.
# After each LLM call, feed back the reported input_tokens:
cm = agent.conversation_manager
cm.calibrate(agent.messages, actual_input_tokens=87450)
# Future estimates are now more accurate โ€” no manual tuning needed.

Weight Presets

Use a built-in preset or define your own custom weights:

ScoringWeights.tool_agent()     # high similarity โ€” for agents with many tool calls
ScoringWeights.conversational() # high recency + frequency โ€” for multi-turn chat
ScoringWeights.research()       # high similarity + frequency โ€” for RAG/research agents

# Custom weights โ€” all four components must sum to 1.0
ScoringWeights(
    similarity=0.5,    # how much query-chunk relevance matters
    recency=0.2,       # how much to favor recent turns
    access_freq=0.2,   # how much to favor chunks the LLM has used before
    size_penalty=0.1,  # how much to penalize large chunks
)

Token Budget

token_budget is the maximum tokens reserved for conversation history. It should be sized as:

token_budget = model_context_limit - expected_query_tokens - system_prompt_tokens - tool_definition_tokens

For example, with Model's 200k context window:

HotContextManager(
    token_budget=100_000,  # leaves headroom for prompts, tools, and the response
)

Setting it too high risks context overflow; too low and hot-context will aggressively evict useful history.

pin_last_n

pin_last_n protects the most recent N turns from eviction, ensuring the LLM always has immediate conversational context regardless of score:

HotContextManager(
    pin_last_n=2,  # last 2 turns are never evicted (default)
)

Increase this if your agent relies heavily on recent tool results that shouldn't be trimmed mid-conversation.

Custom Entity Patterns

import re
from hot_context import HotContextManager

manager = HotContextManager(
    extra_patterns=[
        ("order_id", re.compile(r"\b\d{3}-\d{7}-\d{7}\b")),
        ("asin", re.compile(r"\bB[A-Z0-9]{9}\b")),
    ]
)

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    HotContextManager                         โ”‚
โ”‚                                                              โ”‚
โ”‚  TokenEstimator โ”€โ”€โ†’ EntityExtractor โ”€โ”€โ†’ ContextScorer        โ”‚
โ”‚       โ†‘                                      โ”‚               โ”‚
โ”‚  calibrate()                            score + rank         โ”‚
โ”‚  (from LLM)                                  โ”‚               โ”‚
โ”‚                                              โ†“               โ”‚
โ”‚  Trimmer โ†โ”€โ”€ FeedbackLoop โ†โ”€โ”€ LLM Response โ†โ”€โ”€ Evictor      โ”‚
โ”‚  (line-level    (entity echo)                (entry-level)   โ”‚
โ”‚   relevance)                                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Adapters: Strands | LangChain | OpenAI

Why Not Just Summarize?

Approach Token cost Latency Quality
Sliding window Free None Poor โ€” drops relevant old context
LLM summarization High +500ms/turn Good โ€” but expensive at scale
hot-context Free ~1ms/turn Good โ€” keeps what matters, trims what doesn't

Components

File Purpose
manager.py Core orchestrator: on_query() โ†’ score + evict, on_response() โ†’ feedback
scorer.py Scoring formula with topic shift detection and pluggable similarity
token_estimator.py Adaptive chars-per-token calibration from real LLM feedback
trimmer.py Line-level relevance trimming of tool results
chunker.py Smart chunking respecting tool-use/tool-result pairing
entity_extractor.py Regex-based entity extraction (dates, IDs, numbers, custom patterns)
feedback.py Entity echo feedback loop โ€” updates access logs from LLM response
types.py ContextEntry, AccessRecord, ScoringWeights with presets
adapters/strands.py Drop-in ConversationManager for Strands agents
adapters/langchain.py BaseChatMemory adapter for LangChain
adapters/openai.py Message list manager for OpenAI Chat API

Roadmap

P2 โ€” Benchmarks & Paper

  • Benchmark harness โ€” synthetic multi-turn conversations with known answers. Measure token savings + answer quality (ROUGE/BERTScore on trimmed vs full context)
  • Standard benchmarks โ€” LongBench, SCROLLS, QuALITY, NarrativeQA for long-context evaluation
  • Ablation studies โ€” trimmer-only vs scorer-only vs full pipeline vs baselines (MemGPT, LLMLingua, attention sink)
  • Token savings curves โ€” plot peak context vs conversation length across strategies

Contributing

Issues and PRs welcome at github.com/Ankit28P/hot-context.

License

Apache 2.0 โ€” see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hot_context-0.1.0b1.tar.gz (30.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hot_context-0.1.0b1-py3-none-any.whl (26.3 kB view details)

Uploaded Python 3

File details

Details for the file hot_context-0.1.0b1.tar.gz.

File metadata

  • Download URL: hot_context-0.1.0b1.tar.gz
  • Upload date:
  • Size: 30.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.10

File hashes

Hashes for hot_context-0.1.0b1.tar.gz
Algorithm Hash digest
SHA256 bd5965b9320465b7575978de02a8595aa321e78a83df189958de946e3392f3d6
MD5 a14a0740e4641767f4fb5fbeeb2da46b
BLAKE2b-256 afe44b541edde04716ddb2297bf95326e4636d6e83a1ace1cef417a36c302973

See more details on using hashes here.

File details

Details for the file hot_context-0.1.0b1-py3-none-any.whl.

File metadata

  • Download URL: hot_context-0.1.0b1-py3-none-any.whl
  • Upload date:
  • Size: 26.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.10

File hashes

Hashes for hot_context-0.1.0b1-py3-none-any.whl
Algorithm Hash digest
SHA256 405fbb5e1a5a42153665299a72b941c77d8b8a34e5e22b6f9887e13b7d02cbc7
MD5 25489df0775c49ed5e6a73ae9350b4ab
BLAKE2b-256 d93abbcf55f929800cf0f24d93dab48beb48ef77540634527840518117ba527a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page