diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 1aa972632..5f433be9a 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -6,6 +6,7 @@ - Fixed `pi.registerFlag()` accepting default values that do not match the declared flag type ([#8064](https://github.com/earendil-works/pi/issues/8064)). - Fixed Z.AI Coding Plan defaults referencing the removed GLM-5.1 model ([#8096](https://github.com/earendil-works/pi/issues/8096)). +- Fixed repeated ambiguous truncated-response recovery being mislabeled as context overflow ([#8130](https://github.com/earendil-works/pi/issues/8130)). ## [0.84.2] - 2026-08-14 diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index f0dae74f1..8e7a59e89 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -2008,8 +2008,9 @@ export class AgentSession { // Automatic cases 1 and 2: context overflow. // A length stop is recoverable when output ended below the model's original desired limit, // independent of the configured context size or any context-clamped provider request limit. + const contextOverflow = sameModel && isContextOverflow(assistantMessage, contextWindow); const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0); - if (sameModel && (isContextOverflow(assistantMessage, contextWindow) || recoverableLength)) { + if (contextOverflow || recoverableLength) { const willRetry = assistantMessage.stopReason !== "stop"; // Case 2: the response completed successfully. Compact, but do not retry because @@ -2019,14 +2020,16 @@ export class AgentSession { } if (this._overflowRecoveryAttempted) { + const errorMessage = contextOverflow + ? "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model." + : "Truncated response recovery failed after one compact-and-retry attempt."; this._emit({ type: "compaction_end", reason: "overflow", result: undefined, aborted: false, willRetry: false, - errorMessage: - "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.", + errorMessage, }); return false; } 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 dbb512f37..6a21f7f9f 100644 --- a/packages/coding-agent/test/suite/agent-session-compaction.test.ts +++ b/packages/coding-agent/test/suite/agent-session-compaction.test.ts @@ -353,6 +353,34 @@ describe("AgentSession compaction characterization", () => { expect(harness.faux.state.callCount).toBe(2); expect(harness.eventsOfType("compaction_start").filter((event) => event.reason === "overflow")).toHaveLength(1); expect(harness.eventsOfType("compaction_end").at(-1)?.errorMessage).toBe( + "Truncated response recovery failed after one compact-and-retry attempt.", + ); + }); + + it("keeps overflow wording when a repeated length stop fills the context window", async () => { + const harness = await createHarness({ + models: [{ id: "faux-1", contextWindow: 100, maxTokens: 100 }], + }); + harnesses.push(harness); + const sessionInternals = harness.session as unknown as SessionWithCompactionInternals; + const lengthOverflowMessage = createAssistant(harness, { + stopReason: "length", + totalTokens: 100, + timestamp: Date.now(), + }); + const runAutoCompactionSpy = vi.spyOn(sessionInternals, "_runAutoCompaction").mockResolvedValue(false); + const compactionErrors: string[] = []; + harness.session.subscribe((event) => { + if (event.type === "compaction_end" && event.errorMessage) { + compactionErrors.push(event.errorMessage); + } + }); + + await sessionInternals._checkCompaction(lengthOverflowMessage); + await sessionInternals._checkCompaction({ ...lengthOverflowMessage, timestamp: Date.now() + 1 }); + + expect(runAutoCompactionSpy).toHaveBeenCalledTimes(1); + expect(compactionErrors).toContain( "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.", ); });