Drop dropped-turn excerpts when the summary ledger is included

The ledger supersedes the "Earlier conversation excerpts" message, as on
main; sending both duplicated dropped-turn content. Removal is consistent
whenever the ledger is included, so the cached prefix stays stable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 23:05:21 -04:00
parent 1e638e1e3b
commit 266c6a8d79
2 changed files with 19 additions and 2 deletions
+9
View File
@@ -506,6 +506,15 @@ def trim_history(
"Omitting optional conversation summary to preserve current request"
)
return trimmed
# The ledger supersedes excerpts of dropped turns; whenever it is included
# they are consistently absent, so this doesn't disturb the cached prefix.
if (
with_room
and isinstance(with_room[0], AIMessage)
and isinstance(with_room[0].content, str)
and with_room[0].content.startswith("Earlier conversation excerpts")
):
with_room = with_room[1:]
# The ledger changes every turn, so place it just before the current turn:
# system, tools and retained history then stay byte-identical for the
# prompt cache. Turns start at a HumanMessage, so the last one opens the
+10 -2
View File
@@ -501,8 +501,16 @@ def test_summary_placed_before_current_turn_when_turns_dropped():
assert cost(out) <= 6000
assert out[-4:] == [summary, question, messages[-2], messages[-1]]
assert out.count(summary) == 1
# Excerpts of dropped turns stay at the head; they only change with the cut.
assert out[0].content.startswith("Earlier conversation excerpts")
# The ledger supersedes excerpts of dropped turns; don't send both.
assert not any(
isinstance(m.content, str)
and m.content.startswith("Earlier conversation excerpts")
for m in out
)
assert isinstance(out[0], HumanMessage)
# Without a ledger, the excerpts still cover the dropped turns.
plain = trim_history(messages, token_budget=6000)
assert plain[0].content.startswith("Earlier conversation excerpts")
assert_valid_sequence(out)