ctxmgr

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: May 26, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package ctxmgr is the namespace for context budget, decay, packing, providers, visualisation, and read-only context. See ../REFACTOR_PLAN.md.

Named "ctxmgr" (not "context") to avoid shadowing the stdlib context package.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CollapseRepeatedMessages

func CollapseRepeatedMessages(msgs []types.EyrieMessage) []types.EyrieMessage

CollapseRepeatedMessages finds and collapses similar consecutive messages to save context tokens. It collapses:

  • 3+ consecutive tool_results with similar content into a summary
  • Repeated error messages into a count

func EstimateTokensFromContent

func EstimateTokensFromContent(content string) int

EstimateTokensFromContent provides a quick token estimate for content. Uses len/4 for English text, len/3 for code-heavy content.

func FormatContextItems

func FormatContextItems(items []ContextItem) string

FormatContextItems formats context items into a system prompt section.

func PackingReport

func PackingReport(result *PackingResult, strategy PackingStrategy, totalMessages int, mustKeepCount int) string

PackingReport generates a human-readable report of the packing result.

func SuggestFiles

func SuggestFiles(projectDir string) []string

SuggestFiles returns a list of commonly useful context files that exist in the given directory.

func SummarizeDropped

func SummarizeDropped(dropped []ScoredMessage) string

SummarizeDropped creates a brief summary of what was dropped.

func TokenEstimate

func TokenEstimate(content string) int

TokenEstimate provides a quick token count approximation: len(content) / 4.

Types

type ContextAllocation

type ContextAllocation struct {
	SystemPrompt   int
	ToolDefs       int
	RepoMap        int
	Memory         int
	Workspace      int
	PreloadedFiles int
	Conversation   int
	OutputReserve  int
	SafetyMargin   int
	Remaining      int // should be ~0 if properly allocated
}

ContextAllocation shows where tokens are going for the current conversation state.

type ContextBudget

type ContextBudget struct {
	Total int // model's full context window

	// Fixed allocations
	SystemPrompt int // 3000-5000 tokens (rules, identity)
	ToolDefs     int // 2000-3000 tokens (tool descriptions)
	RepoMap      int // 2000-4000 tokens (ranked symbol map)
	Memory       int // 1000-2000 tokens (yaad/zenbrain context)
	Workspace    int // 500 tokens (git status, branch, recent commits)

	// Adaptive allocations
	PreloadedFiles int // 10000-30000 tokens (relevant code context)
	Conversation   int // remaining (managed by compaction)

	// Reserved
	OutputReserve int // 16000-20000 tokens (model response space)
	SafetyMargin  int // 10000-15000 tokens (estimation errors, API overhead)
}

ContextBudget allocates the model's context window across different content categories. Based on research: proper allocation prevents context overflow and optimizes information density per token spent.

The allocator ensures:

  • Fixed allocations for system prompt, repo map, memory, workspace context
  • Adaptive allocation for pre-loaded files (expands when conversation is short)
  • Managed conversation history (triggers compaction when exceeded)
  • Reserved budget for model output and safety margin

Research basis: All top coding agents (Claude Code, Cursor, Aider) manage context, but none formalize it as an explicit budget with categories. This is the missing architectural glue.

func NewContextBudget

func NewContextBudget(contextSize int) *ContextBudget

NewContextBudget creates a budget for the given model context size. Allocations scale proportionally with the context window while respecting sensible floors and ceilings per category.

func (*ContextBudget) Allocate

func (b *ContextBudget) Allocate(conversationTokens int) *ContextAllocation

Allocate distributes the budget based on current conversation length. As conversation grows, PreloadedFiles shrinks to make room.

func (*ContextBudget) FilesBudget

func (b *ContextBudget) FilesBudget(conversationTokens int) int

FilesBudget returns the current budget available for pre-loaded file context.

func (*ContextBudget) ShouldCompact

func (b *ContextBudget) ShouldCompact(conversationTokens int) bool

ShouldCompact returns true if conversation exceeds its allocation.

func (*ContextBudget) UsageReport

func (b *ContextBudget) UsageReport(conversationTokens int) string

