Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion agent_core/runtime/loop/compact_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ def _partition(
forward += 1
if forward < len(rest):
split_idx = forward
else:
elif split_idx < len(rest):
# The whole tail is tool results — a parallel tool-call turn that
# emitted at least ``keep_recent`` of them. Walking forward runs off
# the end and leaves the last result orphaned (the bug this guard
Expand All @@ -393,6 +393,10 @@ def _partition(
# recent history survives, not a cap.
while split_idx > 0 and is_tool_msg(rest[split_idx]):
split_idx -= 1
# ``split_idx == len(rest)`` (``keep_recent=0``: summarise everything) is
# neither case. The kept window is EMPTY, so no orphan is possible, and
# both walks are meaningless — the forward one has nothing to scan and
# the backward one would index one past the end. Leave the split alone.

return sys_msgs, rest[:split_idx], rest[split_idx:]

Expand Down
27 changes: 27 additions & 0 deletions tests/test_compact_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,33 @@ def test_partition_still_shrinks_the_window_when_it_can() -> None:
assert middle == history[1:3]


def test_partition_summarises_everything_when_nothing_is_kept() -> None:
"""``keep_recent=0`` asks for the whole history to be summarised.

The kept window is then empty, so the orphan guard has nothing to protect:
walking forward runs off the end, and the backward walk added for a
tool-result tail indexed one past it — an ``IndexError`` that callers
summarising a finished session (``keep_recent=0`` is how they ask for it)
swallowed as "no summary available", silently losing the rollup.
"""
history: list[Message] = [
system_msg("S"),
user_msg("q"),
{
"role": "assistant",
"content": "",
"tool_calls": [{"id": "a", "function": {"name": "web_search", "arguments": "{}"}}],
},
tool_msg("result a", "a"),
]

system, middle, recent = LLMSummaryCompactor._partition(history, keep_recent=0)

assert system == [history[0]]
assert middle == history[1:]
assert recent == []


def test_rate_limit_naming_a_retry_delay_is_still_transient() -> None:
"""A bare ``400`` inside a provider message is not a status code.

Expand Down