# Python SDK

Using SurrealDB Agent Memory from Python applications and agents.

The SurrealDB Agent Memory client ships **inside the main SurrealDB Python package** (`surrealdb`). Install one package and import `Spectron` or `AsyncSpectron` alongside the database driver.

> [!NOTE]
> `Spectron` was the project name for SurrealDB Agent Memory. These type names
> will be renamed in a future release.

> **Package naming:** On [PyPI](https://pypi.org), the SurrealDB Agent Memory client ships in the **`surrealdb`** package alongside the database driver. It lands in the **3.x** line, which is still prerelease, so the install needs **`--pre`** - a bare `pip install surrealdb` resolves to the 2.x stable release, which carries no SurrealDB Agent Memory client. The bare name **`spectron`** belongs to an unrelated project; do not install it for SurrealDB Agent Memory.

## Installation

```bash
pip install --pre surrealdb
```

Python 3.10+ recommended.

## Clients

`Spectron` is synchronous (uses `requests`). `AsyncSpectron` is async (uses `aiohttp`). Both expose the same method names; add `await` on the async client.

```python
from surrealdb import Spectron, AsyncSpectron

with Spectron(
    context="acme-prod",
    endpoint="https://api.spectron.example",
    api_key="sk-spec-...",
) as memory:
    memory.remember("Alice was promoted to CTO.")
    hits = memory.recall("What is Alice's role?", k=10)
    for hit in hits.hits:
        print(hit.score, hit.text)

async with AsyncSpectron(
    context="acme-prod",
    endpoint="https://api.spectron.example",
    api_key="sk-spec-...",
) as memory:
    await memory.remember("Alice was promoted to CTO.")
    hits = await memory.recall("What is Alice's role?", k=10)
```

Both clients are pinned to one context and call `/api/v1/{context}/…`. Pass `context`, `endpoint`, and `api_key` explicitly; the SDK does **not** read environment variables.

## Scope

On the wire, scope is a **ScopeSet**: an ordered array of slash-path strings (for example `["org/acme/user/alice"]`). Register paths with `spectron scopes create` before first use; see [Contexts and scope](/docs/agent-memory/mental-model/contexts-and-scope.md).

The Python client accepts:

- A single path: `scope="org/acme/user/alice"`
- A list of paths: `scope=["org/acme/user/alice"]`

| Argument | Default | Description |
| --- | --- | --- |
| `context` | required | Context id, e.g. `"acme-prod"`. |
| `endpoint` | required | SurrealDB Agent Memory host URL, e.g. `"https://api.spectron.example"`. |
| `api_key` | required | Bearer token (`Authorization: Bearer …`). |
| `timeout` | `30.0` | Per-request timeout in seconds. |
| `max_retries` | `3` | Retries for GETs and idempotent writes. |

## Remember (facts)

```python
memory.remember("Alice was promoted to CTO.", infer="full", scopes=["org/acme/user/alice"])
memory.remember("Q3 board notes", labels=["topic=board"], memory_category="context")

memory.remember_many(
    [
        {"role": "user", "content": "I was promoted to CTO."},
        {"role": "assistant", "content": "Congratulations!"},
    ],
    extract="whole_conversation",
    scopes=["org/acme/user/alice"],
)
```

`remember` and `remember_many` send an `Idempotency-Key` header (derived from method, path, body, and a 30-second bucket) so safe retries collapse server-side.

## Recall and context

```python
result = memory.recall(
    "What is Alice's role?",
    k=10,
    mode="hybrid",
    lens=["org/acme/user/alice"],
)

block = memory.query_context(
    "What is Alice's role?",
    k=10,
    lens=["org/acme/user/alice"],
)
```

Optional filters include `labels`, `lens`, `scope_view` (`strict` | `merged` | `crossTeam`), temporal bounds (`as_of`, `valid_from`, …), and geo `location`.

## Documents

```python
upload = memory.documents.upload(
    "policy.pdf",
    content_type="application/pdf",
    title="Returns policy",
    scope=["org/acme/team/eng"],
    labels=["team=eng"],
)
doc = memory.documents.get(upload.id)
hits = memory.documents.query("refund window", k=5, mode="hybrid")
chunks = memory.documents.chunks(upload.id)
memory.documents.keywords.search("returns policy", k=10)
```

## Chat (including streaming)

```python
reply = memory.chat("Summarise what you know about Alice", scopes=["user/alice"])
print(reply.reply)

for chunk in memory.chat("Summarise what you know about Alice", stream=True):
    if chunk.delta:
        print(chunk.delta, end="", flush=True)
    if chunk.done:
        print("\n[trace]", chunk.trace_id)
```

## Other verbs and namespaces

Top-level methods: `consolidate`, `reflect`, `elaborate`, `forget`, `state`, `whoami`, `profile`, `inspect`, `audit`, `health`.

Grouped resources: `memory.documents`, `memory.sessions`, `memory.entities`, `memory.scopes`, `memory.principals`, `memory.keys`, `memory.traces`, `memory.lifecycle`.

→ Full method tables: [Python SDK reference](/docs/agent-memory/reference/sdk-python.md)

## Errors and retries

The SDK raises typed exceptions so you can handle auth, scope, and not-found cases precisely.

```python
from surrealdb import SpectronAPIError, SpectronAuthError, SpectronNotFoundError, SpectronScopeError

try:
    hits = memory.recall("what is my name?", lens=["user/alice"])
except SpectronAuthError as exc:
    print(exc.status_code, exc.message)
except SpectronScopeError as exc:
    print(exc.status_code, exc.message)
except SpectronNotFoundError as exc:
    print(exc.status_code, exc.message)
except SpectronAPIError as exc:
    print(exc.status_code, exc.message, exc.trace_id, exc.body)
```

| Exception | HTTP | When it occurs |
| --- | --- | --- |
| `SpectronError` | n/a | Base class |
| `SpectronAPIError` | Other non-2xx | Generic API failure; carries `status_code`, `message`, `trace_id`, `body` |
| `SpectronAuthError` | 401 | Missing or invalid API key |
| `SpectronScopeError` | 403 | Scope floor or principal rejects the call |
| `SpectronNotFoundError` | 404 | Context, session, document, or other resource not found |

Responses of 400, 422, 429, and 5xx that are not mapped to a subclass surface as `SpectronAPIError`. Inspect `status_code` and `body` (RFC 7807 problem details) for validation and rate-limit information. The async client raises the same exceptions.

`GET` requests and idempotent writes (`remember`, `remember_many`) retry automatically on connection errors and 5xx responses: up to `max_retries` attempts (default 3) with 250 ms, 500 ms, 1000 ms backoff. Other writes and 4xx responses are not retried. Tune or disable on the constructor:

```python
memory = Spectron(..., max_retries=0, timeout=10.0)
```

The default timeout is 30 seconds; streaming chat disables the read timeout while tokens arrive. On a 429, read the problem-detail `body` and back off before retrying manually. All errors follow [RFC 7807 Problem Details](/docs/agent-memory/reference/errors.md).

## Response types

Typed dataclasses include `RememberResponse`, `RecallResponse`, `RecallHit`, `ChatResponse`, `Document`, `Chunk`, `StateResponse`, and others. Import from `surrealdb.spectron` when you need explicit types:

```python
from surrealdb.spectron import RecallResponse, RecallHit
```

## Harness adapters (zero prompt change)

For agent frameworks that should auto-record every turn, SurrealDB Agent Memory ships Python adapters that build on this SDK:

```bash
pip install spectron-crew-ai              # CrewAI
pip install spectron-openai-agents-sdk    # OpenAI Agents SDK
pip install spectron-strands-agents       # Strands Agents
pip install spectron-google-adk           # Google ADK
```

→ [Agent frameworks](/docs/agent-memory/integrations/frameworks/crewai.md)

## CLI alternative

The **`spectron`** binary exposes the same operations without the SDK:

```bash
spectron remember "Alice was promoted to CTO."
spectron recall "What is Alice's role?" --json
```

→ [CLI reference](/docs/agent-memory/reference/cli.md) · [REST API](/docs/agent-memory/reference/rest-api.md)
