memory

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package memory stores and fetches context blobs by content address. Put computes the sha256: ref with contextref.Mint and returns it. Get fetches a blob by that ref. A size budget bounds the store; a Put that would exceed the budget evicts the oldest-inserted blobs first.

Map: store.go = Store, New, Put, Get, and the sentinel errors ErrNoBudget, ErrBudgetExceeded, ErrUnknownRef. Memory holds opaque bytes; it does not parse or validate the content, and it does not know about envelope.Message or any other wire type. The package also holds the principal-scoped spool: spool.go = Spool, NewSpool, Spool, SpoolExpiring, Expire, GrantExpiry, Load, ContentStore, and the sentinels ErrNoGrantBudget and ErrUnknownGrantRef; context.go = WithPrincipal and PrincipalFrom; readtool.go = ReadOutputTool and MoreMarker; tool.go = SpoolTool and WithSpool. A spool grant bounds one principal's oversized content and hands back a bounded view plus a content ref. Rationale: ../docs/history/memory.md. Contribution rules: ../AGENTS.md.

Index

Constants

View Source
const MoreMarker = "[more: offset=%d]"

MoreMarker ends a page with more bytes after it, naming the next offset.

Variables

View Source
var (
	// ErrUnknownGrantRef is Load's error for a ref with no live grant, and
	// for a live grant whose ContentStore.Get fails.
	ErrUnknownGrantRef = errors.New("memory: unknown ref")
	// ErrWrongPrincipal is Load's error when principal does not match
	// the grant's recorded principal.
	ErrWrongPrincipal = errors.New("memory: wrong principal")
	// ErrNoPrincipal is SpoolTool's error for a ctx with no principal
	// attached, when the inner result needs a grant.
	ErrNoPrincipal = errors.New("memory: no principal in context")
	// ErrInvalidOptions is the sentinel for a caller-supplied
	// constructor argument that fails a sanity check, such as a
	// non-positive maxGrantBytes. It also covers a call-time
	// argument that fails its rule, such as Spool.SpoolExpiring's
	// non-positive ttl.
	ErrInvalidOptions = errors.New("memory: invalid options")
	// ErrGrantTooLarge is Spool's error when data alone exceeds
	// maxGrantBytes: no eviction can ever make room for it.
	ErrGrantTooLarge = errors.New("memory: content exceeds grant budget")
	// ErrPrincipalConflict is Spool's error when the store returns a
	// ref already granted to a different principal. A content-addressed
	// ContentStore returns the same ref for identical bytes regardless
	// of caller; without this check, a second principal spooling the
	// same content would silently take over the first principal's
	// grant.
	ErrPrincipalConflict = errors.New("memory: ref already granted to a different principal")
	// ErrExpired is Load's error for a grant whose expiry passed. The
	// grant drops on that Load, freeing its budget.
	ErrExpired = errors.New("memory: grant expired")
	// ErrNilSpool is ReadOutputTool's error for a nil Spool.
	ErrNilSpool = errors.New("memory: spool is required")
	// ErrInvalidLimit is ReadOutputTool's error for a non-positive
	// maxPageBytes.
	ErrInvalidLimit = errors.New("memory: maxPageBytes must be positive")
	// ErrBadArguments is ReadOutputTool's error for a malformed
	// argument decode, a mistyped Run call, a negative offset, or a
	// negative limit.
	ErrBadArguments = errors.New("memory: bad arguments")
)

Sentinel errors for Spool and SpoolTool; test with errors.Is.

View Source
var (
	// ErrBudgetExceeded is the sentinel for a blob that Put rejects
	// because it is larger than the store's budget.
	ErrBudgetExceeded = errors.New("memory: content exceeds store budget")
	// ErrUnknownRef is the sentinel for a ref that Get does not hold.
	ErrUnknownRef = errors.New("memory: unknown ref")
)

Sentinel errors for Store operations; test with errors.Is. ErrInvalidOptions is declared in spool.go and shared across the package.

Functions

func PrincipalFrom added in v0.5.0

func PrincipalFrom(ctx context.Context) (string, bool)

PrincipalFrom reads the principal WithPrincipal attached to ctx. The second return is false when no principal was attached.

func ReadOutputTool added in v0.5.0

func ReadOutputTool(sp *Spool, maxPageBytes int) (tools.Tool, error)

ReadOutputTool builds the model-facing read-back tool over sp. The model pages a spooled body back by ref, offset, and limit. A nil sp wraps ErrNilSpool; a non-positive maxPageBytes wraps ErrInvalidLimit.

func SpoolTool added in v0.5.0

func SpoolTool(name string, maxBytes int, sp *Spool, inner tools.Tool) (tools.Tool, error)