UsageReport returns a human-readable breakdown of current allocation.

type ContextDecay

type ContextDecay struct {
	HalfLife  time.Duration
	MinWeight float64
	Entries   []DecayEntry
	// contains filtered or unexported fields
}

ContextDecay manages context entries with time-based importance decay. Older context gradually loses weight unless pinned or accessed, keeping the most relevant information prioritized for the model's context window.

The decay follows exponential half-life: weight = initial * 0.5^(elapsed/halfLife) This mirrors human memory curves and ensures stale context doesn't crowd out fresh, relevant information.

func NewContextDecay

func NewContextDecay(halfLife time.Duration) *ContextDecay

NewContextDecay creates a new ContextDecay manager with the given half-life. If halfLife is zero or negative, a default of 30 minutes is used.

func (*ContextDecay) Access

func (cd *ContextDecay) Access(id string)

Access marks an entry as accessed, boosting its weight as a relevance signal. Each access resets the decay timer and increases the base weight.

func (*ContextDecay) Add

func (cd *ContextDecay) Add(content, category string, tokens int) string

Add inserts a new context entry with initial weight 1.0. Returns the generated ID for the entry.

func (*ContextDecay) ApplyDecay

func (cd *ContextDecay) ApplyDecay()

ApplyDecay recalculates all entry weights based on time elapsed since last access. Pinned entries are not affected by decay.

func (*ContextDecay) BuildContext

func (cd *ContextDecay) BuildContext(maxTokens int) string

BuildContext formats the top entries fitting within the token budget as a context string.

func (*ContextDecay) FormatEntries

func (cd *ContextDecay) FormatEntries(entries []DecayEntry) string

FormatEntries renders a slice of entries as a human-readable context block showing weight, pin status, and content.

func (*ContextDecay) Get

func (cd *ContextDecay) Get(id string) (*DecayEntry, float64)

Get retrieves an entry by ID and returns it with its current decayed weight. Returns nil if the entry is not found.

func (*ContextDecay) GetByBudget

func (cd *ContextDecay) GetByBudget(maxTokens int) []DecayEntry

GetByBudget returns entries fitting within the given token budget, sorted by weight descending. Entries are selected greedily by weight until the budget is exhausted.

func (*ContextDecay) GetTopN

func (cd *ContextDecay) GetTopN(n int) []DecayEntry

GetTopN returns the N entries with the highest current weight, sorted descending.

func (*ContextDecay) Pin

func (cd *ContextDecay) Pin(id string)

Pin marks an entry as pinned, preventing decay. Pinned entries always have weight 1.0.

func (*ContextDecay) Prune

func (cd *ContextDecay) Prune(minWeight float64) int

Prune removes all entries whose current decayed weight is below the given threshold. Returns the number of entries removed.

func (*ContextDecay) Stats

func (cd *ContextDecay) Stats() DecayStats

Stats returns aggregate statistics about the current context decay state.

func (*ContextDecay) Unpin

func (cd *ContextDecay) Unpin(id string)

Unpin removes the pin from an entry, allowing normal decay to resume.

type ContextFile

type ContextFile struct {
	Path          string
	Content       string
	TokenCount    int
	AddedAt       time.Time
	LastRefreshed time.Time
	AutoRefresh   bool
	Pinned        bool
}

ContextFile represents a single read-only context file loaded into the agent's context.

type ContextFileOption

type ContextFileOption func(*ContextFile)

ContextFileOption configures how a file is added to the read-only context.

func WithAutoRefresh

func WithAutoRefresh() ContextFileOption

WithAutoRefresh marks the file to be re-read on each turn if it changes on disk.

func WithPinned

func WithPinned() ContextFileOption

WithPinned marks the file as pinned so it is never evicted.

type ContextItem

type ContextItem struct {
	Source     string
	Title      string
	Content    string
	Relevance  float64
	TokenCount int
}

ContextItem represents a single piece of context gathered from a provider.

func PrioritizeItems

func PrioritizeItems(items []ContextItem, budget int) []ContextItem

