Metadata-Version: 2.4
Name: lithtrix-langgraph
Version: 0.1.3
Summary: LangGraph BaseStore adapter for Lithtrix agent memory
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: httpx<1,>=0.27
Requires-Dist: langgraph==1.2.9
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Requires-Dist: respx>=0.21; extra == "dev"

# lithtrix-langgraph

A [LangGraph](https://github.com/langchain-ai/langgraph) `BaseStore` adapter that gives your graph persistent, per-agent memory backed by the [Lithtrix](https://lithtrix.ai) API — identity, memory, and reputation infrastructure for AI agents.

## What this is (and isn't)

This package is a **memory store adapter only**. It gives a LangGraph graph a `store=` that reads and writes to Lithtrix's memory API, so your agent's memory survives restarts and is queryable by key or by semantic search.

It does **not** include Lithtrix's swarm primitives (spawning sub-agents, signed delegation contracts, audit traces) — those exist in the wider Lithtrix API but are not wrapped by this package today. If you need them, call the REST API directly; see [docs.lithtrix.ai](https://docs.lithtrix.ai).

## Install

```bash
pip install lithtrix-langgraph
```

Requires Python 3.11+. If you're not in a virtual environment, installing into system Python can fail with a permission error — use a venv (`python -m venv .venv && source .venv/bin/activate`) or `pip install --user lithtrix-langgraph` instead.

## 1. Get an API key

Every Lithtrix agent needs its own identity and key. Register one with a single unauthenticated call — no dashboard, no approval step:

```bash
curl -X POST https://api.lithtrix.ai/v1/register \
  -H "Content-Type: application/json" \
  -H "User-Agent: my-agent/1.0" \
  -d '{
    "agent_name": "my-langgraph-agent",
    "owner_identifier": "you@example.com",
    "agree_to_terms": true
  }'
```

`agent_name` + `owner_identifier` must be unique together — reusing the same pair returns `409`. `agree_to_terms` must be `true` (accepts the [Gentle-Agent Agreement](https://lithtrix.ai/terms)).

The response is a full agent record (identity keys, tier info, etc.) — the only field you need right now is `api_key` (starts with `ltx_`). **Save it now — it is only ever shown once.** Set it as an environment variable:

```bash
export LITHTRIX_API_KEY=ltx_your_key_here
```

## 2. Configure the store

```python
from lithtrix_langgraph import LithtrixStore

store = LithtrixStore()  # reads LITHTRIX_API_KEY from the environment
```

`api_key` / `api_url` can also be passed as constructor kwargs, which override the environment — useful in tests or when running multiple agents from one process.

| Variable | Required | Default |
|----------|----------|---------|
| `LITHTRIX_API_KEY` | Yes | — |
| `LITHTRIX_API_URL` | No | `https://api.lithtrix.ai` |

## 3. A complete working example

Compile a graph with `store=` and any node can read and write memory via LangGraph's `get_store()`:

```python
from lithtrix_langgraph import LithtrixStore
from langgraph.graph import StateGraph
from langgraph.config import get_store
from typing_extensions import TypedDict


class State(TypedDict):
    note: str


def remember(state: State) -> State:
    store = get_store()
    # "my-agent" here is just a namespace prefix you choose for organizing keys —
    # it has no relationship to the agent_name you registered with above.
    store.put(("my-agent",), "last-note", {"text": state["note"]})
    item = store.get(("my-agent",), "last-note")
    return {"note": item.value["text"]}


store = LithtrixStore()
graph = StateGraph(State)
graph.add_node("remember", remember)
graph.set_entry_point("remember")
graph.set_finish_point("remember")
compiled = graph.compile(store=store)

result = compiled.invoke({"note": "hello from LangGraph"})
print(result)  # {'note': 'hello from LangGraph'}
```

This example was run against the live production API as part of writing this README — not just tested against mocks.

> **Note:** the namespace tuple (`("my-agent",)` above) is just a prefix you choose for organizing keys — it has no relationship to the `agent_name` you registered with. Your `LITHTRIX_API_KEY` is what determines whose memory you're reading and writing; the namespace can be anything.

## Key mapping

LangGraph's `(namespace_tuple, key)` gets flattened into a single Lithtrix key, since Lithtrix keys are flat strings (1–128 chars, charset `[a-zA-Z0-9-_.:]`):

| LangGraph call | Lithtrix key |
|----------------|--------------|
| `put(("user", "alice"), "preferences", ...)` | `user:alice:preferences` |
| `put((), "preferences", ...)` | `preferences` |

An empty namespace `()` passes the key through unchanged — useful if you're writing keys that need to match a flat naming convention from another system.

## Values

- **Put:** LangGraph values are `dict` → `PUT /v1/memory/{key}` with body `{"value": <dict>}`. Serialized size is checked locally at **512 KiB** before HTTP (mirrors API `MEMORY_VALUE_TOO_LARGE` / HTTP 413).
- **Get:** JSON objects are returned as-is. String/number/array payloads (DeerFlow Rung 1) are wrapped as `{"content": <raw>}`.
- **Timestamps:** Uses Lithtrix `created_at` / `updated_at` when present; otherwise `datetime.now(UTC)` on read.
- **TTL:** `supports_ttl = False`; `PutOp.ttl` is ignored.

## SearchOp supported subset

| Feature | Support |
|---------|---------|
| `namespace_prefix` | Yes → Lithtrix list `prefix` |
| `query` (semantic) | Yes → `GET /v1/memory/search` |
| `limit` / `offset` | Yes (best-effort pagination) |
| `filter` with `query` | Partial — exact top-level match applied client-side after semantic search |
| `filter` without `query` | Partial — list keys under prefix, fetch values, exact match only |
| `$eq` / `$ne` / `$gt` / … | **No** — raises `NotImplementedError` |
| Cross-namespace search | No |

## HTTP errors

401/403/413/422 responses propagate as `LithtrixAPIError` with `error_code` when the API returns structured JSON (e.g. `MEMORY_VALUE_TOO_LARGE`). 5xx responses are safe to retry — they indicate a transient server-side issue, not a problem with your request.

## Free tier

New agents get **1,000 memory writes/month** and **5 MiB of KV storage**, no credit card required. Reads and semantic search don't count against the write limit. See [docs.lithtrix.ai](https://docs.lithtrix.ai) for paid tiers if you outgrow it.

## Contributing

The source lives in Lithtrix's main repository, which is private — there's no public repo to file a pull request against. If you hit a bug or want a feature, email [hello@lithtrix.ai](mailto:hello@lithtrix.ai).
