compaction

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Ports packages/coding-agent/src/core/compaction/branch-summarization.ts Branch summarization for tree navigation.

When navigating to a different point in the session tree, this generates a summary of the branch being left so context isn't lost.

Mirrors upstream:

.upstream/current/packages/coding-agent/src/core/compaction/branch-summarization.ts

Package compaction: core compaction logic.

Mirrors upstream:

.upstream/current/packages/coding-agent/src/core/compaction/compaction.ts

All functions are pure except Compact (one LLM call via SimpleCompleter).

Retry policy for summarization LLM calls.

Mirrors upstream:

.upstream/current/packages/ai/src/utils/retry.ts (RetryPolicy, RetryCallbacks, retryAssistantCall)
.upstream/current/packages/agent/src/harness/compaction/compaction.ts (completeSimpleWithRetries)

Compaction and branch-summary summarization calls reuse settings.retry so a single transient stream drop no longer fails the whole operation.

Package compaction provides shared utilities for context compaction and branch summarization.

Mirrors upstream:

.upstream/current/packages/coding-agent/src/core/compaction/utils.ts

All functions are pure: no LLM calls, no I/O, no side effects.

Index

Constants

View Source
const BRANCH_SUMMARY_PREAMBLE = "The user explored a different conversation branch before returning here.\nSummary of that exploration:\n\n"

BRANCH_SUMMARY_PREAMBLE is prepended to every generated branch summary so the model understands the provenance of the text. Verbatim from upstream branch-summarization.ts.

View Source
const BRANCH_SUMMARY_PROMPT = `` /* 689-byte string literal not displayed */

BRANCH_SUMMARY_PROMPT is the instruction prompt for branch summarization. Verbatim from upstream branch-summarization.ts.

View Source
const SUMMARIZATION_PROMPT = `` /* 879-byte string literal not displayed */

SUMMARIZATION_PROMPT is the prompt for initial context summarization. Verbatim from upstream compaction.ts:454.

View Source
const SummarizationSystemPrompt = `` /* 310-byte string literal not displayed */

SummarizationSystemPrompt is the system prompt used when requesting a context summary from the LLM. Verbatim from upstream compaction.ts.

View Source
const UPDATE_SUMMARIZATION_PROMPT = `` /* 1257-byte string literal not displayed */

UPDATE_SUMMARIZATION_PROMPT is the prompt used when updating an existing summary. Verbatim from upstream compaction.ts:487.

Variables

View Source
var DefaultCompactionSettings = CompactionSettings{
	Enabled:          true,
	ReserveTokens:    16384,
	KeepRecentTokens: 20000,
}

DefaultCompactionSettings mirrors upstream DEFAULT_COMPACTION_SETTINGS.

View Source
var ErrSummarizationToolCall = errors.New("summarization attempted to call a tool")

ErrSummarizationToolCall rejects a provider response containing a tool call; standalone summarization requests never provide executable tools.

Functions

func ComputeFileLists

func ComputeFileLists(ops FileOperations) (readFiles, modifiedFiles []string)

ComputeFileLists returns read-only and modified paths in JavaScript sort order.

func EstimateContextTokens

func EstimateContextTokens(messages []agent.AgentMessage) agent.ContextUsageEstimate

EstimateContextTokens estimates context size from the last valid assistant usage plus an estimate of the messages after it, or from the messages alone when no usage exists (compaction.ts estimateContextTokens). LastUsageIndex is -1 for Pi's null.

func EstimateProjectedContextTokens

func EstimateProjectedContextTokens(projection codingagent.SessionProjection, branchEntries []codingagent.SessionEntry) agent.ContextUsageEstimate

EstimateProjectedContextTokens estimates a projected context without trusting usage captured before a later context edit or compaction on the branch (compaction.ts estimateProjectedContextTokens). Without trusted usage, it counts the replayed current system state once plus every non-system projected message.

func EstimateTokens

func EstimateTokens(message agent.AgentMessage) int

EstimateTokens estimates one context message with the chars/4 heuristic, counting JavaScript string lengths (compaction.ts estimateTokens). Unknown roles count as zero.

func ExtractFileOpsFromMessage

func ExtractFileOpsFromMessage(msg agent.AgentMessage, ops *FileOperations)

ExtractFileOpsFromMessage records read/write/edit tool calls in an assistant message, or the nested calls recorded on a tool result. Calls made from codemode scripts are recorded on the script's result.

upstream: .upstream/current/packages/coding-agent/src/core/compaction/utils.ts (extractFileOpsFromMessage, addFileOp)

func FindTurnStartIndex

func FindTurnStartIndex(entries []codingagent.SessionEntry, entryIndex, startIndex int) int

