rath.memory#

Memory backends, store handles, memory operations, typed results, registry helpers, and local/OpenViking adapter boundaries.

OpenRath memory plane

Memory is a runtime plane beside sandbox execution: agents can read and write durable knowledge without coupling memory backends to tool backends.#

Source#

Module

Source

rath.memory.abc

src/rath/memory/abc.py

rath.memory.op_types

src/rath/memory/op_types.py

rath.memory.results

src/rath/memory/results.py

rath.memory.registry

src/rath/memory/registry.py

rath.memory.adapters.local

src/rath/memory/adapters/local.py

rath.memory.adapters.openviking

src/rath/memory/adapters/openviking.py

rath.memory.persistence

src/rath/memory/persistence/

Public contract#

Store lifecycle#

API

Behavior

MemoryBackend.open(spec=None)

Opens a store handle with refcount == 0. Bind it to an agent or enter with store: before holding it.

MemoryStore.acquire() / release()

Adds or drops one reference; final release calls backend.close(store).

MemoryStore.dispatch(op)

Applies a MemoryOp* payload and returns a typed MemoryResult.

MemoryStoreSpec.from_config(name=None)

Reads memory.providers from ~/.openrath/config.json; currently models local store presets.

Operations and results#

Operation

Purpose

Typical result

MemoryOpWrite

Write or replace text at a memory://... URI.

MemoryWriteResult

MemoryOpRead

Read one entry at abstract/overview/detail level.

MemoryReadResult

MemoryOpList / MemoryOpTree

List entries under a URI.

MemoryListResult

MemoryOpFind

Semantic or lexical search.

MemoryFindResult with MemoryHit rows

MemoryOpSearch

Intent-aware search when a backend supports it.

MemoryFindResult

MemoryOpResource

Ingest a file, directory, or URL resource.

Backend-specific result or MemoryExecutionFailure

MemoryOpCommit

Archive a session and extract durable memory.

MemoryCommitResult

Registry#

Function

Behavior

register(name)

Decorator that registers a MemoryBackend class.

list_names()

Returns registered memory backend names.

get(name) / get_class(name)

Returns a backend instance or registered class.

is_available(name)

Checks registration plus backend availability.

preferred(names)

Returns the first available backend instance.

set_default(name) / current()

Sets and gets the default backend. The base install defaults to local.

Built-in adapters#

Backend

Availability

Notes

local

Ships with base openrath.

Persists under .openrath/memory/local/, supports read/write/list/tree, BM25 search, optional embedding search, resources, and session commit.

openviking

Optional openrath[openviking].

Connects to OpenViking and maps public memory:// operations to the backend’s internal URI and extraction APIs.

Agent integration#

flow.Agent(memory=...) accepts a MemoryStore, MemoryStoreSpec, a configured backend/preset string such as "local", or None.

Agent API

Behavior

remember_memory(...)

Writes explicit memory content.

recall_memory(...)

Searches attached memory and returns hits.

commit_memory(session, ...)

Commits a session transcript for archive and extraction.

memory_inject=True

Injects recalled memory into the prompt path.

commit_on_forward=True

Best-effort commit after each agent forward call.

URI boundary#

OpenRath exposes memory://... as the public user-facing URI scheme. Adapter-specific schemes such as OpenViking’s internal viking://... stay inside the adapter and should not appear in portable OpenRath workflows.

Autodoc#

class rath.memory.MemoryBackend[source]#

Abstract base class for memory backends.

Subclasses must:

  1. Set the name class attribute and register via rath.memory.register().

  2. Implement the classmethods is_available, capabilities and supported_ops.

  3. Implement the instance methods store_count, open, close and dispatch.

abstractmethod classmethod is_available() bool[source]#

Return whether this backend is usable in the current environment.

Must be cheap (microseconds, no network, no subprocess). Examples: check that a required SDK is importable, or that a config file or environment variable is present.

abstractmethod classmethod capabilities() MemoryCapabilities[source]#

Return the static capability description of this backend type.

abstractmethod classmethod supported_ops() frozenset[type[MemoryOp]][source]#

Return MemoryOp subclasses this backend handles.

abstractmethod store_count() int[source]#

Return the number of open memory stores managed by this instance.

