Conversation and message operations

Message CRUD and NAMS conversation operations from ShortTermMemory API reference. Signatures show types, keyword-only arguments (*), and defaults; they are reference declarations, not calls to execute directly.

Message operations (bolt)

add_message

Add a message and optionally extract entities/relations and generate an embedding. Roles are user, assistant, system, and tool. Timestamp is generated by the SDK; timestamp overrides are accepted in batch message dictionaries, not as an add_message keyword.

async def add_message(
    session_id: str,
    role: MessageRole | str,
    content: str,
    *,
    conversation_id: UUID | str | None=None,
    extract_entities: bool=True,
    extract_relations: bool=True,
    generate_embedding: bool=True,
    metadata: dict[str, Any] | None=None,
    extraction_mode: Literal['auto', 'skip', 'explicit']='auto',
    explicit_mentions: list[Any] | None=None,
    user_identifier: str | None=None,
) -> Message: ...
Parameter Description

session_id

Session identifier

role

Message role (user, assistant, system, tool)

content

Message content

conversation_id

Optional specific conversation ID

extract_entities

Whether to extract entities from content. Has no effect when extraction_mode != 'auto'.

extract_relations

Whether to extract and store relations between entities

generate_embedding

Whether to generate embedding

metadata

Optional metadata

extraction_mode

How to populate :MENTIONS edges for this message. 'auto' (default): run the configured extractor pipeline. 'skip': do not run extraction, do not write :MENTIONS edges. 'explicit': do not run extraction, write :MENTIONS edges only for the entities supplied via explicit_mentions.

explicit_mentions

When extraction_mode='explicit', a list of EntityRef (element type ~neo4j_agent_memory.schema.models.EntityRef) describing the entities to link. An id links that entity; a typed reference is stored the way an extracted mention is (strict-mode check, ingest-time resolution, then a MERGE on name and type); a name alone links the one existing entity with that surface form and never creates one.

user_identifier

When provided, scopes the conversation to a :User node via (:User)-[:HAS_CONVERSATION]→(:Conversation). Required when MemorySettings.memory.multi_tenant=True.

add_messages_batch

Store message dictionaries in transaction batches. Each dictionary requires role and content; optional metadata and ISO-format timestamp are supported.

async def add_messages_batch(
    session_id: str,
    messages: list[dict[str, Any]],
    *,
    batch_size: int=100,
    generate_embeddings: bool=True,
    extract_entities: bool=False,
    extract_relations: bool=True,
    on_progress: Callable[[int, int], None] | None=None,
    on_batch_complete: Callable[[int, list[Message]], None] | None=None,
    user_identifier: str | None=None,
) -> list[Message]: ...
Parameter Description

session_id

Session identifier

messages

List of message dicts with 'role' and 'content' keys. Optional keys: 'metadata', 'timestamp' (ISO format string)

batch_size

Number of messages per transaction batch

generate_embeddings

Whether to generate embeddings for messages. Can be set to False and called separately with generate_embeddings_batch() for deferred processing.

extract_entities

Whether to extract entities (disabled by default for performance - can use extract_entities_from_session() later)

extract_relations

Whether to extract and store relations between entities (only applies when extract_entities=True)

on_progress

Callback for progress updates (completed_count, total_count)

on_batch_complete

Callback after each batch completes (batch_num, batch_messages)

user_identifier

When provided, scopes the conversation to a :User node via (:User)-[:HAS_CONVERSATION]→(:Conversation). Required when MemorySettings.memory.multi_tenant=True.

There is no add_messages method. For the portable batch name, see bulk_add_messages below; its honored options differ by backend.

get_conversation

Return a Conversation with its messages, oldest first. On Bolt, limit=None uses the implementation’s 1,000-message cap; pass an explicit larger limit when required. On NAMS the service returns at most the newest 200 messages, so limit=None asks for 200 and a larger limit is clamped to 200 with a warning; older messages cannot be listed. since filters the fetched messages by timestamp, so it does not provide server-side pagination.

async def get_conversation(
    session_id: str,
    *,
    conversation_id: UUID | str | None=None,
    limit: int | None=None,
    since: datetime | None=None,
) -> Conversation: ...
Parameter Description

session_id

Session identifier

conversation_id

Optional specific conversation ID

limit

Maximum number of messages

since

Only get messages after this time

There are no public get_messages or get_message methods. Read the conversation and inspect conversation.messages, or use a read-only query for an ID-specific lookup.

delete_message

Attempt to delete one message; cascade=True also removes its :MENTIONS relationships. Returns False for an ID that is not a UUID or matches no message. Not supported on NAMS.

The query removes only :MENTIONS relationships, not the conversation and sequence links that add_message always creates. For a message stored through add_message, the call therefore raises a Neo4j ConstraintError ("still has relationships") instead of returning False. It never reconnects neighboring messages. To remove a whole conversation, use clear_session.