FindTurnStartIndex returns the index of the context-visible user-role entry that starts the span containing entryIndex, or -1 when none exists at or after startIndex (compaction.ts findTurnStartIndex).

func FormatFileOperations

func FormatFileOperations(readFiles, modifiedFiles []string) string

FormatFileOperations renders the shared summary metadata tags.

func GenerateBugReportSummary

func GenerateBugReportSummary(ctx context.Context, opts GenerateBugReportSummaryOptions) (string, error)

GenerateBugReportSummary asks the session model for a report when the user does not share the transcript. Mirrors upstream generateBugReportSummary.

func GetLastAssistantUsage

func GetLastAssistantUsage(entries []codingagent.SessionEntry) *ai.Usage

GetLastAssistantUsage returns the usage of the last assistant message with valid usage in entries (compaction.ts getLastAssistantUsage).

func SerializeConversation

func SerializeConversation(messages []ai.Message) string

SerializeConversation converts wire-format LLM messages to a plain-text representation suitable for summarization. Call convertToLLM first to normalise custom message types (bashExecution, compactionSummary, etc.) before passing the slice here.

Roles handled:

  • "user" → [User]: <text>
  • "assistant" → [Assistant thinking]: … / [Assistant]: … / [Assistant tool calls]: …
  • "tool" → [Tool result]: <text> (truncated to 2000 chars)

Mirrors upstream serializeConversation (utils.ts).

func ShouldCompact

func ShouldCompact(contextTokens, contextWindow int, s CompactionSettings) bool

ShouldCompact reports whether compaction should trigger. Mirrors upstream shouldCompact (compaction.ts).

Types

type BranchPreparation

type BranchPreparation struct {
	// Messages extracted for summarization, in chronological order.
	Messages []agent.AgentMessage
	// FileOps extracted from tool calls and prior branch_summary details.
	FileOps FileOperations
	// TotalTokens is the estimated token count of Messages.
	TotalTokens int
}

BranchPreparation is the output of PrepareBranchEntries. Mirrors upstream BranchPreparation (branch-summarization.ts:55).

func PrepareBranchEntries

func PrepareBranchEntries(entries []codingagent.SessionEntry, tokenBudget int) BranchPreparation

PrepareBranchEntries builds the message list and file-op summary for a slice of branch entries, respecting the given token budget.

Two-pass algorithm:

  1. Collect file ops from ALL entries (even if they exceed the budget). File ops from prior branch_summary entries seed the cumulative tracker.
  2. Walk newest-to-oldest, adding messages until the budget is hit. Summary entries (compaction, branch_summary) get priority fit when totalTokens < 90% of the budget.

tokenBudget == 0 means no limit.

Mirrors upstream prepareBranchEntries (branch-summarization.ts:196).

type BranchSummaryDetails

type BranchSummaryDetails struct {
	ReadFiles     []string `json:"readFiles"`
	ModifiedFiles []string `json:"modifiedFiles"`
}

BranchSummaryDetails is stored in BranchSummaryEntry.details for cumulative file tracking across nested branch summaries. Mirrors upstream BranchSummaryDetails (branch-summarization.ts:43).

type BranchSummaryResult

type BranchSummaryResult struct {
	Summary       string
	ReadFiles     []string
	ModifiedFiles []string
	Aborted       bool
	Error         string
	// Usage is the summarization LLM call usage, if reported.
	Usage *ai.Usage
}

BranchSummaryResult is the return type of GenerateBranchSummary. Mirrors upstream BranchSummaryResult (branch-summarization.ts:31).

func GenerateBranchSummary

func GenerateBranchSummary(ctx context.Context, entries []codingagent.SessionEntry, opts GenerateBranchSummaryOptions) BranchSummaryResult

GenerateBranchSummary produces a structured summary of abandoned branch entries by calling the LLM via opts.Completer.

Returns BranchSummaryResult{Aborted: true} when ctx is cancelled. Returns BranchSummaryResult{Error: "..."} with Pi's operation label and tool-call diagnostic on LLM failure.

Mirrors upstream generateBranchSummary (branch-summarization.ts:250).

type BranchSummarySettings

type BranchSummarySettings struct {
	ReserveTokens int
}

BranchSummarySettings controls the token budget for branch summarization. Mirrors upstream BranchSummarySettings (branch-summarization.ts).

type CollectEntriesResult

type CollectEntriesResult struct {
	// Entries to summarize, in chronological order.
	Entries []codingagent.SessionEntry
	// CommonAncestorID is the deepest node on both the old and target paths,
	// or "" if none found.
	CommonAncestorID string
}

CollectEntriesResult is the output of CollectEntriesForBranchSummary. Mirrors upstream CollectEntriesResult (branch-summarization.ts:62).

