Skip to content

fix(agent): capture on_pre_compress return value and pass to compressor - #22576

Closed
hbtjm9000 wants to merge 2 commits into
NousResearch:mainfrom
hbtjm9000:fix/on-pre-compress-return-discarded
Closed

fix(agent): capture on_pre_compress return value and pass to compressor#22576
hbtjm9000 wants to merge 2 commits into
NousResearch:mainfrom
hbtjm9000:fix/on-pre-compress-return-discarded

Conversation

@hbtjm9000

@hbtjm9000 hbtjm9000 commented May 9, 2026

Copy link
Copy Markdown

What does this PR do?

Captures the return value of MemoryProvider.on_pre_compress() and passes it through to the context compressor's summarization prompt. Previously, the return value was silently discarded — every memory plugin returning compression context was broken without any error.

The fix threads memory_context through three layers:

  1. run_agent.py — capture return value as pre_compress_context
  2. ContextCompressor.compress() — accept memory_context parameter
  3. ContextCompressor._generate_summary() — inject into compression prompt

Related Issue

Fixes #7192

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

run_agent.py (+28 lines)

  • Capture on_pre_compress() return value as pre_compress_context
  • Pass memory_context=pre_compress_context to self._context_compressor.compress()

agent/context_compressor.py (+36 lines)

  • compress(): add memory_context: str = "" parameter + docstring note
  • _generate_summary(): add memory_context: str = "" parameter
  • Template: inject ## Memory Provider Context section when non-empty (using pre-defined variable to avoid Python 3.11 f-string backslash restriction)
  • All 3 retry call sites: pass memory_context through

tests/agent/test_context_compressor.py (+83 lines)

  • TestOnPreCompressIntegration class with 3 tests:
    • test_compress_accepts_memory_context_kwarg
    • test_generate_summary_injects_memory_context_into_prompt
    • test_empty_memory_context_does_not_add_section

How to Test

cd hermes-agent
source venv/bin/activate
python -m pytest tests/agent/test_context_compressor.py::TestOnPreCompressIntegration -v

All 75 existing tests continue to pass.

Checklist

  • fix(agent): Conventional Commits
  • No duplicate PRs
  • Only changes related to this fix
  • pytest tests/agent/test_context_compressor.py -q passes
  • Tests added
  • No config keys, docs, or schemas changed (bug fix restoring documented behavior)

hbtjm.agent added 2 commits May 9, 2026 07:56
Two-channel pattern:
1. Side effect: persist tagged insights (decisions, artifacts, blockers,
   config changes) to Honcho via create_conclusion() on a daemon thread.
   Survives compression; feeds future sessions through dialectic layer.
2. Return: structured summary string injected into compression LLM prompt.
   Activates automatically once upstream fixes discarded return value
   (GH #7192).

Scope: last 12 messages (6 turns) — current task cycle only.
Honcho's per-turn dialectic already captures user-model facts;
this targets operational facts the compression LLM needs.

Tested: guard paths (no-session, empty-messages, cron_skipped),
extraction + threading + create_conclusion call all verified.
MemoryProvider.on_pre_compress() return value was silently discarded at
the call site in run_agent.py. This broke all memory plugins (Honcho,
Holographic, Mem0, etc.) that rely on this hook to inject context into
the compression summary.

Changes:
- run_agent.py: capture return value as pre_compress_context, pass
  memory_context=pre_compress_context to ContextCompressor.compress()
- agent/context_compressor.py: add memory_context parameter to compress()
  and _generate_summary(); inject ## Memory Provider Context section into
  compression prompt when non-empty; update all 3 retry call sites
  to pass memory_context through
- tests/agent/test_context_compressor.py: add TestOnPreCompressIntegration
  (3 tests)

Fixes #7192
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/plugins Plugin system and bundled plugins tool/memory Memory tool and memory providers labels May 11, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Competing with #7195 and #11236 for the same fix (issue #7192). All address on_pre_compress() return value being silently discarded.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for identifying a real contract break: MemoryProvider.on_pre_compress() and MemoryManager.on_pre_compress() explicitly return text intended for the compression prompt (agent/memory_provider.py:220-230, agent/memory_manager.py:883-900). Current main still discards it at agent/conversation_compression.py:631-644.

Problems

  • The PR applies the handoff in run_agent.py, but compression orchestration was extracted to agent/conversation_compression.py by 5311d9959e19477aac8aa7deca46c1ee0b8e7000. The current production path will need the handoff there.
  • The added compressor-only tests do not exercise that orchestrator boundary, where the defect currently exists.

Suggested changes

  • Port the capture and forwarding logic to agent/conversation_compression.py:631-644, then thread it through ContextCompressor.compress() and _generate_summary() including retry paths.
  • Add an orchestration regression test with a provider returning a sentinel and assert the summarizer prompt receives it.

This is an automated hermes-sweeper review.

assert parsed["content"].endswith("...[truncated]")


# ---------------------------------------------------------------------------

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add a regression test for the actual orchestration boundary: a MemoryManager/provider returning a sentinel must cause the current compression flow to place that sentinel in the summary prompt. The production defect is now at agent/conversation_compression.py:631-644, so direct ContextCompressor.compress() coverage alone would not catch a dropped handoff.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit labels Jul 13, 2026
@teknium1 teknium1 added the area/compression Context compression and continuation sessions label Jul 19, 2026
@teknium1

Copy link
Copy Markdown
Contributor

This fix has landed on main via PR #67938 (salvaged from PR #64342 by @GottZ, which consolidated the on_pre_compress return-value forwarding with sanitization, engine-signature compatibility, and lock hardening).

Your PR correctly identified the same root cause — the provider's return value being silently discarded before compression. The merged implementation supersedes this one, so closing it. First-submitter credit goes to @jairodriguez (#11236, Apr 16); thank you for the independent confirmation and fix.

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

Labels

area/compression Context compression and continuation sessions comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: MemoryProvider.on_pre_compress() return value silently discarded — provider insights never reach the compressor

3 participants