Skip to content

aimu.memory

Semantic facts, path-based documents, and a shared abstract base.

aimu.memory.MemoryStore

Bases: ABC

Abstract interface for memory store implementations.

All implementations must support storing, searching, deleting, and listing content. Concrete subclasses add implementation-specific methods on top of this baseline.

store abstractmethod

store(content: str) -> None

Store a string in the memory store.

search abstractmethod

search(query: str, n_results: int = 10) -> list[str]

Return up to n_results strings relevant to query.

Concrete stores may accept additional store-specific keyword arguments (e.g. SemanticMemoryStore.search(..., max_distance=...)); those are not part of this interface, so code typed against MemoryStore should not rely on them.

delete abstractmethod

delete(identifier: str) -> None

Remove content by identifier (path, exact string, or UUID).

list_all abstractmethod

list_all() -> list[str]

Return all stored identifiers or content strings.

aimu.memory.SemanticMemoryStore

SemanticMemoryStore(collection_name: str = 'memories', persist_path: Optional[str] = None, embedding_client: Optional[Any] = None)

Bases: MemoryStore

Persistent store for factual memories backed by ChromaDB.

Memories are natural-language strings in subject-predicate-object form, e.g. "Paul works at Google" or "Sarah is the sister of Emma". ChromaDB embeds each fact so that topic-based retrieval ("work", "family life") finds semantically relevant facts without exact-string matching.

Thread-safe: every public method is serialized on a re-entrant per-instance lock, so one store can be shared across concurrent threads or turns (e.g. an async agent dispatching sync memory tools via asyncio.to_thread).

Parameters:

Name Type Description Default
collection_name str

ChromaDB collection name (default: "memories").

'memories'
persist_path Optional[str]

Directory path for persistent storage. If None, uses an in-memory ephemeral client.

None
embedding_client Optional[Any]

Optional AIMU embedding client (e.g. from aimu.embedding_client("openai:text-embedding-3-small")) to embed facts. When None (default), ChromaDB's built-in default embedding model is used, preserving the original behaviour exactly. A custom embedding model is not persisted in the collection config, so reopen a persistent store with the same embedding_client=.

None

Examples:

>>> store = SemanticMemoryStore()
>>> store.store("Paul works at Google")
>>> store.store("Paul is married to Sarah")
>>> store.store("Sarah is the sister of Emma")
>>> store.search("work")        # ["Paul works at Google"]
>>> store.search("family life") # marriage / sibling facts
>>> client = aimu.embedding_client("openai:text-embedding-3-small")
>>> store = SemanticMemoryStore(embedding_client=client)

store

store(content: str) -> None

Store a fact string in the memory store.

The fact should be a natural-language sentence in subject-predicate-object form, e.g. "Paul works at Google" or "Sarah is the sister of Emma".

Parameters:

Name Type Description Default
content str

The fact string to store.

required

search

search(query: str, n_results: int = 10, max_distance: float | None = None) -> list[str]

Retrieve facts semantically related to a query.

Uses ChromaDB's vector similarity search so broad topics like "work" or "family life" match relevant facts without exact-string matching.

Note: max_distance is specific to this store and is not part of the :class:~aimu.memory.base.MemoryStore interface; code typed against the base MemoryStore (or a DocumentStore, which has no distance notion) cannot pass it. Type the variable as SemanticMemoryStore to use it.

Parameters:

Name Type Description Default
query str

Natural-language query (e.g. "work", "family").

required
n_results int

Maximum number of facts to return.

10
max_distance float | None

Optional cosine-distance cutoff (0 = identical, 2 = maximally dissimilar). Facts with a distance above this threshold are excluded. Typical useful range: 0.3 (tight) – 0.6 (loose). Defaults to None (no cutoff).

None

Returns:

Type Description
list[str]

List of fact strings ordered by relevance.

delete

delete(identifier: str) -> None

Remove all stored facts that exactly match the given string.

Parameters:

Name Type Description Default
identifier str

The exact fact string to remove.

required

list_all

list_all() -> list[str]

Return all stored fact strings.

aimu.memory.DocumentStore

DocumentStore(persist_path: Optional[str] = None)

Bases: MemoryStore

Path-addressed document store backed by the filesystem or an in-memory dict.

