MemoryClient API reference

MemoryClient connects to the configured backend and exposes its memory stores. The concrete stores and supported operations differ between bolt and NAMS.

Signatures below show types, keyword-only arguments (*), and defaults. They are reference declarations; the examples show calls to execute.

See Backend capabilities for availability and data scope.

Overview

Export the connection values for a dedicated AuraDB instance using the Aura connection setup. BoltSettings selects the direct Neo4j backend for Aura.

import asyncio
import os
from neo4j_agent_memory import BoltSettings, MemoryClient

async def main():
    settings = BoltSettings(
        neo4j={
            "uri": os.environ["NEO4J_URI"],
            "username": os.environ["NEO4J_USERNAME"],
            "password": os.environ["NEO4J_PASSWORD"],
            "database": os.getenv("NEO4J_DATABASE", "neo4j"),
        },
    )
    async with MemoryClient(settings) as client:
        message = await client.short_term.add_message("example", "user", "Hello")
        print(message.id)

asyncio.run(main())

For hosted setup use NamsSettings and the returned conversation ID, as shown in NAMS quickstart. connect(settings) is also available as an async construction helper: it returns an already-connected BoltMemoryClient or NamsMemoryClient for the corresponding settings type. Close that client in finally. The SDK aliases improve static typing; they do not change the service.

Constructor

def MemoryClient(
    settings: MemorySettings | None=None,
    *,
    embedder: Embedder | None=None,
    extractor: EntityExtractor | None=None,
    resolver: EntityResolver | None=None,
    geocoder: Geocoder | None=None,
    enrichment_provider: _EnrichmentProviderProtocol | None=None,
    ontology: OntologyDocument | str | Path | None=None,
) -> None: ...
Parameter Description

settings

Memory settings (uses defaults if not provided)

embedder

Optional embedder override (for testing)

extractor

Optional extractor override (for testing)

resolver

Optional resolver override (for testing). Without it, bolt builds the resolver from settings.resolution; the default composite strategy builds OntologyResolver, after the Neo4j connection exists.

geocoder

Optional geocoder override (for testing)

enrichment_provider

Optional enrichment provider override (for testing)

ontology

The ontology this client extracts and validates against: an OntologyDocument, or a path to a .json/.yaml file loaded through load_ontology (an EntitySchemaConfig file is converted). Bolt only; the highest-priority source, see Ontology precedence.

Ontology precedence

On bolt, connect() resolves one ontology document before it builds the extractor, and hands it to the extractor factory, the resolver, and the short-term and long-term stores. The first source that yields a document wins:

  1. MemoryClient(ontology=…​)

  2. settings.schema_config.ontology_path

  3. settings.schema_config.custom_schema_path

  4. the active stored ontology version, when settings.schema_config.use_active_ontology is True and a version is activated

  5. settings.schema_config.model set to custom with settings.schema_config.entity_types (an ad-hoc document, one label per name)

  6. the built-in template named by settings.schema_config.ontology_template (default poleo), falling back to the built-in POLE+O ontology when the name is unknown

The validation mode is settings.schema_config.validation_mode when set, then the active stored version’s mode when that version supplied the document, then strict if strict_types is True, otherwise permissive.

Because resolution happens at connect time, activating a version affects the next connection, not the client that activated it. Read the result back with the ontology_document and validation_mode properties. See Graph schema configuration for the settings.

Properties

Property Type / backend Description

short_term

ShortTermMemory / NamsShortTermMemory

Conversation operations; connection required.

long_term

LongTermMemory / NamsLongTermMemory

Entity operations; preferences and facts are bolt-only.

reasoning

ReasoningMemory / NamsReasoningMemory

Reasoning operations; NAMS assembles conversation-level steps into compatibility traces.

backend

str

Resolved bolt or nams backend.

is_nams

bool

Whether NAMS is selected.

is_connected

bool

Whether the backend is connected.

query

CypherQueryProtocol

Read-only await client.query.cypher(query, params) on either backend; returns records as dictionaries.

