fix(compaction): ignore synthetic tail turn boundaries

This commit is contained in:
Aiden Cline
2026-05-12 10:14:54 -05:00
parent 831a18faaf
commit 169560a557
2 changed files with 39 additions and 0 deletions

View File

@@ -186,6 +186,7 @@ function turns(messages: MessageV2.WithParts[]) {
const msg = messages[i]
if (msg.info.role !== "user") continue
if (msg.parts.some((part) => part.type === "compaction")) continue
if (msg.parts.some((part) => part.type === "text" && part.metadata?.compaction_tail === true)) continue
result.push({
start: i,
end: messages.length,

View File

@@ -1497,6 +1497,44 @@ describe("session.compaction.process", () => {
}).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }) }))
})
itCompaction.instance("summarizes previous synthetic tail on repeated compaction", () => {
const stub = llm()
let captured = ""
stub.push(reply("summary one"))
stub.push(reply("summary two", (input) => (captured = JSON.stringify(input.messages))))
return Effect.gen(function* () {
const ssn = yield* SessionNs.Service
const session = yield* ssn.create({})
yield* createUserMessage(session.id, "older")
yield* createUserMessage(session.id, "previous tail")
yield* createCompactionMarker(session.id)
let msgs = yield* ssn.messages({ sessionID: session.id })
let parent = msgs.at(-1)?.info.id
expect(parent).toBeTruthy()
yield* SessionCompaction.use.process({ parentID: parent!, messages: msgs, sessionID: session.id, auto: false })
yield* createUserMessage(session.id, "new tail")
yield* createCompactionMarker(session.id)
msgs = MessageV2.filterCompacted(MessageV2.stream(session.id))
parent = msgs.at(-1)?.info.id
expect(parent).toBeTruthy()
yield* SessionCompaction.use.process({ parentID: parent!, messages: msgs, sessionID: session.id, auto: false })
const tails = (yield* ssn.messages({ sessionID: session.id })).filter(
(item) => item.info.role === "user" && item.parts.some((part) => part.type === "text" && part.metadata?.compaction_tail === true),
)
const latestTail = tails.at(-1)
expect(captured).toContain("previous tail")
expect(captured).toContain("latest-messages")
expect(JSON.stringify(latestTail?.parts)).toContain("new tail")
expect(JSON.stringify(latestTail?.parts)).not.toContain("previous tail")
}).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 10_000 }) }))
})
itCompaction.instance(
"ignores previous summaries when sizing the serialized tail",
Effect.gen(function* () {