memory

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 23, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package memory defines short-term and long-term memory primitives.

Short-term memory keeps the running conversation bounded — by message count or by token budget — and is what feeds the LLM on every turn. Window is the in-process implementation; a Summarizer hook can be plugged in to compress overflowing turns instead of dropping them.

Long-term memory is the retrieval side: documents are chunked, optionally embedded, and stored in a Store. A Retriever queries the Store at agent time to bring relevant context back into the prompt. Store is an interface; this package ships an in-memory implementation (Memory) for tests, examples and quick prototypes. SQLite + BM25 and external vector backends (pgvector, qdrant, weaviate, chroma) ship as separate modules under memory/<backend>/.

Chunking helpers live in subpackage memory/chunk.

Status: Phase 6 — Session A (interfaces + short-term + in-mem store + chunkers). SQLite/BM25 and external adapters land in Sessions B and C.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnsupported = errors.New("memory: operation not supported by this Store")

ErrUnsupported is returned by Store implementations for operations they do not implement (typically Delete on append-only backends).

Functions

This section is empty.

Types

type Chunk

type Chunk struct {
	// ID uniquely identifies the chunk inside a Store.
	ID string

	// DocumentID points back to the parent Document.
	DocumentID string

	// Index is the chunk's ordinal within its parent document
	// (0-based). Useful for assembling neighbor windows at query time.
	Index int

	// Text is the chunk body.
	Text string

	// Embedding is the dense vector representation of Text. Stores
	// that operate on text-only retrieval (e.g., BM25) may leave it
	// nil; vector stores require it to be populated before Add.
	Embedding []float32

	// Metadata carries through from the parent Document.
	Metadata map[string]string
}

Chunk is the retrieval unit: a span of text small enough to embed and rank, together with the metadata needed to reconstruct its origin. A Store contains Chunks; Documents are upstream of them.

type Document

type Document struct {
	// ID uniquely identifies the document inside a Store. Callers may
	// assign it (stable IDs make re-ingestion idempotent); when empty,
	// the Store assigns one.
	ID string

	// Source is the human-readable origin (file path, URL, ticket
	// reference, ...). Stored as-is; not interpreted.
	Source string

	// Text is the full document body. Chunkers split this.
	Text string

	// Metadata is opaque key/value data that flows through chunking
	// and is preserved on every resulting Chunk.
	Metadata map[string]string

	// CreatedAt records when the document was ingested. Stores that
	// support time-based filtering use this field.
	CreatedAt time.Time
}

Document is the ingestion unit: a piece of source content together with its origin and any metadata the caller wants to round-trip through retrieval. Documents are chunked before being written to a Store; the chunks carry a back-reference via Chunk.DocumentID.

type Embedder

type Embedder interface {
	Embed(ctx context.Context, texts []string) ([][]float32, error)

	// Dimensions reports the vector size produced by Embed. Stores
	// use it to allocate columns / validate inputs.
	Dimensions() int
}

Embedder turns text into dense vectors. Implementations wrap provider-specific embedding APIs (OpenAI, Google, Cohere, ...) or local models. Embed must preserve input order: out[i] is the vector for texts[i].

type EmbedderFunc

type EmbedderFunc struct {
	Dim int
	Fn  func(ctx context.Context, texts []string) ([][]float32, error)
}

EmbedderFunc adapts a plain function to the Embedder interface. The Dim field declares the embedding dimensionality so Dimensions() can satisfy the interface.

func (EmbedderFunc) Dimensions

func (e EmbedderFunc) Dimensions() int

Dimensions implements Embedder.

func (EmbedderFunc) Embed

func (e EmbedderFunc) Embed(ctx context.Context, texts []string) ([][]float32, error)

Embed implements Embedder.

type HashingEmbedder

type HashingEmbedder struct {
	// Dim is the embedding dimensionality. 256 is a reasonable
	// default for small corpora.
	Dim int
}