PrioritizeItems performs greedy selection sorted by relevance, picking items until budget is exhausted while ensuring source diversity.

type ContextManager

type ContextManager struct {
	Providers   []ContextProvider
	TotalBudget int
	// contains filtered or unexported fields
}

ContextManager manages multiple context providers and orchestrates context gathering.

func NewContextManager

func NewContextManager(totalBudget int) *ContextManager

NewContextManager creates a new ContextManager with the given total token budget.

func (*ContextManager) GatherAll

func (cm *ContextManager) GatherAll(ctx context.Context, query string) ([]ContextItem, error)

GatherAll calls all providers in parallel, collects items, sorts by relevance, and truncates to fit within TotalBudget.

func (*ContextManager) Register

func (cm *ContextManager) Register(provider ContextProvider)

Register adds a context provider to the manager.

type ContextPacker

type ContextPacker struct {
	MaxTokens          int             // model's context window
	ReservedForOutput  int             // tokens reserved for response
	SystemPromptTokens int             // tokens consumed by system prompt
	Strategy           PackingStrategy // packing strategy to use
}

ContextPacker optimally selects which messages to keep when approaching context window limits, maximizing information density per token spent.

func NewContextPacker

func NewContextPacker(maxTokens int) *ContextPacker

NewContextPacker creates a new context packer for the given model context size.

func (*ContextPacker) OptimalSelection

func (cp *ContextPacker) OptimalSelection(messages []ScoredMessage, budget int) []int

OptimalSelection performs greedy selection by score/token ratio, respecting constraints (tool pairs, pinned messages).

func (*ContextPacker) Pack

func (cp *ContextPacker) Pack(messages []ScoredMessage, currentTask string) *PackingResult

Pack scores each message and selects the optimal subset within budget. It ensures tool_use/tool_result pairs stay together, always keeps the system prompt context, first user message, and the last 4 messages.

func (*ContextPacker) ScoreMessage

func (cp *ContextPacker) ScoreMessage(msg ScoredMessage, currentTask string, position int, total int) float64

ScoreMessage computes a composite score for a message based on multiple factors.

type ContextProvider

type ContextProvider interface {
	Name() string
	Description() string
	Gather(ctx context.Context, query string) ([]ContextItem, error)
	TokenBudget() int
}

ContextProvider is a pluggable source of context that can be injected into the agent's system prompt.

type ContextSection

type ContextSection struct {
	Name         string // "system_prompt", "memory", "conversation", "tool_results", "reserved"
	Tokens       int
	Percentage   float64
	Color        string // ANSI color code for the bar
	Items        []VizContextItem
	Compressible bool
}

ContextSection represents a named region of the context window.

type ContextSnapshot

type ContextSnapshot struct {
	Turn        int
	TotalTokens int
	Percentage  float64
	Compacted   bool
}

ContextSnapshot captures context state at a particular turn for history tracking.

type ContextStats

type ContextStats struct {
	TotalFiles  int
	TotalTokens int
	BudgetUsed  float64
	PinnedCount int
}

ContextStats provides statistics about the read-only context state.

type ContextVisualizer

type ContextVisualizer struct {
	MaxTokens int
	Sections  []ContextSection
	// contains filtered or unexported fields
}

ContextVisualizer provides a real-time view of context window usage, showing users exactly what occupies their context and how space is allocated.

func NewContextVisualizer

func NewContextVisualizer(maxTokens int) *ContextVisualizer

NewContextVisualizer creates a visualizer for the given maximum token budget.

func (*ContextVisualizer) HistoryChart

func (cv *ContextVisualizer) HistoryChart(snapshots []ContextSnapshot, width int) string

HistoryChart renders context usage across turns as a sparkline-style chart.

Example:

Turn  1: [██░░░░░░░░░░░░░░░░░░]  8%
Turn  5: [████████░░░░░░░░░░░░] 35%
Turn 10: [████████████████░░░░] 78%  ← compacted
Turn 11: [██████░░░░░░░░░░░░░░] 28%

func (*ContextVisualizer) Recommend

func (cv *ContextVisualizer) Recommend() []string