graph

Neo4jClient, bolt only

Deprecated direct graph access; see the graph property.

schema

Graph SchemaManager, bolt only

Constraints/index inspection and management; see Schema objects.

users

UserMemory, bolt only

User nodes and explicit user-scoped operations; see Manage user records.

buffered

BufferedWriter, bolt only

Explicit buffered writes; see Buffered writes.

consolidation

ConsolidationMemory, bolt only

Conversation hygiene and audit operations; see Consolidation.

eval

EvalMemory

Retrieval evaluation; the operations evaluated must be supported by the selected backend.

ontology

OntologyAPI

Versioned domain ontologies on both backends: NamsOntology on NAMS, BoltOntology on bolt (stored as :Ontology and :OntologyVersion nodes). Operations a backend cannot honour raise NotSupportedError; see Ontology API.

ontology_document

OntologyDocument | None

The effective ontology resolved at connect time, which drives extraction, relation validation, and the write paths. None before connect() and on NAMS, where these run server-side; use ontology.get_active() there. It can differ from ontology.get_active() when a file or the ontology= keyword outranked the stored version.

validation_mode

Literal['permissive', 'strict']

How strictly the write paths enforce ontology_document. strict makes long_term.add_entity and add_relationship raise ValidationError for undeclared types and patterns and makes message ingestion drop undeclared entities; permissive writes them and drops only the extracted relations the ontology forbids. permissive before connect().

auth

NamsAuth, NAMS only

Key management; see Authentication.

write_errors

list[BufferedWriteError]

Errors collected by explicit buffered writes on bolt; always an empty list on NAMS.

Store access before connection raises NotConnectedError. A property being present is not evidence of backend support. On NAMS, the bolt-only users, buffered, consolidation and schema accessors return a placeholder whose method calls raise NotSupportedError, and graph raises NotSupportedError on access. Unsupported store methods that NAMS defines raise NotSupportedError; bolt-only methods it does not define, for example long_term.get_preferences_by_category, raise AttributeError. The NAMS placeholder long_term.get_preferences_for takes keyword arguments only, so the bolt positional form get_preferences_for(user) raises TypeError instead. The NAMS long_term.supersede_preference takes one preference_id plus keyword arguments, so the bolt two-argument call raises TypeError whether it is written positionally or with the old_preference_id/new_preference_id keywords. The NAMS long_term.get_facts_about takes one positional entity_name and no keyword arguments, so a bolt call that passes subject= or limit= raises TypeError. Keep the MemorySettings object you passed to the constructor if you need to inspect configuration; there is no public client.settings property.

Methods

connect

Connect to the configured backend. Called by async with; bolt initializes schema and providers, while NAMS configures HTTP transport and optionally validates the connection.

async def connect() -> None: ...

close

Close backend resources. Called when leaving async with, including on exceptions.

async def close() -> None: ...

graph

On bolt, client.graph exposes the existing connection for domain-specific Cypher. execute_read emits a deprecation warning; prefer client.query.cypher for read-only queries. Direct write access remains bolt-only.

rows = await client.query.cypher(
    "MATCH (c:Customer {id: $id}) RETURN c.name AS name",
    {"id": "CUST-001"},
)
# Bolt only: writes require the direct graph client.
await client.graph.execute_write(
    "CREATE (n:MyNode {name: $name})", {"name": "example"}
)

Neo4jClient also provides execute_batch and vector_search. Use graph operations only while the client is connected. NAMS does not expose direct bolt access or write Cypher.

get_context

Return a formatted string assembled from the enabled stores. There is no MemoryContext object or to_prompt() conversion.

async def get_context(
    query: str,
    *,
    session_id: str | None=None,
    include_short_term: bool=True,
    include_long_term: bool=True,
    include_reasoning: bool=True,
    max_items: int=10,
) -> str: ...
Parameter Description

query

The query to search for relevant context

session_id

Optional session ID for short-term filtering

include_short_term

Whether to include conversation history

include_long_term

Whether to include matching entities and preferences on bolt (facts are not included). On NAMS, long-term context is an empty string.

include_reasoning

Whether to include similar task traces

max_items

Maximum items per memory type

session_id is passed to short-term context retrieval, which also appends global semantic matches on bolt when an embedder is configured. It does not scope long-term or reasoning retrieval. This method is not an authorization boundary. On NAMS, a conversation ID is required when short-term context is enabled; the server-provided short-term context does not use query to filter its contents.

context = await client.get_context(
    "restaurant recommendations", session_id="example", max_items=5
)
prompt = f"Context from memory:\n{context}\nUser question: Suggest a restaurant."

get_stats

Bolt only. Return a flat dictionary of counts; NAMS raises NotSupportedError. Use a supported read-only counting query when hosted statistics are needed.

async def get_stats() -> dict[str, Any]: ...
stats = await client.get_stats()
print(stats["messages"], stats["entities"], stats["traces"])

The count keys are conversations, messages, entities, preferences, facts, and traces.

get_graph

Bolt only. Return a MemoryGraph for visualization, containing nodes, relationships, and metadata. The limit applies per memory type.

async def get_graph(
    *,
    memory_types: list[Literal['short_term', 'long_term', 'reasoning']] | None=None,
    session_id: str | None=None,
    since: datetime | None=None,
    until: datetime | None=None,
    include_embeddings: bool=False,
    limit: int=1000,
) -> MemoryGraph: ...
Parameter Description

memory_types

Which memory types to include. Defaults to all.

session_id

Filter by session ID (for short_term and reasoning)

since

Only include data created/updated after this time

until

Only include data created/updated before this time

include_embeddings

Whether to include embedding vectors in properties. Set to False (default) for smaller payloads.

limit

Maximum number of nodes to return per memory type

export_graph is not a Python SDK method. For NAMS, use long_term.expand_graph or a supported read-only Cypher query.

get_locations

Bolt only; on NAMS it raises NotSupportedError. Return location dictionaries with coordinates, enrichment details, and conversation references for map rendering.

async def get_locations(
    *,
    session_id: str | None=None,
    has_coordinates: bool=True,
    limit: int=500,
) -> list[dict[str, Any]]: ...
Parameter Description

session_id

Filter to locations mentioned in this conversation. When provided, only returns locations that have an :EXTRACTED_FROM relationship to messages in this session.

has_coordinates

Only return locations with lat/lon coordinates. Defaults to True for map visualization use cases.

limit

Maximum number of locations to return. Defaults to 500.

flush

Wait for writes submitted through client.buffered. Bolt only; ordinary store methods do not become buffered automatically. On NAMS, flush raises NotSupportedError.

async def flush() -> None: ...

wait_for_pending

Alias for flushing explicit buffered writes. Bolt only; on NAMS it raises NotSupportedError.

async def wait_for_pending() -> None: ...

Context manager and concurrency

Use async with MemoryClient(settings) to connect and close reliably. Async calls may share one client within the same event loop; create separate clients for separate threads/event loops. Flush submitted buffered work before consuming its results and inspect write_errors as described in the buffered-write guide.

Graph models

GraphNode

Fields and defaults:

Field Type Default Description

id

str

required

Node identifier

labels

list[str]

required

Node labels (e.g., ['Message'], ['Entity'])

properties

dict[str, Any]

{}

Node properties

GraphRelationship

Fields and defaults:

Field Type Default Description

id

str

required

Relationship identifier

type

str

required

Relationship type (e.g., 'HAS_MESSAGE', 'MENTIONS')

from_node

str

required

Source node ID

to_node

str

required

Target node ID

properties

dict[str, Any]

{}

Relationship properties

MemoryGraph

Fields and defaults:

Field Type Default Description

nodes

list[GraphNode]

[]

Graph nodes

relationships

list[GraphRelationship]

[]

Graph relationships

metadata

dict[str, Any]

{}

Export metadata (filters applied, counts, etc.)