fix(coding-agent): preserve branch summary source leaf

Record the pre-navigation leaf in branch summary fromId instead of the destination node.
This commit is contained in:
David Brailovsky 2026-08-19 12:02:37 +02:00
parent ed867e9094
commit d711bd5f0a
4 changed files with 9 additions and 4 deletions

View file

@ -19,6 +19,7 @@
- Fixed llama.cpp login guidance to direct users to `/llama` before `/model` when no local models are loaded ([#8203](https://github.com/earendil-works/pi/issues/8203)).
- Fixed hung pi.dev model catalog requests consuming the entire refresh deadline without retrying ([#8198](https://github.com/earendil-works/pi/issues/8198)).
- Fixed inherited Xiaomi model catalogs listing shut-down MiMo V2 models in `/model` and `--list-models` ([#8187](https://github.com/earendil-works/pi/issues/8187)).
- Fixed branch summary entries recording the navigation destination in `fromId` instead of the pre-navigation source leaf.
## [0.84.2] - 2026-08-14

View file

@ -1388,13 +1388,14 @@ export class SessionManager {
if (branchFromId !== null && !this.byId.has(branchFromId)) {
throw new Error(`Entry ${branchFromId} not found`);
}
const fromId = this.leafId ?? "root";
this.leafId = branchFromId;
const entry: BranchSummaryEntry = {
type: "branch_summary",
id: generateId(this.byId),
parentId: branchFromId,
timestamp: new Date().toISOString(),
fromId: branchFromId ?? "root",
fromId,
summary,
details,
usage,

View file

@ -38,12 +38,14 @@ describe("Branch summary extensions", () => {
const targetId = harness.sessionManager.appendMessage(userMsg("first branch"));
harness.sessionManager.appendMessage(assistantMsg("first reply"));
harness.sessionManager.appendMessage(userMsg("abandoned branch work"));
harness.sessionManager.appendMessage(assistantMsg("abandoned reply"));
const sourceId = harness.sessionManager.appendMessage(assistantMsg("abandoned reply"));
const result = await harness.session.navigateTree(targetId, { summarize: true });
const summaryEntry = result.summaryEntry;
expect(summaryEntry?.type).toBe("branch_summary");
expect(summaryEntry?.parentId).toBeNull();
expect(summaryEntry?.fromId).toBe(sourceId);
expect(summaryEntry?.fromHook).toBe(true);
expect(summaryEntry?.summary).toBe("Summary provided by extension");
expect(summaryEntry?.usage).toEqual(usage);

View file

@ -321,12 +321,12 @@ describe("SessionManager append and tree traversal", () => {
});
describe("branchWithSummary", () => {
it("inserts branch summary and advances leaf", () => {
it("inserts branch summary with the source and destination and advances leaf", () => {
const session = SessionManager.inMemory();
const id1 = session.appendMessage(userMsg("1"));
const _id2 = session.appendMessage(assistantMsg("2"));
const _id3 = session.appendMessage(userMsg("3"));
const id3 = session.appendMessage(userMsg("3"));
const usage = {
input: 10,
@ -345,6 +345,7 @@ describe("SessionManager append and tree traversal", () => {
expect(summaryEntry).toBeDefined();
expect(summaryEntry?.parentId).toBe(id1);
if (summaryEntry?.type === "branch_summary") {
expect(summaryEntry.fromId).toBe(id3);
expect(summaryEntry.summary).toBe("Summary of abandoned work");
expect(summaryEntry.usage).toEqual(usage);
}