abstractmethod open(spec: MemoryStoreSpec | None = None) MemoryStore[source]#

Open a fresh memory store and return its handle.

abstractmethod close(store: MemoryStore) None[source]#

Close store and release resources.

Calling close on an already-closed store is a no-op.

abstractmethod dispatch(store: MemoryStore, op: MemoryOp) MemoryResult[source]#

Execute op against store and return its result.

Implementations should raise UnsupportedMemoryOp for op types not in supported_ops().

class rath.memory.MemoryStore(backend: MemoryBackend, handle: str, spec: MemoryStoreSpec | None = None, closed: bool = False, _refcount: int = 0)[source]#

Memory store handle with reference counting.

Lifecycle mirrors BackendSandbox: each Agent slot, each with store: block, and any explicit acquire() counts as one reference. release() decrements and, when the count reaches zero, calls backend.close(self). There is no “force close” path — callers that want immediate teardown must drop all references.

MemoryBackend.open() returns a store with _refcount == 0. The caller is expected to either bind it to an Agent (which acquires) or enter with store: (which acquires) before it can be safely held.

property refcount: int#

Current number of live references; read-only mirror of internal state.

acquire() MemoryStore[source]#

Add one reference; return self for chaining.

release() None[source]#

Drop one reference; close via the backend when the count hits zero.

dispatch(op: MemoryOp) MemoryResult[source]#

Apply op through MemoryBackend.dispatch().

class rath.memory.MemoryStoreSpec(namespace: str | None = None, account_id: str | None = None, user_id: str | None = None, agent_id: str | None = None, options: Mapping[str, Any] | None = None)[source]#

User-facing description of a memory store to open.

All fields are optional; backends may ignore fields that do not apply (e.g. an embedded backend ignores account_id/user_id).

classmethod from_config(name: str | None = None, *, store: ConfigStore | None = None, **overrides: Any) MemoryStoreSpec[source]#

Build a MemoryStoreSpec from ~/.openrath/config.json.

Looks up name (or memory.default_provider when name=None) under memory.providers. Only local presets are modeled in config today; OpenViking stores should be built explicitly via MemoryStoreSpec kwargs / options.

Lazy-imports rath.config so import rath.memory never touches the filesystem.

Raises KeyError when the named provider is missing.

class rath.memory.MemoryCapabilities(scope_model: ScopeModel, supports_write: bool, supports_read: bool, supports_list: bool, supports_tree: bool, supports_vector_search: bool, supports_intent_search: bool, supports_resource_ingest: bool, supports_session_commit: bool, supports_l0_l1_l2: bool)[source]#

Static, class-level capability description for a memory backend.

class rath.memory.ScopeModel(*values)[source]#

How a memory backend organises its keyspace.

class rath.memory.MemoryOp[source]#

Marker root for memory-plane op payloads.

Concrete subclasses are frozen dataclasses. The marker exists so backends can declare supported_ops() and so the registry can refuse unknown subtypes.

class rath.memory.MemoryOpWrite(uri: str, content: str, mode: str = 'replace', wait: bool = False, timeout_seconds: float | None = None, metadata: Mapping[str, str] | None = None)[source]#

Update an existing memory entry at uri with free-form text content.

OpenViking’s write semantics are an update of an existing memory file (created by commit_session extraction or seeded via MemoryOpResource); it is not a generic create-file path.

class rath.memory.MemoryOpRead(uri: str, level: Literal['abstract', 'overview', 'detail'] = 'detail', encoding: str | None = 'utf-8')[source]#

Read the entry at uri at the requested hierarchical level.

class rath.memory.MemoryOpList(uri: str)[source]#

List immediate entries under uri (non-recursive).

class rath.memory.MemoryOpTree(uri: str, depth: int = 2)[source]#

Recursively list entries under uri up to depth levels.

class rath.memory.MemoryOpFind(query: str, target_uri: str | None = None, top_k: int = 8)[source]#

Direct semantic search; target_uri scopes the search namespace.

class rath.memory.MemoryOpSearch(query: str, session_id: str | None = None, target_uri: str | None = None, top_k: int = 8)[source]#

Intent-aware search; session_id scopes ranking against a session.

