mirror of
https://github.com/usestrix/strix.git
synced 2026-08-21 10:48:59 +02:00
fix(context): never floor summary input above the model's remaining room
The 1,000-token floor on summary-input room could exceed the space actually left after instructions, the reserved summary output, and any existing checkpoint. On a small window the summary request then overflowed and returned nothing, leaving the oversized session uncompacted. Clamp to the real room instead so the request always fits.
This commit is contained in:
@@ -28,8 +28,6 @@ logger = logging.getLogger(__name__)
|
||||
_CHECKPOINT_TAG = "<conversation-checkpoint>"
|
||||
_TOOL_OUTPUT_MAX_CHARS = 2_000
|
||||
_MIN_ITEMS_TO_COMPACT = 6
|
||||
# Floor for how much of the head we still try to summarise even on a tiny model.
|
||||
_MIN_SUMMARY_INPUT_TOKENS = 1_000
|
||||
_HEAD_TRUNCATED_MARKER = "\n\n[... older conversation omitted to fit the summary request ...]\n\n"
|
||||
|
||||
# Substrings that identify a context-window-overflow error across providers.
|
||||
@@ -214,9 +212,11 @@ def _summary_input_budget(model: str, previous: str | None) -> int:
|
||||
if previous:
|
||||
overhead += count_tokens(model, previous)
|
||||
# Leave slack for the prompt's wrapper text ("Conversation to summarise:",
|
||||
# the update instructions, etc.) that is not part of ``overhead``.
|
||||
# the update instructions, etc.) that is not part of ``overhead``. Never
|
||||
# floor above the actual room: doing so would let the summary request
|
||||
# itself overflow a small window (and then compaction silently fails).
|
||||
room = context_window(model) - context.summary_max_tokens - overhead - 256
|
||||
return max(_MIN_SUMMARY_INPUT_TOKENS, room)
|
||||
return max(0, room)
|
||||
|
||||
|
||||
def _build_summary_prompt(serialized_head: str, previous: str | None) -> str:
|
||||
|
||||
@@ -202,6 +202,29 @@ async def test_maybe_compact_bounds_summary_prompt(monkeypatch: pytest.MonkeyPat
|
||||
assert len(captured["prompt"]) <= 4_000
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_summary_request_fits_when_room_is_below_old_floor(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
# When the window leaves less head-input room than the old fixed floor, the
|
||||
# budget must shrink to the real room so the request still fits the window
|
||||
# (a fixed floor above the room would overflow and silently fail).
|
||||
instructions = len(compaction._SUMMARY_INSTRUCTIONS)
|
||||
window = instructions + 64 + 256 + 300 # summary_max(64)+slack(256)+room(300)
|
||||
_patch_budget(monkeypatch, keep_tokens=30, window=window)
|
||||
captured: dict[str, str] = {}
|
||||
|
||||
async def fake_acompletion(**kwargs: Any) -> Any:
|
||||
captured["prompt"] = kwargs["messages"][0]["content"]
|
||||
return SimpleNamespace(choices=[SimpleNamespace(message=SimpleNamespace(content="S"))])
|
||||
|
||||
monkeypatch.setattr("strix.llm.compaction.litellm.acompletion", fake_acompletion)
|
||||
session = FakeSession([{"role": "user", "content": "y" * 5_000} for _ in range(20)])
|
||||
|
||||
assert await compaction.maybe_compact(session, model="m") is True
|
||||
assert len(captured["prompt"]) <= window
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_maybe_compact_skips_when_summary_fails(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
_patch_budget(monkeypatch, keep_tokens=30, window=50)
|
||||
|
||||
Reference in New Issue
Block a user