Documentation
¶
Overview ¶
Package plan manages token budget windows and compaction. Compact and Calibrated adapt provider messages to bounded context windows. Summarize turns the messages a compaction drops into one validated, bounded summary document, through one bounded provider.Completer call. A summary failure is a caller-visible error; no structural fallback exists. The loop wiring lives in agentloop.
Layering: context holds three public packages. plan consumes ref and provider; agentloop wires plan above it. budget states byte caps beside it. The durable session contract and its store live in contextstate (github.com/MiviaLabs/mivia-ai-sdk/contextstate).
See docs/history/context/plan.md.
Index ¶
Constants ¶
const ( // DefaultSmoothingFactor is the EWMA weight Observe applies when // Calibrate receives a non-positive alpha. DefaultSmoothingFactor = 0.3 // MinCorrectionFactor is the floor Observe clamps the correction // factor to. MinCorrectionFactor = 0.5 // MaxCorrectionFactor is the ceiling Observe clamps the correction // factor to. MaxCorrectionFactor = 2.0 )
EWMA smoothing bounds for Calibrated.
const ( // DefaultTriggerPercent compacts at this percent of Window.Budget(). DefaultTriggerPercent = 100 // DefaultTargetPercent compacts down to this percent of Budget(). DefaultTargetPercent = 10 // DefaultRecentTail is the message-count bound of the tail fill. DefaultRecentTail = 8 // MaxRecentTail is the highest tail bound a caller may set. MaxRecentTail = 64 // CompactionAlgorithm names the idempotency-key fingerprint scheme. CompactionAlgorithm = "context-compact-v1" )
Compaction thresholds and bounds.
const MaxExcerptTotalBytes = 16 * 1024
MaxExcerptTotalBytes bounds the whole source-excerpt section of one summarize prompt.
const MaxFieldBytes = 2 * 1024
MaxFieldBytes bounds every individual Summary text field and every list item.
const MaxItems = 32
MaxItems bounds every Summary list.
const SummaryMessageName = "context-summary"
SummaryMessageName is the provider.Message.Name of the injected summary message. Compaction preserves it through PreserveNames.
const SummaryPreamble = "This message restates the conversation that compaction removed."
SummaryPreamble is the framing line SummaryMessage places before Render output; Render itself carries no preamble.
const SummaryTimeout = 20 * time.Second
SummaryTimeout bounds one summarize call.
Variables ¶
var ( // ErrNoMessages is Compact's error for an empty message list. ErrNoMessages = errors.New("plan: no messages to compact") // ErrEstimateFailed is Compact's error when the token estimator // fails. ErrEstimateFailed = errors.New("plan: token estimate failed") // ErrRetentionOverflow is Compact's error when the retention set // alone exceeds the window budget. ErrRetentionOverflow = errors.New("plan: retention set alone exceeds the window") // ErrNoObjective is Compact's error when no user message exists to // retain as the objective. ErrNoObjective = errors.New("plan: no user message to retain as objective") )
Sentinel errors for Compact; test with errors.Is.
var ( // ErrNoMessagesToSummarize is Summarize's error for an empty message list. ErrNoMessagesToSummarize = errors.New("plan: no messages to summarize") // ErrInvalidReply is Summarize's error when the reply fails // strict parsing or Summary.Validate. ErrInvalidReply = errors.New("plan: reply failed strict parsing or validation") // ErrCallFailed is Summarize's error when the Completer call // itself fails. ErrCallFailed = errors.New("plan: summary call failed") // ErrSummarySkipped is the sentinel a summarize adapter returns // to decline summary injection; the concrete Summarizer never // returns it. An adapter may wrap it with a reason, for example // fmt.Errorf("%w: %s", ErrSummarySkipped, reason); agentloop's // summarizeDropped matches the skip through errors.Is, so a // wrapped sentinel still takes the skip path and the wrapping // error's own message carries the reason to the caller. ErrSummarySkipped = errors.New("plan: summary skipped") )
Sentinel errors; test with errors.Is.
var ( // ErrMaxTokensNotPositive is Validate's error when MaxTokens <= 0. // Kept separate from ErrInvalidOptions: agentloop/agentloop_test // asserts on this sentinel by name, so it stays a distinct value. ErrMaxTokensNotPositive = errors.New("plan: max tokens must be positive") // ErrInvalidOptions is the shared sentinel for every other // construction-time argument error in this package. Wrap it with // fmt.Errorf("%w: %s", ErrInvalidOptions, "<field>: <rule>") and // test with errors.Is plus a substring check on the field name. ErrInvalidOptions = errors.New("plan: invalid options") )
Sentinel errors for Window.Validate; test with errors.Is.
Functions ¶
func SummaryMessage ¶
SummaryMessage renders s as one RoleUser message named SummaryMessageName, whose Content is SummaryPreamble, one newline, then s.Render().
func TokenEstimate ¶
TokenEstimate prices n bytes at n/4 tokens, minimum one for non-zero input, zero for zero input.
Types ¶
type Calibrated ¶
type Calibrated struct {
// contains filtered or unexported fields
}
Calibrated wraps a provider.TokenEstimator with an exponentially weighted moving average, corrected after each completed turn through Observe. A *Calibrated implements provider.TokenEstimator. Safe for concurrent use: one mutex guards factor, the only mutable field.
func Calibrate ¶
func Calibrate(est provider.TokenEstimator, alpha float64) *Calibrated
Calibrate wraps est with an EWMA correction factor. alpha is the EWMA smoothing weight in (0, 1]; a value outside that range, including zero or negative, falls back to DefaultSmoothingFactor. A nil est is a caller error caught at the first EstimateTokens call, not at construction, matching the wrapped interface's own contract.
func (*Calibrated) EstimateTokens ¶
func (c *Calibrated) EstimateTokens(req provider.Request) (int, error)
EstimateTokens calls the wrapped estimator, then scales the result by the current EWMA correction factor, itself always within [MinCorrectionFactor, MaxCorrectionFactor].
func (*Calibrated) Observe ¶
func (c *Calibrated) Observe(estimated, actual int)
Observe records one completed turn: estimated is the value EstimateTokens returned to the caller for that turn - the already-corrected figure, not a raw pre-scale count - and actual is the real provider.Usage.TotalTokens for the same turn. Observe corrects factor multiplicatively against estimated, so the fixed point is unchanged from before this fix: a corrected estimate that tracks actual. The result is clamped to [MinCorrectionFactor, MaxCorrectionFactor]. A non-positive estimated or a non-positive actual is a no-op.
type CompactResult ¶
type CompactResult struct {
Kept []provider.Message
Dropped []provider.Message
BeforeTokens int
AfterTokens int
TriggerTokens int
TargetTokens int
Compacted bool
Key string
}
CompactResult is Compact's output.
func Compact ¶
func Compact(msgs []provider.Message, w Window, e provider.TokenEstimator) (CompactResult, error)
Compact applies the trigger check and the retention policy. An invalid window fails Window.Validate before any estimate. A request at or above the trigger compacts; below it passes through with Compacted false. The retention set is mandatory; the tail fill is optional and stops at the first unit that breaks contiguity, the message-count bound, or the target. Kept preserves the original relative order. The Key is deterministic per input.
type Compaction ¶
type Compaction struct {
TriggerPercent int
TargetPercent int
TargetTokens int
RecentTail int
PreserveNames []string
}
Compaction configures compaction thresholds and retention. The zero value means the defaults, never "disabled": TriggerPercent zero means DefaultTriggerPercent, TargetPercent zero means DefaultTargetPercent, RecentTail zero means DefaultRecentTail.
func (Compaction) Validate ¶
func (c Compaction) Validate() error
Validate rejects percents outside [0, 100], a negative TargetTokens or RecentTail, a RecentTail over MaxRecentTail, an empty but present PreserveNames entry, and duplicate PreserveNames entries. When TargetTokens is zero, a TargetPercent at or above the resolved TriggerPercent is rejected; when TargetTokens is positive, that comparison is skipped and Window.Validate instead rejects a TargetTokens at or above Budget().
type Summarizer ¶
type Summarizer struct {
MaxTokens *int
// contains filtered or unexported fields
}
Summarizer adapts one provider.Completer to summary generation. MaxTokens caps the summarize call's provider.Request.MaxTokens. Nil means the Completer's own default, the same behavior as before this field existed. Set it before the first Summarize call. Summarize reads MaxTokens exactly once, on the first call, and freezes that snapshot for every later call on this Summarizer; a write to MaxTokens after the first Summarize call has no effect. Summarize makes no promise about concurrent calls on the same Summarizer; use one Summarizer from one goroutine at a time.
func NewSummarizer ¶
func NewSummarizer(c provider.Completer) (*Summarizer, error)
NewSummarizer binds one Completer. A nil Completer wraps ErrInvalidOptions.
type Summary ¶
type Summary struct {
Objective string `json:"objective"`
State string `json:"state"`
Decisions []string `json:"decisions,omitempty"`
Evidence []string `json:"evidence,omitempty"`
ChangedSurfaces []string `json:"changed_surfaces,omitempty"`
OpenWork []string `json:"open_work,omitempty"`
Risks []string `json:"risks,omitempty"`
}
Summary is one validated summary document. Data only: no tool, policy, or credential fields. The json tags pin the host durable schema keys; version and source_range stay with the caller.
func (Summary) Render ¶
Render returns the deterministic text form of s: one labeled line or bullet per field, in field order.
type Window ¶
type Window struct {
MaxTokens int
Reserve int
Compaction Compaction
}
Window is the token budget for one planned request. MaxTokens is the model's context window; Reserve is the headroom Plan never spends, held back for the model's own reply. Compaction carries the compaction thresholds and retention rules; its zero value means the defaults, never "disabled".
func (Window) Budget ¶
Budget returns MaxTokens - Reserve, the tokens Plan may spend on Request.Messages.
func (Window) CompactTarget ¶
CompactTarget returns the target in tokens: TargetTokens when positive, else Budget times TargetPercent, floored.
func (Window) CompactTrigger ¶
CompactTrigger returns the trigger in tokens: Budget times TriggerPercent, floored.