class rath.memory.MemoryOpResource(source: str, target_uri: str | None = None, reason: str = '', instruction: str = '', wait: bool = True, timeout_seconds: float | None = None)[source]#

Register an external resource (URL / file / dir) for ingestion.

target_uri is the destination directory under memory://resources/.

class rath.memory.MemoryOpCommit(session_id: str, messages: ~collections.abc.Sequence[~typing.Any], used_uris: ~collections.abc.Sequence[str] = <factory>, wait: bool = False, timeout_seconds: float | None = None)[source]#

Commit a session’s messages for archive + memory extraction.

Each entry in messages is a {"role": ..., "content": ...} dict (or {"role": ..., "parts": [...]} for multipart messages).

class rath.memory.MemoryHit(uri: str, score: float, snippet: str | None = None, level: Literal['abstract', 'overview', 'detail'] | None = None)[source]#

One ranked hit returned by MemoryFindResult.

class rath.memory.MemoryEntry(name: str, uri: str, is_dir: bool, size: int | None = None)[source]#

A single entry inside MemoryListResult.

class rath.memory.MemoryFindResult(hits: tuple[MemoryHit, ...])[source]#

Result of MemoryOpFind / MemoryOpSearch.

class rath.memory.MemoryReadResult(uri: str, data: str | bytes, level: Literal['abstract', 'overview', 'detail'])[source]#

Result of MemoryOpRead.

data is str when the op carried an encoding and the backend decoded the bytes; bytes when encoding=None.

class rath.memory.MemoryListResult(entries: tuple[MemoryEntry, ...])[source]#

Result of MemoryOpList / MemoryOpTree.

class rath.memory.MemoryWriteResult(uri: str, bytes_written: int)[source]#

Result of MemoryOpWrite.

class rath.memory.MemoryCommitResult(task_id: str | None, archived_uri: str | None, extracted_count: int)[source]#

Result of MemoryOpCommit.

extracted_count is -1 when the backend cannot report the count (e.g. wait=False async extraction).

class rath.memory.MemoryExecutionFailure(kind: Literal['not_found', 'unsupported', 'transport', 'extraction_failed', 'store_closed', 'unauthorized', 'timeout', 'invalid_uri', 'internal'], message: str, detail: str | None = None)[source]#

Structured failure surface for memory dispatch.

kind must be one of _KNOWN_FAILURE_KINDS; adapters route unexpected exceptions through kind="internal".

rath.memory.register(name: str) Callable[[type[B]], type[B]][source]#

Decorator: register a MemoryBackend subclass under name.

rath.memory.list_names() list[str][source]#

Return the names of all registered memory backends, in registration order.

rath.memory.get(name: str) MemoryBackend[source]#

Look up a memory backend by name and return a fresh instance.

rath.memory.get_class(name: str) type[MemoryBackend][source]#

Look up the registered class for name without instantiating it.

rath.memory.is_available(name: str) bool[source]#

Return True iff a memory backend named name is registered and available.

rath.memory.preferred(names: list[str]) MemoryBackend[source]#

Return an instance of the first available memory backend in names.

Raises MemoryBackendNotFound if none of the listed backends are registered and available.

rath.memory.set_default(name: str) None[source]#

Set the default memory backend used by current().

rath.memory.current() MemoryBackend[source]#

Return a fresh instance of the default memory backend.

Raises MemoryBackendNotFound if no default has been set.

exception rath.memory.MemoryBackendError[source]#

Base class for all rath.memory errors.

exception rath.memory.MemoryBackendNotFound(name: str, available: list[str])[source]#

Raised when a memory backend is requested by name but isn’t registered.

exception rath.memory.MemoryStoreClosed(handle: str)[source]#

Raised when an op is dispatched against an already-closed MemoryStore.

exception rath.memory.UnsupportedMemoryOp(op_type: type['MemoryOp'], backend_name: str)[source]#

Raised when a memory backend cannot service a given MemoryOp type.

exception rath.memory.MemoryNotFound(uri: str)[source]#

Raised when an explicit URI is read but the backend has no such entry.

exception rath.memory.MemoryConflict(uri: str)[source]#

Raised when a write collides with an existing entry under conflicting rules.

← API Reference