Implements the :class:MemoryStore abstract interface so it can be swapped with :class:SemanticMemoryStore in any application, and adds the richer path-based API in the spirit of Anthropic's memory tool (not its interface).

Thread-safe: every public method is serialized on a re-entrant per-instance lock, so the in-memory dict and on-disk files stay consistent when the store is shared across concurrent threads or turns (edit -> read + write stays atomic).

With persist_path set, the directory is the single source of truth: reads, listings, and searches hit the filesystem on each call, so a document copied into the directory by hand shows up without restarting the process. Files that are not UTF-8 text (a PDF, a binary artifact) are not documents; they are skipped, with a warning naming the file, and dot-files are ignored outright.

Parameters:

Name Type Description Default
persist_path Optional[str]

Root directory for persistent storage. If None the store is ephemeral (in-memory only).

None

Examples:

>>> store = DocumentStore()
>>> store.write("/preferences.md", "Use concise responses.")
>>> store.read("/preferences.md")
'Use concise responses.'
>>> store.edit("/preferences.md", "concise", "detailed")
>>> store.search_full_text("detailed")
[{"path": "/preferences.md", "content": "Use detailed responses."}]

write

write(path: str, content: str) -> None

Create or overwrite a document at path.

Parameters:

Name Type Description Default
path str

Memory path, e.g. "/preferences.md".

required
content str

Text content to store (≤ 100 KB recommended).

required

read

read(path: str) -> str

Return the content of the document at path.

Raises:

Type Description
KeyError

If no document exists at path.

edit

edit(path: str, old_str: str, new_str: str) -> None

Replace the one occurrence of old_str with new_str in the document at path.

old_str must appear exactly once. Zero matches and two-or-more matches both raise, and nothing is written either way: replacing the first of several matches answers a question the caller did not ask, and it does so silently, in the file, where the mistake is discovered later by whoever reads it. Include enough surrounding text to make the match unique.

To genuinely intend the first of several, say so where it can be seen::

store.write(path, store.read(path).replace(old_str, new_str, 1))

Parameters:

Name Type Description Default
path str

Memory path of the document to edit.

required
old_str str

Exact substring to find, unique within the document.

required
new_str str

Replacement text.

required

Raises:

Type Description
KeyError

If no document exists at path.

ValueError

If old_str is absent, or appears more than once.

list_paths

list_paths(prefix: Optional[str] = None) -> list[str]

Return all memory paths, optionally filtered by prefix.

Parameters:

Name Type Description Default
prefix Optional[str]

Only return paths that start with this string. Pass None (default) to return all paths.

None

Returns:

Type Description
list[str]

Sorted list of path strings.

search_full_text

search_full_text(query: str, n_results: int = 10) -> list[dict]

Case-insensitive substring search across all document contents.

Parameters:

Name Type Description Default
query str

Search string.

required
n_results int

Maximum number of results to return.

10

Returns:

Type Description
list[dict]

List of {"path": ..., "content": ...} dicts for matching

list[dict]

documents, ordered by path.

unreadable_paths

unreadable_paths() -> list[str]

Return the paths of files in the store's directory that are not readable as text.

These are files someone put in the directory that can never become documents (a PDF, a Word export, a binary artifact). They are excluded from :meth:list_paths and :meth:search_full_text, so this is what lets a caller tell the difference between "you gave me nothing" and "what you gave me is not text" -- the distinction an agent needs in order to say something useful back. Dot-files are not reported: they are not documents anyone placed here.

Rescans the directory; returns [] for an ephemeral store, which has no directory.

Returns:

Type Description
list[str]

Sorted list of memory paths.

store

store(content: str) -> None

Store content at an auto-assigned path (/note-{uuid}.md).

Use :meth:write directly when you need control over the path.

Parameters:

Name Type Description Default
content str

Text content to store.

required

search

search(query: str, n_results: int = 10) -> list[str]

Full-text search; returns a list of matching content strings.

Parameters:

Name Type Description Default
query str

Search string.

required
n_results int

Maximum number of results.

10

Returns:

Type Description
list[str]

List of content strings from matching documents.

delete

delete(identifier: str) -> None

Delete the document at identifier (treated as a memory path).

No-op if the path does not exist.

Parameters:

Name Type Description Default
identifier str

Memory path of the document to remove.

required

list_all

list_all() -> list[str]

Return all memory paths (sorted).