Help us shape the future of Go! Take the 2026 Go Developer Survey

index

package
v2.3.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DecodeEmbedding

func DecodeEmbedding(s string) ([]float32, error)

DecodeEmbedding deserializes a base64 string produced by EncodeEmbedding back to a float32 vector. Returns nil for an empty string.

func EncodeEmbedding

func EncodeEmbedding(vec []float32) string

EncodeEmbedding serializes a float32 vector to a base64 string (little-endian). Returns an empty string for a nil or empty slice.

func TruncateNormalize

func TruncateNormalize(vec []float32, dims int) []float32

TruncateNormalize applies the Matryoshka reduction: keep the first dims components, then L2-renormalize. dims <= 0 or dims >= len(vec) returns the vector unchanged (still renormalized when truncated). Renormalization is required — a raw slice of a unit vector is not itself a unit vector, so cosine distances would be skewed without it.

func WithTimingSink

func WithTimingSink(ctx context.Context, fn func(SearchTiming)) context.Context

WithTimingSink asks Search, SearchSubject and SearchExhaustive to report their phase split to fn.

Types

type CellNeighborhood

type CellNeighborhood struct {
	Center    IndexEntry
	Neighbors []CellSearchResult
	Edges     []NeighborEdge
}

CellNeighborhood is the semantic neighbourhood of one cell: its nearest neighbours and the links among them that mark sub-clusters.

type CellSearchResult

type CellSearchResult struct {
	Document IndexEntry
	Score    float32
}

CellSearchResult is a memory cell returned by CellStore.Search.

func CutAtGap

func CutAtGap(results []CellSearchResult, gap float32) []CellSearchResult

CutAtGap drops the tail of results (sorted by Score, best first) that falls more than gap below the top score. A zero or negative gap keeps everything.

func CutAtLargestGap

func CutAtLargestGap(results []CellSearchResult) []CellSearchResult

CutAtLargestGap drops the tail of results (sorted by Score, best first) at their steepest score drop. On a corpus whose documents resemble each other, every document scores something against every query, so a query with one right answer still fills the window with near-ties a few points below it. The signal is not the absolute score, which moves with the query, but where the list falls off a cliff; keeping everything above the largest single drop adapts to how many answers the query has, which a fixed threshold cannot. It trades recall for precision, so it is for a caller that wants it.

type CellStore

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

CellStore holds a per-subject HNSW index. Each subject's cells are isolated so cross-subject interference is impossible.

func NewCellStore

func NewCellStore(embedder *Embedder, logger zerolog.Logger) *CellStore

NewCellStore creates an empty CellStore.

func (*CellStore) CollectionSize

func (s *CellStore) CollectionSize() int64

CollectionSize returns total indexed cells across all subjects.

func (*CellStore) Delete

func (s *CellStore) Delete(_ context.Context, id string) error

Delete removes a memory cell by ID across all subject indexes. The graph is rebuilt lazily before the next search (see subjectIndex.dirty), so a sweep that deletes hundreds of cells costs one rebuild.

func (*CellStore) GetRecentBySubject

func (s *CellStore) GetRecentBySubject(_ context.Context, partition, service string, topN int, since time.Time) ([]IndexEntry, error)

GetRecentBySubject returns up to topN cells of one service, oldest first, inside the "since" window, keeping the newest when topN cuts. Only cells that carry a Disposition are returned. A cell is visible when its Partition equals partition or is empty; one naming another partition is never returned, so a same-named service in two partitions never shares history.

func (*CellStore) Index

func (s *CellStore) Index(ctx context.Context, doc IndexEntry) ([]float32, error)

Index embeds and stores a memory cell document.

func (*CellStore) Neighborhood

func (s *CellStore) Neighborhood(id string, topK, edgesPerNeighbor int, keep func(IndexEntry) bool) (*CellNeighborhood, bool)

