From 9e381e1e4f714272e43965b1da3bf0c43f112d39 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Thu, 28 May 2026 03:56:10 +0000 Subject: [PATCH] fix(compact_20260112): carry prior compaction summary into Phase C summary call When a request already contains a compaction block, Phase A slices `effective_messages` to the turns since that block. Previously Phase C passed the original `system` to the summary model, so multi-round compaction silently dropped accumulated history each time the polyfill fired. Pass `augmented_system` (original system + prior summary prefix) so the summary model can produce a comprehensive summary that incorporates both the prior round's context and the current slice. `summarized_system` for the downstream call stays built from the original `system` + new `summary_text`. --- .../context_management/editors/compact.py | 6 ++- .../context_management/test_compact.py | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py index 9c4b52205c6..a13b2d288fe 100644 --- a/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py +++ b/litellm/llms/anthropic/experimental_pass_through/context_management/editors/compact.py @@ -620,10 +620,12 @@ async def apply_compact_20260112( applied_edits=[applied], ) - # Phase C: summarize. + # Phase C: summarize. ``augmented_system`` carries any prior compaction + # summary so multi-round compaction does not lose accumulated history — + # ``effective_messages`` only contains turns since the last compaction. prompt = _build_summary_prompt(edit_spec, tools) summary_messages = _build_summary_messages( - effective_messages, prompt, system=system + effective_messages, prompt, system=augmented_system ) propagated_metadata = _propagate_metadata(metadata) diff --git a/tests/test_litellm/llms/anthropic/experimental_pass_through/context_management/test_compact.py b/tests/test_litellm/llms/anthropic/experimental_pass_through/context_management/test_compact.py index 8ce5f06bcf1..059414ea695 100644 --- a/tests/test_litellm/llms/anthropic/experimental_pass_through/context_management/test_compact.py +++ b/tests/test_litellm/llms/anthropic/experimental_pass_through/context_management/test_compact.py @@ -896,6 +896,49 @@ async def test_system_prompt_forwarded_to_summary_call_as_content_blocks(): assert "Initial task: review PR #123." in content +async def test_summary_call_carries_prior_compaction_summary_into_system(): + """Multi-round: when a prior compaction block is present, the summary + model receives the augmented system (with ``Previous conversation + summary: ``) so it can produce a comprehensive summary that + incorporates both the prior round's context and the current slice. + Without this, multi-round compaction would silently drop accumulated + history each time the polyfill fires. + """ + messages = _messages_with_compaction(summary="ROUND_ONE_SUMMARY_TEXT") + mock_response = _make_mock_response("Round two") + + captured_calls: list = [] + + async def _fake_call_summary_model(**kwargs): + captured_calls.append(kwargs) + return mock_response + + with ( + patch( + "litellm.llms.anthropic.experimental_pass_through.context_management.editors.compact._read_summary_model_setting", + return_value="claude-haiku-4-5", + ), + patch("litellm.token_counter", return_value=200_000), + patch( + "litellm.llms.anthropic.experimental_pass_through.context_management.editors.compact._call_summary_model", + side_effect=_fake_call_summary_model, + ), + ): + await apply_compact_20260112( + model=MODEL, + messages=messages, + tools=None, + system="Original agent role.", + edit_spec=_EDIT_SPEC_DEFAULT, + ) + + summary_messages = captured_calls[0]["summary_messages"] + assert summary_messages[0]["role"] == "system" + system_content = summary_messages[0]["content"] + assert "ROUND_ONE_SUMMARY_TEXT" in system_content + assert "Original agent role." in system_content + + async def test_summary_call_omits_system_message_when_system_is_none(): """No system message is prepended when the caller did not provide one.""" messages = _simple_messages()