HashingEmbedder is a deterministic, network-free Embedder useful for tests, examples and offline development. It hashes each whitespace-separated token of the input into a fixed-size float32 vector with the "feature hashing" / "hashing trick" technique used in scikit-learn's HashingVectorizer.

Quality is not comparable to a trained embedding model — the vectors capture lexical overlap, not semantic similarity. Use it to wire up RAG plumbing end-to-end without depending on a paid API; swap in a real embedder (OpenAI text-embedding-3-small, Cohere, Voyage, ...) when running for real.

func NewHashingEmbedder

func NewHashingEmbedder(dim int) HashingEmbedder

NewHashingEmbedder returns a HashingEmbedder with the given dimensionality (must be > 0).

func (HashingEmbedder) Dimensions

func (h HashingEmbedder) Dimensions() int

Dimensions implements Embedder.

func (HashingEmbedder) Embed

func (h HashingEmbedder) Embed(_ context.Context, texts []string) ([][]float32, error)

Embed implements Embedder.

type InMemoryStore

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

InMemoryStore is a goroutine-safe Store backed by Go slices and maps. It is meant for tests, examples and quick prototypes; it does not persist across process restarts and is not optimized for large corpora.

Retrieval mode: when the Query carries an Embedding, ranking is by cosine similarity. Otherwise the Query.Text is matched against chunk text with case-insensitive substring scoring (a poor man's BM25; the embedded SQLite + BM25 backend lands in Session B).

The zero value is not usable; call NewInMemoryStore.

func NewInMemoryStore

func NewInMemoryStore() *InMemoryStore

NewInMemoryStore returns an empty, usable InMemoryStore.

func (*InMemoryStore) Add

func (s *InMemoryStore) Add(_ context.Context, chunks []Chunk) error

Add appends chunks to the store. Chunks without an ID are assigned one (a v4 UUID). Re-adding a chunk with an existing ID overwrites the previous entry, so callers can use stable IDs to make re-ingestion idempotent.

func (*InMemoryStore) Close

func (*InMemoryStore) Close() error

Close is a no-op for InMemoryStore.

func (*InMemoryStore) Delete

func (s *InMemoryStore) Delete(_ context.Context, documentID string) error

Delete removes every chunk whose DocumentID matches the argument. Returns nil even when no chunks were removed (idempotent).

func (*InMemoryStore) Len

func (s *InMemoryStore) Len() int

Len returns the number of chunks currently stored. Useful for tests; not part of the Store interface.

func (*InMemoryStore) Retrieve

func (s *InMemoryStore) Retrieve(_ context.Context, q Query) ([]Result, error)

Retrieve returns the top-K chunks for q in descending score order. See InMemoryStore's package comment for the ranking rules.

type Query

type Query struct {
	// Text is the natural-language query. Used by lexical stores
	// (BM25) and by hybrid stores; vector-only stores ignore it
	// unless an Embedder is plugged in upstream.
	Text string

	// Embedding is the dense vector representation of the query.
	// Required by vector-only stores.
	Embedding []float32

	// K is the maximum number of results to return. Zero or negative
	// values mean "store default" (typically 5).
	K int

	// Filter, when non-nil, restricts results to chunks whose
	// Metadata satisfies every key/value pair (exact match). Stores
	// that cannot filter ignore this field.
	Filter map[string]string
}

Query is a retrieval request. At least one of Text or Embedding must be set. Stores that support both modes pick whichever is available; pure vector stores ignore Text, pure text stores ignore Embedding.

type Result

type Result struct {
	Chunk Chunk
	Score float32
}

Result is one hit returned by Store.Retrieve. Score's meaning is store-specific (cosine distance for vector stores, BM25 score for lexical stores), but higher always means "more relevant".

type Retriever

type Retriever struct {
	Store    Store
	Embedder Embedder
	DefaultK int
}

Retriever is a convenience wrapper that composes an Embedder and a Store: callers pass a Query with only Text set, Retriever fills in Embedding before delegating to the underlying Store. Use it when the calling code shouldn't know whether the backend is lexical or vector-based.

func (*Retriever) Retrieve

func (r *Retriever) Retrieve(ctx context.Context, q Query) ([]Result, error)

Retrieve runs q through the configured Embedder (when Text is set and Embedding is not) and forwards the result to Store.Retrieve. When Embedder is nil, Retrieve forwards the query unchanged.

type Store

type Store interface {
	Add(ctx context.Context, chunks []Chunk) error
	Retrieve(ctx context.Context, q Query) ([]Result, error)
	Delete(ctx context.Context, documentID string) error
	Close() error
}

Store is the long-term memory interface. Implementations may be purely lexical (BM25), purely vector (pgvector, qdrant) or hybrid (SQLite + BM25 with optional embeddings).

Add ingests chunks. Retrieve returns the top-K results for a query in descending relevance order. Delete removes the chunks belonging to a document; implementations that don't support deletion return ErrUnsupported. Close releases store-owned resources (DB handles, gRPC clients) and is safe to call multiple times.

type Summarizer

type Summarizer interface {
	Summarize(ctx context.Context, messages []schema.Message) (string, error)
}

Summarizer compresses a slice of messages into a short paragraph. Implementations typically call an LLM; see SummarizerFunc for a trivial wrapper. Errors fall back to dropping the messages.

type SummarizerFunc

type SummarizerFunc func(ctx context.Context, messages []schema.Message) (string, error)

SummarizerFunc adapts a plain function to the Summarizer interface.

func (SummarizerFunc) Summarize

func (f SummarizerFunc) Summarize(ctx context.Context, m []schema.Message) (string, error)

Summarize implements Summarizer.

type Window

type Window struct {
	// MaxMessages, when > 0, caps how many messages the snapshot may
	// contain (including the system message and the summary).
	MaxMessages int

	// MaxTokens, when > 0, caps the estimated total token count of
	// the snapshot. Estimation uses a 4-chars-per-token heuristic
	// over Message.Text(); accurate enough for budgeting, not for
	// billing.
	MaxTokens int

	// Summarizer, when non-nil, is called with the messages about to
	// be evicted. The returned text replaces them as a single system
	// message tagged with Name="summary". When nil, evicted messages
	// are simply dropped.
	Summarizer Summarizer
	// contains filtered or unexported fields
}

Window is a bounded short-term memory: a list of messages capped by either message count or estimated token count (or both). Callers drive the conversation through Append, then Snapshot to obtain the trimmed slice that should be fed to the next LLM call.

Trimming preserves the first system message (if any) so the agent's instructions are never dropped, and prefers to evict the oldest non-system turns. When a Summarizer is configured, evicted turns are compressed into a single system message instead of discarded — useful for long-running agents that need to remember earlier context cheaply.

Window is goroutine-safe.

func (*Window) Append

func (w *Window) Append(m schema.Message)

Append adds m to the window. It does not trim; trimming runs in Snapshot so that the configured Summarizer can be invoked with a caller-provided context.

func (*Window) AppendAll

func (w *Window) AppendAll(ms []schema.Message)

AppendAll is a convenience for adding many messages at once.

func (*Window) Len

func (w *Window) Len() int

Len returns the number of messages currently stored in the window (including any leading system message). Useful for tests.

func (*Window) Snapshot

func (w *Window) Snapshot(ctx context.Context) ([]schema.Message, error)

Snapshot returns the trimmed slice of messages to feed to the next LLM call. The returned slice is safe to mutate; the window's internal storage is not aliased.

When a Summarizer is configured and the window exceeds its caps, the oldest non-system messages are summarized into a single system message and prepended to the snapshot.

Directories

Path Synopsis
Package chunk splits Documents into Chunks suitable for embedding and retrieval.
Package chunk splits Documents into Chunks suitable for embedding and retrieval.

Jump to

Keyboard shortcuts

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