contextmgr

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package contextmgr owns context preparation policy and provider-message conversion. Durable state remains in the dependency-neutral contextstate package.

Index

Constants

View Source
const (
	OutcomeComplete    = "complete"
	OutcomeCancelled   = "cancelled"
	OutcomeTruncated   = "truncated"
	OutcomeUpstreamErr = "upstream-error"
)
View Source
const (
	// MaxSummaryFieldBytes bounds every individual summary envelope field,
	// including each list item. Host trackers and injection paths share it so
	// the loop and the validators cannot drift apart.
	MaxSummaryFieldBytes = 2 * 1024
	// MaxSummaryItems bounds every summary envelope list. The turn-state
	// tracker and OmittedEvidence share it with the validators.
	MaxSummaryItems = 32
)
View Source
const (
	SummaryReasonTimeout          = "the summary call timed out"
	SummaryReasonTransport        = "the summary call could not reach the provider"
	SummaryReasonCancelled        = "the turn was cancelled before the summary returned"
	SummaryReasonReplyMalformed   = "the summary reply was not valid summary JSON"
	SummaryReasonEchoMismatch     = "the summary reply did not echo the request identity"
	SummaryReasonOutputTooLarge   = "the summary reply exceeded its output bound"
	SummaryReasonRedactionRefused = "the summary was refused by the redaction policy"
	SummaryReasonPolicyRefused    = "the summary policy is not enabled for this session"
	SummaryReasonBindingChanged   = "the summary binding or policy changed mid-turn"
	SummaryReasonRequestInvalid   = "the host could not build a valid summary request"
	SummaryReasonHostState        = "the host turn state was unreadable"
	SummaryReasonMetadataTooLarge = "the summary metadata exceeded its persistence bound"
	SummaryReasonOverBudget       = "the summary did not fit the remaining context budget"
	SummaryReasonUnclassified     = "the summary call failed for an unclassified reason"
)

Closed, content-free vocabulary of summary failure reasons. These constants are rendered verbatim in compaction event details and durable ledger records.

View Source
const MaxSummaryExcerptTotalBytes = 16 * 1024

MaxSummaryExcerptTotalBytes caps the whole source-excerpt section of one summary request (about 4k tokens): large enough to carry a real dropped segment, small enough that the summarize call stays cheap on every model.

View Source
const SummarySchemaVersion uint32 = 1

SummarySchemaVersion is the sealed summary envelope schema version minted by BuildSummaryRequest. ValidateSummary requires provider output to echo it.

Variables

View Source
var (
	ErrSummaryReplyMalformed   = fmt.Errorf("%w: summary reply is not usable", contextstate.ErrInvalidDTO)
	ErrSummaryEchoMismatch     = fmt.Errorf("%w: summary reply does not echo the request", contextstate.ErrInvalidDTO)
	ErrSummaryOutputTooLarge   = fmt.Errorf("%w: summary output exceeds its bound", contextstate.ErrInvalidDTO)
	ErrSummaryRedactionRefused = fmt.Errorf("%w: summary rejected by redaction policy", contextstate.ErrInvalidDTO)
)

Summary failure sentinels. Each wraps contextstate.ErrInvalidDTO so existing errors.Is(err, contextstate.ErrInvalidDTO) assertions continue to hold while allowing exact classification of the failure mode.

Functions

func BuildCommitRequest

func BuildCommitRequest(_ context.Context, preparation Preparation, result TurnResult, principal contextstate.Principal, expected contextstate.Revision, binding contextstate.BindingRevision) (contextstate.CommitRequest, error)

BuildCommitRequest is the only conversion from provider-facing turn state into the durable context contract. It validates all captured fences before constructing bytes that storage may publish.

func ClassifySummaryFailure

func ClassifySummaryFailure(err error) string

ClassifySummaryFailure maps a summary error to one of the closed SummaryReason* constants. It never includes raw error text or model output in the returned reason.

func CommitPreparation

func CommitPreparation(ctx context.Context, request PublicationRequest) error

CommitPreparation validates and summarizes before calling Store.Commit. Summary/provider failures therefore occur before any durable CAS attempt, and a persistence failure leaves the caller's preparation untouched.