Neighborhood returns the semantic neighbourhood of the cell with the given id, searched in the index of the subject that holds it: subjects never share a graph. The second result is false when the id has no embedding in any index (never seeded, private, or since deleted), so a caller can tell "not indexed" from "no neighbours". keep is an optional per-cell filter; nil keeps all.

Neighbour-to-neighbour edges follow a scale-free rule, not an absolute similarity threshold: an edge survives only when the two cells are more similar to each other than either is to the centre, and then only if it is among each endpoint's edgesPerNeighbor strongest such links (symmetrised, the union, so a hub may end up with a higher degree). Embeddings of same-kind cells crowd into a narrow high band, so any fixed threshold either admits the complete graph or is retuned per corpus and per embedder. "Tighter to each other than to the centre" is what sub-cluster means and holds at any scale. A neighbourhood with no sub-structure returns no edges: a star.

func (*CellStore) QueryEmbedCacheEntries

func (s *CellStore) QueryEmbedCacheEntries() int

QueryEmbedCacheEntries is how many queries the query-embedding cache holds; 0 when the store has no embedder.

func (*CellStore) QueryEmbedCacheStats

func (s *CellStore) QueryEmbedCacheStats() QueryEmbedCacheStats

QueryEmbedCacheStats reads the query-embedding cache counters; zero when the store has no cache.

func (*CellStore) Search

func (s *CellStore) Search(ctx context.Context, query string, topK int, kindFilter string) ([]CellSearchResult, error)

Search returns the top-k results across every subject's index. An optional kindFilter (e.g. "stable_fact") restricts them to one kind. Subject-scoped search is SearchSubject.

func (*CellStore) SearchByEmbedding

func (s *CellStore) SearchByEmbedding(_ context.Context, partition string, embedding []float32, since time.Time, minSimilarity float32, source string) (*CellSearchResult, error)

SearchByEmbedding returns the single most similar cell above minSimilarity (cosine) among the cells that carry a Disposition, are visible to partition (their Partition equals it or is empty), fall inside the "since" window and, when source is not empty, name exactly that Source.

The source guard is a correctness guard: templated texts embed almost identically across sources, so the nearest vector alone can belong to another source whose recorded outcome does not apply. The partition rule is the one GetRecentBySubject applies.

func (*CellStore) SearchExhaustive

func (s *CellStore) SearchExhaustive(ctx context.Context, query, subject string, kindFilter string) ([]CellSearchResult, error)

SearchExhaustive ranks every entry the caller may see by exact cosine, with no graph and no fetch window: the subject's own cells and the global ones, or every subject's when subject is empty. It exists for one caller. A graph search returns its top-K window, and a caller that drops hits afterwards (a cell deleted or retired on another replica is still indexed here) can see the whole window rejected although other cells would have qualified. This hands back the full ranked population so the caller's filter gets every candidate. No score gap is applied.

func (*CellStore) SearchExhaustiveTimed

func (s *CellStore) SearchExhaustiveTimed(ctx context.Context, query, kind string, keep func(IndexEntry) bool) ([]CellSearchResult, SearchTiming, error)

SearchExhaustiveTimed ranks every entry of every subject against the query by exact cosine, with no graph and no fetch window, optionally restricted to a kind and narrowed by keep before scoring. A graph search returns its top-K window, and a caller that rejects hits afterwards (visibility, state) can see the whole window rejected although other cells would have qualified; this hands back the full ranked population. keep is a pre-filter for a caller that can already tell from the entry (its tags, say) that it would reject a cell. No score gap is applied.

func (*CellStore) SearchSince

func (s *CellStore) SearchSince(ctx context.Context, query string, topK int, kind string, since time.Time) ([]CellSearchResult, error)

SearchSince returns the top-k cells of one kind most similar to the query text that carry a Timestamp inside the "since" window (a zero since keeps the whole kind). A caller names its own kinds; the index knows none.

func (*CellStore) SearchSubject

func (s *CellStore) SearchSubject(ctx context.Context, query, subject string, topK int, kindFilter string) ([]CellSearchResult, error)

