From f58c11562605a21bcf3d3e45553c78fe105809f9 Mon Sep 17 00:00:00 2001 From: Vegard Stikbakke Date: Wed, 1 Jul 2026 15:37:00 +0200 Subject: [PATCH] fix(coding-agent): serialize split-turn compaction summaries closes #5536 --- packages/agent/CHANGELOG.md | 4 +++ .../src/harness/compaction/compaction.ts | 16 +++++++--- packages/coding-agent/CHANGELOG.md | 1 + .../src/core/compaction/compaction.ts | 32 +++++++++---------- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index 7b89b46e7..fb693ad86 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed harness split-turn compaction to serialize summary requests so single-concurrency providers are not asked to run overlapping generations ([#5536](https://github.com/earendil-works/pi/issues/5536)). + ## [0.80.3] - 2026-06-30 ### Added diff --git a/packages/agent/src/harness/compaction/compaction.ts b/packages/agent/src/harness/compaction/compaction.ts index 2d6d55837..4132e3ddc 100644 --- a/packages/agent/src/harness/compaction/compaction.ts +++ b/packages/agent/src/harness/compaction/compaction.ts @@ -653,9 +653,9 @@ export async function compact( let summary: string; if (isSplitTurn && turnPrefixMessages.length > 0) { - const [historyResult, turnPrefixResult] = await Promise.all([ + const historyResult = messagesToSummarize.length > 0 - ? generateSummary( + ? await generateSummary( messagesToSummarize, models, model, @@ -665,10 +665,16 @@ export async function compact( previousSummary, thinkingLevel, ) - : Promise.resolve(ok("No prior history.")), - generateTurnPrefixSummary(turnPrefixMessages, models, model, settings.reserveTokens, signal, thinkingLevel), - ]); + : ok("No prior history."); if (!historyResult.ok) return err(historyResult.error); + const turnPrefixResult = await generateTurnPrefixSummary( + turnPrefixMessages, + models, + model, + settings.reserveTokens, + signal, + thinkingLevel, + ); if (!turnPrefixResult.ok) return err(turnPrefixResult.error); summary = `${historyResult.value}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult.value}`; } else { diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 810834a71..fd23c6e89 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -9,6 +9,7 @@ ### Fixed +- Fixed split-turn compaction to serialize summary requests so single-concurrency local providers do not fail with 429 errors ([#5536](https://github.com/earendil-works/pi/issues/5536)). - Fixed custom session entries appended during assistant streaming to render before the live assistant message, matching persisted session order. - Fixed oversized bash tool timeouts to fail with a clear validation error instead of being clamped to an immediate timeout ([#6181](https://github.com/earendil-works/pi/issues/6181)). diff --git a/packages/coding-agent/src/core/compaction/compaction.ts b/packages/coding-agent/src/core/compaction/compaction.ts index f369601cf..46da21c4a 100644 --- a/packages/coding-agent/src/core/compaction/compaction.ts +++ b/packages/coding-agent/src/core/compaction/compaction.ts @@ -778,14 +778,13 @@ export async function compact( settings, } = preparation; - // Generate summaries (can be parallel if both needed) and merge into one + // Generate summaries and merge into one let summary: string; if (isSplitTurn && turnPrefixMessages.length > 0) { - // Generate both summaries in parallel - const [historyResult, turnPrefixResult] = await Promise.all([ + const historyResult = messagesToSummarize.length > 0 - ? generateSummary( + ? await generateSummary( messagesToSummarize, model, settings.reserveTokens, @@ -798,19 +797,18 @@ export async function compact( streamFn, env, ) - : Promise.resolve("No prior history."), - generateTurnPrefixSummary( - turnPrefixMessages, - model, - settings.reserveTokens, - apiKey, - headers, - env, - signal, - thinkingLevel, - streamFn, - ), - ]); + : "No prior history."; + const turnPrefixResult = await generateTurnPrefixSummary( + turnPrefixMessages, + model, + settings.reserveTokens, + apiKey, + headers, + env, + signal, + thinkingLevel, + streamFn, + ); // Merge into single summary summary = `${historyResult}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult}`; } else {