func OmittedEvidence

func OmittedEvidence(input, retained []provider.Message) []string

OmittedEvidence derives content-free summary evidence from the difference between the pre-compaction history and the retained preparation. Each item records only the role, the tool name (for tool results), and the size bucket of one omitted message - never Content, Arguments, digests, or identifiers, mirroring elisionNotice. The result is capped at MaxSummaryItems items and byte-deterministic for identical inputs.

Items are DISTINCT, in first-seen order. An item is content-free, so two dropped messages of the same role in the same size bucket render the same string - the ordinary case once a compaction drops several similar messages, not an edge case. The summary envelope validator refuses duplicate evidence, and every caller degrades silently on a build error, so emitting duplicates here meant automatic compaction produced no summary at all while still reporting success. The cap therefore bounds distinct items: applying it before dedup let one repeated item consume the whole budget and report a single fact.

func PercentFloor

func PercentFloor(value, numerator, denominator int) int

PercentFloor returns floor(value * numerator / denominator) without overflowing on large token budgets. Shared by Plan's trigger/target math and any other caller that needs the same hysteresis shape (trigger at numerator/denominator of a budget, prune down to a lower target).

func ProjectSource

func ProjectSource(ctx context.Context, principal contextstate.Principal, messages []provider.Message, firstSequence uint64, policy contextstate.RedactionPolicy) ([]contextstate.SourceEvent, []contextstate.PayloadRecord, error)

ProjectSource is the allowlisted source boundary for a completed turn. It records message metadata and, when the workspace explicitly configures a redaction classifier, bounded sanitized payloads. System prompts, tool-call arguments, and hidden provider fields never cross this boundary.

func RetryableSummaryFailure

func RetryableSummaryFailure(err error) bool

RetryableSummaryFailure reports whether a summary error represents a transient failure that should be retried. Permanent failures (reply shape errors, redaction refusal, stale bindings, policy refusal, cancellation) return false immediately.

Types

type Calibration

type Calibration struct {
	// Alpha is the smoothing factor (0 < alpha <= 1). Higher values
	// react faster to changes. Defaults to 0.2.
	Alpha float64
	// Ratio is the current correction factor: reported/estimated.
	// Bounded to [calibrationMinRatio, calibrationMaxRatio] once samples
	// exist. The zero value is 0.0, which means no correction (treated as
	// 1.0 everywhere it is applied).
	Ratio float64
	// Samples is the number of updates applied.
	Samples int
}

Calibration maintains a per-binding (provider+model) rolling correction ratio between estimated and provider-reported token usage. It uses EWMA (exponentially weighted moving average) to smooth noise from individual requests while tracking systematic drift in the len(s)/4 heuristic.

The zero value is valid and means unity (no correction): Ratio is 0.0, which applyCalibration and the loop's emission path treat as 1.0.

func (Calibration) Apply

func (c Calibration) Apply(estimated int) int

Apply scales an estimated token count by this calibration's correction ratio, exactly as the planner does when it scores a history against the compaction trigger.

