Skip to main content

Persistence substrate for the Cogno cognitive pipeline — memory store, knowledge graph, conversation buffer, and sleep-time consolidation (hypnos)

Project description

cogno-engram

Persistence substrate for the Cogno cognitive pipeline — memory store, knowledge graph, conversation buffer, and sleep-time consolidation.

cogno-engram is the memory to cogno-anima's mind. Where cogno-anima is pure, infrastructure-agnostic cognition (no I/O), cogno-engram is the opinionated substrate that remembers: it persists conversation turns, consolidates them into long-term semantic memories, and threads them into a relational knowledge graph.

Status: alpha — the contract (ports + types) and the zero-dependency in-memory adapter are in place. The Postgres/Redis reference adapters and the LLM-driven consolidation tiers are in build-out.

Philosophy: ports, not a universal store

A single abstraction over relational + key-value + graph collapses to a lowest-common-denominator that throws away vector search and graph traversal. Instead, cogno-engram defines three capability-scoped ports, each backed by the storage engine that fits it:

Port Shape Reference adapter
MemoryStore sessions / turns / memories + hybrid retrieval + per-turn traces Postgres + pgvector
ConversationBuffer sliding short-term window (+ TTL) Redis
KnowledgeGraph typed nodes + directed edges + multi-hop walk Postgres (recursive CTE)

Vector search is an optional capability (SupportsVectorSearch) — a store without it degrades retrieval to lexical/chronological instead of breaking.

Decoupled by an opaque scope

Every row is isolated by an opaque scope string. cogno-engram never interprets it — the host composes it (e.g. "tenant/phone") and owns its meaning and any cross-scope aggregation. There is no tenant_id/phone_id in the schema; the substrate is reusable for any domain.

from cogno_engram import InMemoryStore, MemoryRecord, RetrievalQuery

store = InMemoryStore()
session = await store.create_session(scope="acme/phone1")
await store.save_memory(MemoryRecord("acme/phone1", "preference", "likes oat milk", embedding=[...]))

hits = await store.load_memories(
    "acme/phone1",
    query=RetrievalQuery(text="what milk?", embedding=[...]),   # hybrid: vector + lexical + feedback
)

hypnos — sleep-time consolidation (3-tier)

Named for the god of sleep: consolidation runs while a session "sleeps". As everywhere in Cogno, engram provides the steps, the host runs the loop — there is no daemon here.

  • Tier 1 — micro_consolidate — synchronous, per-turn, LLM-free (goal transitions, sentiment spikes, PII leaks, new-domain interest).
  • Tier 2 — periodic_consolidate — async, every N turns, LLM extraction (+ KG relations).
  • Tier 3 — consolidate_session — async, on session close/idle, holistic LLM pass (+ feedback-driven KG pruning).

Install

pip install cogno-engram                 # core: ports + in-memory adapter (zero deps)
pip install "cogno-engram[postgres]"     # Postgres + pgvector adapter
pip install "cogno-engram[redis]"        # Redis buffer adapter

The Tier-2/3 consolidation drives an LLM through a cogno-anima LLMBackend (host-injected).

Postgres + pgvector adapter

The reference adapter implements MemoryStore (hybrid retrieval = 0.60·vector + 0.40·BM25 + 0.05·feedback) and KnowledgeGraph (recursive-CTE multi-hop walk) over one database. Call ensure_schema once for the idempotent DDL (tables + indexes; no alembic required — re-running it additively creates any new table via CREATE TABLE IF NOT EXISTS):

