Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ print(result.text)
| **[📡 Observability](https://locusagents.oracle.com/concepts/observability/)** | Opt-in `EventBus` — one `run_context()` streams 40+ canonical events from every layer, no external broker. `TelemetryHook` for OpenTelemetry/OTLP. |
| **[🧠 Reasoning](https://locusagents.oracle.com/concepts/reasoning/)** | `reflexion=True` · `grounding=True` · `CausalChain` · **GSAR** typed grounding layer (`arXiv:2604.23366`). |
| **[🛡 Idempotent tools](https://locusagents.oracle.com/concepts/idempotency/)** | `@tool(idempotent=True)` — dedupes on `(name, args)`. The model can't double-charge, double-book, or double-page. |
| **[💾 Durable memory](https://locusagents.oracle.com/concepts/checkpointers/)** | 8 checkpoint backends — Oracle 26ai · OCI Object Storage · PostgreSQL · Redis · OpenSearch · in-memory · file · HTTP. |
| **[💾 Durable memory](https://locusagents.oracle.com/concepts/checkpointers/)** | 9 checkpoint backends — Oracle 26ai · OCI Object Storage · PostgreSQL · MySQL · Redis · OpenSearch · in-memory · file · HTTP. |
| **[🧠 Long-term memory](https://locusagents.oracle.com/concepts/memory-manager/)** | Oracle-native path: `OracleAgentMemoryManager` over Oracle's [`oracleagentmemory`](https://pypi.org/project/oracleagentmemory/) — LongMemEval-tuned recall, context cards, scoped retrieval. Portable path: `LLMMemoryManager` over any `BaseStore` (InMemory / Redis / Postgres / OpenSearch / Oracle). |
| **[🔎 RAG](https://locusagents.oracle.com/concepts/rag/)** | 4 vector stores — Oracle 26ai · OpenSearch · pgvector · in-memory. OCI Cohere + OpenAI embeddings · multimodal (PDF, image OCR, audio). |
| **[📡 Streaming + Server](https://locusagents.oracle.com/concepts/server/)** | Typed events · SSE · `AgentServer` (FastAPI, per-principal thread isolation). |
Expand Down Expand Up @@ -266,7 +266,7 @@ loop is the inner engine — the SDK is the whole stack around it.
- **PRISM Cognitive Router** — an LLM classifier reads the task and fills a typed `GoalFrame` (intent · domain · complexity · risk); the `CognitiveCompiler` emits the matching runtime shape. The model classifies, never authors graph topology.
- **Eight orchestration shapes** — `SequentialPipeline`, `ParallelPipeline`, `LoopAgent`, `StateGraph`, `Orchestrator + Specialists`, `Swarm`, `Handoff Chain`, and cross-process `A2A Mesh`. One `Agent` class composes them all; one event stream covers them all.
- **The agent loop** — **Think → Execute → Reflect → Terminate** with one immutable state flowing through. `@tool(idempotent=True)` dedupes Execute on `(name, args)`; Reflect runs Reflexion + Grounding + Causal on cadence or on error; Terminate is composable algebra (`MaxIterations(10) | ToolCalled("submit") & ConfidenceMet(0.9)`).
- **Foundations** — Models (OCI GenAI V1/SDK/Responses · OpenAI · Anthropic · Ollama), Memory (8 checkpoint backends, long-term store), RAG (4 vector stores, multimodal, rerank), Observability (40+ typed events, EventBus, OpenTelemetry), Tools / MCP / Skills (idempotent, both-ways MCP, guardrails, steering, evaluation).
- **Foundations** — Models (OCI GenAI V1/SDK/Responses · OpenAI · Anthropic · Ollama), Memory (9 checkpoint backends, long-term store), RAG (4 vector stores, multimodal, rerank), Observability (40+ typed events, EventBus, OpenTelemetry), Tools / MCP / Skills (idempotent, both-ways MCP, guardrails, steering, evaluation).
- **Oracle Database 26ai** — native `VECTOR(N, FLOAT32)`, durable agent threads, in-DB chunking + embeddings, cross-thread store, versioned saver.

Every node at every layer emits a write-protected typed event — the same stream powers SSE, telemetry hooks, and your own `async for event in agent.run(…)` consumer.
Expand Down
1 change: 1 addition & 0 deletions docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ does, and where to find it.
| **`OCIBucketBackend`** | OCI-native, lifecycle policies, region replication | `locus.memory.backends.oci_bucket` |
| `RedisBackend` | Multi-replica, fast, TTLs (OCI Cache with Redis) | `locus.memory.backends.redis` |
| `PostgreSQLBackend` | Production DB with metadata queries | `locus.memory.backends.postgresql` |
| `MySQLBackend` | Production MySQL with official async Connector/Python | `locus.memory.backends.mysql` |
| `OpenSearchBackend` | Full-text search across past runs | `locus.memory.backends.opensearch` |
| `OracleBackend` | Oracle DB with JSON queries | `locus.memory.backends.oracle` |

Expand Down
4 changes: 3 additions & 1 deletion docs/api/checkpointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ Three flavours, depending on how you want state stored:
## Other backends

When you can't run on Oracle / OCI, the same `BaseCheckpointer`
contract is implemented for Redis, PostgreSQL, OpenSearch, file
contract is implemented for Redis, PostgreSQL, MySQL, OpenSearch, file
system, and an HTTP-API adapter.

::: locus.memory.backends.RedisBackend
::: locus.memory.backends.PostgreSQLBackend
::: locus.memory.backends.MySQLBackend
::: locus.memory.backends.OpenSearchBackend
::: locus.memory.backends.FileCheckpointer
::: locus.memory.backends.HTTPCheckpointer
Expand All @@ -58,5 +59,6 @@ factory functions below are one-line shortcuts.
::: locus.memory.backends.adapters.oracle_checkpointer
::: locus.memory.backends.adapters.oci_bucket_checkpointer
::: locus.memory.backends.adapters.opensearch_checkpointer
::: locus.memory.backends.adapters.mysql_checkpointer
::: locus.memory.backends.adapters.postgresql_checkpointer
::: locus.memory.backends.adapters.redis_checkpointer
1 change: 1 addition & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ the model invented.
| **`OCIBucketBackend`** | OCI-native, lifecycle policies, region replication | `locus.memory.backends.oci_bucket` |
| `RedisBackend` | Multi-replica, fast, TTLs (OCI Cache with Redis) | `locus.memory.backends.redis` |
| `PostgreSQLBackend` | Production DB with metadata queries | `locus.memory.backends.postgresql` |
| `MySQLBackend` | Production MySQL with official async Connector/Python | `locus.memory.backends.mysql` |
| `OpenSearchBackend` | Full-text search across past runs | `locus.memory.backends.opensearch` |
| `OracleBackend` | Oracle DB with JSON queries | `locus.memory.backends.oracle` |

Expand Down
26 changes: 23 additions & 3 deletions docs/concepts/checkpointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ agent.run_sync("What were we discussing?", thread_id="user-c42")
| Local development, single machine | `FileCheckpointer` |
| Multi-worker deployment, fast access, TTLs | `redis_checkpointer` |
| Postgres shop, want SQL queries on metadata | `postgresql_checkpointer` |
| MySQL shop, want official Connector/Python async access | `mysql_checkpointer` |
| Need full-text search across past runs | `opensearch_checkpointer` |
| Oracle Database shop, want JSON queries | `oracle_checkpointer` |
| **[Oracle 26ai][oracle-db] with versioned history + pending writes** | `OracleCheckpointSaver` — LangGraph-shape, native |
Expand Down Expand Up @@ -105,6 +106,25 @@ agent = Agent(
Tables auto-created on first save. Index on `thread_id` plus a JSONB
column for ad-hoc metadata queries.

### MySQL: `mysql_checkpointer`

```python
from locus.memory.backends import mysql_checkpointer

agent = Agent(
model=...,
tools=[...],
checkpointer=mysql_checkpointer(
dsn="mysql://user:pass@host:3306/locus",
table_name="locus_threads",
),
)
```

Tables auto-created on first save. Uses the official
`mysql-connector-python` asyncio API, MySQL `JSON` columns, and
`JSON_CONTAINS` metadata queries.

### Redis: `redis_checkpointer`

```python
Expand Down Expand Up @@ -199,10 +219,10 @@ to wire them differently:

2. **Storage backends** expose a simpler dict-shaped interface and
need adapter wrapping:
- `RedisBackend`, `PostgreSQLBackend`, `OpenSearchBackend`,
- `RedisBackend`, `PostgreSQLBackend`, `MySQLBackend`, `OpenSearchBackend`,
`OracleBackend`.
- Use the factory function: `redis_checkpointer(...)`,
`postgresql_checkpointer(...)`, etc.
`postgresql_checkpointer(...)`, `mysql_checkpointer(...)`, etc.

```python
# WRONG — passing a storage backend directly will fail at save time
Expand Down Expand Up @@ -317,7 +337,7 @@ schema, both checkpoint state and long-term memory live in Oracle.
|---|---|
| `AttributeError: 'RedisBackend' has no attribute 'save'` (with `state` arg) | Storage backend passed without the adapter. Use `redis_checkpointer(...)` factory instead. |
| Threads forgotten between deployments | `FileCheckpointer` directory inside an ephemeral container. Mount a volume, or move to `oci_bucket_checkpointer`. |
| Two replicas show different conversation state for the same thread | The checkpointer isn't shared between replicas. `FileCheckpointer` is per-host; switch to a centralised backend (Redis, Postgres, OCI bucket). |
| Two replicas show different conversation state for the same thread | The checkpointer isn't shared between replicas. `FileCheckpointer` is per-host; switch to a centralised backend (Redis, Postgres, MySQL, OCI bucket). |
| Slow first save | Some backends auto-create schema on first call. Pre-create in your deployment script if startup latency matters. |

## Source
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/multi-agent/production.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ agent = Agent(config=AgentConfig(
))
```

Seven backend implementations, one `Checkpointer` Protocol — Postgres,
Redis, OCI Bucket, OCI Object Storage, OpenSearch, Oracle ADB,
Nine backend implementations, one `Checkpointer` Protocol — Oracle ADB,
OCI Object Storage, Postgres, MySQL, Redis, OpenSearch, HTTP, file, and
in-memory. The graph snapshots state at every `interrupt()`
boundary; you can pause for a human Friday afternoon and resume Monday
morning from a different process, region, or runtime.
Expand Down
14 changes: 13 additions & 1 deletion docs/how-to/persist-conversations.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ factory):

- `redis_checkpointer(...)` — Redis cluster (OCI Cache with Redis)
- `postgresql_checkpointer(...)` — managed Postgres (OCI Database with PostgreSQL)
- `mysql_checkpointer(...)` — MySQL with the official Connector/Python async driver
- `opensearch_checkpointer(...)` — OpenSearch cluster (OCI Search with OpenSearch)
- `oracle_checkpointer(...)` — Oracle Autonomous Database

The native ones are normal classes — `OCIBucketBackend(...)` and
hand it to `Agent`. The storage-backed ones are the underlying
`RedisBackend` / `PostgreSQLBackend` / etc. wrapped by an adapter; if
`RedisBackend` / `PostgreSQLBackend` / `MySQLBackend` / etc. wrapped by an adapter; if
you instantiate the backend class directly and pass it to `Agent`,
save/load will fail at runtime (the agent calls
`checkpointer.save(state, thread_id)` but backends expose
Expand Down Expand Up @@ -65,6 +66,17 @@ checkpointer = postgresql_checkpointer(
agent = Agent(model="oci:openai.gpt-5.5", tools=[...], checkpointer=checkpointer)
```

MySQL with the official async driver:

```python
from locus.memory.backends import mysql_checkpointer

checkpointer = mysql_checkpointer(
dsn="mysql://locus:locus@db.example.com:3306/locus",
)
agent = Agent(model="oci:openai.gpt-5.5", tools=[...], checkpointer=checkpointer)
```

## 3. Use a stable thread_id

```python
Expand Down
4 changes: 2 additions & 2 deletions docs/img/architecture.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/img/locus-stack.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/notebooks/notebook_52_checkpoint_backends.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ The checkpointer contract is backend-agnostic, but the production
default on OCI is Oracle 26ai — native JSON columns, vector and
text indexes in one schema, and the full capability set
(`list_threads`, `search`, `vacuum`) over a single durable store.
Portable SQL deployments can use PostgreSQL or MySQL through the
same adapter shape; MySQL uses the official Connector/Python asyncio
driver.
Notebook 06 covers the checkpointer contract itself; this notebook
drives it against a real ADB.

Expand Down
96 changes: 89 additions & 7 deletions examples/checkpointer_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,87 @@ async def example_postgresql_backend():


# =============================================================================
# 4. OpenSearchBackend - For search and analytics
# 4. MySQLBackend - For official MySQL deployments
# =============================================================================


async def example_mysql_backend():
"""
MySQLBackend stores state in MySQL with JSON columns.

Use cases:
- Existing MySQL infrastructure
- Official Connector/Python requirement
- ACID guarantees required
- Metadata queries over JSON

Features:
- Official mysql-connector-python asyncio driver
- JSON columns for checkpoint data and metadata
- Connection pooling
- MySQL JSON_CONTAINS metadata queries

Requires: mysql-connector-python and running MySQL server
"""
print("\n" + "=" * 60)
print("4. MySQLBackend Example")
print("=" * 60)

try:
from locus.memory.backends import MySQLBackend

# Create backend
backend = MySQLBackend(
host="localhost",
port=3306,
database="locus_demo",
user="root",
password="",
table_name="agent_checkpoints",
)
print("\nConnecting to MySQL...")

# Or use DSN
# backend = MySQLBackend(
# dsn="mysql://user:pass@localhost:3306/mydb"
# )

# Save with metadata
state = create_sample_state()
data = state.to_checkpoint()
checkpoint_id = await backend.save(
"mysql-thread-1",
data,
metadata={"user_id": "user-123", "session_type": "support"},
)
print(f"Saved checkpoint: {checkpoint_id}")

# Query by metadata
results = await backend.query_by_metadata("user_id", "user-123")
print(f"Found {len(results)} threads for user-123")

# Search by data field
results = await backend.search_data("agent_id", "demo-agent")
print(f"Found {len(results)} threads with demo-agent")

# Get count
count = await backend.count()
print(f"Total checkpoints: {count}")

# Cleanup
await backend.delete("mysql-thread-1")
await backend.close()

except ImportError:
print("\nSkipping: mysql-connector-python package not installed")
print("Install with: pip install mysql-connector-python")
except Exception as e:
print(f"\nSkipping: {e}")
print("Ensure MySQL is running")


# =============================================================================
# 5. OpenSearchBackend - For search and analytics
# =============================================================================


Expand All @@ -263,7 +343,7 @@ async def example_opensearch_backend():
Requires: opensearch-py and running OpenSearch
"""
print("\n" + "=" * 60)
print("4. OpenSearchBackend Example")
print("5. OpenSearchBackend Example")
print("=" * 60)

try:
Expand Down Expand Up @@ -314,7 +394,7 @@ async def example_opensearch_backend():


# =============================================================================
# 5. OCIBucketBackend - For OCI cloud deployments
# 6. OCIBucketBackend - For OCI cloud deployments
# =============================================================================


Expand All @@ -337,7 +417,7 @@ async def example_oci_bucket_backend():
Requires: oci package and OCI credentials
"""
print("\n" + "=" * 60)
print("5. OCIBucketBackend Example")
print("6. OCIBucketBackend Example")
print("=" * 60)

try:
Expand Down Expand Up @@ -390,7 +470,7 @@ async def example_oci_bucket_backend():


# =============================================================================
# 6. Agent with Checkpointing Example
# 7. Agent with Checkpointing Example
# =============================================================================


Expand All @@ -401,7 +481,7 @@ async def example_agent_with_checkpointing():
This shows how to integrate checkpointing with an agent.
"""
print("\n" + "=" * 60)
print("6. Agent with Checkpointing (Full Integration)")
print("7. Agent with Checkpointing (Full Integration)")
print("=" * 60)

from locus.core.messages import Message, Role
Expand Down Expand Up @@ -450,14 +530,15 @@ async def example_agent_with_checkpointing():
print(f" Loaded: {len(loaded.messages)} messages, agent_id={loaded.agent_id}")

# ==========================================================================
# Option 3: Production backends (Redis, PostgreSQL, Oracle, etc.)
# Option 3: Production backends (Redis, PostgreSQL, MySQL, Oracle, etc.)
# ==========================================================================
print("\nOption 3: Production Backends")
print("-" * 40)

print(" Available factory functions:")
print(" - redis_checkpointer(url='redis://localhost:6379')")
print(" - postgresql_checkpointer(host='localhost', database='myapp')")
print(" - mysql_checkpointer(host='localhost', database='myapp')")
print(" - opensearch_checkpointer(hosts=['localhost:9200'])")
print(" - oracle_checkpointer(dsn='mydb_high', user='admin', password='...')")
print(" - oci_bucket_checkpointer(bucket_name='...', namespace='...')")
Expand Down Expand Up @@ -510,6 +591,7 @@ async def main():
await example_memory_checkpointer()
await example_redis_backend()
await example_postgresql_backend()
await example_mysql_backend()
await example_opensearch_backend()
await example_oci_bucket_backend()
await example_agent_with_checkpointing()
Expand Down
4 changes: 3 additions & 1 deletion examples/notebook_52_checkpoint_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
text indexes in one schema, and the full capability set (list_threads,
search, vacuum) over a single durable store. Notebook 06 covers the
checkpointer contract itself; this notebook drives it against a real
ADB.
ADB. Portable SQL deployments can use PostgreSQL or MySQL through the
same adapter shape; MySQL uses the official Connector/Python asyncio
driver.

- Save and load AgentState via oracle_checkpointer.
- Inspect the reported capabilities.
Expand Down
Loading