Documentation
¶
Overview ¶
Package compactionfacts provides protocol-neutral semantic facts extraction, deterministic item hashing, start-rule matching, and streaming fact builder primitives for compaction recognition without prompt retention.
The package serves as the single internal source of truth for compaction facts shared between the canonical compaction detector (internal/infra/compactiondetect), execution runtime, and future streaming frontend proof compilation workers.
Index ¶
- Constants
- Variables
- func Digest(f RequestFacts, complete bool) [32]byte
- func EstimateTokens(call lipapi.Call) int
- func HashItem(it lipapi.Item) [32]byte
- func WriteField(w io.Writer, name, val string)
- func WriteFieldHeader(w io.Writer, name string, valLen int)
- func WriteFieldTrailer(w io.Writer)
- func WriteItemCanonical(w io.Writer, it lipapi.Item)
- type Builder
- func (b *Builder) AddItem(it lipapi.Item) error
- func (b *Builder) AddItemHash(h [32]byte) error
- func (b *Builder) AddToolCount(n int)
- func (b *Builder) Build() (RequestFacts, error)
- func (b *Builder) EndField()
- func (b *Builder) FeedField(text string)
- func (b *Builder) FeedTextChunk(chunk string)
- func (b *Builder) FeedTextChunkBytes(chunk []byte)
- type Evidence
- type ItemHasher
- func (ih *ItemHasher) AddContentPart(kind lipapi.ContentPartKind, text, refusal, summary string)
- func (ih *ItemHasher) AddToolCall(name string)
- func (ih *ItemHasher) AddToolResult(output string)
- func (ih *ItemHasher) BeginContentText(valLen int) io.Writer
- func (ih *ItemHasher) EndContentText()
- func (ih *ItemHasher) Sum() [32]byte
- func (ih *ItemHasher) Writer() io.Writer
- type RequestFacts
- type RuleMode
- type StartRule
- type TextMatcher
Constants ¶
const ( // ItemHashSizeBytes is the memory size in bytes of one SHA-256 item hash (32 bytes). ItemHashSizeBytes = 32 // DefaultMaxFactItems bounds the maximum number of retained item hashes for wire ingestion // (4096 items * 32 bytes/item = 128 KiB fact memory budget). DefaultMaxFactItems = 4096 // HeuristicTailItems is the number of recent semantic tail fingerprints. HeuristicTailItems = 2 // HeuristicPrefixItems is the number of leading item hashes folded into PrefixHash. HeuristicPrefixItems = 8 )
const ( EvidenceProtocolStrict = compaction.EvidenceProtocolStrict EvidenceSignatureStrict = compaction.EvidenceSignatureStrict EvidenceHistoryHeuristic = compaction.EvidenceHistoryHeuristic )
const ( MarkerCodexCheckpoint = "context checkpoint compaction" MarkerConversationTag = "<conversation>" MarkerPiSummaryCarrier = "<summary>" MarkerClineSummaryPost = "context summary:" MarkerSystemNotice = "<system_notice>" MarkerClineCompactedPost = "earlier context was compacted" MarkerOpenCodeHistoryHead = "the following is the conversation history:" MarkerHermesRefOnly = "[context compaction \u2014 reference only]" MarkerHermesLegacySummary = "[context summary]:" MarkerKiloObjective = "objective" MarkerKiloDetails = "important details" MarkerKiloWorkState = "work state" MarkerKiloNextMove = "next move" MarkerKiloFiles = "relevant files" MarkerAiderUserTag = "# user" MarkerAiderAssistantTag = "# assistant" )
Shared compaction rule markers.
const ( RuleProtocolContextCompaction = "protocol.context_compaction.v1" RuleCodexLocalCheckpoint = "codex.local_checkpoint.v1" RulePiOpenClawCompactionSummary = "pi_openclaw.compaction_summary.v1" RuleClineAgenticCompaction = "cline.agentic_compaction.v1" RuleClineBasicCompactionPost = "cline.basic_compaction_post.v1" RuleOpenCodeAnchoredSummary = "opencode.anchored_summary.v1" RuleOpenCodeCustomCompactionHistory = "opencode.custom_compaction_history.v1" RuleHermesLocalCompactionPost = "hermes.local_compaction_post.v1" RuleHermesLegacyCompactionPost = "hermes.legacy_compaction_post.v1" RuleKiloCodeAnchoredSummary = "kilocode.anchored_summary.v1" RuleClaudeCodeCompaction = "claude_code_2026_03.compaction.v1" RuleGeminiCLIStateSnapshot = "gemini_cli.state_snapshot.v1" RuleRooCodeCondense = "roo_code.condense.v1" RuleAiderChatSummary = "aider.chat_summary.v1" RuleCrushSessionSummary = "crush.session_summary.v1" RuleHeuristicCompaction = "local.compaction_heuristic.v1" )
Shared compaction rule IDs.
Variables ¶
var ErrFactBudgetExceeded = errors.New("compactionfacts: item count exceeds fact budget")
ErrFactBudgetExceeded is returned when the retained facts (item hashes) exceed the configured budget.
var StartRules = []StartRule{ { ID: RuleProtocolContextCompaction, Mode: RuleModeSingle, Evidence: EvidenceProtocolStrict, Match: func(op lipapi.Operation, _ int, _ func(string) bool) bool { return op == lipapi.OperationContextCompaction }, }, { ID: RuleCodexLocalCheckpoint, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText(MarkerCodexCheckpoint) }, }, { ID: RulePiOpenClawCompactionSummary, Mode: RuleModeSeries, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText(MarkerConversationTag) && hasText("summar") && hasText("checkpoint") }, }, { ID: RuleClineAgenticCompaction, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText("continuation-note") && hasText("summar") }, }, { ID: RuleOpenCodeAnchoredSummary, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText(MarkerConversationTag) && hasText("summar") && hasText(MarkerKiloObjective) && hasText(MarkerKiloWorkState) }, }, { ID: RuleOpenCodeCustomCompactionHistory, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText(MarkerOpenCodeHistoryHead) }, }, { ID: RuleKiloCodeAnchoredSummary, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText(MarkerKiloObjective) && hasText(MarkerKiloDetails) && hasText(MarkerKiloWorkState) && hasText(MarkerKiloNextMove) && hasText(MarkerKiloFiles) }, }, { ID: RuleClaudeCodeCompaction, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, toolCount int, hasText func(string) bool) bool { return toolCount == 0 && hasText("text only") && hasText("compaction") && hasText("conversation") }, }, { ID: RuleGeminiCLIStateSnapshot, Mode: RuleModeSeries, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { if !hasText("state snapshot") { return false } return hasText("generate") || hasText("verify") }, }, { ID: RuleRooCodeCondense, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText("condense") && hasText("summar") && hasText("conversation") }, }, { ID: RuleAiderChatSummary, Mode: RuleModeSeries, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText(MarkerAiderUserTag) && hasText(MarkerAiderAssistantTag) && hasText("summar") }, }, { ID: RuleCrushSessionSummary, Mode: RuleModeSingle, Evidence: EvidenceSignatureStrict, Match: func(_ lipapi.Operation, _ int, hasText func(string) bool) bool { return hasText("session summary") && hasText("preserve") && hasText("context") }, }, }
StartRules is the ordered table of compaction start rules. The protocol rule must stay first so canonical semantics dominate text signatures.
Functions ¶
func Digest ¶
func Digest(f RequestFacts, complete bool) [32]byte
Digest computes a deterministic 32-byte SHA-256 digest over ALL behavior-relevant compaction fact fields and the completion status.
func EstimateTokens ¶
EstimateTokens calculates characters/4 from all WalkCallTexts sources.
func WriteField ¶
WriteField writes a length-prefixed key-value field to w: name + "=" + strconv.Itoa(len(val)) + ":" + val + "|"
func WriteFieldHeader ¶
WriteFieldHeader writes the length-prefixed header for a field: name + "=" + strconv.Itoa(valLen) + ":"
func WriteFieldTrailer ¶
WriteFieldTrailer writes the field delimiter "|".
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder accumulates bounded semantic facts across incremental decoded fragments.
func NewBuilder ¶
NewBuilder creates a new facts Builder. maxFactItems bounds the number of retained ItemHashes.
- If maxFactItems > 0: strictly bounds retained item hashes. When exceeded, the builder sets a sticky error (ErrFactBudgetExceeded) and Build returns empty facts and the sticky error. The bound is checked BEFORE item-hash allocation.
- If maxFactItems <= 0: unbounded (retains all item hashes without limit), preserving canonical exact semantics for arbitrary item counts.
func NewBuilderWithByteBudget ¶
NewBuilderWithByteBudget creates a Builder whose item hash budget is derived from a byte budget: maxFactItems = maxFactBytes / ItemHashSizeBytes. If maxFactBytes <= 0, the builder is unbounded.
func (*Builder) AddItem ¶
AddItem hashes a complete lipapi.Item and feeds its text fields into the text matcher and token counter with proper field boundaries. If the budget is exceeded, it sets and returns a sticky ErrFactBudgetExceeded BEFORE hashing or allocating.
func (*Builder) AddItemHash ¶
AddItemHash appends a precomputed item hash. If the budget is exceeded, it sets and returns a sticky ErrFactBudgetExceeded BEFORE allocating or appending.
func (*Builder) AddToolCount ¶
AddToolCount increments the tool count for the request.
func (*Builder) Build ¶
func (b *Builder) Build() (RequestFacts, error)
Build produces the final bounded RequestFacts. If the builder encountered an error (such as ErrFactBudgetExceeded), it returns an empty RequestFacts and the sticky error.
func (*Builder) EndField ¶
func (b *Builder) EndField()
EndField ends the current text field, flushing any pending UTF-8 bytes and inserting the canonical '\n' field boundary.
func (*Builder) FeedField ¶
FeedField feeds an entire field and ends it with a canonical field boundary.
func (*Builder) FeedTextChunk ¶
FeedTextChunk feeds a chunk of text within the current field into the bounded text matcher and accumulates its UTF-8 rune count towards EstimatedTokens.
func (*Builder) FeedTextChunkBytes ¶
FeedTextChunkBytes feeds a chunk of byte text within the current field into the bounded text matcher and accumulates its UTF-8 rune count towards EstimatedTokens.
type Evidence ¶
type Evidence = compaction.Evidence
Evidence defines evidence levels matching canonical compaction semantics.
type ItemHasher ¶
type ItemHasher struct {
// contains filtered or unexported fields
}
ItemHasher computes an item hash incrementally by streaming fields and chunks.
func NewItemHasher ¶
func NewItemHasher(kind lipapi.ItemKind, role lipapi.Role) *ItemHasher
NewItemHasher starts hashing an item with the given kind and role.
func (*ItemHasher) AddContentPart ¶
func (ih *ItemHasher) AddContentPart(kind lipapi.ContentPartKind, text, refusal, summary string)
AddContentPart records a content part on the item.
func (*ItemHasher) AddToolCall ¶
func (ih *ItemHasher) AddToolCall(name string)
AddToolCall records a tool call on the item.
func (*ItemHasher) AddToolResult ¶
func (ih *ItemHasher) AddToolResult(output string)
AddToolResult records a tool result on the item.
func (*ItemHasher) BeginContentText ¶
func (ih *ItemHasher) BeginContentText(valLen int) io.Writer
BeginContentText begins streaming a ContentPartText with a known byte length. It writes "content.kind=4:text|" and the header "content.text=<valLen>:". The returned io.Writer streams into the hash. Call EndContentText() after writing exactly valLen bytes to complete the part.
func (*ItemHasher) EndContentText ¶
func (ih *ItemHasher) EndContentText()
EndContentText closes the content.text field and emits trailing empty refusal and summary fields.
func (*ItemHasher) Sum ¶
func (ih *ItemHasher) Sum() [32]byte
Sum returns the final 32-byte SHA-256 hash.
func (*ItemHasher) Writer ¶
func (ih *ItemHasher) Writer() io.Writer
Writer returns an io.Writer to stream payload chunks directly into the item hash.
type RequestFacts ¶
type RequestFacts struct {
Operation lipapi.Operation
ToolCount int
EstimatedTokens int
ItemCount int
ItemHashes [][32]byte
TailHashes [HeuristicTailItems][32]byte
TailLen int
PrefixHash [32]byte
PrefixItems int
StartRuleMatched bool
StartRuleID string
StartRuleMode RuleMode
StartRuleEvidence Evidence
}
RequestFacts holds bounded semantic facts extracted from a request for compaction recognition without retaining prompt or payload content.
func ExtractFactsFromCall ¶
func ExtractFactsFromCall(call lipapi.Call) RequestFacts
ExtractFactsFromCall extracts exact bounded RequestFacts from a canonical Call. It preserves ALL WalkCallTexts sources with canonical '\n' field boundaries, and retains full exact semantics for arbitrary item counts without silent truncation.
func (RequestFacts) Clone ¶
func (f RequestFacts) Clone() RequestFacts
Clone returns an owned deep copy of RequestFacts, ensuring that mutations to ItemHashes in the clone or original do not affect each other.
type RuleMode ¶
type RuleMode int
RuleMode declares the transaction behavior of a compaction rule.
const ( // RuleModeSingle: the first matching opened request emits a start; a strict // later completion closes it; otherwise the transaction closes silently. RuleModeSingle RuleMode = iota // RuleModeSeries: later matching utility subcalls reuse one active transaction // and suppress repeated starts; the first strict/heuristic completion closes. RuleModeSeries // RuleModeCompletionOnly: no start is ever emitted; a post marker or heuristic // creates one completed event transaction. RuleModeCompletionOnly )
type StartRule ¶
type StartRule struct {
ID string
Mode RuleMode
Evidence Evidence
Match func(op lipapi.Operation, toolCount int, hasText func(string) bool) bool
}
StartRule defines one compaction request start rule.
type TextMatcher ¶
type TextMatcher struct {
// contains filtered or unexported fields
}
TextMatcher performs bounded substring matching for start-rule markers across streamed chunks of text without buffering full request text. It distinguishes chunks within ONE field (carrying overlap and incomplete UTF-8 bytes) from different fields (separated by the canonical '\n' field boundary).
func NewTextMatcher ¶
func NewTextMatcher() *TextMatcher
NewTextMatcher constructs an empty bounded text matcher.
func (*TextMatcher) EndField ¶
func (tm *TextMatcher) EndField() int
EndField ends the current text field. It flushes any pending UTF-8 bytes and feeds the canonical '\n' separator, matching base collectCallText where each nonempty field is joined with a newline. This ensures markers cannot match across distinct field boundaries.
func (*TextMatcher) Feed ¶
func (tm *TextMatcher) Feed(chunk string)
Feed is an alias for FeedChunk for backward compatibility with chunk streaming.
func (*TextMatcher) FeedBytesChunk ¶
func (tm *TextMatcher) FeedBytesChunk(chunk []byte) int
FeedBytesChunk updates the matcher with a new byte slice within the CURRENT field. It carries overlap and incomplete UTF-8 bytes across chunks within this field, and returns the number of complete UTF-8 runes processed in this chunk.
func (*TextMatcher) FeedChunk ¶
func (tm *TextMatcher) FeedChunk(chunk string) int
FeedChunk updates the matcher with a new chunk of text within the CURRENT field. It carries overlap and incomplete UTF-8 bytes across chunks within this field, and returns the number of complete UTF-8 runes processed in this chunk.
func (*TextMatcher) FeedField ¶
func (tm *TextMatcher) FeedField(text string) int
FeedField feeds an entire field, immediately inserting the canonical field boundary.
func (*TextMatcher) HasText ¶
func (tm *TextMatcher) HasText(marker string) bool
HasText reports whether the specified marker was encountered in fed text.