The high-volume tables (turns, memories, turn_traces) opt into HASH(scope) partitioning. turn_traces is a dedicated table holding one opaque JSONB trace per turn (save_turn_trace / traces_for_session) — the host composes it (e.g. the pipeline's NER/EGO signals for an audit view); engram never interprets it.

import psycopg
from cogno_engram.adapters.postgres import PostgresStore, ensure_schema

async with await psycopg.AsyncConnection.connect(dsn, autocommit=True) as conn:
    await ensure_schema(conn)                 # CREATE TABLE/INDEX IF NOT EXISTS

store = PostgresStore(dsn=dsn, mask_pii=True)
hits = await store.load_memories("acme/phone1", query=RetrievalQuery(text="...", embedding=[...]))

For scale, opt the high-volume tables into HASH(scope) partitioning (the generic equivalent of the parent's LIST(tenant), with zero DDL per new scope):

await ensure_schema(conn, partition_by_scope=True, partitions=8)

Maintenance (sleep-time upkeep)

Like hypnos, the host schedules; engram does the work — keeping the substrate bounded and consistent over time:

from cogno_engram import maintenance

await maintenance.prune_memories(store, scope, older_than=timedelta(days=180), max_confidence=0.75)
await maintenance.reembed_memories(store, embedder, scope)      # after an embedding-model change
await maintenance.prune_orphan_nodes(kg, scope)                 # drop edgeless graph nodes

Reranking

load_memories returns relevance-ordered candidates; rerank refines them with a two-pass pipeline before you inject the top-k:

from cogno_engram import rerank, RerankConfig

candidates = await store.load_memories("acme/phone1", query=q, limit=20)
top = rerank(candidates, query_text=q.text, top_k=5)   # sim + recency-decay + category boost

Pass 1 is pure (sim·0.60 + recency·0.25 + category·0.15, half-life and boosts configurable via RerankConfig). Pass 2 is an optional host-injected cross-encoder callable (query, [content]) -> [score] — so cogno-engram ships no heavy ML dependency.

EngramBench

A self-contained quality harness (no DB, no model — deterministic) over the in-memory adapter, scoring the substrate's three jobs:

python3 cognobench.py                 # 5 deterministic dims: retrieval/buffer/consolidation/graph/lifecycle
python3 cognobench.py --only graph
python3 cognobench.py --min-score 100 # CI gate
# opt-in, model-dependent: hypnos Tier-2 extraction quality vs a real Ollama model
python3 cognobench.py --only llm_consolidation
# opt-in: the FULL edge-capture path (Tier-2 relation extraction → graph at kg_scope)
python3 cognobench.py --only graph_capture --model mistral:latest
# visualize every graph the bench built/captured as one self-contained HTML
python3 cognobench.py --only graph graph_capture --graph-html graphs.html

Dimensions: retrieval (hit@1, vector + BM25-only), buffer (sliding-window retention), consolidation (Tier-1 micro), graph (multi-hop walk), lifecycle (end-to-end: turns → Tier-1 → retrieval+rerank), and the opt-in llm_consolidation (Tier-2 memory quality against Ollama) and graph_capture (Tier-2 relation extraction against Ollama: hard invariants — no dangling edges, valid confidence, session-tagged, graph rows only at kg_scope — plus soft entity-connectivity checks). Case distributions are modelled on the parent's real data (goal-heavy memories, BM25-dominant retrieval, NEEDS/PREFERS graph) — all synthetic.

The Cogno ecosystem

cogno-engram is one organ of Cogno — a family of small, composable, Apache-2.0 libraries that together form a complete conversational-agent platform. Each library owns a single concern and stays infra-agnostic; a host assembles them into a running agent:

The Cogno ecosystem

The open-source libraries are the organs; the host is the body that joins them. Our reference host — cogno-host, with its cogno-ui dashboard — is the private product layer, but it holds no special powers: everything it does rides on the public seams documented in each library's docs/HOST_INTEGRATION.md, so you can assemble a body of your own.

Testing

pip install -e ".[dev]"
python3 -m pytest -q                   # unit + bench-smoke (Postgres tests auto-skip)

# Run the integration suites against real services:
docker run -d --rm --name engram-pg -e POSTGRES_PASSWORD=postgres \
    -p 55432:5432 pgvector/pgvector:pg16
docker run -d --rm --name engram-redis -p 56379:6379 redis:7-alpine
ENGRAM_TEST_DSN=postgresql://postgres:postgres@localhost:55432/postgres \
ENGRAM_TEST_REDIS_URL=redis://localhost:56379/0 \
    python3 -m pytest tests/test_postgres_integration.py tests/test_redis_integration.py -q

What lives in the host (not here)

Business identity (tenants/identities), billing/token ledgers, persona/domain schemas, feedback capture (emoji → ±1), persona switching, OTP/rate-limiting, and the consolidation worker loop. cogno-engram only knows scope, sessions/turns/memories, the graph, and the buffer.

License

Apache-2.0 © Sudoers AI

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cogno_engram-0.1.0.tar.gz (59.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cogno_engram-0.1.0-py3-none-any.whl (42.5 kB view details)

Uploaded Python 3

File details

Details for the file cogno_engram-0.1.0.tar.gz.

File metadata

  • Download URL: cogno_engram-0.1.0.tar.gz
  • Upload date:
  • Size: 59.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for cogno_engram-0.1.0.tar.gz
Algorithm Hash digest
SHA256 349ac78aae7ffe2c66510501bb6cb2bebb4798b58aefb3a0455d0d913a9bfa76
MD5 e5a4ee7e4a96d42466151b6d39b86468
BLAKE2b-256 5556c89272ae00d6698aea134f4ff9226d9a078db8101870207967122c2aef0c

See more details on using hashes here.

File details

Details for the file cogno_engram-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: cogno_engram-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 42.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for cogno_engram-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ae2ee589852a5d8f00f80491a146ae3a1b1ecd1288be2f4d99758c8b23bc8442
MD5 55831da016b09674862ca782bd848c35
BLAKE2b-256 a3de236c1fad76eb6fe3614e79ebf132d4af1d503cf36ec9ac7eadb324809c47

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page