diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index 2db04ad4..f3c213d8 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -1704,7 +1704,7 @@ export class AgentSession { let summaryEntry: BranchSummaryEntry | undefined; if (summaryText) { // Create summary at target position (can be null for root) - const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails); + const summaryId = this.sessionManager.branchWithSummary(newLeafId, summaryText, summaryDetails, fromHook); summaryEntry = this.sessionManager.getEntry(summaryId) as BranchSummaryEntry; } else if (newLeafId === null) { // No summary, navigating to root - reset leaf diff --git a/packages/coding-agent/src/core/compaction/branch-summarization.ts b/packages/coding-agent/src/core/compaction/branch-summarization.ts index 132fd2ec..3647afb8 100644 --- a/packages/coding-agent/src/core/compaction/branch-summarization.ts +++ b/packages/coding-agent/src/core/compaction/branch-summarization.ts @@ -215,8 +215,9 @@ export function prepareBranchEntries(entries: SessionEntry[], tokenBudget: numbe // First pass: collect file ops from ALL entries (even if they don't fit in token budget) // This ensures we capture cumulative file tracking from nested branch summaries + // Only extract from pi-generated summaries (fromHook !== true), not hook-generated ones for (const entry of entries) { - if (entry.type === "branch_summary" && entry.details) { + if (entry.type === "branch_summary" && !entry.fromHook && entry.details) { const details = entry.details as BranchSummaryDetails; if (Array.isArray(details.readFiles)) { for (const f of details.readFiles) fileOps.read.add(f); diff --git a/packages/coding-agent/src/core/session-manager.ts b/packages/coding-agent/src/core/session-manager.ts index f1adda2a..11e4a146 100644 --- a/packages/coding-agent/src/core/session-manager.ts +++ b/packages/coding-agent/src/core/session-manager.ts @@ -64,6 +64,8 @@ export interface CompactionEntry extends SessionEntryBase { tokensBefore: number; /** Hook-specific data (e.g., ArtifactIndex, version markers for structured compaction) */ details?: T; + /** True if generated by a hook, undefined/false if pi-generated (backward compatible) */ + fromHook?: boolean; } export interface BranchSummaryEntry extends SessionEntryBase { @@ -72,6 +74,8 @@ export interface BranchSummaryEntry extends SessionEntryBase { summary: string; /** Hook-specific data (not sent to LLM) */ details?: T; + /** True if generated by a hook, false if pi-generated */ + fromHook?: boolean; } /** @@ -872,7 +876,7 @@ export class SessionManager { * Same as branch(), but also appends a branch_summary entry that captures * context from the abandoned conversation path. */ - branchWithSummary(branchFromId: string | null, summary: string, details?: unknown): string { + branchWithSummary(branchFromId: string | null, summary: string, details?: unknown, fromHook?: boolean): string { if (branchFromId !== null && !this.byId.has(branchFromId)) { throw new Error(`Entry ${branchFromId} not found`); } @@ -885,6 +889,7 @@ export class SessionManager { fromId: branchFromId ?? "root", summary, details, + fromHook, }; this._appendEntry(entry); return entry.id;