fix: preserve condensation summary during task resume (#11487) (#11488)

Co-authored-by: Sannidhya <sann@Sannidhyas-MacBook-Pro.local>
This commit is contained in:
SannidhyaSah 2026-02-16 22:51:52 +05:30 committed by GitHub
parent 77ed60a173
commit 3e24e21c3d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 63 additions and 1 deletions

View file

@ -518,4 +518,56 @@ describe("Rewind After Condense - Issue #8295", () => {
})
})
})
describe("Resume after condense preserves summary", () => {
it("should keep condensed messages filtered when a new user message is added after summary", () => {
const condenseId = "summary-resume-test"
// Simulate post-condensation state: all old messages tagged, summary at end,
// then a new user message added after resume (the fix preserves summary)
const historyAfterResume: ApiMessage[] = [
{ role: "user", content: "Original task", ts: 100, condenseParent: condenseId },
{ role: "assistant", content: "Response 1", ts: 200, condenseParent: condenseId },
{ role: "user", content: "Follow-up", ts: 300, condenseParent: condenseId },
{ role: "assistant", content: "Response 2", ts: 400, condenseParent: condenseId },
{
role: "user",
content: [{ type: "text", text: "## Conversation Summary\nSummary of work done" }],
ts: 401,
isSummary: true,
condenseId,
},
// New user message added after resume (no isSummary, no condenseId)
{ role: "user", content: [{ type: "text", text: "Please continue with the next step" }], ts: 500 },
]
const effective = getEffectiveApiHistory(historyAfterResume)
// Should only include summary + new message (fresh start model)
expect(effective).toHaveLength(2)
expect(effective[0].isSummary).toBe(true)
expect(effective[1].ts).toBe(500)
})
it("should restore ALL messages if summary is missing (the bug scenario before fix)", () => {
const condenseId = "summary-bug-demo"
// Simulate the bug: summary was stripped during resume, replaced with regular message.
// condenseParent tags still exist but point to a non-existent summary.
const historyWithoutSummary: ApiMessage[] = [
{ role: "user", content: "Original task", ts: 100, condenseParent: condenseId },
{ role: "assistant", content: "Response 1", ts: 200, condenseParent: condenseId },
{ role: "user", content: "Follow-up", ts: 300, condenseParent: condenseId },
{ role: "assistant", content: "Response 2", ts: 400, condenseParent: condenseId },
// Summary was REMOVED and replaced with a regular user message (no isSummary)
{ role: "user", content: [{ type: "text", text: "Summary content merged with new input" }], ts: 500 },
]
const effective = getEffectiveApiHistory(historyWithoutSummary)
// Without the summary, ALL messages are restored (orphaned condenseParent)
// This demonstrates the bug: condensation is effectively undone
expect(effective).toHaveLength(5)
})
})
})

View file

@ -2099,7 +2099,17 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
if (existingApiConversationHistory.length > 0) {
const lastMessage = existingApiConversationHistory[existingApiConversationHistory.length - 1]
if (lastMessage.role === "assistant") {
if (lastMessage.isSummary) {
// IMPORTANT: If the last message is a condensation summary, we must preserve it
// intact. The summary message carries critical metadata (isSummary, condenseId)
// that getEffectiveApiHistory() uses to filter out condensed messages.
// Removing or merging it would destroy this metadata, causing all condensed
// messages to become "orphaned" and restored to active status — effectively
// undoing the condensation and sending the full history to the API.
// See: https://github.com/RooCodeInc/Roo-Code/issues/11487
modifiedApiConversationHistory = [...existingApiConversationHistory]
modifiedOldUserContent = []
} else if (lastMessage.role === "assistant") {
const content = Array.isArray(lastMessage.content)
? lastMessage.content
: [{ type: "text", text: lastMessage.content }]