async def delete_message(message_id: UUID | str, *, cascade: bool=True) -> bool: ...
Parameter Description

message_id

The message UUID to delete

cascade

If True, also delete :MENTIONS relationships to entities. The entities themselves are not deleted as they may be referenced by other messages.

NAMS and shared conversation operations

On NAMS, session_id means the server-issued conversation ID. conversation_id is an alias where listed; session_id wins when both are supplied.

create_conversation

Create a conversation. Pass session_id on both backends. NAMS also accepts the conversation_id alias and raises TypeError when both are omitted, even though its signature defaults them to None.

On NAMS, the name is not sent: the request carries only user_identifier and metadata from kwargs. The name only fills the local Conversation.session_id field. Pass the server-issued Conversation.id as the session_id of later calls. On bolt, the method idempotently creates local metadata under the given session ID and honors user_identifier.

async def create_conversation(
    session_id: str | None=None,
    *,
    conversation_id: str | None=None,
    **kwargs: Any,
) -> Conversation: ...

list_conversations

List conversation metadata, most recently updated first. Both backends accept user_identifier and limit through kwargs, and both default to 100 results. NAMS serves at most 200 conversations per page, so a larger limit is collected over several requests that follow the service’s next_cursor. Message bodies are not populated by either listing.

async def list_conversations(**kwargs: Any) -> list[Conversation]: ...

bulk_add_messages

NAMS: send message dictionaries to the bulk endpoint, using only role and content. The endpoint contract allows up to 100 messages; this wrapper does not split or validate the batch size. On bolt, this delegates to add_messages_batch.

async def bulk_add_messages(
    session_id: str | None=None,
    messages: list[dict[str, Any]] | None=None,
    *,
    conversation_id: str | None=None,
    **kwargs: Any,
) -> list[Message]: ...

get_observations

NAMS only. Return observation dictionaries for a conversation. Bolt raises NotSupportedError.

async def get_observations(session_id: str | None=None, **kwargs: Any) -> list[dict[str, Any]]: ...

get_reflections

NAMS only. Return reflection dictionaries for a conversation. Bolt raises NotSupportedError.

async def get_reflections(session_id: str | None=None, **kwargs: Any) -> list[dict[str, Any]]: ...

get_extraction_status

NAMS only. Return ExtractionStatus, whose pending_count and is_complete properties summarize extraction progress. Bolt has no status accessor; client.long_term.wait_for_extraction() is a no-op returning True there.

async def get_extraction_status(session_id: str | None=None, *, conversation_id: str | None=None) -> ExtractionStatus: ...
NAMS operation Honored options and behavior

add_message

session_id / conversation_id, role, content. Other kwargs, including metadata and extraction flags, are not sent.

get_conversation

Conversation ID and limit (at most 200, the newest messages); assembles header and messages from two requests and returns the messages oldest first, although the service lists them newest first. Bolt’s since is not sent.

search_messages

query, required conversation ID, optional limit. threshold and metadata_filters are not sent. Returns Message objects; do not assume a bolt-style similarity score is present.

get_context

Required conversation ID; formats reflections, observations, and recent messages. query and bolt context-size controls are not sent to the endpoint.

clear_session

Deletes the entire conversation, not one message.

list_sessions, delete_message, get_conversation_summary

Raise NotSupportedError. Use list_conversations, whole-conversation deletion, or client-side summarization as appropriate.

add(content, kwargs) and search(query, kwargs) are bolt convenience aliases for add_message and search_messages; prefer the explicit operation names in cross-backend code.

Models

Message

Pydantic model; inherited memory-entry fields are included.

Field Type Default Description

id

UUID

new UUID

Unique identifier.

created_at

datetime

current UTC time

Creation time.

updated_at

datetime | None

None

Last update time, if updated.

embedding

list[float] | None

None

Embedding vector, if one was generated.

metadata

dict[str, Any]

{}

Arbitrary key-value metadata, stored as JSON.

role

MessageRole

required

Message role

content

str

required

Message content

conversation_id

UUID | None

None

Parent conversation ID

tool_calls

list[dict[str, Any]] | None

None

Tool calls if any

Conversation

Fields and defaults:

Field Type Default Description

id

UUID

new UUID

Unique identifier.

session_id

str

required

User/agent session identifier

title

str | None

None

Conversation title

messages

list[Message]

[]

Messages in the conversation

created_at

datetime

current UTC time

Creation time.

updated_at

datetime | None

None

Last update time, if updated.

metadata

dict[str, Any]

{}

Arbitrary key-value metadata.

ExtractionStatus

Fields and defaults:

Field Type Default Description

messages

list[dict[str, Any]]

[]

Per-message extraction detail

summary

dict[str, int]

{}

Count of messages per extraction status (pending, completed, failed, and so on)