Nous.Memory (nous v0.17.1)

Copy Markdown View Source

Top-level module for the Nous Memory System.

Provides persistent memory for agents with hybrid text + vector search, temporal decay, importance weighting, and flexible scoping.

Quick Start

# Minimal setup (ETS store, keyword-only search)
agent = Agent.new("openai:gpt-4",
  plugins: [Nous.Plugins.Memory],
  deps: %{memory_config: %{store: Nous.Memory.Store.ETS}}
)

Architecture

Three layers, all plain modules and structs (no GenServer):

  • Data LayerEntry (struct), Store (behaviour + backends)
  • Search LayerSearch (orchestrator), Scoring (RRF, decay)
  • IntegrationPlugins.Memory (plugin), Memory.Tools (agent tools)

Store Backends

BackendText searchVector searchDeps
Store.ETSJaro distanceNoneNone
Store.SQLiteFTS5 (BM25)Cosine similarity, computed in Elixir over every stored embeddingexqlite
Store.DuckDBILIKE (the fts extension is loaded best-effort)list_cosine_similarity in SQLduckdbex

No shipped backend does indexed (ANN) vector search — both vector paths above are full scans over the entries that have an embedding. That is usually the right trade at the corpus sizes agent memory reaches, but it is a scan, and it is worth knowing before you point one at a million rows.

Need something else — Tantivy, HNSW, a vector database, your own search cluster? Nous.Memory.Store is a documented extension point: implement the behaviour in your own application, pass the module as :store, and every consumer treats it like a built-in. See that module for the contract, Nous.Memory.Store.Results for the shared retrieval tail, and Nous.Memory.Store.Conformance for the contract suite Nous runs against its own backends.

Embedding Providers

ProviderDescriptionDeps
Embedding.BumblebeeLocal on-device (Qwen 0.6B)bumblebee, exla
Embedding.OpenAIOpenAI text-embedding-3-smallNone (uses Req)
Embedding.LocalOllama / vLLM / LMStudioNone (uses Req)

No embedding configured = keyword-only search. The system never fails if no embedding provider is set.

Summary

Functions

Search memories directly (bypassing agent tools).

Store a memory entry directly (bypassing agent tools).

Validate a memory configuration map.

Functions

search(store_mod, store_state, query, embedding_provider \\ nil, opts \\ [])

@spec search(module(), term(), String.t(), module() | nil, keyword()) ::
  {:ok, [{Nous.Memory.Entry.t(), float()}]}

Search memories directly (bypassing agent tools).

Examples

{:ok, results} = Nous.Memory.search(Nous.Memory.Store.ETS, store_state, "dark mode")

store(store_mod, store_state, entry)

@spec store(module(), term(), Nous.Memory.Entry.t()) ::
  {:ok, term()} | {:error, term()}

Store a memory entry directly (bypassing agent tools).

Examples

{:ok, store_state} = Nous.Memory.Store.ETS.init([])
entry = Nous.Memory.Entry.new(%{content: "User likes dark mode"})
{:ok, store_state} = Nous.Memory.store(Nous.Memory.Store.ETS, store_state, entry)

validate_config(config)

@spec validate_config(map()) :: {:ok, map()} | {:error, String.t()}

Validate a memory configuration map.

Returns {:ok, config} with defaults applied, or {:error, reason}.