fix(coding-agent): clear tree navigation compaction state

closes #3688
This commit is contained in:
Mario Zechner
2026-04-25 17:03:09 +02:00
parent 3e7ffff184
commit a363b668ac
3 changed files with 165 additions and 120 deletions

View File

@@ -8,6 +8,7 @@
### Fixed ### Fixed
- Fixed `/tree` cancellation via `session_before_tree` leaving the session stuck in compaction state ([#3688](https://github.com/badlogic/pi-mono/issues/3688))
- Fixed Escape interrupt handling when extensions hide the built-in working loader row ([#3674](https://github.com/badlogic/pi-mono/issues/3674)) - Fixed Escape interrupt handling when extensions hide the built-in working loader row ([#3674](https://github.com/badlogic/pi-mono/issues/3674))
- Fixed coding-agent test expectations for current default models and missing-auth guidance. - Fixed coding-agent test expectations for current default models and missing-auth guidance.

View File

@@ -2711,6 +2711,8 @@ export class AgentSession {
// Set up abort controller for summarization // Set up abort controller for summarization
this._branchSummaryAbortController = new AbortController(); this._branchSummaryAbortController = new AbortController();
try {
let extensionSummary: { summary: string; details?: unknown } | undefined; let extensionSummary: { summary: string; details?: unknown } | undefined;
let fromExtension = false; let fromExtension = false;
@@ -2759,7 +2761,6 @@ export class AgentSession {
replaceInstructions, replaceInstructions,
reserveTokens: branchSummarySettings.reserveTokens, reserveTokens: branchSummarySettings.reserveTokens,
}); });
this._branchSummaryAbortController = undefined;
if (result.aborted) { if (result.aborted) {
return { cancelled: true, aborted: true }; return { cancelled: true, aborted: true };
} }
@@ -2804,7 +2805,12 @@ export class AgentSession {
let summaryEntry: BranchSummaryEntry | undefined; let summaryEntry: BranchSummaryEntry | undefined;
if (summaryText) { if (summaryText) {
// Create summary at target position (can be null for root) // Create summary at target position (can be null for root)
const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromExtension); const summaryId = this.sessionManager.branchWithSummary(
newLeafId,
summaryText,
summaryDetails,
fromExtension,
);
summaryEntry = this.sessionManager.getEntry(summaryId) as BranchSummaryEntry; summaryEntry = this.sessionManager.getEntry(summaryId) as BranchSummaryEntry;
// Attach label to the summary entry // Attach label to the summary entry
@@ -2839,8 +2845,10 @@ export class AgentSession {
// Emit to custom tools // Emit to custom tools
this._branchSummaryAbortController = undefined;
return { editorText, cancelled: false, summaryEntry }; return { editorText, cancelled: false, summaryEntry };
} finally {
this._branchSummaryAbortController = undefined;
}
} }
/** /**

View File

@@ -0,0 +1,36 @@
import { afterEach, describe, expect, it } from "vitest";
import { assistantMsg, userMsg } from "../../utilities.js";
import { createHarness, type Harness } from "../harness.js";
describe("issue #3688 tree cancellation compaction state", () => {
const harnesses: Harness[] = [];
afterEach(() => {
while (harnesses.length > 0) {
harnesses.pop()?.cleanup();
}
});
it("clears branch summary state when session_before_tree cancels navigation", async () => {
const harness = await createHarness({
extensionFactories: [
(pi) => {
pi.on("session_before_tree", () => ({ cancel: true }));
},
],
});
harnesses.push(harness);
const targetId = harness.sessionManager.appendMessage(userMsg("first"));
harness.sessionManager.appendMessage(assistantMsg("reply"));
const currentLeafId = harness.sessionManager.appendMessage(userMsg("second"));
expect(harness.sessionManager.getLeafId()).toBe(currentLeafId);
const result = await harness.session.navigateTree(targetId, { summarize: false });
expect(result).toEqual({ cancelled: true });
expect(harness.session.isCompacting).toBe(false);
expect(harness.sessionManager.getLeafId()).toBe(currentLeafId);
});
});