jeevesagent.memory¶
Memory backends.
The simplest way to pick a backend is to pass a string or URL to
Agent(memory=...):
Agent(..., memory="inmemory") # default; lost on restart
Agent(..., memory="sqlite:./bot.db") # persistent, no infra
Agent(..., memory="chroma:./vectors") # local Chroma
Agent(..., memory="postgres://...") # Postgres + pgvector
Agent(..., memory="redis://...") # Redis (+ RediSearch)
The resolve_memory() resolver handles the string parsing; it
also accepts a config dict ({"backend": "chroma", ...}) and
already-constructed Memory instances pass through unchanged.
Backends explicitly:
InMemoryMemory— dict-backed, no embeddings. Default.SqliteMemory— single sqlite file. Persistent, no server.VectorMemory— in-process with cosine recall. No persistence.ChromaMemory— Chroma client (local persistent or in-process).PostgresMemory— Postgres + pgvector + HNSW index.RedisMemory— Redis (+ optional RediSearch HNSW vector index).
Embedders in jeevesagent.memory.embedder:
HashEmbedder— deterministic, zero-key, fine for dev / tests.OpenAIEmbedder/VoyageEmbedder/CohereEmbedder— real semantic embeddings.
Submodules¶
- jeevesagent.memory.auto_extract
- jeevesagent.memory.chroma
- jeevesagent.memory.chroma_facts
- jeevesagent.memory.consolidator
- jeevesagent.memory.embedder
- jeevesagent.memory.facts
- jeevesagent.memory.inmemory
- jeevesagent.memory.lazy
- jeevesagent.memory.postgres
- jeevesagent.memory.postgres_facts
- jeevesagent.memory.redis
- jeevesagent.memory.redis_facts
- jeevesagent.memory.resolver
- jeevesagent.memory.sqlite
- jeevesagent.memory.sqlite_facts
- jeevesagent.memory.vector
- jeevesagent.memory.worker
Classes¶
Wraps a |
|
Bi-temporal fact store backed by a Chroma collection. |
|
Memory backed by |
|
Embeddings via Cohere's |
|
Periodic consolidator for any |
|
Wraps a |
|
Storage surface for bi-temporal facts. |
|
Deterministic SHA256-seeded unit vectors. |
|
Dict-backed bi-temporal fact store. |
|
Dict-backed implementation of |
|
Defer construction of an async-built |
|
Embeddings via OpenAI's |
|
Postgres-backed bi-temporal fact store. |
|
Postgres-backed |
|
Bi-temporal fact store over plain Redis hashes. |
|
Redis-backed |
|
Durable bi-temporal fact store rooted at a sqlite file. |
|
Durable |
|
Pure-Python embedding-backed |
|
Embeddings via Voyage AI's |
Functions¶
|
Resolve a |
Package Contents¶
- class jeevesagent.memory.AutoExtractMemory(inner: jeevesagent.core.protocols.Memory, consolidator: jeevesagent.memory.consolidator.Consolidator, *, on_extract_error: collections.abc.Callable[[BaseException], collections.abc.Awaitable[None]] | None = None, telemetry: jeevesagent.core.protocols.Telemetry | None = None, auto_picked: bool = False)[source]¶
Wraps a
Memoryand runs auto fact extraction on everyremembercall.Construct via the
Agentauto_extract=kwarg; this class isn’t normally instantiated by user code. The wrapped memory must expose a.factsattribute (aFactStore) for extraction to do anything — wheninner.facts is None, the wrapper still installs cleanly but every extraction is a no-op.- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
Persist the episode, then run auto-extraction.
The episode write happens first and is the contract — the function returns its id even when extraction fails. So the consolidator’s fragility never leaks into the agent’s own durability guarantees.
- async session_messages(session_id: str, *, user_id: str | None = None, limit: int = 20) list[jeevesagent.core.types.Message][source]¶
- property facts: Any¶
Forward the inner backend’s fact store. Reading this gives callers the same access to the bi-temporal store the consolidator writes into.
- property inner: jeevesagent.core.protocols.Memory¶
The wrapped backend. Power-user introspection — most call sites just use the protocol methods.
- class jeevesagent.memory.ChromaFactStore(client: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None, collection_name: str = DEFAULT_FACTS_COLLECTION)[source]¶
Bi-temporal fact store backed by a Chroma collection.
- async all_facts() list[jeevesagent.core.types.Fact][source]¶
- async append(fact: jeevesagent.core.types.Fact) str[source]¶
- classmethod ephemeral(*, embedder: jeevesagent.core.protocols.Embedder | None = None, collection_name: str = DEFAULT_FACTS_COLLECTION) ChromaFactStore[source]¶
- classmethod local(persist_directory: str, *, embedder: jeevesagent.core.protocols.Embedder | None = None, collection_name: str = DEFAULT_FACTS_COLLECTION) ChromaFactStore[source]¶
- async query(*, subject: str | None = None, predicate: str | None = None, object_: str | None = None, valid_at: datetime.datetime | None = None, limit: int = 10, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async recall_text(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- property embedder: jeevesagent.core.protocols.Embedder¶
- class jeevesagent.memory.ChromaMemory(client: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None, collection_name: str = DEFAULT_COLLECTION, fact_store: Any | None = None)[source]¶
Memory backed by
chromadb.Construct via
local()for an on-disk persistent client orephemeral()for a process-local in-memory client.- classmethod ephemeral(*, embedder: jeevesagent.core.protocols.Embedder | None = None, collection_name: str = DEFAULT_COLLECTION, with_facts: bool = False, facts_collection_name: str = 'jeeves_facts') ChromaMemory[source]¶
In-memory client (lost on process exit). Great for tests.
- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- classmethod local(persist_directory: str, *, embedder: jeevesagent.core.protocols.Embedder | None = None, collection_name: str = DEFAULT_COLLECTION, with_facts: bool = False, facts_collection_name: str = 'jeeves_facts') ChromaMemory[source]¶
Persistent on-disk client at
persist_directory.with_facts=Trueattaches aChromaFactStorerooted at the same client so facts persist alongside episodes in the same on-disk store.
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- class jeevesagent.memory.CohereEmbedder(model: str = 'embed-english-v3.0', *, client: Any | None = None, api_key: str | None = None, input_type: str = 'search_document')[source]¶
Embeddings via Cohere’s
cohereSDK.Models and dimensions:
embed-english-v3.0/embed-multilingual-v3.0-> 1024embed-english-light-v3.0/embed-multilingual-light-v3.0-> 384
input_typeis required by Cohere v3 models:"search_document"(default) — corpus / fact-store entries"search_query"— retrieval queries"classification"/"clustering"for non-retrieval uses
- class jeevesagent.memory.ConsolidationWorker(memory: jeevesagent.core.protocols.Memory, *, interval_seconds: float = 60.0, on_consolidated: OnConsolidatedCb | None = None, on_error: OnErrorCb | None = None)[source]¶
Periodic consolidator for any
Memorybackend.- async run_forever() None[source]¶
Sleep
interval_secondsthen consolidate. Repeat until cancelled.Spawn this in an
anyio.create_task_group()— the cancel scope at scope exit terminates the worker cooperatively.
- async run_once() int[source]¶
Run a single consolidation pass. Returns the number of new facts extracted (
0when no fact store / nothing changed).Errors in
memory.consolidate()are routed toon_errorand not re-raised, so callers can use this in a polling loop without wrapping it in their own try/except.
- class jeevesagent.memory.Consolidator(*, model: jeevesagent.core.protocols.Model, system_prompt: str = DEFAULT_SYSTEM_PROMPT, max_facts_per_episode: int = 20)[source]¶
Wraps a
Modelto extractFactrows from episodes.- async consolidate(episodes: collections.abc.Iterable[jeevesagent.core.types.Episode], *, store: jeevesagent.memory.facts.FactStore) list[jeevesagent.core.types.Fact][source]¶
Process
episodes; append extracted facts tostore; return the newFactinstances in extraction order.Uses
store.append_manywhen available so the underlying store can batch the embedder calls (oneembed_batchAPI round-trip instead of N individualembedcalls). Falls back to per-factappendfor stores that haven’t implementedappend_many.
- class jeevesagent.memory.FactStore[source]¶
Bases:
ProtocolStorage surface for bi-temporal facts.
- async all_facts() list[jeevesagent.core.types.Fact][source]¶
- async append(fact: jeevesagent.core.types.Fact) str[source]¶
- async query(*, subject: str | None = None, predicate: str | None = None, object_: str | None = None, valid_at: datetime.datetime | None = None, limit: int = 10, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async recall_text(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- class jeevesagent.memory.HashEmbedder(dimensions: int = DEFAULT_HASH_DIMENSIONS)[source]¶
Deterministic SHA256-seeded unit vectors.
Each text gets a fresh
random.Randomseeded by the SHA256 of its UTF-8 bytes, then samplesdimensionsGaussian values and L2-normalises the result. Same text always produces the same vector; different texts produce well-distributed vectors with cosine distances that correlate with literal text equality (not semantic similarity).Use this in tests (fast, no network) and as a default for in-memory backends that need some vector but don’t need real semantic recall.
- class jeevesagent.memory.InMemoryFactStore(*, embedder: jeevesagent.core.protocols.Embedder | None = None)[source]¶
Dict-backed bi-temporal fact store.
All operations are coordinated by an
anyio.Lockso concurrent appends from the consolidator and reads from the agent loop don’t tear the index.When an
embedderis supplied, every appended fact’s triple ("subject predicate object") is embedded and stored alongside the fact, andrecall_text()ranks by cosine similarity against the query’s embedding. When no embedder is given,recall_text()falls back to token-overlap matching.- async all_facts() list[jeevesagent.core.types.Fact][source]¶
- async append(fact: jeevesagent.core.types.Fact) str[source]¶
Append a fact, invalidating any superseded predecessors.
Supersession rule: any existing fact with matching subject + predicate, currently valid (
valid_until is None), and a differentobjectgets itsvalid_untilset to the new fact’svalid_from.
- async append_many(facts: collections.abc.Iterable[jeevesagent.core.types.Fact]) list[str][source]¶
Append a batch of facts. Embedder calls are coalesced via
Embedder.embed_batch()when an embedder is configured — one network round-trip for the batch instead of N.
- async query(*, subject: str | None = None, predicate: str | None = None, object_: str | None = None, valid_at: datetime.datetime | None = None, limit: int = 10, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async recall_text(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
Rank facts against
query.With an embedder configured: cosine-similarity over the query’s embedding vs each fact triple’s stored embedding. Without one: token-overlap with a small stop-word list (longer overlaps win, ties break by shorter haystack = more specific match).
user_idpartitions the candidate set as a hard namespace boundary — seeFactfor semantics.
- snapshot() dict[str, jeevesagent.core.types.Fact][source]¶
- property embedder: jeevesagent.core.protocols.Embedder | None¶
- class jeevesagent.memory.InMemoryMemory(*, consolidator: jeevesagent.memory.consolidator.Consolidator | None = None, fact_store: jeevesagent.memory.facts.FactStore | None = None, max_users: int | None = _DEFAULT_MAX_USERS, user_idle_ttl_seconds: float | None = _DEFAULT_USER_TTL_SECONDS)[source]¶
Dict-backed implementation of
Memory.Multi-tenant accounting (M10): per-user working-block state is held in a bounded LRU + TTL container so a runaway tenant or one-shot user_id explosion can’t grow the in-process dict without limit. Defaults:
max_users=100_000anduser_idle_ttl_seconds=86_400(24h). PassNoneto disable bounding for single-tenant or fixed-tenant deployments. Eviction drops a user’s working blocks; callers needing durable spill-to-disk should useSqliteMemoryor a SQL-backed memory instead.- async consolidate() None[source]¶
Process unconsolidated episodes through the configured
Consolidator, appending facts toself.facts.
- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- async session_messages(session_id: str, *, user_id: str | None = None, limit: int = 20) list[jeevesagent.core.types.Message][source]¶
Return user/assistant pairs from prior runs of this session.
Materialises each persisted
Episodefor the givensession_id(within theuser_idpartition) into a[USER input, ASSISTANT output]pair, ordered oldest-first and capped atlimitturns total — i.e. up tolimit / 2Q/A exchanges. Tool-call traces are not replayed; the final assistant text per turn is sufficient context for follow-ups.
- class jeevesagent.memory.LazyMemory(builder: collections.abc.Callable[[], collections.abc.Awaitable[Any]], *, description: str = 'memory')[source]¶
Defer construction of an async-built
Memoryuntil first use.Users rarely instantiate this directly — it’s what the
_resolve_memory()resolver returns when given apostgres://orredis://URL. Pass a zero-arg async callable that builds the real backend; everything else (working / remember / recall / facts / session_messages / consolidate) is forwarded once that callable resolves.- async aclose() None[source]¶
Close the inner backend if it was constructed.
Safe to call when the backend was never resolved (no-op).
- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- async session_messages(session_id: str, *, user_id: str | None = None, limit: int = 20) list[jeevesagent.core.types.Message][source]¶
- property description: str¶
Human-readable label (e.g.
"postgres://prod-db/agent") — used in error messages so users can tell which Memory failed to connect.
- property facts: Any | None¶
Direct access to the inner backend’s fact store (if any).
Reading this BEFORE the backend has connected returns
None— the connection deliberately hasn’t happened yet. Once the backend is resolved (after the firstagent.runor an explicitawait mem._resolve()), this returns the liveFactStore. Power-user escape hatch; most callers go throughrecall_facts().
- class jeevesagent.memory.OpenAIEmbedder(model: str = 'text-embedding-3-small', *, dimensions: int | None = None, client: Any | None = None, api_key: str | None = None)[source]¶
Embeddings via OpenAI’s
embeddings.createAPI.Dimensions are fixed by the model:
text-embedding-3-small-> 1536text-embedding-3-large-> 3072text-embedding-ada-002-> 1536
Pass
dimensions=only fortext-embedding-3-*models, which support thedimensionsparameter for projection.
- class jeevesagent.memory.PostgresFactStore(pool: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None)[source]¶
Postgres-backed bi-temporal fact store.
- async all_facts() list[jeevesagent.core.types.Fact][source]¶
- async append(fact: jeevesagent.core.types.Fact) str[source]¶
- async append_many(facts: collections.abc.Iterable[jeevesagent.core.types.Fact]) list[str][source]¶
- classmethod connect(dsn: str, *, embedder: jeevesagent.core.protocols.Embedder | None = None, min_size: int = 1, max_size: int = 10) PostgresFactStore[source]¶
- Async:
- async query(*, subject: str | None = None, predicate: str | None = None, object_: str | None = None, valid_at: datetime.datetime | None = None, limit: int = 10, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async recall_text(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- schema_sql() list[str][source]¶
Return the DDL for this fact store’s schema.
Exposed so tests can assert on the SQL strings, and so migration scripts can apply the schema in their own transaction.
- property embedder: jeevesagent.core.protocols.Embedder | None¶
- class jeevesagent.memory.PostgresMemory(pool: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None, namespace: str = DEFAULT_NAMESPACE, fact_store: Any | None = None)[source]¶
Postgres-backed
Memory.poolis anasyncpg.Pool(or anything with the same API). Tests can pass a fake pool whoseacquire()returns a fake connection.- classmethod connect(dsn: str, *, embedder: jeevesagent.core.protocols.Embedder | None = None, namespace: str = DEFAULT_NAMESPACE, min_size: int = 1, max_size: int = 10, with_facts: bool = False) PostgresMemory[source]¶
- Async:
Open an asyncpg pool and register the pgvector codec.
When
with_facts=TrueaPostgresFactStorerooted at the same pool is attached asself.factsso the agent loop’s memory.facts integration just works.
- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async init_schema() None[source]¶
Apply
schema_sql()against the connected pool.When a
PostgresFactStoreis attached asself.facts, its schema is initialised in the same call.
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- schema_sql() list[str][source]¶
Return the DDL needed to bootstrap this backend’s schema.
Exposed so tests can assert on the SQL without running it; also usable from migration scripts that want to apply the schema in their own transaction.
- class jeevesagent.memory.RedisFactStore(client: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None, key_prefix: str = DEFAULT_KEY_PREFIX)[source]¶
Bi-temporal fact store over plain Redis hashes.
- async all_facts() list[jeevesagent.core.types.Fact][source]¶
- async append(fact: jeevesagent.core.types.Fact) str[source]¶
- classmethod connect(url: str = 'redis://localhost:6379/0', *, embedder: jeevesagent.core.protocols.Embedder | None = None, key_prefix: str = DEFAULT_KEY_PREFIX) RedisFactStore[source]¶
- Async:
- async query(*, subject: str | None = None, predicate: str | None = None, object_: str | None = None, valid_at: datetime.datetime | None = None, limit: int = 10, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async recall_text(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- property embedder: jeevesagent.core.protocols.Embedder¶
- class jeevesagent.memory.RedisMemory(client: Any, *, embedder: jeevesagent.core.protocols.Embedder | None = None, key_prefix: str = DEFAULT_KEY_PREFIX, index_name: str = DEFAULT_INDEX_NAME, use_vector_index: bool = True, fact_store: Any | None = None)[source]¶
Redis-backed
Memory. Useconnect()to construct.- classmethod connect(url: str = 'redis://localhost:6379/0', *, embedder: jeevesagent.core.protocols.Embedder | None = None, key_prefix: str = DEFAULT_KEY_PREFIX, index_name: str = DEFAULT_INDEX_NAME, use_vector_index: bool = True, with_facts: bool = False, fact_key_prefix: str = 'jeeves:fact:') RedisMemory[source]¶
- Async:
Open an async Redis connection.
with_facts=Trueattaches aRedisFactStoresharing the same client; facts go to{fact_key_prefix}*keys so they don’t collide with episode keys.
- async ensure_index() None[source]¶
Create the RediSearch HNSW index, if not already present.
Skipped silently when
use_vector_index=Falseor when RediSearch isn’t available on the server.
- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- class jeevesagent.memory.SqliteFactStore(path: str | pathlib.Path, *, embedder: jeevesagent.core.protocols.Embedder | None = None)[source]¶
Durable bi-temporal fact store rooted at a sqlite file.
- async all_facts() list[jeevesagent.core.types.Fact][source]¶
- async append(fact: jeevesagent.core.types.Fact) str[source]¶
Append a fact, invalidating any superseded predecessors.
Same supersession rule as
InMemoryFactStore: if there’s an existing currently-valid fact with matching subject + predicate but different object, set itsvalid_untilto the new fact’svalid_from.
- async query(*, subject: str | None = None, predicate: str | None = None, object_: str | None = None, valid_at: datetime.datetime | None = None, limit: int = 10, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async recall_text(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- property embedder: jeevesagent.core.protocols.Embedder | None¶
- property path: pathlib.Path¶
- class jeevesagent.memory.SqliteMemory(path: str | pathlib.Path, *, embedder: jeevesagent.core.protocols.Embedder | None = None, with_facts: bool = True, fact_store: jeevesagent.memory.facts.FactStore | None = None)[source]¶
Durable
Memoryrooted at a single sqlite file.Construct directly from a path:
memory = SqliteMemory("./bot.db") agent = Agent("...", model="gpt-4.1-mini", memory=memory)
Or via the resolver:
agent = Agent("...", model="gpt-4.1-mini", memory="sqlite:./bot.db")
Pass
path=":memory:"for an ephemeral in-process database (lost on close — useful for tests).The fact store is auto-attached: the same
.dbfile holds afactstable managed bySqliteFactStore. Passwith_facts=Falseto skip it; pass an explicitfact_store=to override (e.g. point facts at a different sqlite file).- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- async session_messages(session_id: str, *, user_id: str | None = None, limit: int = 20) list[jeevesagent.core.types.Message][source]¶
- property embedder: jeevesagent.core.protocols.Embedder¶
- property path: pathlib.Path¶
- class jeevesagent.memory.VectorMemory(*, embedder: jeevesagent.core.protocols.Embedder | None = None, max_episodes: int | None = None, consolidator: jeevesagent.memory.consolidator.Consolidator | None = None, fact_store: jeevesagent.memory.facts.FactStore | None = None)[source]¶
Pure-Python embedding-backed
Memory.- async consolidate() None[source]¶
Process unconsolidated episodes through the configured
Consolidator, appending facts toself.facts.No-op when no consolidator is configured.
- async export(*, user_id: str | None = None) jeevesagent.core.types.MemoryExport[source]¶
- async forget(*, user_id: str | None = None, session_id: str | None = None, before: datetime.datetime | None = None) int[source]¶
- async profile(*, user_id: str | None = None) jeevesagent.core.types.MemoryProfile[source]¶
- async recall(query: str, *, kind: str = 'episodic', limit: int = 5, time_range: tuple[datetime.datetime, datetime.datetime] | None = None, user_id: str | None = None) list[jeevesagent.core.types.Episode][source]¶
- async recall_facts(query: str, *, limit: int = 5, valid_at: datetime.datetime | None = None, user_id: str | None = None) list[jeevesagent.core.types.Fact][source]¶
- async remember(episode: jeevesagent.core.types.Episode) str[source]¶
- async session_messages(session_id: str, *, user_id: str | None = None, limit: int = 20) list[jeevesagent.core.types.Message][source]¶
- property embedder: jeevesagent.core.protocols.Embedder¶
- class jeevesagent.memory.VoyageEmbedder(model: str = 'voyage-3', *, client: Any | None = None, api_key: str | None = None, input_type: str = 'document')[source]¶
Embeddings via Voyage AI’s
voyageaiSDK.Models and dimensions:
voyage-3/voyage-3-large/voyage-code-3-> 1024voyage-3-lite-> 512
input_typecontrols how Voyage encodes the text:"document"(default) — for corpus / fact-store entries"query"— for retrieval queries
Pass an explicit
input_type=if your embedder is dedicated to one role; for the agent loop’s mixed use (we embed both stored triples and recall queries through the same embedder), the"document"default is the safer choice.
- jeevesagent.memory.resolve_memory(spec: Any) jeevesagent.core.protocols.Memory[source]¶
Resolve a
memory=argument into a concreteMemory.Nonereturns the default in-memory backend; a string parses by URL scheme; a dict parses bybackendkey; anything else is assumed to already be aMemoryand passed through unchanged.