Recommend returns actionable suggestions based on current context state.

func (*ContextVisualizer) RenderBar

func (cv *ContextVisualizer) RenderBar(width int) string

RenderBar renders a horizontal stacked bar showing each section's proportion.

Example output:

Context: [████████░░░░░░░░░░░░] 42% used (84,000/200,000)
         [sys|mem|████conv████|tool|░░░reserved░░░]

func (*ContextVisualizer) RenderCompact

func (cv *ContextVisualizer) RenderCompact() string

RenderCompact renders a single-line summary of context usage.

Example: [42% | sys:2% mem:1% conv:26% repo:4% ctx:6% | 116K free]

func (*ContextVisualizer) RenderDetailed

func (cv *ContextVisualizer) RenderDetailed() string

RenderDetailed renders a full breakdown table of context usage by section.

func (*ContextVisualizer) TakeSnapshot

func (cv *ContextVisualizer) TakeSnapshot(turn int) ContextSnapshot

TakeSnapshot captures the current context state for a given turn number.

func (*ContextVisualizer) Update

func (cv *ContextVisualizer) Update(sections []ContextSection)

Update replaces the current sections and recalculates percentages.

func (*ContextVisualizer) WarnIfCritical

func (cv *ContextVisualizer) WarnIfCritical() string

WarnIfCritical returns a warning string if context usage is dangerously high. Returns empty string if usage is within safe limits.

type DecayEntry

type DecayEntry struct {
	ID           string
	Content      string
	Weight       float64
	CreatedAt    time.Time
	LastAccessed time.Time
	AccessCount  int
	Category     string
	Tokens       int
	Pinned       bool
}

DecayEntry represents a single piece of context with decay metadata.

type DecayStats

type DecayStats struct {
	TotalEntries int
	AvgWeight    float64
	Oldest       time.Time
	Newest       time.Time
	PinnedCount  int
	TotalTokens  int
}

DecayStats provides aggregate statistics about the context decay state.

type DependencyContextProvider

type DependencyContextProvider struct {
	ProjectDir string
}

DependencyContextProvider provides dependency information from project files.

func (*DependencyContextProvider) Description

func (d *DependencyContextProvider) Description() string

func (*DependencyContextProvider) Gather

func (d *DependencyContextProvider) Gather(ctx context.Context, query string) ([]ContextItem, error)

func (*DependencyContextProvider) Name

func (*DependencyContextProvider) TokenBudget

func (d *DependencyContextProvider) TokenBudget() int

type EnvironmentContextProvider

type EnvironmentContextProvider struct{}

EnvironmentContextProvider provides system and environment information.

func (*EnvironmentContextProvider) Description

func (e *EnvironmentContextProvider) Description() string

func (*EnvironmentContextProvider) Gather

func (*EnvironmentContextProvider) Name

func (*EnvironmentContextProvider) TokenBudget

func (e *EnvironmentContextProvider) TokenBudget() int

type ErrorContextProvider

type ErrorContextProvider struct {
	LogDir string
}

ErrorContextProvider provides recent build/test errors as context.

func (*ErrorContextProvider) Description

func (e *ErrorContextProvider) Description() string

func (*ErrorContextProvider) Gather

func (e *ErrorContextProvider) Gather(ctx context.Context, query string) ([]ContextItem, error)

func (*ErrorContextProvider) Name

func (e *ErrorContextProvider) Name() string

func (*ErrorContextProvider) TokenBudget

func (e *ErrorContextProvider) TokenBudget() int

type FileContextProvider

type FileContextProvider struct {
	RepoDir  string
	MaxFiles int
}

FileContextProvider provides recently modified files as context.

func (*FileContextProvider) Description

func (f *FileContextProvider) Description() string

func (*FileContextProvider) Gather

func (f *FileContextProvider) Gather(ctx context.Context, query string) ([]ContextItem, error)

func (*FileContextProvider) Name

func (f *FileContextProvider) Name() string

func (*FileContextProvider) TokenBudget

func (f *FileContextProvider) TokenBudget() int

type GitContextProvider