Every surface that reports "how full is the context" must go through this method. The planner compares a CALIBRATED cost against the trigger (planner.go's Plan), so a gauge that divides an UNCALIBRATED estimate by the same budget is measuring the same history with a different ruler: with a ratio below 1.0 the displayed percentage runs ahead of the trigger and can sit far above 100% while the planner correctly sees a history below the threshold and never compacts. That disagreement is what this method exists to make impossible.

A calibration with no samples applies no correction, matching PlanInput.CalibrationRatio, which callers leave unset until the first estimate-vs-actual observation lands.

func (*Calibration) Update

func (c *Calibration) Update(estimated, reported int)

Update incorporates a new (estimated, reported) observation into the EWMA. If estimated is zero, the update is skipped to avoid division by zero.

type CheckpointCandidate

type CheckpointCandidate struct {
	ActiveContext   []byte
	SummaryMetadata []byte
	SourceEvents    []contextstate.SourceEvent
	Payloads        []contextstate.PayloadRecord
	SourceRange     contextstate.SourceRange
}

func (CheckpointCandidate) CandidateAlgorithm

func (c CheckpointCandidate) CandidateAlgorithm() string

type CheckpointPublisher

type CheckpointPublisher interface {
	Commit(context.Context, Preparation, TurnResult) error
}

type CommitToken

type CommitToken struct {
	Principal        contextstate.Principal
	Revision         contextstate.Revision
	Binding          contextstate.BindingRevision
	WorktreeInstance contextstate.WorktreeInstance
	Range            contextstate.SourceRange
	IdempotencyKey   string
}

type ContextManager

type ContextManager struct {
	PreparationManager  PreparationManager
	CheckpointPublisher CheckpointPublisher
	// Summarizer is the optional LLM summarizer wiring point. Nil keeps every
	// path structural-only (today's production state: no SummaryProvider
	// exists). It is copied into chat turn configurations so both the agent
	// loop and plain chat can inject a validated summary at the request
	// boundary; the checkpoint committer reaches it through the
	// PreparationCommitter fields.
	Summarizer *Summarizer
	Enabled    bool
	// SummaryUnavailableReason names why Summarizer is nil, when it is: a
	// fixed, classified, content-free string set once at session setup (see
	// internal/cli's summaryDisabledReason). Every compaction path in the
	// session's lifetime reads it to report a real cause instead of a bare
	// "not summarized" boolean. Empty when Summarizer is configured.
	SummaryUnavailableReason string
	// UsageWriter is the optional durable usage-measurement sink. Nil keeps
	// usage events ephemeral (bus-only, today's production state everywhere
	// this isn't wired). Constructed once per session, alongside Summarizer,
	// and copied into agent.Options per turn the same way.
	UsageWriter usage.UsageWriter
}

func (ContextManager) Commit

func (m ContextManager) Commit(ctx context.Context, preparation Preparation, result TurnResult) error

func (ContextManager) Prepare

func (m ContextManager) Prepare(ctx context.Context, input PrepareInput) (Preparation, error)

type ElisionStats

type ElisionStats struct {
	Messages int
	Bytes    int
}

ElisionStats is a content-free aggregate of tool-result replacements made during one compaction plan. Bytes is the sum of original Content lengths.

type LLMSummaryProvider

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

LLMSummaryProvider adapts one provider.Completer to the SummaryProvider contract. It renders a host-authored prompt from the sealed envelope, calls the completer once, and decodes one strict JSON reply. It never logs and never retries (retry policy lives in Summarizer.Summarize). Any error lets the caller degrade to structural-only compaction.

func NewLLMSummaryProvider

func NewLLMSummaryProvider(completer provider.Completer, sessionID string) (LLMSummaryProvider, error)

NewLLMSummaryProvider binds one completer to one session. A nil completer is refused the same way NewSummarizer refuses a nil provider. sessionID may be empty for callers with no session concept.

func (LLMSummaryProvider) Summarize

func (p LLMSummaryProvider) Summarize(ctx context.Context, request SummaryRequest) (Summary, error)

Summarize runs one non-stream completion and decodes the reply. It checks the two mandated echoes before it returns. ValidateSummary in Summarizer.Summarize owns the full field, redaction, and size validation. The adapter does not read request.RedactionPolicy: the host blanks it before the call, because classifier configuration is host policy.

type PlanInput

type PlanInput struct {
	Messages []provider.Message
	Budget   int
	Tools    []provider.ToolSpec
	// OutputReserve is validated (must not be negative) and folded into the
	// idempotency-key fingerprint (planIdempotencyKey) - it is NOT subtracted
	// from Budget anywhere in the trigger/target math below. Budget already
	// excludes the reserved completion allowance (callers derive it from
	// config.EffectivePromptTokens, which does the subtraction once, upstream
	// of the planner). Using OutputReserve again here would double-subtract
	// the same reserve. If a future caller needs the planner itself to
	// account for an output reserve, pass a Budget that has NOT already
	// excluded it and remove this comment along with the double-subtraction
	// it warns against - do not add a second, silent subtraction beside this
	// one.
	OutputReserve    int
	Force            bool
	CurrentObjective string
	SourceRange      contextstate.SourceRange
	SourceEvents     []contextstate.SourceEvent
	IdempotencyKey   string
	RecentTail       int
	// Revision is the session revision the compaction starts FROM. It is
	// part of the derived idempotency key: two compactions of the same
	// retained set off the same source range (a resumed process compacting
	// an already-compacted session again) are different operations that
	// commit different work, so sharing a key made the store reject the
	// second as a conflicting retry. Retries of the SAME compaction carry
	// the same revision and stay idempotent.
	Revision contextstate.Revision
	// PreserveNames lists provider.Message.Name values that structural
	// retention keeps whole alongside the mandatory set. The chat layer uses
	// it for the session-owned core-memory context frame so compaction never
	// drops it.
	PreserveNames []string
	// CalibrationRatio scales token estimates to correct for heuristic drift.
	// 0 means use 1.0 (no correction). Should come from a Calibration.Ratio.
	CalibrationRatio float64
	// ContextAccounting carries the bound provider's declared context-billing
	// profile (provider.ContextAccountingProfile) opaquely: the planner never
	// interprets its fields itself, only passes it to the provider estimators
	// it already calls. The zero value is the conservative "bill everything"
	// default, so a caller that leaves this unset behaves exactly as before
	// the field existed.
	ContextAccounting provider.ContextAccountingProfile
	// Spool: nil = elision mints no refs (plain notices), keeping the planner free of storage side effects.
	Spool *remainder.Spool
	// Principal: the session principal that receives the remainder grant when Spool is set.
	Principal contextstate.Principal
}

PlanInput contains only immutable inputs to the structural planner. The planner stays pure except for an explicit caller-provided Spool seam: when Spool is nil there are no side effects and output is byte-identical to before; when set, elision spools bytes through that seam only.

type PlanResult

type PlanResult struct {
	Messages      []provider.Message
	Candidate     CheckpointCandidate
	BeforeTokens  int
	AfterTokens   int
	TriggerTokens int
	TargetTokens  int
	Compacted     bool
	// ElidedMessages and ElidedBytes are content-free aggregates of prior-turn
	// tool-result replacements applied on the compaction path. Both are zero
	// when the request is below the trigger or no body was eligible.
	ElidedMessages int
	ElidedBytes    int
	// ElidedReasoningMessages and ElidedReasoningBytes are content-free
	// aggregates of stale assistant reasoning replaced with
	// reasoningElisionMarker on the compaction path. Both are zero when the
	// request is below the trigger or no reasoning was eligible.
	ElidedReasoningMessages int
	ElidedReasoningBytes    int
	SourceRange             contextstate.SourceRange
	IdempotencyKey          string
}

PlanResult is the deterministic structural result. Summary generation and durable publication happen in later seams; this value is safe to discard.

func Plan

func Plan(input PlanInput) (PlanResult, error)

Plan applies threshold/target math and strict structural retention. A request exactly at the trigger is compacted; a request exactly at the hard budget is accepted, while one token over is rejected.

type PlannerInput

type PlannerInput = PlanInput

PlannerInput is a descriptive alias for callers that use the planner as a standalone preparation boundary.

type PlannerResult

type PlannerResult = PlanResult

PlannerResult is a descriptive alias for PlanResult.

type Preparation

type Preparation struct {
	Messages      []provider.Message
	Candidate     CheckpointCandidate
	Token         CommitToken
	Compacted     bool
	BeforeTokens  int
	AfterTokens   int
	TriggerTokens int
	TargetTokens  int
	// ElidedMessages and ElidedBytes are content-free aggregates of prior-turn
	// tool-result replacements from the planner (or turn-level accumulation on
	// the agent loop). Both are zero when nothing was elided.
	ElidedMessages int
	ElidedBytes    int
	// ElidedReasoningMessages and ElidedReasoningBytes are content-free
	// aggregates of stale assistant reasoning replaced with a constant marker
	// on the planner compaction path. Both are zero when nothing was elided.
	ElidedReasoningMessages int
	ElidedReasoningBytes    int
}

func CapturePreparation

func CapturePreparation(input PrepareInput, candidate CheckpointCandidate, messages []provider.Message, compacted bool, idempotencyKey string) (Preparation, error)

CapturePreparation creates an immutable preparation token from one policy snapshot. It is intentionally independent of storage and provider I/O.

func (Preparation) ValidateToken

func (p Preparation) ValidateToken(revision contextstate.Revision, binding contextstate.BindingRevision) error

ValidateToken checks that an asynchronous preparation still belongs to the captured durable revision and provider/model generation before publication.

type PreparationCommitter

type PreparationCommitter struct {
	Store          contextstate.Store
	Summarizer     *Summarizer
	SummaryRequest SummaryRequest
	SummaryBuilder SummaryRequestBuilder
}

PreparationCommitter adapts the publication function to the narrow CheckpointPublisher interface used by chat. The summary request is captured by the host together with the preparation's provider/model policy snapshot, or derived per preparation through SummaryBuilder when the host has live turn state to draw on.

func (PreparationCommitter) Commit

func (c PreparationCommitter) Commit(ctx context.Context, preparation Preparation, result TurnResult) error

type PreparationManager

type PreparationManager interface {
	Prepare(context.Context, PrepareInput) (Preparation, error)
	Discard(Preparation)
}

type PrepareInput

type PrepareInput struct {
	// Spool, when non-nil, lets compaction elision store the full body of an
	// elided tool result and name the remainder ref in the notice, so the model
	// can fetch the original bytes with read_output. Nil keeps plain
	// (non-recoverable) notices.
	Spool *remainder.Spool

	Messages         []provider.Message
	Budget           int
	Tools            []provider.ToolSpec
	OutputReserve    int
	Force            bool
	CurrentObjective string
	RecentTail       int
	// PreserveNames lists provider.Message.Name values that structural
	// retention keeps whole alongside the mandatory set. The chat layer uses
	// it for the session-owned core-memory context frame so compaction never
	// drops it.
	PreserveNames []string
	// CalibrationRatio scales token estimates in the planner for
	// heuristic drift correction. 0 means no correction.
	CalibrationRatio float64
	// ContextAccounting carries the bound provider's declared context-billing
	// profile through to Plan(), opaquely - see PlanInput.ContextAccounting.
	ContextAccounting provider.ContextAccountingProfile
	SourceRange       contextstate.SourceRange
	Principal         contextstate.Principal
	Revision          contextstate.Revision
	Binding           contextstate.BindingRevision
	WorktreeInstance  contextstate.WorktreeInstance
	Policy            contextstate.PolicySnapshot
}

type PublicationRequest

type PublicationRequest struct {
	Store          contextstate.Store
	Summarizer     *Summarizer
	SummaryRequest SummaryRequest
	SummaryBuilder SummaryRequestBuilder
	Preparation    Preparation
	Result         TurnResult
}

PublicationRequest keeps summary generation, request mapping, and durable publication in one explicit call boundary. No memory publication happens in this package; the caller adopts the preparation only after success.

type SourceExcerpt

type SourceExcerpt struct {
	Role string
	Name string
	Text string
}

SourceExcerpt is one bounded, content-bearing quote of a message the compaction dropped. It rides the summary REQUEST only - never the sealed envelope, the durable metadata, or the injected message - so the persisted summary contract stays unchanged while the model reads real content.

func SourceExcerpts

func SourceExcerpts(input, retained []provider.Message) []SourceExcerpt

SourceExcerpts derives bounded excerpts of the dropped messages, newest first, so the summarizer reads the real conversation content instead of size labels. The FIRST dropped user message keeps a guaranteed opening slot: it frames the task of the summarized segment. Tool-call arguments and assistant reasoning never ride the request; tool results do. Item, per-field, and total-byte bounds cap the section.

type StructuralPreparationManager

type StructuralPreparationManager struct {
	Tools         []map[string]any
	OutputReserve int
	RecentTail    int
}

StructuralPreparationManager adapts the pure planner to the preparation capability. It owns no storage and never publishes a checkpoint.

func (StructuralPreparationManager) Discard

func (StructuralPreparationManager) Prepare

type Summarizer

type Summarizer struct {
	Provider SummaryProvider
	Binding  contextstate.BindingRevision
	Policy   contextstate.PolicySnapshot
	Timeout  time.Duration
}

Summarizer binds one captured provider/model/policy snapshot to a summary request. It has no provider discovery or network fallback path.

func (Summarizer) Summarize

func (s Summarizer) Summarize(ctx context.Context, request SummaryRequest) (UntrustedSummary, error)

Summarize executes a bounded provider call (with one retry on transient failure) and validates its result before returning it. The caller's context remains the outer cancellation authority.

type Summary

type Summary struct {
	Version         uint32                   `json:"version"`
	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"`
	SourceRange     contextstate.SourceRange `json:"source_range"`
}

type SummaryBuildInput

type SummaryBuildInput struct {
	Version           uint32
	Objective         string
	State             string
	Decisions         []string
	Evidence          []string
	ChangedSurfaces   []string
	OpenWork          []string
	Risks             []string
	SourceRange       contextstate.SourceRange
	PolicyDigest      string
	Provider          string
	Model             string
	EndpointAllowlist []string
	RedactionPolicy   contextstate.RedactionPolicy
	Budget            int
	OutputLimit       int
	// SourceExcerpts carries bounded quotes of the dropped messages for the
	// summarize REQUEST. BuildSummaryRequest sanitizes them and drops every
	// item the redaction policy flags; the envelope never sees them.
	SourceExcerpts []SourceExcerpt
	// Focus is an optional caller-supplied bias string telling the
	// summarizer what to prioritize (e.g. `/compact <focus instructions>`).
	// Empty is the default, unbiased behavior. See SummaryRequest.Focus.
	Focus string
}

SummaryBuildInput is the host-side accumulation BuildSummaryRequest converts into a validated SummaryRequest. Envelope lists are already bounded by the turn-state tracker or OmittedEvidence; the constructor re-validates every field through the same validators Summarizer.Summarize will apply.

type SummaryEnvelope

type SummaryEnvelope struct {
	Version         uint32
	Objective       string
	State           string
	Decisions       []string
	Evidence        []string
	ChangedSurfaces []string
	OpenWork        []string
	Risks           []string
	SourceRange     contextstate.SourceRange
	PolicyDigest    string
	// contains filtered or unexported fields
}

SummaryEnvelope is the only input accepted by a summary provider. The unexported seal prevents callers from manufacturing provider input with a struct literal; the host must construct and validate it through the bounded constructor below.

func NewSummaryEnvelope

func NewSummaryEnvelope(version uint32, objective, state string, decisions, evidence, surfaces, openWork, risks []string, sourceRange contextstate.SourceRange, policyDigest string) (SummaryEnvelope, error)

func (SummaryEnvelope) Validate

func (e SummaryEnvelope) Validate() error

type SummaryProvider

type SummaryProvider interface {
	Summarize(context.Context, SummaryRequest) (Summary, error)
}

type SummaryRequest

type SummaryRequest struct {
	Input             SummaryEnvelope
	Budget            int
	OutputLimit       int
	SourceRange       contextstate.SourceRange
	Provider          string
	Model             string
	EndpointAllowlist []string
	// SourceExcerpts are bounded quotes of the dropped messages, for the
	// summarize request only. The sealed envelope never carries them, so no
	// durable record or injected message contains excerpt content.
	SourceExcerpts []SourceExcerpt `json:"-"`
	// Focus is an optional caller-supplied bias string (e.g. `/compact <focus
	// instructions>`) telling the summarizer what to prioritize. It rides the
	// request only - never the sealed envelope the model echoes back or the
	// durable metadata - since it is host-side guidance, not conversation
	// content the model needs to round-trip.
	Focus           string                       `json:"-"`
	RedactionPolicy contextstate.RedactionPolicy `json:"-"`
}

func BuildSummaryRequest

func BuildSummaryRequest(input SummaryBuildInput) (SummaryRequest, error)

BuildSummaryRequest is the production constructor for a summary request: it seals the bounded envelope, fills the transport fields, and validates the whole request exactly as Summarizer.Summarize will re-validate it.

func (SummaryRequest) Validate

func (r SummaryRequest) Validate() error

type SummaryRequestBuilder

type SummaryRequestBuilder func(Preparation) (SummaryRequest, error)

SummaryRequestBuilder derives the summary request for one preparation from real host state (objective, source range, policy digest, turn state). It is consulted only for a compacted preparation with a non-nil Summarizer; a nil builder falls back to the fixed SummaryRequest field, keeping existing callers byte-identical.

type TurnResult

type TurnResult struct {
	User         []provider.Message
	Assistant    []provider.Message
	Tool         []provider.Message
	Active       []provider.Message
	Ordered      []provider.Message
	SourceEvents []contextstate.SourceEvent
	TurnID       uint64
	Outcome      string
	BaseDigest   string
}

type TurnState

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

TurnState is a bounded per-turn accumulator of host-observable facts that a summary request may carry. Every list is capped at MaxSummaryItems items and every field at MaxSummaryFieldBytes, matching the summary validators in summary.go, so a validated Snapshot is always envelope-valid.

The zero value and a nil *TurnState are valid empty trackers: callers that must never fail the turn (the agent loop, the chat turn path) treat a rejected fact as a drop, never as an error.

func NewTurnState

func NewTurnState() *TurnState

NewTurnState returns an empty bounded tracker.

func (*TurnState) AddChangedSurface

func (t *TurnState) AddChangedSurface(surface string) error

AddChangedSurface appends one bounded changed file surface. A rejected item is never stored.

func (*TurnState) AddDecision

func (t *TurnState) AddDecision(decision string) error

AddDecision appends one bounded decision. A rejected item (list full, oversized, duplicate, control characters, invalid UTF-8) is never stored.

func (*TurnState) AddEvidence

func (t *TurnState) AddEvidence(evidence string) error

AddEvidence appends one bounded evidence item (tool names, omitted-segment markers). A rejected item is never stored.

func (*TurnState) AddOpenWork

func (t *TurnState) AddOpenWork(work string) error

AddOpenWork appends one bounded open-work item. A rejected item is never stored.

func (*TurnState) AddRisk

func (t *TurnState) AddRisk(risk string) error

AddRisk appends one bounded risk item. A rejected item is never stored.

func (*TurnState) SetState

func (t *TurnState) SetState(state string) error

SetState replaces the accumulated state text (host-observed latest completed assistant content). An empty state is valid: nothing was observed yet.

func (*TurnState) Snapshot

func (t *TurnState) Snapshot() (TurnStateSnapshot, error)

Snapshot validates the accumulator against the summary validators and returns a defensive copy. Mutating the returned slices never changes the tracker. A nil tracker snapshots to an empty valid snapshot.

type TurnStateSnapshot

type TurnStateSnapshot struct {
	State           string
	Decisions       []string
	Evidence        []string
	ChangedSurfaces []string
	OpenWork        []string
	Risks           []string
}

TurnStateSnapshot is a validated defensive copy of a TurnState.

type UntrustedSummary

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

UntrustedSummary is a validated data-only result from a summarizer. The private seal and private payload prevent callers from manufacturing an authority-bearing summary with a struct literal.

func ValidateSummary

func ValidateSummary(summary Summary, request SummaryRequest) (UntrustedSummary, error)

ValidateSummary validates provider output against the exact request that produced it and seals it as untrusted state data.

func (UntrustedSummary) Metadata

func (s UntrustedSummary) Metadata(redactionConfigured bool) ([]byte, error)

Metadata returns bounded persistence bytes. Without an explicitly configured redaction policy, only structural metadata and a digest survive; summary content remains ephemeral.

func (UntrustedSummary) Validate

func (s UntrustedSummary) Validate() error

func (UntrustedSummary) Value

func (s UntrustedSummary) Value() Summary

Value returns a defensive copy for host framing. The returned Summary is data only; it has no tool, policy, credential, or dispatcher fields.

Jump to

Keyboard shortcuts

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