mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-05 07:37:50 +00:00
fix(context_management): move a client compaction summary into the system prompt when clearing runs before compact
This commit is contained in:
parent
2209041e4a
commit
7fd95b5f69
2 changed files with 24 additions and 16 deletions
|
|
@ -163,17 +163,17 @@ async def prepare_context_managed_request(
|
|||
)
|
||||
|
||||
# Skip the client-history pre-processing when a ``compact_20260112``
|
||||
# polyfill spec will run: that editor already slices around any client-sent
|
||||
# polyfill edit runs first: that editor already slices around any client-sent
|
||||
# compaction block in its Phase A (and uses the full post-compaction tail
|
||||
# for its token-threshold check). Pre-collapsing to just the latest user
|
||||
# question here would starve the polyfill of conversation context and
|
||||
# silently drop intermediate turns.
|
||||
polyfill_will_run: Final = _polyfill_will_run(
|
||||
compact_runs_first: Final = _compact_runs_first(
|
||||
context_management_spec=context_management_spec,
|
||||
additional_drop_params=additional_drop_params,
|
||||
)
|
||||
|
||||
if polyfill_will_run:
|
||||
if compact_runs_first:
|
||||
history_result: PolyfillResult | None = None
|
||||
working_messages: _AnthropicMessages = messages
|
||||
working_system: _AnthropicSystem = system
|
||||
|
|
@ -211,7 +211,7 @@ async def prepare_context_managed_request(
|
|||
# ``_run_polyfill_if_enabled``), apply the slice-only fallback now so
|
||||
# Anthropic-specific ``compaction`` content blocks don't leak through
|
||||
# to non-Anthropic backends that would reject them.
|
||||
if polyfill_will_run and history_result is None:
|
||||
if compact_runs_first and history_result is None:
|
||||
history_result = apply_client_compaction_block_history(
|
||||
messages=messages,
|
||||
system=system,
|
||||
|
|
@ -219,18 +219,18 @@ async def prepare_context_managed_request(
|
|||
return history_result
|
||||
|
||||
|
||||
def _polyfill_will_run(
|
||||
def _compact_runs_first(
|
||||
*,
|
||||
context_management_spec: _ContextManagementSpec,
|
||||
additional_drop_params: list[str] | None,
|
||||
) -> bool:
|
||||
"""Return True when ``compact_20260112`` will run via the polyfill dispatcher.
|
||||
"""Return True when ``compact_20260112`` is the first edit the polyfill dispatcher runs.
|
||||
|
||||
Mirrors the gating in ``_run_polyfill_if_enabled``: an empty spec or an
|
||||
explicit ``context_management`` entry in ``additional_drop_params``
|
||||
short-circuits the polyfill. The pre-processing skip only applies when the
|
||||
dispatcher will actually invoke ``apply_compact_20260112`` (which has its
|
||||
own compaction-block slicing).
|
||||
short-circuits the polyfill. The pre-processing skip only applies when
|
||||
``apply_compact_20260112`` (which has its own compaction-block slicing)
|
||||
sees the messages before any other editor does.
|
||||
"""
|
||||
edits: Final = _normalize_spec_edits(
|
||||
context_management_spec=context_management_spec,
|
||||
|
|
@ -243,7 +243,7 @@ def _polyfill_will_run(
|
|||
COMPACT_EDIT_TYPE,
|
||||
)
|
||||
|
||||
return any(edit.get("type") == COMPACT_EDIT_TYPE for edit in edits)
|
||||
return bool(edits) and edits[0].get("type") == COMPACT_EDIT_TYPE
|
||||
|
||||
|
||||
def _spec_has_non_compact_edits(
|
||||
|
|
|
|||
|
|
@ -724,8 +724,9 @@ def test_input_tokens_trigger_counts_the_system_prompt(system: str | list[dict[s
|
|||
assert with_system["cleared_input_tokens"] == met_without_system["cleared_input_tokens"] > 0
|
||||
|
||||
|
||||
async def test_input_tokens_trigger_counts_a_client_compaction_summary() -> None:
|
||||
"""A client compaction summary moves into the system prompt, so the trigger counts it too."""
|
||||
@pytest.mark.parametrize("compact_position", [None, "after", "before"], ids=["alone", "before_compact", "after_compact"])
|
||||
async def test_input_tokens_trigger_counts_a_client_compaction_summary(compact_position: str | None) -> None:
|
||||
"""A client compaction summary moves into the system prompt, so the trigger counts it too, in any edit order."""
|
||||
tail: Final = _make_history(n_pairs=3)
|
||||
edit_spec: Final = {
|
||||
"type": "clear_tool_uses_20250919",
|
||||
|
|
@ -733,6 +734,10 @@ async def test_input_tokens_trigger_counts_a_client_compaction_summary() -> None
|
|||
"keep": {"type": "tool_uses", "value": 1},
|
||||
}
|
||||
compacted_turn: Final = {"role": "assistant", "content": [{"type": "compaction", "content": "Earlier work. " * 400}]}
|
||||
compact_spec: Final = {"type": "compact_20260112", "trigger": {"type": "input_tokens", "value": 50_000}}
|
||||
edits: Final = {None: [edit_spec], "after": [edit_spec, compact_spec], "before": [compact_spec, edit_spec]}[
|
||||
compact_position
|
||||
]
|
||||
|
||||
async def prepare(messages: list[dict[str, object]]) -> PolyfillResult | None:
|
||||
return await prepare_context_managed_request(
|
||||
|
|
@ -740,18 +745,21 @@ async def test_input_tokens_trigger_counts_a_client_compaction_summary() -> None
|
|||
messages=messages,
|
||||
tools=None,
|
||||
system=None,
|
||||
context_management_spec={"edits": [edit_spec]},
|
||||
context_management_spec={"edits": edits},
|
||||
litellm_metadata=None,
|
||||
additional_drop_params=None,
|
||||
llm_router=None,
|
||||
)
|
||||
|
||||
def cleared(result: PolyfillResult | None) -> list[object]:
|
||||
applied: Final = result.applied_edits if result is not None else []
|
||||
return [edit.get("cleared_tool_uses") for edit in applied if edit.get("type") == "clear_tool_uses_20250919"]
|
||||
|
||||
without_summary: Final = await prepare(deepcopy(tail))
|
||||
with_summary: Final = await prepare([compacted_turn, *deepcopy(tail)])
|
||||
|
||||
assert without_summary is None or not without_summary.applied_edits
|
||||
assert with_summary is not None
|
||||
assert [edit.get("cleared_tool_uses") for edit in with_summary.applied_edits] == [2]
|
||||
assert cleared(without_summary) == []
|
||||
assert cleared(with_summary) == [2]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("clear_tool_inputs", "triggers"), [(False, False), (True, True)])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue