diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index cda0b2c65..b268db98d 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixed +- Fixed split-turn compaction summaries being refused by Claude Fable 5.1 by clearly separating the conversation and using continuation-oriented instructions ([#9652](https://github.com/earendil-works/pi/issues/9652)). - Fixed missing or invalid `--mode` values being silently ignored instead of reporting an error and exiting with a nonzero status ([#9045](https://github.com/earendil-works/pi/issues/9045)). ## [0.87.0] - 2026-09-21 diff --git a/packages/coding-agent/src/core/compaction/compaction.ts b/packages/coding-agent/src/core/compaction/compaction.ts index ea45ea6e0..1757c535c 100644 --- a/packages/coding-agent/src/core/compaction/compaction.ts +++ b/packages/coding-agent/src/core/compaction/compaction.ts @@ -961,20 +961,20 @@ export function prepareCompaction( // Main compaction function // ============================================================================ -const TURN_PREFIX_SUMMARIZATION_PROMPT = `This is the PREFIX of a turn that was too large to keep. The SUFFIX (recent work) is retained. +const TURN_PREFIX_SUMMARIZATION_PROMPT = `The messages above are earlier context from an ongoing conversation. Later messages are stored separately and do not need to be reconstructed. -Summarize the prefix to provide context for the retained suffix: +Create a concise checkpoint of the user's request and the progress shown above. This checkpoint will be placed before the later messages so the conversation can continue with the necessary context. ## Original Request -[What did the user ask for in this turn?] +[What did the user ask for?] -## Early Progress -- [Key decisions and work done in the prefix] +## Progress So Far +- [Key decisions and work completed in these messages] -## Context for Suffix -- [Information needed to understand the retained recent work] +## Context Needed to Continue +- [Information from these messages needed to understand the later work] -Be concise. Focus on what's needed to understand the kept suffix.`; +Only summarize information explicitly present above. Do not infer or recreate later messages.`; /** * Generate summaries for compaction using prepared data. @@ -1115,7 +1115,7 @@ async function generateTurnPrefixSummary( ); // Smaller budget for turn prefix const llmMessages = convertToLlm(messages); const conversationText = serializeConversation(llmMessages); - const promptText = `\n${conversationText}\n\n\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`; + const promptText = `# Conversation\n${conversationText}\n\n# Instructions\n${TURN_PREFIX_SUMMARIZATION_PROMPT}`; const response = await completeSummarization( model, diff --git a/packages/coding-agent/test/compaction-summary-reasoning.test.ts b/packages/coding-agent/test/compaction-summary-reasoning.test.ts index ab4a721ee..ce8303cbf 100644 --- a/packages/coding-agent/test/compaction-summary-reasoning.test.ts +++ b/packages/coding-agent/test/compaction-summary-reasoning.test.ts @@ -146,8 +146,9 @@ describe("generateSummary reasoning options", () => { expect(result.summary).toContain("previous checkpoint"); const requestContext = completeSimpleMock.mock.calls[0][1] as TranscriptContext; const prompt = JSON.stringify(requestContext.messages); - expect(prompt).toContain("This is the PREFIX of a turn that was too large to keep"); - expect(prompt).toContain(""); + // Regression test for #9652: clear boundaries and continuation wording avoid the reasoning-extraction false positive. + expect(prompt).toContain("# Conversation\\n[User]: Summarize this."); + expect(prompt).toContain("# Instructions\\nThe messages above are earlier context from an ongoing conversation."); }); it("rejects tool calls from conversation summaries", async () => { diff --git a/packages/coding-agent/test/suite/agent-session-compaction.test.ts b/packages/coding-agent/test/suite/agent-session-compaction.test.ts index 62dc2f10a..ef547736b 100644 --- a/packages/coding-agent/test/suite/agent-session-compaction.test.ts +++ b/packages/coding-agent/test/suite/agent-session-compaction.test.ts @@ -354,7 +354,8 @@ describe("AgentSession compaction characterization", () => { expect(transformContext).not.toHaveBeenCalled(); expect(getCurrentSystemPrompt(requestContext?.messages ?? [])).not.toBe(harness.session.agent.state.systemPrompt); expect(getCurrentTools(requestContext?.messages ?? [])).toEqual([]); - expect(JSON.stringify(requestContext?.messages)).toContain(""); + // Regression test for #9652: split-turn summaries use a clear Markdown conversation boundary. + expect(JSON.stringify(requestContext?.messages)).toContain("# Conversation\\n[User]: message to compact"); expect(requestOptions).toMatchObject({ cacheRetention: "none" }); expect(requestOptions?.sessionId).not.toBe("active-routing-session"); expect(requestOptions?.transport).toBeUndefined();