func CollectEntriesForBranchSummary

func CollectEntriesForBranchSummary(session ReadonlySession, oldLeafID, targetID string) CollectEntriesResult

CollectEntriesForBranchSummary finds the entries that should be summarized when navigating from oldLeafID to a different position in the tree.

It walks from oldLeafID back to the deepest common ancestor with targetID and returns the collected entries in chronological order.

If oldLeafID is empty, returns an empty result (nothing to summarize).

Mirrors upstream collectEntriesForBranchSummary (branch-summarization.ts:104).

type CompactionDetails

type CompactionDetails struct {
	ReadFiles     []string `json:"readFiles"`
	ModifiedFiles []string `json:"modifiedFiles"`
}

CompactionDetails is stored in a CompactionEntry.Details for file tracking across compactions. Mirrors upstream CompactionDetails (compaction.ts:36).

type CompactionPreparation

type CompactionPreparation struct {
	FirstKeptEntryID    string               `json:"firstKeptEntryId"`
	MessagesToSummarize []agent.AgentMessage `json:"messagesToSummarize"`
	TurnPrefixMessages  []agent.AgentMessage `json:"turnPrefixMessages"`
	IsSplitTurn         bool                 `json:"isSplitTurn"`
	TokensBefore        int                  `json:"tokensBefore"`
	PreviousSummary     string               `json:"previousSummary,omitempty"`
	FileOps             FileOperations       `json:"fileOps"`
	Settings            CompactionSettings   `json:"settings"`
}

CompactionPreparation is the output of PrepareCompaction. Mirrors upstream CompactionPreparation (compaction.ts:600).

Extensions receive it in session_before_compact, so the JSON keys are upstream's field names.

func PrepareCompaction

func PrepareCompaction(
	pathEntries []codingagent.SessionEntry,
	s CompactionSettings,
) *CompactionPreparation

PrepareCompaction selects what a compaction of pathEntries, a root-to-leaf branch, summarizes and keeps (compaction.ts prepareCompaction). It works on the canonical session projection, so context edits, omissions, and the previous compaction's retained range all apply. It returns nil when the branch ends in a compaction or nothing would be summarized.

type CompactionResult

type CompactionResult struct {
	Summary          string
	FirstKeptEntryID string
	TokensBefore     int
	Details          CompactionDetails
	// Usage is the combined usage of the summarization LLM call(s), if the
	// completer reported it. Mirrors upstream CompactionResult.usage.
	Usage *ai.Usage
}

CompactionResult is the output of Compact. Mirrors upstream CompactionResult (compaction.ts:100).

func Compact

func Compact(
	ctx context.Context,
	prep CompactionPreparation,
	model *ai.Model,
	completer SimpleCompleter,
	streamFn StreamFn,
	customInstructions string,
	thinkingLevel ai.ThinkingLevel,
	retry *RetryOptions,
	sessionID string,
) (CompactionResult, error)

Compact generates summaries for compaction using PrepareCompaction output. thinkingLevel applies to reasoning-capable models; an empty sessionID gives each summary request a fresh routing ID. Mirrors upstream compact (compaction.ts:714).

type CompactionSettings

type CompactionSettings struct {
	Enabled          bool `json:"enabled"`
	ReserveTokens    int  `json:"reserveTokens"`    // tokens reserved for response; default 16384
	KeepRecentTokens int  `json:"keepRecentTokens"` // tokens to keep from recent history; default 20000
}

CompactionSettings controls when and how compaction runs. Mirrors upstream CompactionSettings (compaction.ts:115).

type CutPointResult

type CutPointResult struct {
	// FirstKeptEntryIndex is the index in entries[] of the first entry to keep.
	FirstKeptEntryIndex int
	// TurnStartIndex is the index of the user/bash message starting the split
	// turn, or -1 if not splitting.
	TurnStartIndex int
	// IsSplitTurn is true when the cut lands in the middle of a turn.
	IsSplitTurn bool
}

CutPointResult from FindCutPoint. Mirrors upstream CutPointResult (compaction.ts:383).

func FindCutPoint

func FindCutPoint(entries []codingagent.SessionEntry, startIndex, endIndex, keepRecentTokens int) CutPointResult

FindCutPoint finds the raw-entry cut point that keeps approximately keepRecentTokens of recent context between startIndex and endIndex (exclusive) (compaction.ts findCutPoint).

type FileOperations

type FileOperations struct {
	Read    map[string]struct{}
	Written map[string]struct{}
	Edited  map[string]struct{}
}

FileOperations tracks files read/written/edited during a session segment. Mirrors upstream FileOperations (utils.ts): three Sets of paths.

