Documentation
¶
Overview ¶
Package attachment provides durable, content-addressed blob storage for session attachments.
Index ¶
- Variables
- func DefaultBaseDir() (string, error)
- func WithScope(ctx context.Context, scope *Scope) context.Context
- type Descriptor
- type PutMeta
- type Scope
- type Store
- func (s *Store) AddRef(sessionID string, d Descriptor) error
- func (s *Store) EnsureSessionViewDir(sessionID string) (string, error)
- func (s *Store) EnsureView(sessionID, attID string) (string, error)
- func (s *Store) Lookup(sessionID, attID string) (Descriptor, bool)
- func (s *Store) MaterializeMessages(sessionID string, msgs []core.Message) ([]core.Message, error)
- func (s *Store) MaterializerFor(sessionID string) func(context.Context, []core.Message) ([]core.Message, error)
- func (s *Store) Open(sessionID, attID string) (io.ReadCloser, Descriptor, error)
- func (s *Store) Put(data []byte, meta PutMeta) (Descriptor, error)
- func (s *Store) PutRef(sessionID string, data []byte, meta PutMeta) (Descriptor, error)
- func (s *Store) Reconcile(live map[string][]Descriptor) error
- func (s *Store) ReconcileExisting(liveSessionIDs map[string]bool) error
- func (s *Store) ReleaseSession(sessionID string) error
- func (s *Store) RemoveRef(sessionID, attID string) error
Constants ¶
This section is empty.
Variables ¶
var ErrNoScope = errors.New("attachment: no attachment scope (work inline)")
ErrNoScope is returned by Scope methods called on a nil Scope, i.e. by code that tried to produce an attachment reference without holding the capability.
var ErrScopeRevoked = errors.New("attachment: attachment scope revoked")
ErrScopeRevoked is returned after the owning session has been deleted.
Functions ¶
func DefaultBaseDir ¶
DefaultBaseDir resolves the production attachments root. MOA_CONFIG_DIR is honored for container and custom deployments.
func WithScope ¶ added in v0.30.0
WithScope tags ctx with the attachment capability of the agent that is running, so shared tools (a `read` object built by the parent and reused by an ephemeral reviewer, an MCP wrapper) resolve it PER INVOCATION instead of capturing it at construction time.
Passing a nil scope is not a no-op and must never be optimized into one: it writes nil over any inherited value, hiding a parent's capability from an agent that must not externalize. See Agent.executeWithOptions.
Types ¶
type Descriptor ¶
type Descriptor struct {
ID string `json:"id"`
SHA256 string `json:"sha256"`
Name string `json:"name"`
Mime string `json:"mime"`
Size int64 `json:"size"`
Kind string `json:"kind"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
Descriptor is the persisted, byte-free reference to a stored blob. It is what a message/session carries instead of base64.
type Scope ¶ added in v0.30.0
type Scope struct {
// contains filtered or unexported fields
}
Scope is the indivisible capability to externalize attachments for ONE owning session: it bundles the store, the owning session ID, the producer (PutRef) and the consumer (the materializer that turns references back into provider-ready bytes).
The bundling is the whole point. Producing references and being able to resolve them are two halves of the same capability: whoever holds one MUST hold the other, or a reference reaches the provider with no bytes behind it and the model silently sees an empty image. Keeping the halves in separate config fields (a store here, a materializer hook there) is exactly how that gap opens, so Scope has no exported fields and no partial constructor.
A nil *Scope is a valid, meaningful value: it means "no capability", i.e. work inline exactly as before. Every method is nil-safe.
func NewScope ¶ added in v0.30.0
NewScope builds the capability for sessionID on store. It rejects a nil store or an invalid session ID so a Scope can never exist half-built: if it exists, both halves work.
func ScopeFromContext ¶ added in v0.30.0
ScopeFromContext returns the scope installed by WithScope, or nil when the caller holds no capability (work inline).
func (*Scope) Materializer ¶ added in v0.30.0
Materializer returns the consumer half: the hook that expands references owned by this session back into inline bytes before a provider request. It is derived from the same value that produces the references, so the two can never disagree about the owner. Returns nil for a nil Scope.
func (*Scope) Put ¶ added in v0.30.0
func (s *Scope) Put(data []byte, meta PutMeta) (Descriptor, error)
Put stores data and registers the reference under the owning session in a single locked operation (see Store.PutRef). The owner is baked in: callers cannot pass a different one.
func (*Scope) Revoke ¶ added in v0.32.0
func (s *Scope) Revoke()
Revoke prevents a deleted session's in-flight tools from recreating its attachment index after it has been released. It is safe to call repeatedly.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a durable, content-addressed attachment blob store shared across sessions. Blobs are keyed by sha256 of their bytes and reference-counted by occurrence; a blob is deleted when no session references it.
func (*Store) AddRef ¶
func (s *Store) AddRef(sessionID string, d Descriptor) error
AddRef records one attachment occurrence in a session. It is idempotent for an existing (sessionID, descriptor ID) pair.
func (*Store) EnsureSessionViewDir ¶
EnsureSessionViewDir creates and returns the durable, session-scoped parent directory for attachment views. Callers may grant this directory to a tool path policy; it never exposes blobs or another session's views.
func (*Store) EnsureView ¶
EnsureView returns a durable, session-scoped path for a session-owned attachment. Tool views are session-local read-only copies (0400), never hardlinks: the view is exposed to agent tools, and a hardlink would let a tool corrupt the shared immutable blob across sessions. A view duplicates its bytes on disk for integrity and is released with its session. An empty legacy descriptor name uses "file" plus a MIME-derived extension when available.
func (*Store) Lookup ¶
func (s *Store) Lookup(sessionID, attID string) (Descriptor, bool)
Lookup returns the descriptor for a session-owned attachment occurrence.
func (*Store) MaterializeMessages ¶
MaterializeMessages returns a copy of msgs in which referenced images become inline base64, while referenced documents become an advisory with a durable, session-scoped tool path. Messages/blocks without a reference are passed through unchanged. The input slice and its content are never mutated.
func (*Store) MaterializerFor ¶
func (s *Store) MaterializerFor(sessionID string) func(context.Context, []core.Message) ([]core.Message, error)
MaterializerFor returns a per-session materializer closure suitable for the agent's MaterializeContent hook. sessionID is baked in.
func (*Store) Open ¶
func (s *Store) Open(sessionID, attID string) (io.ReadCloser, Descriptor, error)
Open returns a read-only handle to an attachment only when the requested session owns the occurrence.
func (*Store) Put ¶
func (s *Store) Put(data []byte, meta PutMeta) (Descriptor, error)
Put stores raw bytes, deduplicating by their SHA-256 hash. It creates an occurrence descriptor but does not attach that occurrence to a session.
func (*Store) PutRef ¶
PutRef publishes data (deduplicating by hash) AND records a provisional reference from sessionID in ONE locked operation, so the blob can never be garbage-collected between publication and referencing. This is the method callers should use when the owning session is already known (the normal ingestion path). Returns the minted Descriptor (already referenced).
func (*Store) Reconcile ¶
func (s *Store) Reconcile(live map[string][]Descriptor) error
Reconcile rewrites the session ownership indexes and catalog from live descriptors, removes indexes absent from live, and garbage-collects old unreferenced blobs and stale staging files. It MUST run at startup (or in a maintenance window) with no concurrent uploads, AddRef, or PutRef for sessions absent from live: live is a snapshot and is not safe for an actively uploading store.
func (*Store) ReconcileExisting ¶
ReconcileExisting is the lightweight startup reconcile path. It trusts the store's per-session indexes and is O(sessions-with-attachments), rather than walking conversation transcripts. Indexes for sessions absent from live are released, then the catalog, orphan blobs, and stale staging are reconciled.
func (*Store) ReleaseSession ¶
ReleaseSession removes every occurrence owned by a session and unlinks blobs which are no longer referenced by any remaining session index.