SpoolTool wraps inner so any string result longer than maxBytes spools to store under the ctx principal (see WithPrincipal) instead of returning in full. The wrapped tool's Out.Value becomes the truncated view string; the reference is appended to the view text. A result that is not a string, or one at or under maxBytes, passes through unchanged. A call with no principal in ctx returns ErrNoPrincipal. The returned tools.Tool always implements tools.ProfiledTool, tools.ResultBudgetTool, tools.PrivilegedTool, and tools.SchemaTool. Each forwards through tools.ExecutionProfileOf, tools.ResultBudgetOf, tools.IsPrivileged, and tools.SchemaOf, so a caller reading inner's published values through those helpers sees no difference. tools.SchemaOf fails closed: a schema-less inner reports nil, false, and agentloop.New then fails with ErrNoSchema naming the wrapper. Wrap schema-bearing inners for model-facing registries. SpoolTool changes only Run's result handling, not inner's declared execution class, result budget, privilege, or schema. A nil sp wraps ErrNilSpool. A negative maxBytes clamps to zero. Two or more SpoolTool calls sharing one sp share its grant budget and its Load-time principal checks. A caller pairs a SpoolTool call with a ReadOutputTool call by passing the same sp to both.

func WithPrincipal added in v0.5.0

func WithPrincipal(ctx context.Context, principal string) context.Context

WithPrincipal returns a context carrying principal for a later SpoolTool call to read.

Types

type ContentStore added in v0.5.0

type ContentStore interface {
	Put(content []byte) (ref string, err error)
	Get(ref string) ([]byte, error)
}

ContentStore is the storage a Spool writes spooled bytes to and reads them back from. Store satisfies this interface with no import needed on either side; a caller wires the two together.

type Spool added in v0.5.0

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

Spool stores oversized content under a principal-scoped grant and returns a bounded view plus a reference to the full content. The zero value is not usable; create a Spool with NewSpool. Mutex-guarded, safe for concurrent use.

func NewSpool added in v0.5.0

func NewSpool(store ContentStore, maxGrantBytes int) (*Spool, error)

NewSpool creates a Spool backed by store, tracking grants under a maxGrantBytes budget. A non-positive maxGrantBytes wraps ErrInvalidOptions.

func (*Spool) Expire added in v0.5.0

func (s *Spool) Expire(ref string) error

Expire marks one live grant expired immediately. Unknown ref wraps ErrUnknownGrantRef.

func (*Spool) GrantExpiry added in v0.5.0

func (s *Spool) GrantExpiry(ref string) (time.Time, bool)

GrantExpiry reports a grant's expiry. The second return is false for no live grant. A zero time means no expiry.

func (*Spool) Load added in v0.5.0

func (s *Spool) Load(ctx context.Context, principal, ref string) ([]byte, error)

Load returns the full bytes stored under ref. It wraps ErrUnknownGrantRef when no live grant matches ref, ErrWrongPrincipal when principal does not match the grant's recorded principal, even on an expired grant, and ErrExpired when the right principal's grant expired: that grant drops on this Load, freeing its budget. When the grant is live but the underlying ContentStore.Get fails (for example, the store's own independent budget evicted the blob first), Load wraps that error under ErrUnknownGrantRef too: a live grant whose bytes are gone is, from the caller's view, an unknown ref.

func (*Spool) Spool added in v0.5.0

func (s *Spool) Spool(ctx context.Context, principal string, data []byte) (view string, ref string, err error)

Spool writes data to the underlying store, grants principal the right to read it back, and returns a bounded view of data plus the content's reference. Spool evicts the oldest grants, by insertion order, until the new grant fits the byte budget. Spool wraps ErrGrantTooLarge when data alone exceeds maxGrantBytes, and ErrPrincipalConflict when the store's ref already belongs to a different principal's live grant.

func (*Spool) SpoolExpiring added in v0.5.0

func (s *Spool) SpoolExpiring(ctx context.Context, principal string, data []byte, ttl time.Duration) (view string, ref string, err error)

SpoolExpiring writes data, grants principal read-back, and sets a time-to-live on the grant. A non-positive ttl wraps ErrInvalidOptions before any store write. Re-spooling an existing ref under the same principal refreshes the expiry, the same way Spool refreshes insertion order.

type Store

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

Store holds content-addressed blobs under a fixed byte budget. Mutex-guarded, safe for concurrent use. The zero value is not usable; create a Store with New. A Put that would exceed the budget evicts the oldest-inserted blobs, in insertion order, until the new blob fits.

func New

func New(maxBytes int) (*Store, error)

New creates a Store with a fixed byte budget. A non-positive maxBytes wraps ErrInvalidOptions.

func (*Store) Get

func (s *Store) Get(ref string) ([]byte, error)

Get returns a copy of the blob stored under ref. An unknown ref wraps ErrUnknownRef. Get does not change insertion order.

func (*Store) Put

func (s *Store) Put(content []byte) (ref string, err error)

Put computes ref as contextref.Mint(content) and stores content under it. A content whose length exceeds the store's budget wraps ErrBudgetExceeded and stores nothing. A content that fits evicts the oldest-inserted blobs, in insertion order, until the new blob fits within the budget, then stores it. Putting a content whose ref already exists overwrites the stored bytes and refreshes its insertion order to most-recent.

Jump to

Keyboard shortcuts

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