SearchSubject searches within the given subject's index and merges results from the global (empty subject) index, returning top-k by score.

func (*CellStore) SearchTimed

func (s *CellStore) SearchTimed(ctx context.Context, query string, topK int, kindFilter string) ([]CellSearchResult, SearchTiming, error)

SearchTimed is Search that also returns the embed-versus-index split.

func (*CellStore) SeedFromEmbedding

func (s *CellStore) SeedFromEmbedding(doc IndexEntry, embedding []float32) bool

SeedFromEmbedding inserts a pre-embedded cell without calling the embedding API. It returns false, inserting nothing, when the vector's length disagrees with the store dimension (a cell embedded by another model): the caller should re-embed it. An empty embedding has nothing to seed and returns true.

The dimension is the embedder's configured output dimension when known, so a stale wrong-dimension cell seeded first cannot lock the store to a wrong shape; a seeded vector only sets it when it is not known.

func (*CellStore) SeedOrEmbed

func (s *CellStore) SeedOrEmbed(ctx context.Context, cell *memoryv1.MemoryCell, doc IndexEntry) (embedded string, err error)

SeedOrEmbed makes sure a cell is in the index. A cell that carries an embedding which decodes and has the index's dimension is seeded from it, and nothing needs writing: the returned string is empty. A cell with none, or with one that cannot be decoded or has the wrong dimension (it was embedded by another model), is embedded now, and the returned string is the new embedding for the caller to persist on the cell. doc is the cell's index entry.

func (*CellStore) SetQueryEmbedCounter

func (s *CellStore) SetQueryEmbedCounter(fn func(hit bool))

SetQueryEmbedCounter sets where the query-embedding cache reports each lookup's outcome, true for a hit. Call before the store is searched.

func (*CellStore) SetScoreGap deprecated

func (s *CellStore) SetScoreGap(float32)

SetScoreGap is kept for callers that still set a cutoff. The store no longer cuts its results: a cutoff applied here, before the caller has filtered what it may see and fused the semantic channel with the lexical one, starves a caller whose answers sit a few points below a hit it cannot read. A caller that wants a cutoff applies CutAtGap or CutAtLargestGap to the results it kept.

Deprecated: it has no effect.

type EmbedMetrics

type EmbedMetrics struct {
	CacheHits  int64 `json:"cacheHits"`
	EmbedCalls int64 `json:"embedCalls"`
}

EmbedMetrics holds cache and API call counters.

type Embedder

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

Embedder generates vector embeddings. It has two modes:

  • Vertex AI (genai != nil): uses google.golang.org/genai SDK with BackendVertexAI, authenticated via Workload Identity (ADC). Created when endpoint == "".

  • Gateway (endpoint != ""): routes through an OpenAI-compatible /v1/embeddings endpoint.

func NewEmbedder

func NewEmbedder(ctx context.Context, endpoint, model, project, location string, outputDims, maxInputChars int, logger zerolog.Logger) (*Embedder, error)

NewEmbedder creates an Embedder. When endpoint == "", uses Vertex AI via Workload Identity (ADC); project and location are required. When endpoint != "", routes through the OpenAI-compatible gateway; project and location are unused. outputDims reduces the output vector dimension (0 = model default). Applied to Vertex AI natively, and to the gateway via the OpenAI-compatible "dimensions" param (e.g. Matryoshka models like nomic-embed-text truncate cleanly to 128/256/512). maxInputChars hard-caps input length before the embed call (0 = defaultMaxInputChars); set it below the model's token window × ~4 to avoid the gateway rejecting oversized input.

func (*Embedder) EmbedBatch

func (e *Embedder) EmbedBatch(ctx context.Context, texts []string) ([][]float32, error)

EmbedBatch returns embeddings for multiple texts, preserving input order. It issues up to embedBatchConcurrency requests concurrently (see the const) and fails fast on the first error, cancelling the rest.

func (*Embedder) EmbedDocument

