Connect a Python application to NAMS

To store and retrieve messages through NAMS, configure the Python client with a workspace key and use the conversation ID returned by the service.

Prerequisites

  • Python 3.10+ and a POSIX shell.

  • A data-plane workspace key and the intended NAMS endpoint. Obtain these from your workspace administrator or the dashboard. A key’s permissions and workspace association determine access; two keys can belong to the same workspace.

  • Review backend capabilities before moving existing Bolt code.

This procedure uses the published Python 0.7.0 package. It performs a message write and leaves the test conversation available for inspection.

1. Install the client

Create a directory for the connection check and install the package in its own environment:

mkdir nams-connection-check
cd nams-connection-check
python3 -m venv .venv
source .venv/bin/activate
python -m pip install 'neo4j-agent-memory[nams]==0.7.0'
export MEMORY_API_KEY='nams_replace_with_workspace_key'
export MEMORY_ENDPOINT='https://memory.neo4jlabs.com/v1'

Keep the key out of source control. A workspace header is needed only when required by your deployment; see NAMS settings for explicit precedence and fields.

2. Save a complete connection check

Save this as check_nams.py in nams-connection-check/:

Save as check_nams.py
import asyncio
from uuid import uuid4

from neo4j_agent_memory import NamsSettings, connect


async def main():
    client = await connect(NamsSettings())
    try:
        conversation = await client.short_term.create_conversation(
            f"connection-check-{uuid4().hex[:8]}"
        )
        conversation_id = str(conversation.id)
        content = "Connection check: the workshop starts in Denver."
        message = await client.short_term.add_message(
            conversation_id, "user", content
        )
        history = await client.short_term.get_conversation(conversation_id)
        assert any(item.id == message.id and item.content == content for item in history.messages)
        print(f"Verified message {message.id} in conversation {conversation_id}")
    finally:
        await client.close()


asyncio.run(main())

3. Run and verify

python check_nams.py

Success prints Verified message followed by the returned identifiers. Retain the conversation ID to reopen this conversation.

Resolve a failed check

  • AuthenticationError before any request: no key is configured. Export MEMORY_API_KEY.

  • AuthenticationError on a request (HTTP 401 or 403): confirm the key is current and belongs to the intended workspace, and check the endpoint.

  • RateLimitError or TransportError: the request failed after the transport’s retries. RateLimitError.retry_after carries the server’s Retry-After value when it sent one. Python retries only its configured status/network set; see REST transport behavior for the full status-to-exception mapping.

  • NotSupportedError while porting code: the operation is Bolt-only. Follow the migration procedure.

Configuration and operational scope

The maintained NAMS configuration and environment reference describe constructor arguments, aliases and provider wiring. Use the scope reference before adding user metadata.

Limits and gotchas

  • Configuration alone does not migrate stored data or make all Bolt operations available.

  • The connection check above verifies connection, message storage and readback only — it does not certify entity extraction, long-term search scope or reasoning-trace durability. A conversation’s display name and a user ID are not substitutes for its returned ID.

  • Do not replace a workspace key with an admin key merely to bypass a data-plane failure.

  • No service pricing tier is inferred from a rate-limit or transport error.

  • There is no universal user_identifier parameter or automatic cross-conversation authorization boundary.

  • Workspace database provisioning and bring-your-own-database management are separate administrative service operations. Verify the deployed service’s OpenAPI and workspace permissions before using them; they are not part of this connection check.

  • Client-side extraction, embeddings, resolution, enrichment and geocoding settings do not configure the NAMS extraction service.

Trace NAMS requests

The NAMS transport can wrap each HTTP request in a span named nams.http.request. Its attributes are http.method, http.url, nams.method (the SDK operation, for example list_conversations), nams.protocol, http.status_code and, when the request was retried, nams.retry_count.

In Python 0.7.0, connect() and MemoryClient create the transport without a tracer, so requests made through the client emit no spans. To trace requests, build the lower-level NamsBackend yourself and pass a tracer from get_tracer() (see observability configuration). The backend exposes the same short_term, long_term, reasoning, query and ontology accessors that MemoryClient binds on NAMS:

import asyncio

from neo4j_agent_memory import NamsSettings
from neo4j_agent_memory.nams import NamsBackend
from neo4j_agent_memory.observability import get_tracer


async def main():
    settings = NamsSettings()
    tracer = get_tracer()
    async with NamsBackend.from_config(settings.nams, tracer=tracer) as backend:
        conversations = await backend.short_term.list_conversations(limit=5)
        print(f"Listed {len(conversations)} conversations")


asyncio.run(main())

With no tracing library installed, get_tracer() returns a no-op tracer and no spans are exported.

Recover from an interrupted tutorial run

The three hosted Python tutorials — Store and read back memory, Activate and restore an ontology and Distil and download a skill — each keep a private ledger under .tutorial-state/. Use its recorded state to decide whether it is safe to start a new run:

Recorded state Next action

No mutation was attempted

Correct the failed prerequisite, then use the guarded new-run check on the tutorial page.

Every recorded resource was verified absent

Keep the ledger as evidence, recheck the lesson prerequisites and use a new run directory.

Retained/shared resources or cleanup exit 2

Have the owner record the actual disposition. This is not an automatic permission to reseed.

Pending or uncertain mutation

Use owner reconciliation; do not replay seed or erase the pending operation. The ontology tutorial’s own recover command handles this case for ontology state specifically.

Credential changed

Use the local inspection/handoff procedure in the tutorial’s "Inspect locally after a credential change" section; authenticated commands remain blocked.

Each tutorial’s own check-new-run command verifies the ledger before you start a fresh lesson directory; it does not by itself change the disposition above.

See also

Runnable examples in the repository: