Skip to main content

aegisdb-langgraph — AegisDB as a LangGraph store

Use AegisDB as the long-term memory behind a LangGraph agent.

pip install aegisdb-langgraph
from aegisdb_langgraph import AegisStore

store = AegisStore(host="127.0.0.1", port=9470, namespace="my-agent")

store.put(("users", "42"), "prefs", {"theme": "dark"})
store.get(("users", "42"), "prefs").value        # {"theme": "dark"}
store.search(("users",), query="dark")           # BM25 over stored values
store.list_namespaces()                          # [("users", "42")]

…and inside a graph, the way LangGraph injects it:

graph = builder.compile(store=AegisStore(namespace="my-agent"))

def remember(state, *, store):
    store.put(("users", state["user"]), "last", {"seen": "hello"})

BaseStore funnels get / put / search / delete / list_namespaces through one abstract batch(ops), so that is all this implements — the concrete methods come from the base class and cannot drift from it. aput, aget and friends work too, on a worker thread.

The mapping

LangGraph addresses items by a hierarchical namespace: tuple[str, ...] plus a key, and searches by namespace prefix. AegisDB has a flat agent_id that is an isolation boundary rather than a path, so the hierarchy is carried in tags:

agent_id the store's own namespace= — one tenant, isolated by the server
tags a marker, a hash of (namespace, key), and a hash of every prefix of the namespace
data JSON: {"ns": [...], "key": ..., "value": {...}}

A tag per prefix is what makes a prefix search an index lookup rather than a scan. Tags are hashed because AegisDB caps one at 64 bytes (and 32 per record) while a namespace or key can be longer; the readable copy lives in data, which is also what makes list_namespaces possible.

The digest is length-prefixed per segment, so ("a", "bc") and ("ab", "c") cannot collide — joining on a separator would make them the same string, and two namespaces sharing a tag is a cross-namespace read.

Namespace depth is capped at 29. Marker + key + one tag per prefix has to fit in AegisDB's 32-tag ceiling. Deeper raises ValueError naming the limit, rather than an INVALID_REQUEST that says nothing about namespaces.

Three things it does not do

TTL is refused, not ignored. AegisDB expires only working memory, which is a per-session ring buffer rather than a store, so a TTL here would never fire. Silently never expiring something a caller asked to expire is a retention surprise. Use the server's forget op, which ages records out by importance and recency — and which the LangGraph API has no way to express.

No vector indexing. query= runs the server's BM25 index: no embedding provider needed, and exact tokens (an error string, a flag, an identifier) match well, with the server's relevance score carried through to SearchItem.score. index= is accepted and ignored, because honouring it would mean this package owning an embeddings function. A server started with --no-lexical-index raises a RuntimeError naming that flag when a query was actually passed — a queryless search keeps working, and any other NOT_READY is re-raised untouched rather than blamed on an index it never used.

filter= is applied client-side. AegisDB cannot filter on arbitrary JSON fields, so candidates are pulled back and matched here — using LangGraph's own _compare_values, so the semantics are identical to InMemoryStore rather than a second implementation that drifts. It inherits that function's limits too: $eq, $ne, $gt, $gte, $lt, $lte are supported and $in is not, in both stores alike.

Because filtering happens here, paging does too — asking the server for an offset would skip rows before they were filtered, so page 2 would silently omit matches. An unfiltered search does page on the server, so a deep page stays a small read.

search_scan_limit (default 1000) bounds how many candidates a filtered search pulls back; list_namespaces is bounded the same way, since AegisDB indexes tags but cannot enumerate them. It is clamped to 1000, because the server clamps top_k there and says nothing — a larger value would read as "scans more" while changing nothing.

Past that bound the answer is short and cannot say so. search and list_namespaces return plain lists, with nowhere to put a flag. A store holding more than search_scan_limit items can therefore be missing matches from a filtered search, or namespaces from a listing. Stated here because it cannot be signalled there.

Isolation

namespace= is the AegisDB namespace, enforced by the server. Two stores with different ones cannot see each other's items even though they share a server — so one AegisDB instance can back many agents, and the LangGraph hierarchy lives inside each.

Passing your own client= makes its agent_id authoritative, since that is what the server enforces; giving both and disagreeing raises, rather than reporting one namespace while writing into another.

Concurrency

One store is one connection, and batch holds a lock. The client owns a socket and is not thread-safe, while abatch runs on a worker thread and LangGraph's sync runner executes a superstep's tasks on a pool — so without serialising, two nodes touching the store interleave on the same socket and one reads the other's response. Concurrent nodes therefore queue; for real parallelism, build a store per worker.

Across processes nothing here can help: put is a read-modify-write and AegisDB has no upsert, so two racing writers can leave two records for one key. Reads pick deterministically (lowest id) so the store keeps answering consistently if that happens.

Tests

make langgraph-test        # from the repo root

Every behaviour meant to match the reference implementation is asserted by running the same case against InMemoryStore and comparing — an assertion written from a reading of the contract would only encode that reading. The suite also compiles a real graph with store= and lets LangGraph inject it, which is the part that would break if the class satisfied the ABC but not the runtime's expectations of it.

Download files

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

Source Distribution

aegisdb_langgraph-0.8.1.tar.gz (19.0 kB view details)

Uploaded Source

Built Distribution

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

aegisdb_langgraph-0.8.1-py3-none-any.whl (11.9 kB view details)

Uploaded Python 3

File details

Details for the file aegisdb_langgraph-0.8.1.tar.gz.

File metadata

  • Download URL: aegisdb_langgraph-0.8.1.tar.gz
  • Upload date:
  • Size: 19.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for aegisdb_langgraph-0.8.1.tar.gz
Algorithm Hash digest
SHA256 f9213f03e2b32dc55d63405796cda5d4fb81c7db214c29ad0b124a20cb8297bc
MD5 77cf8e92c29a215bb7e4c382c34cfc2d
BLAKE2b-256 efcc3e65824d80f187249921ff2ca82d2738e44055e887f224bf3ac5f10412be

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisdb_langgraph-0.8.1.tar.gz:

Publisher: pypi.yml on d4n-larsson/aegisdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aegisdb_langgraph-0.8.1-py3-none-any.whl.

File metadata

File hashes

Hashes for aegisdb_langgraph-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 387b1e65a6af508462876609302fcec4362ddb18433cf3376bf25525c3dc4dd2
MD5 7f153e735148662b43c87ec4310c1133
BLAKE2b-256 25f702c9ad5f07fb53a27a1c48a4a1da5b68e4c9fcb5aeeb0c270a202ebf60a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for aegisdb_langgraph-0.8.1-py3-none-any.whl:

Publisher: pypi.yml on d4n-larsson/aegisdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.9.4

2 files

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

0.9.0

2 files

0.8.3

2 files

0.8.2

2 files

This release

0.8.1 This release

2 files

0.8.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page