budget

package
v1.4.2 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package budget tracks per-model context window utilisation and enforces the global 70%/75%/80% budget rules defined in CLAUDE.md.

Index

Constants

View Source
const (
	MaxPctHistory = 12 // bounded claude_pct series kept in state.json

	// RiskHorizon is the look-ahead RiskFromHistory computes over, in
	// observations ("within the next ~3 claude_pct updates"), not wall-clock
	// time and not chat turns. Exported so a UI can state the horizon it is
	// reporting instead of restating the number and drifting from it.
	RiskHorizon = 3.0
)

The orchestrator's claude_pct is the one genuinely session-cumulative budget quantity: it only climbs as the context window fills. Modelling it as a drift-diffusion process on the utilisation fraction x ∈ [0,1] lets the governor act on the *rate* of burn (and its noise), not just the current level, a session climbing fast at 55% is riskier than one parked at 74%, which the static band table (ModeFor) cannot see. The 80% emergency line is an absorbing barrier; each recorded claude_pct observation is one step.

Variables

This section is empty.

Functions

func AppendPctHistory

func AppendPctHistory(hist []int, pct, max int) []int

AppendPctHistory returns hist with pct appended, but only when pct differs from the last entry (the series tracks the claude_pct trajectory, so flat periods add no points), trimmed to the newest max observations. A non-positive pct (unknown) is ignored. Pure, so the state.json writer can stay a thin shell.

func FirstPassageProb

func FirstPassageProb(dist, mu, sigma, horizon float64) float64

FirstPassageProb returns the probability that a Brownian motion with per-step drift mu and per-step volatility sigma, starting dist below an absorbing barrier, reaches that barrier within horizon steps. This is the closed-form first-passage-time CDF for drifted Brownian motion (reflection principle):

P(τ ≤ H) = Φ( (μH − d)/(σ√H) ) + exp(2μd/σ²)·Φ( (−μH − d)/(σ√H) )

with d = dist. Degenerate inputs collapse to the deterministic answer: no distance left → already absorbed (1); no horizon → 0; zero volatility → pure drift (1 iff μH ≥ d). The result is clamped to [0,1]; it is a governor heuristic, so numerically extreme regimes clamp rather than error.

func LoadWindows

func LoadWindows(home string) map[string]int

LoadWindows reads registry/models.yaml, an on-disk copy under home if one exists, otherwise the copy embedded in the binary, and returns a map of model-id → context window size. Missing entries get provider-based fallbacks (ollama → 32 768, everything else → 200 000).

home is the Hydra home directory, not the registry directory: Read appends "registry" itself so every caller resolves the override the same way.

func RiskFromHistory

func RiskFromHistory(hist []int) (burnRatePct, risk float64)

RiskFromHistory estimates the burn rate and the probability of hitting the 80% emergency line within the horizon, from a claude_pct series. burnRatePct is the mean per-observation increment in percentage points; risk is the first-passage probability. With fewer than two observations there is no rate signal and both are zero, so the governor falls back to the level band.

Types

type Mode

type Mode int

Mode represents the current budget pressure level for a model.

const (
	ModeNormal    Mode = iota // 0-49%
	ModeCompact               // 50-64%
	ModeCaution               // 65-69%
	ModeWarning               // 70-74%
	ModeCritical              // 75-79%
	ModeEmergency             // 80%+
)

func EffectiveMode

func EffectiveMode(pct int, risk float64) Mode

EffectiveMode combines the level band ModeFor(pct) with the rate-driven risk floor: the governor acts on whichever is more urgent. With risk 0 (flat or unknown history) it is exactly ModeFor(pct), backward compatible.

func ModeFor

func ModeFor(pct int) Mode

ModeFor computes the budget mode from a percentage.

func (Mode) String

func (m Mode) String() string

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry manages Trackers for every model seen at runtime.

func NewRegistry

func NewRegistry(windows map[string]int) *Registry

NewRegistry returns a Registry seeded with the given window sizes.

func (*Registry) All

func (r *Registry) All() []Snapshot

All returns snapshots for every tracked model, in no guaranteed order. Trackers are collected under r.mu then snapshotted outside it to avoid holding two locks simultaneously.

func (*Registry) Get

func (r *Registry) Get(modelID string) Snapshot

Get returns the latest snapshot for modelID, or a zero Snapshot if unseen.

func (*Registry) Record

func (r *Registry) Record(modelID string, used int, source string) Snapshot

Record updates (or creates) the Tracker for modelID with fresh token counts. source should be "real" when the count came from the API, "estimate" otherwise.

type Snapshot

type Snapshot struct {
	ModelID   string
	Used      int
	Window    int
	Pct       int
	Mode      Mode
	Source    string // "real" or "estimate"
	UpdatedAt time.Time
}

Snapshot is an immutable point-in-time view of a model's budget state.

type Tracker

type Tracker struct {
	// contains filtered or unexported fields
}

Tracker holds the latest snapshot for a single model. Safe for concurrent use. modelID is set once at construction and never mutated, no lock needed for reads.

func (*Tracker) Snapshot

func (t *Tracker) Snapshot() Snapshot

func (*Tracker) Update

func (t *Tracker) Update(used, window int, source string) Snapshot

Jump to

Keyboard shortcuts

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