Documentation
¶
Overview ¶
Package remainder owns the truncated-result spool and its caller-scoped visibility grants.
When a tool result is shortened, the full body is stored under a content reference and the principal that received the truncation notice is granted read access. The model pages that body via the host's read_output tool.
Invariants:
- INV-AG-10 / INV-CE-07-A: a reference is handed to the model only after a successful store; a store failure yields an empty ref (plain notice).
- INV-CE-07-C: store failure must not fail the tool call.
- Visibility is caller-scoped: only the principal that received the grant may Load the ref (stricter than open ledger_read digest lookup).
Index ¶
- Variables
- func CapWithSpool(spool *Spool, principal string, result string, maxBytes int) (string, bool)
- func CapWithSpoolRef(spool *Spool, principal string, result string, maxBytes int) (body, ref string, truncated bool)
- func Fit(body string, total, maxBytes int, ref, trailer string) string
- func ParseTruncationNotice(s string) (prefix string, kept, total int, ref string, ok bool)
- func TruncationNotice(kept, total int, ref string) string
- type ContentStore
- type ContentStoreAdapter
- func (a ContentStoreAdapter) CheckSpoolGrant(ctx context.Context, ref, principal string) (bool, error)
- func (a ContentStoreAdapter) GrantSpool(ctx context.Context, ref, principal string) error
- func (a ContentStoreAdapter) IsContentNotFound(err error) bool
- func (a ContentStoreAdapter) LoadContent(ctx context.Context, ref string) ([]byte, error)
- func (a ContentStoreAdapter) StoreContent(ctx context.Context, ref string, data []byte) error
- type FailingStore
- type MemoryStore
- type NotFoundReporter
- type Spool
- type SpoolGrantStore
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotFound means the ref is unknown (never spooled, or never stored). ErrNotFound = errors.New("remainder not found") // ErrDenied means content exists (or was granted to someone else) but the // calling principal was not the recipient of the remainder ref. ErrDenied = errors.New("remainder access denied") // ErrExpired means the principal once held a grant but the remainder is no // longer available (retention expiry or explicit expiry). Distinct from // not-found so the model does not treat a timed-out ref as a corrupt key. ErrExpired = errors.New("remainder expired") )
Sentinel load failures. The read_output tool maps each to a distinct model-visible status so callers can tell them apart.
ErrStoreUnavailable is returned by FailingStore on every write.
Functions ¶
func CapWithSpool ¶
CapWithSpool shortens result so the whole return value fits in maxBytes, spools the original body for principal, and appends an honest truncation notice. When no truncation is needed the original body is returned unchanged.
maxBytes <= 0 means uncapped (no truncation). A nil spool (or failed store) yields a notice without a ref - the call still succeeds (INV-CE-07-C).
func CapWithSpoolRef ¶
func CapWithSpoolRef(spool *Spool, principal string, result string, maxBytes int) (body, ref string, truncated bool)
CapWithSpoolRef is CapWithSpool that also reports the ref it minted.
A second shaping pass needs the ref itself, not just the notice that names it: re-cutting the original body means naming the SAME remainder again, and recovering that ref by parsing it back out of the notice would make the notice's wording a load-bearing interface. The ref is empty when the body was not truncated, when there is no spool, or when the store failed.
func Fit ¶
Fit builds "content + trailer + notice" within maxBytes from an ALREADY stored body: it performs no store, reports total as the body's true size, and names ref (empty for a plain notice).
The trailer is caller-supplied framing charged inside the same envelope. Its whole reason for existing is that a status line appended AFTER a built body would push the result past the budget that built it; composed here, the envelope bound holds by construction.
func ParseTruncationNotice ¶
ParseTruncationNotice recognizes a TruncationNotice trailer at the end of s. It reports the content preceding the trailer (prefix), the kept/total byte counts, the named remainder ref (empty when the notice carried none), and whether s ended with a well-formed notice at all.
This exists so a renderer can distinguish "this result was truncated" from "this is just a tool result that happens to contain the word truncated" - parsing the exact format TruncationNotice emits, not guessing from a substring match.
func TruncationNotice ¶
TruncationNotice formats the model-visible truncation trailer.
When ref is non-empty the notice names the remainder and directs the model to read_output. When ref is empty (store failed, or no spool) the notice still reports kept/total honestly and invents no reference.
Types ¶
type ContentStore ¶
type ContentStore interface {
StoreContent(ctx context.Context, ref string, data []byte) error
LoadContent(ctx context.Context, ref string) ([]byte, error)
}
ContentStore is the durable byte store the spool writes to. ledger repositories satisfy it; the interface keeps this package free of ledger imports so agent and runtime layers can use it without cycles.
StoreContent must be idempotent: storing the same data twice returns the same ref and the store must not grow unboundedly for duplicates — determinism of refs across repeated prepares depends on it.
type ContentStoreAdapter ¶
type ContentStoreAdapter struct {
Store ContentStore
NotFoundError error
}
ContentStoreAdapter adapts a store whose not-found sentinel is known.
func (ContentStoreAdapter) CheckSpoolGrant ¶
func (a ContentStoreAdapter) CheckSpoolGrant(ctx context.Context, ref, principal string) (bool, error)
CheckSpoolGrant forwards the durable spool grant lookup to the wrapped store when it implements SpoolGrantStore; otherwise it reports no durable grant.
func (ContentStoreAdapter) GrantSpool ¶
func (a ContentStoreAdapter) GrantSpool(ctx context.Context, ref, principal string) error
GrantSpool forwards the durable spool grant to the wrapped store when it implements SpoolGrantStore; otherwise it is a no-op (nil), so the adapter never breaks a store that only provides in-process visibility.
func (ContentStoreAdapter) IsContentNotFound ¶
func (a ContentStoreAdapter) IsContentNotFound(err error) bool
IsContentNotFound reports whether err is the configured not-found sentinel.
func (ContentStoreAdapter) LoadContent ¶
LoadContent forwards to the wrapped store.
func (ContentStoreAdapter) StoreContent ¶
StoreContent forwards to the wrapped store.
type FailingStore ¶
type FailingStore struct{}
FailingStore implements ContentStore but rejects every StoreContent call. Used to prove INV-CE-07-C / INV-AG-10: a failed spool omits the ref.
func (FailingStore) IsContentNotFound ¶
func (FailingStore) IsContentNotFound(err error) bool
IsContentNotFound always true for the not-found sentinel.
func (FailingStore) LoadContent ¶
LoadContent always reports not found.
func (FailingStore) StoreContent ¶
StoreContent always fails.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is an in-process ContentStore for tests and host wiring that does not share the ledger repository. It is keyed by content reference: the same body always mints the same ref (sdkadapter.Mint is deterministic), so re-storing a duplicate lands on the same key and never grows the store.
func NewMemoryStore ¶
func NewMemoryStore() *MemoryStore
NewMemoryStore returns an empty memory-backed content store. Storing the same content twice yields the same ref and does not duplicate storage.
func (*MemoryStore) Delete ¶
func (m *MemoryStore) Delete(ref string)
Delete removes a ref so subsequent loads report not-found / expired.
func (*MemoryStore) IsContentNotFound ¶
func (m *MemoryStore) IsContentNotFound(err error) bool
IsContentNotFound reports whether err is this store's absence sentinel.
func (*MemoryStore) Len ¶
func (m *MemoryStore) Len() int
Len reports how many bodies are stored. Tests that assert nothing was spooled need to distinguish "stored nothing" from "stored something under a ref I did not predict"; counting is the only way to say the former.
func (*MemoryStore) LoadContent ¶
LoadContent retrieves previously stored bytes.
func (*MemoryStore) StoreContent ¶
StoreContent persists raw bytes under ref. It is idempotent: re-storing the same content under the same ref (dedupe by ref) is a no-op, so repeated prepares do not grow the store (see the ContentStore contract in spool.go).
type NotFoundReporter ¶
NotFoundReporter is implemented by stores that surface a typed not-found error (ledger.ErrContentNotFound). When the store does not implement it, any LoadContent error is treated as not-found for visibility decisions.
type Spool ¶
type Spool struct {
// contains filtered or unexported fields
}
Spool stores truncated tool-result bodies and gates reads by principal.
func NewSpool ¶
func NewSpool(store ContentStore) *Spool
NewSpool returns a principal-scoped remainder spool over store. A nil store is allowed: Spool then never mints refs (degrades to plain notices).
func (*Spool) Load ¶
Load returns the stored body when principal holds a live grant. Errors are the package sentinels ErrNotFound, ErrDenied, or ErrExpired.
func (*Spool) MarkExpired ¶
MarkExpired marks every grant on ref as expired. Used by retention and tests. The stored bytes may still be present; Load reports ErrExpired either way.
func (*Spool) Spool ¶
Spool stores the full body under a content-addressed output ref and grants principal read access. It returns the minted ref, or "" when the body is empty, the principal is empty, the store is nil, or the write fails. A failed write never invents a ref (INV-AG-10 / INV-CE-07-A/C).
type SpoolGrantStore ¶
type SpoolGrantStore interface {
// GrantSpool durably records that principal holds a grant on ref.
GrantSpool(ctx context.Context, ref, principal string) error
// CheckSpoolGrant reports whether principal holds a durable grant on ref.
CheckSpoolGrant(ctx context.Context, ref, principal string) (bool, error)
}
SpoolGrantStore is the optional durable grant surface of a ContentStore. Spool grants are normally in-memory (they vanish on restart), so stores that also persist grants - currently the sqlite-backed ledger repository - expose them here. The spool calls GrantSpool best-effort and consults CheckSpoolGrant only on the in-memory grant miss path, so a store without this interface keeps today's purely in-process visibility semantics.