func NewFileOps

func NewFileOps() FileOperations

NewFileOps initializes the shared file-operation accumulator.

func (FileOperations) MarshalJSON

func (ops FileOperations) MarshalJSON() ([]byte, error)

MarshalJSON carries each Set on the subprocess wire as a sorted string array.

type GenerateBranchSummaryOptions

type GenerateBranchSummaryOptions struct {
	// Model to use for summarization.
	Model *ai.Model
	// Completer handles the actual LLM call.
	Completer SimpleCompleter
	// StreamFn overrides Completer when supplied, as in compaction.
	StreamFn StreamFn
	// CustomInstructions are appended to (or replace) the default prompt.
	CustomInstructions string
	// ReplaceInstructions, when true, replaces the default prompt entirely.
	ReplaceInstructions bool
	// ReserveTokens are subtracted from the model context window for the
	// prompt + response budget. Default 16384.
	ReserveTokens int
	// Retry, when non-nil, retries transient summarization errors with bounded
	// exponential backoff. Mirrors upstream branch-summarization retry wiring.
	Retry *RetryOptions
}

GenerateBranchSummaryOptions controls how GenerateBranchSummary runs. Mirrors upstream GenerateBranchSummaryOptions (branch-summarization.ts:69).

type GenerateBugReportSummaryOptions

type GenerateBugReportSummaryOptions struct {
	Messages  []agent.AgentMessage
	Hint      string
	Model     *ai.Model
	Completer SimpleCompleter
	StreamFn  StreamFn
	Retry     *RetryOptions
	// ThinkingLevel applies to reasoning-capable models.
	ThinkingLevel ai.ThinkingLevel
	// SessionID is the routing session ID forwarded without prompt caching.
	SessionID string
}

GenerateBugReportSummaryOptions configures GenerateBugReportSummary.

type ReadonlySession

type ReadonlySession interface {
	// Branch returns the root-first path ending at leafID.
	// Returns nil if leafID is not found.
	Branch(leafID string) []codingagent.SessionEntry
	// EntryByID looks up a single entry by ID.
	// Returns (zero, false) if not found.
	EntryByID(id string) (codingagent.SessionEntry, bool)
}

ReadonlySession provides read-only access needed for branch entry collection. Mirrors upstream ReadonlySessionManager used in branch-summarization.ts.

*codingagent.Session satisfies this interface via its Branch and EntryByID methods.

type RetryCallbacks

type RetryCallbacks struct {
	// OnRetryScheduled fires before the backoff sleep of each retry (1-indexed).
	OnRetryScheduled func(attempt, maxAttempts, delayMs int, errMsg string)
	// OnRetryAttemptStart fires after the backoff sleep, before the retried call.
	OnRetryAttemptStart func()
	// OnRetryFinished fires once when a retried loop ends.
	OnRetryFinished func()
}

RetryCallbacks are emitted around each retry. Nil fields are skipped. Mirrors upstream RetryCallbacks.

type RetryOptions

type RetryOptions struct {
	Policy      RetryPolicy
	IsRetryable func(errMsg string) bool
	Callbacks   RetryCallbacks
}

RetryOptions bundles the policy, transient-error classifier, and callbacks. A nil *RetryOptions disables retries. IsRetryable is injected so this package need not import the coding-layer classifier (which would be an import cycle).

type RetryPolicy

type RetryPolicy struct {
	Enabled bool
	// MaxRetries is the max retry attempts (0 = no retries). The initial call
	// never counts as a retry.
	MaxRetries int
	// BaseDelayMs is the base backoff; per-attempt delay is
	// BaseDelayMs * 2^(attempt-1).
	BaseDelayMs int
	// MaxAgentDelayMs caps each delay; nil uses ai.DefaultMaxAgentRetryDelayMs.
	MaxAgentDelayMs *int
}

RetryPolicy is the bounded-attempts, exponential-backoff policy for summarization retries. Mirrors upstream RetryPolicy.

type SimpleCompleter

type SimpleCompleter interface {
	CompleteSimple(ctx context.Context, model *ai.Model, systemPrompt string, messages []agent.AgentMessage, options ai.StreamOptions) (string, *ai.Usage, error)
}

SimpleCompleter is a minimal interface for LLM calls used by Compact. Allows test injection without live LLM calls. options are the request options completeSummarization built (upstream SimpleStreamOptions).

type StreamFn

type StreamFn func(ctx context.Context, model *ai.Model, systemPrompt string, messages []agent.AgentMessage, options ai.StreamOptions) (string, *ai.Usage, error)

StreamFn is an optional summarization path used instead of CompleteSimple. Mirrors upstream's streamFn forwarding for compaction requests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL