Documentation
¶
Index ¶
- Constants
- func ExtractFacts(ctx context.Context, text string, cfg ExtractConfig) ([]string, error)
- type ConsolidateConfig
- type EntityExtractorAccessor
- type ExtractConfig
- type Fact
- type GraphAccessor
- type MemoryStats
- type Store
- func (s *Store) Close() error
- func (s *Store) Consolidate(ctx context.Context, agentID string, cfg ConsolidateConfig) error
- func (s *Store) DB() *bolt.DB
- func (s *Store) Delete(agentID, factID string) error
- func (s *Store) LaunchAsyncConsolidate(agentID string, cfg ConsolidateConfig)
- func (s *Store) List(agentID string) ([]Fact, error)
- func (s *Store) ListAgents() ([]string, error)
- func (s *Store) MaybeConsolidate(ctx context.Context, agentID string, cfg ConsolidateConfig) error
- func (s *Store) PendingVectorCount() int
- func (s *Store) Put(ctx context.Context, agentID, text string) error
- func (s *Store) PutShared(ctx context.Context, text string) error
- func (s *Store) Recall(ctx context.Context, agentID, query string, topK int) ([]string, error)
- func (s *Store) RecallAll(ctx context.Context, agentID, query string, topK int) ([]string, error)
- func (s *Store) RecallShared(ctx context.Context, query string, topK int) ([]string, error)
- func (s *Store) SetKG(graph GraphAccessor, extractor EntityExtractorAccessor)
- func (s *Store) Stats(agentID string) (MemoryStats, error)
- func (s *Store) UpdateFact(agentID string, f Fact) error
- type StoreConfig
- type VectorResult
- type VectorStore
Constants ¶
SharedAgentID is the reserved agent ID for the shared memory namespace. Facts stored here are readable by all agents via RecallShared and RecallAll.
Concurrency note: bbolt serialises concurrent write access via a file-level lock. Multiple processes writing shared memory will serialise, not race. Concurrent reads are always safe.
Variables ¶
This section is empty.
Functions ¶
func ExtractFacts ¶
ExtractFacts calls the configured LLM and returns a slice of atomic facts extracted from text. Each element is a self-contained declarative sentence suitable for passing directly to Put / Remember.
Without an Anthropic API key, ExtractFacts returns the raw text as a single fact (graceful degradation — useful in offline or test contexts).
Types ¶
type ConsolidateConfig ¶
type ConsolidateConfig interface {
GetAnthropicAPIKey() string
GetConsolidateLLM() string
GetConsolidateModel() string
GetConsolidateThreshold() int
GetDecayHalfLife() time.Duration
}
ConsolidateConfig is the subset of configuration used by consolidation. Defined as an interface to avoid a circular import with the root package.
type EntityExtractorAccessor ¶
type EntityExtractorAccessor interface {
ExtractIDs(text string) ([]string, error) // returns canonical node IDs
}
EntityExtractorAccessor extracts entities from a text string. Implemented by pkg/kg.EntityExtractor.
type ExtractConfig ¶
type ExtractConfig interface {
GetAnthropicAPIKey() string
GetConsolidateModel() string // reuses the same model field
}
ExtractConfig is the subset of configuration needed for fact extraction. Satisfied by graymatter.Config via the same method-set pattern as ConsolidateConfig.
type Fact ¶
type Fact struct {
ID string `json:"id"`
AgentID string `json:"agent_id"`
Text string `json:"text"`
CreatedAt time.Time `json:"created_at"`
AccessedAt time.Time `json:"accessed_at"`
AccessCount int `json:"access_count"`
// Weight is the decay-adjusted relevance score in [0, 1].
// New facts start at 1.0 and decay over time via the forgetting curve.
Weight float64 `json:"weight"`
Embedding []float32 `json:"embedding,omitempty"`
}
Fact is a single unit of memory: a piece of text an agent observed, enriched with metadata used for retrieval scoring and decay.
type GraphAccessor ¶
type GraphAccessor interface {
// Upsert inserts or updates a node in the graph.
UpsertNode(id, label, entityType string) error
// NeighborTexts returns text labels of nodes reachable from nodeID within depth hops.
NeighborTexts(nodeID string, depth int) ([]string, error)
}
GraphAccessor is a narrow interface that pkg/memory uses to interact with the knowledge graph without importing pkg/kg (prevents import cycles).
type MemoryStats ¶
type MemoryStats struct {
AgentID string `json:"agent_id"`
FactCount int `json:"fact_count"`
OldestAt time.Time `json:"oldest_at"`
NewestAt time.Time `json:"newest_at"`
AvgWeight float64 `json:"avg_weight"`
}
MemoryStats holds aggregate statistics for a single agent.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the central storage layer. It combines bbolt for durable structured storage with a pluggable VectorStore for similarity search. All public methods are safe for concurrent use.
func Open ¶
func Open(cfg StoreConfig) (*Store, error)
Open creates or opens the GrayMatter store at cfg.DataDir.
func (*Store) Close ¶
Close signals all background goroutines to stop, waits for them to exit, then flushes and closes the underlying stores.
func (*Store) Consolidate ¶
Consolidate runs the full consolidation pipeline for agentID:
- Apply exponential decay weights to all facts.
- If fact count > threshold, LLM-summarise the weakest batch.
- Prune facts with weight < 0.01.
func (*Store) LaunchAsyncConsolidate ¶
func (s *Store) LaunchAsyncConsolidate(agentID string, cfg ConsolidateConfig)
LaunchAsyncConsolidate starts MaybeConsolidate in a tracked, bounded goroutine. Non-blocking: if the semaphore is at capacity the trigger is silently dropped rather than blocking the caller.
func (*Store) ListAgents ¶
ListAgents returns all known agent IDs.
func (*Store) MaybeConsolidate ¶
MaybeConsolidate triggers consolidation only when the fact count for agentID meets or exceeds the threshold. Safe to call concurrently.
func (*Store) PendingVectorCount ¶ added in v0.3.0
PendingVectorCount returns the number of facts currently waiting to be indexed in the vector store. A non-zero value after a quiescent period indicates a persistent embedder/vector-store failure worth investigating.
func (*Store) Put ¶
Put stores a new observation for agentID.
Durability model:
- Compute embedding (best-effort; on failure the fact is keyword-only).
- Single bbolt transaction commits the fact AND, if an embedding exists, a marker in bucketPendingVector. The marker is the durable "this still needs to land in the vector store" intent.
- Inline vector upsert. On success the marker is cleared. On failure the marker remains and the background reconciler will retry it; the caller still sees nil because bbolt is the source of truth.
This closes the crash window between the bbolt write and the vector write: after a crash, reconcileVectors() at Open() drains the pending bucket.
func (*Store) PutShared ¶
PutShared stores a new observation in the shared memory namespace. Shared facts are accessible to all agents via RecallShared and RecallAll.
func (*Store) Recall ¶
Recall performs hybrid retrieval for agentID given a query string. It fuses three signals via Reciprocal Rank Fusion (RRF):
- Vector similarity (cosine, pluggable VectorStore) — when embeddings available
- Keyword relevance (TF-IDF approximation over bbolt facts)
- Recency score (exponential decay from CreatedAt)
Returns the top-k fact texts, ready to inject into a system prompt.
func (*Store) RecallAll ¶
RecallAll merges agent-scoped and shared-scoped results, deduplicates, and re-ranks by Reciprocal Rank Fusion. It returns at most topK combined facts.
func (*Store) RecallShared ¶
RecallShared returns the top-k most relevant shared facts for query.
func (*Store) SetKG ¶
func (s *Store) SetKG(graph GraphAccessor, extractor EntityExtractorAccessor)
SetKG wires an optional knowledge graph and entity extractor into the store. Call this after Open() to enable graph enrichment in Recall and Consolidate. Both arguments are optional; pass nil to disable the corresponding feature.
type StoreConfig ¶
type StoreConfig struct {
DataDir string
Embedder embedding.Provider
DecayHalfLife time.Duration
// VectorBackend overrides the default chromem-go vector store.
// If nil, a persistent chromem-go instance is created under DataDir/vectors.
// Use this to plug in Qdrant, Weaviate, pgvector, or any VectorStore impl.
VectorBackend VectorStore
// MaxAsyncConsolidations bounds concurrent background consolidations.
// 0 is normalised to 2 by Open().
MaxAsyncConsolidations int
// OnConsolidateError is called when an async consolidation goroutine errors.
// If nil, errors are discarded. Must be safe for concurrent use.
OnConsolidateError func(agentID string, err error)
// OnVectorIndexError is called when an inline vector upsert fails after the
// bbolt write has already committed. The fact remains in the pending-vector
// queue and will be retried by the background reconciler. Must be safe for
// concurrent use.
OnVectorIndexError func(agentID, factID string, err error)
// VectorReconcileInterval controls how often the background reconciler
// drains the pending-vector queue. 0 disables the background loop entirely
// (Open() still runs one drain at startup).
VectorReconcileInterval time.Duration
// OnRecall, if non-nil, is called after each Recall with timing and count.
OnRecall func(agentID, query string, resultCount int, duration time.Duration)
// OnPut, if non-nil, is called after each successful Put.
OnPut func(agentID, factID string, duration time.Duration)
// Logger receives structured log events. Uses log.Default() if nil.
Logger interface {
Printf(format string, v ...any)
}
}
StoreConfig is passed to Open to configure the Store.
type VectorResult ¶ added in v0.2.0
VectorResult is a single result from a vector similarity query.
type VectorStore ¶ added in v0.2.0
type VectorStore interface {
// AddDocument upserts a document with its pre-computed embedding.
AddDocument(ctx context.Context, collection, id, content string, embedding []float32, metadata map[string]string) error
// Query returns at most n documents ranked by cosine similarity to embedding.
Query(ctx context.Context, collection string, embedding []float32, n int) ([]VectorResult, error)
// EnsureCollection creates the collection if it does not exist.
EnsureCollection(collection string) error
// Close flushes and releases any resources held by the store.
Close() error
}
VectorStore is the pluggable vector search backend. The default implementation wraps chromem-go (zero-infra, pure-Go, persistent). Future implementations can wrap Qdrant, Weaviate, pgvector, etc.
Implementations must be safe for concurrent use.