func (e *Embedder) EmbedDocument(ctx context.Context, text string) ([]float32, error)

EmbedDocument returns the embedding vector for a document to be indexed.

func (*Embedder) EmbedQuery

func (e *Embedder) EmbedQuery(ctx context.Context, text string) ([]float32, error)

EmbedQuery returns the embedding vector for a search query.

func (*Embedder) Metrics

func (e *Embedder) Metrics() EmbedMetrics

Metrics returns a snapshot of cache hit and API call counters.

func (*Embedder) Model

func (e *Embedder) Model() string

Model is the embedding model name.

func (*Embedder) OutputDims

func (e *Embedder) OutputDims() int

OutputDims returns the configured Matryoshka output dimension. 0 means the model's own size, with no truncation.

func (*Embedder) SetErrorSink

func (e *Embedder) SetErrorSink(fn ErrorFunc)

SetErrorSink reports every failed provider request this embedder makes. Set it before the embedder is shared.

func (*Embedder) SetUsageSink

func (e *Embedder) SetUsageSink(fn UsageFunc)

SetUsageSink accounts every provider request this embedder makes. The sink may be called from several goroutines (EmbedBatch). Set it before the embedder is shared.

type ErrorFunc

type ErrorFunc func(ctx context.Context, model, path string, err error)

ErrorFunc receives every failed provider request: the model, the endpoint path it went to ("/v1/embeddings" for a gateway, "vertex" for Vertex AI) and the error. ctx is the caller's, so a receiver can tell a cancelled caller from a failing endpoint.

type IndexEntry

type IndexEntry struct {
	ID         string
	Kind       string
	Scope      string
	Subject    string
	Title      string
	Content    string
	Confidence string
	Status     string
	Tags       []string
	EventDate  string // RFC3339, only set for kind=event

	// Timestamp is when the underlying occurrence happened; the "since" window of
	// GetRecentBySubject and SearchByEmbedding filters on it.
	Timestamp time.Time
	// Source is where the occurrence came from. SearchByEmbedding can require an
	// exact match, so a near-identical text from another source is not a hit.
	Source string
	// Service is the key GetRecentBySubject filters on.
	Service string
	// Disposition is the outcome recorded for the occurrence. Empty while it is
	// still in flight; SearchByEmbedding and GetRecentBySubject skip such cells.
	Disposition string
	// Partition is the partition the cell belongs to. Empty means visible to
	// every partition; a cell naming another partition is never returned.
	Partition string
	// GroupID ties the cell to a caller-side group (may be empty).
	GroupID string
	// Type, Message, Severity and Classification are free labels the caller
	// reads back from a hit.
	Type, Message, Severity, Classification string
}

IndexEntry is the per-cell record indexed in CellStore: the searchable metadata projection of a memory cell (Title+Content is what gets embedded; the other fields drive filtering). Not a document/file.

type NeighborEdge

type NeighborEdge struct {
	A, B  string
	Score float32
}

NeighborEdge is one neighbour-to-neighbour similarity link. Score uses the same [0,1] mapping as CellSearchResult.Score, so an edge and a neighbour score compare directly.

type QueryEmbedCacheStats

type QueryEmbedCacheStats struct {
	Hits    int64
	Misses  int64
	Entries int
}

QueryEmbedCacheStats is a point-in-time counter readout for observability.

type SearchTiming

type SearchTiming struct {
	Embed time.Duration
	Index time.Duration
}

SearchTiming is the embed-versus-index split of one search: an embedder latency spike and an in-memory scan spike are indistinguishable from the total.

type UsageFunc

type UsageFunc func(ctx context.Context, model string, latency time.Duration, inputTokens int64, failed bool)

UsageFunc receives every provider request the embedder makes: the model, how long it took, its input tokens (the provider's count, or an estimate of 4 characters per token when it gives none) and whether it failed. A request answered from the embedder's cache is not reported. ctx is the caller's, so a receiver can attribute the call.

Jump to

Keyboard shortcuts

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