type GitContextProvider struct {
	RepoDir    string
	MaxCommits int
}

GitContextProvider provides recent git history as context.

func (*GitContextProvider) Description

func (g *GitContextProvider) Description() string

func (*GitContextProvider) Gather

func (g *GitContextProvider) Gather(ctx context.Context, query string) ([]ContextItem, error)

func (*GitContextProvider) Name

func (g *GitContextProvider) Name() string

func (*GitContextProvider) TokenBudget

func (g *GitContextProvider) TokenBudget() int

type PackingResult

type PackingResult struct {
	KeptMessages    []int   // indices of kept messages
	DroppedMessages []int   // indices of dropped messages
	TotalTokens     int     // total tokens of kept messages
	Utilization     float64 // percentage of context used (0.0 - 1.0)
	Summary         string  // summary of dropped content
}

PackingResult contains the outcome of a context packing operation.

type PackingStrategy

type PackingStrategy string

PackingStrategy determines how the context packer selects messages to keep.

const (
	// StrategyRecent keeps the most recent messages (simple truncation).
	StrategyRecent PackingStrategy = "recent"

	// StrategyRelevance scores messages by relevance to the current task.
	StrategyRelevance PackingStrategy = "relevance"

	// StrategyHybrid combines recency and relevance scoring (default).
	StrategyHybrid PackingStrategy = "hybrid"

	// StrategyCompression summarizes old messages, keeps recent verbatim.
	StrategyCompression PackingStrategy = "compression"
)

type ReadOnlyContext

type ReadOnlyContext struct {
	Files          map[string]*ContextFile
	Patterns       []string
	MaxTokenBudget int
	// contains filtered or unexported fields
}

ReadOnlyContext manages a set of files loaded for agent reference that cannot be edited. Files are tracked with token budgets and can be auto-refreshed when they change on disk.

func NewReadOnlyContext

func NewReadOnlyContext(maxBudget int) *ReadOnlyContext

NewReadOnlyContext creates a new ReadOnlyContext with the given token budget.

func (*ReadOnlyContext) AddFile

func (rc *ReadOnlyContext) AddFile(path string, opts ...ContextFileOption) error

AddFile reads a file from disk and adds it to the read-only context. Returns an error if the file cannot be read or would exceed the token budget.

func (*ReadOnlyContext) AddPattern

func (rc *ReadOnlyContext) AddPattern(pattern string) error

AddPattern adds a glob pattern and immediately resolves matching files. Files that match the pattern are added to the read-only context.

func (*ReadOnlyContext) BuildContextBlock

func (rc *ReadOnlyContext) BuildContextBlock() string

BuildContextBlock formats all context files for system prompt injection.

func (*ReadOnlyContext) Evict

func (rc *ReadOnlyContext) Evict() []string

Evict removes unpinned files by LRU (oldest AddedAt first) until within budget. Returns the list of evicted file paths.

func (*ReadOnlyContext) IsReadOnly

func (rc *ReadOnlyContext) IsReadOnly(path string) bool

IsReadOnly checks if a path is in the read-only context. Used by Edit/Write tools to block modifications to context files.

func (*ReadOnlyContext) RefreshStale

func (rc *ReadOnlyContext) RefreshStale() error

RefreshStale re-reads files that have been modified on disk since last refresh. Only refreshes files with AutoRefresh=true.

func (*ReadOnlyContext) RemoveFile

func (rc *ReadOnlyContext) RemoveFile(path string)

RemoveFile removes a file from the read-only context.

func (*ReadOnlyContext) Stats

func (rc *ReadOnlyContext) Stats() ContextStats

Stats returns statistics about the current read-only context state.

type ScoredMessage

type ScoredMessage struct {
	Index    int
	Role     string
	Content  string
	Tokens   int
	Score    float64
	MustKeep bool // pinned messages, tool pairs
}

ScoredMessage represents a message with scoring metadata for packing decisions.

type VizContextItem

type VizContextItem struct {
	Label     string
	Tokens    int
	Role      string
	Truncated bool
}

VizContextItem represents a single piece of content within a section.

Jump to

Keyboard shortcuts

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