Skip to content

feat: add context compaction hook - #12196

Draft
sjrl wants to merge 16 commits into
mainfrom
add-context-compaction
Draft

feat: add context compaction hook#12196
sjrl wants to merge 16 commits into
mainfrom
add-context-compaction

Conversation

@sjrl

@sjrl sjrl commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Related Issues

Proposed Changes:

Added experimental context compaction for the Agent. ContextCompactionHook runs before LLM calls and shortens the conversation when it reaches a configured fraction of the model's context window.

The first built-in strategy, SlidingWindowCompactor, preserves leading system messages and as much recent history as the target allows. It replaces removed history with a short omission note.

from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.hooks.compaction import ContextCompactionHook, SlidingWindowCompactor

hook = ContextCompactionHook(
    compactor=SlidingWindowCompactor(),
    context_window=200_000,
    compact_at=0.7,
    compact_to=0.4,
)
agent = Agent(
    chat_generator=OpenAIChatGenerator(model="gpt-5.4-nano"),
    tools=[web_search],
    hooks={"before_llm": [hook]},
)

The hook uses provider-reported context usage when available and locally estimates the request otherwise, including
tool schemas. Leave headroom above compact_at for the next reply and its tool results.

SlidingWindowCompactor keeps tool calls together with their results, so it may retain slightly more history than the requested target. Compaction is lossy: removed messages cannot be recovered or summarized by this strategy. Implement the Compactor protocol to provide a custom strategy.

ContextCompactionHook and SlidingWindowCompactor emit an ExperimentalWarning and may change without a deprecation cycle.

How did you test it?

New tests

Notes for the reviewer

Checklist

  • I have read the contributors guidelines and the code of conduct.
  • I have updated the related issue with new insights and changes.
  • I have added unit tests and updated the docstrings.
  • I've used one of the conventional commit types for my PR title: fix:, feat:, build:, chore:, ci:, docs:, style:, refactor:, perf:, test: and added ! in case the PR includes breaking changes.
  • I have documented my code.
  • I have added a release note file, following the contributors guidelines.
  • I have run pre-commit hooks and fixed any issue.

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
haystack-docs Ignored Ignored Preview Jul 31, 2026 10:10am

Request Review

@sjrl sjrl self-assigned this Jul 30, 2026
@github-actions github-actions Bot added topic:tests type:documentation Improvements on the docs labels Jul 30, 2026
@sjrl
sjrl force-pushed the add-context-compaction branch from f150d3a to bc92e30 Compare July 30, 2026 12:47
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/hooks/compaction
  __init__.py
  hooks.py 215, 222, 227, 239-240
  sliding_window.py
  utils.py
  haystack/hooks/compaction/types
  __init__.py
  protocol.py
Project Total  

This report was generated by python-coverage-comment-action

@sjrl sjrl mentioned this pull request Jul 30, 2026
Base automatically changed from add-token-counters to main July 30, 2026 16:00
@sjrl
sjrl requested a review from anakin87 July 31, 2026 10:10
# The conversation is not yet large enough to compact, so leave it alone.
return None
# Calculate an overhead that is not compactable: the system prompt, tool schemas, and chat-template overhead.
overhead = estimated - self.token_counter.count(messages=messages)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the overhead is negative, should we log a warning to alert the user that the token_counter tends to overestimate?

Comment on lines +50 to +52
:param min_keep_messages: The fewest recent messages to keep even when they exceed the target. Keeping at least
1 is recommended, since the caller may be mid-step with a pending tool call whose result is appended right
after compaction. `0` removes everything after the leading system messages.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some doubts about min_keep_messages

  • I'm not sure that the explanation is correct
  • looking at how it works, what about using min_keep_turns instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats fair! For something like min_keep_turns what would you say a full turn is? Is one turn a "user" --> "assistant" --> "all tool results" group?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Sorry, maybe min_keep_steps is better where step = assistant msg + all tool results
  2. I now notice that we risk losing the first user message that probably contains the most relevant info

Implement `to_dict` so the compactor's settings survive serialization. The default `from_dict` passes them straight
back to the constructor, which is enough for plain values; override it when `to_dict` emitted something that has to
be rebuilt first, such as a `Secret` or a nested component.
"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhere we should mention that a Compactor should not divide tool results from tool calls

Comment thread haystack/hooks/compaction/utils.py
@anakin87

Copy link
Copy Markdown
Member

I left some comments but overall I like the design!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants