Metadata-Version: 2.4
Name: guepard-relml
Version: 0.2.1
Summary: RelML — relational deep learning with a natural-language agent over your database.
Keywords: relational,machine-learning,graph-neural-network,graphsage,database,agent,duckdb
Author: Guepard Corp
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: C++
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Project-URL: Homepage, https://github.com/Guepard-Corp/relml
Project-URL: Repository, https://github.com/Guepard-Corp/relml
Project-URL: Issues, https://github.com/Guepard-Corp/relml/issues
Requires-Python: >=3.9
Requires-Dist: duckdb>=0.9
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: pytz
Requires-Dist: anthropic>=0.40
Requires-Dist: prompt_toolkit
Requires-Dist: scikit-learn
Provides-Extra: api
Requires-Dist: fastapi; extra == "api"
Requires-Dist: uvicorn; extra == "api"
Provides-Extra: plots
Requires-Dist: matplotlib; extra == "plots"
Description-Content-Type: text/markdown

# guepard-relml

**RelML** is a natural-language agent over your relational database. You ask a
question in plain English; it inspects your schema, decides what to predict,
trains a model on your data, checks itself against held-out rows, and answers —
no ML code and no feature engineering on your side.

- **CLI:** `relml-agent` — an interactive assistant for your database.
- **Python:** the `Agent` class — the same power, embeddable in your code.

---

## Table of contents

1. [Install](#install)
2. [Configure the model backend](#configure-the-model-backend-aws-bedrock)
3. [Connect your data](#connect-your-data)
4. [Command line](#command-line)
5. [Python API](#python-api)
6. [Embedding in another app](#embedding-in-another-app)
7. [Scaling](#scaling)
8. [How it works](#how-it-works)
9. [Troubleshooting](#troubleshooting)
10. [License](#license)

---

## Install

Requires **Python 3.9+**. Always install into a virtual environment:

```bash
python3 -m venv .venv
source .venv/bin/activate       # Windows: .venv\Scripts\activate
pip install guepard-relml
```

Verify it imported and the CLI is on your PATH:

```bash
python -c "import guepard.qwery.relml._relml_core as c; print('core ok:', hasattr(c, 'train'))"
relml-agent --help
```

> **Debian/Ubuntu:** if `pip install` prints `error: externally-managed-environment`,
> you skipped the virtual environment. The `venv` steps above are the fix — do
> **not** use `--break-system-packages`.

---

## Configure the model backend (AWS Bedrock)

The agent is powered by **Claude on AWS Bedrock**. Provide credentials as
environment variables, or put them in a `.env` file in the directory you run
`relml-agent` from:

```bash
export AWS_BEARER_TOKEN_BEDROCK=your-bedrock-api-key
export AWS_REGION=us-east-1
export RELML_AGENT_MODEL=us.anthropic.claude-sonnet-4-5-20250929-v1:0
```

| variable | purpose |
|---|---|
| `AWS_BEARER_TOKEN_BEDROCK` | **required** — your Bedrock API key (AWS console → Bedrock → *API keys*) |
| `AWS_REGION` | the region your Bedrock access is in (default `us-east-1`) |
| `RELML_AGENT_MODEL` | the Bedrock model id to use |
| `RELML_AGENT_BACKEND` | optional — set to `bedrock` to be explicit (auto-selected when the token is present) |

Before the first run, open the Bedrock console → **Model access** and make sure
the Claude model above is **enabled** for your region.

**Other backends.** RelML can also use the Anthropic API directly
(`RELML_AGENT_BACKEND=anthropic`, `ANTHROPIC_API_KEY=…`) or Ollama
(`RELML_AGENT_BACKEND=ollama`, `OLLAMA_API_KEY=…`).

---

## Connect your data

Tell RelML where your data lives via `--source` (CLI) or the first argument to
`Agent(...)` (Python). Three source types are supported.

### 1. A PostgreSQL database

Pass a connection string — libpq keyword form **or** a URL. The database is
opened **read-only**; RelML never writes to it.

```bash
relml-agent --source "dbname=mydb host=localhost user=me password=secret"
relml-agent --source "postgresql://me:secret@localhost:5432/mydb"
```

The first Postgres run downloads DuckDB's `postgres` extension, so it needs
network access once.

### 2. A folder of CSV / Parquet files

Every `.csv` / `.parquet` file in the folder becomes a table (named after the
file). Great for quick experiments.

```bash
relml-agent --source ./my_data
```

### 3. A single CSV / Parquet file

```bash
relml-agent --source ./sales.parquet
```

---

## Command line

`relml-agent` has two modes.

**Interactive** — omit the question to open a REPL you can converse with:

```bash
relml-agent --source ./my_data
```

**One-shot** — pass a question to get a single answer and exit:

```bash
relml-agent "which customers are most likely to churn next month?" --source ./my_data
```

Run `relml-agent --help` for the full flag list.

### REPL commands

Inside the interactive session, type a question, or a `/command` (these inspect
state without spending model calls):

| command | what it does |
|---|---|
| `/tables` | list tables — row counts, primary/foreign keys, detected column types |
| `/schema [table]` | show columns, types, and keys (all tables, or just one) |
| `/sql <query>` | run a **read-only** SQL query and print the rows |
| `/models` | models trained this session, with their held-out metrics |
| `/model <id>` | full detail on one model (features used, hyper-parameters) |
| `/predict <id> [k]` | run a trained model; show the top-k predictions |
| `/evaluate <id>` | critique a model against leakage-free baselines |
| `/plot` | terminal chart of actual vs predicted |
| `/source <src>` | connect to a different database (resets models) |
| `/help` | list all commands |
| `/quit` | exit |

### A typical session

```
$ relml-agent --source ./ecommerce
› /tables
  customers (12,043 rows, pk customer_id)
  orders    (98,220 rows, pk order_id, fk customer_id → customers)
  ...
› will customer 5512 order again in the next 30 days?
  [the agent explores the data, trains a model, and answers with a probability]
› /plot
  [actual vs predicted over the backtest]
› /quit
```

---

## Python API

```python
from guepard.tools.agent import Agent

# source: a CSV/Parquet folder, a single file, or a Postgres connection string
agent = Agent("./my_data")

answer = agent.ask("Forecast next week's daily order volume.")
print(answer)
```

**Quiet mode** — suppress the live progress output (useful in scripts/services):

```python
agent = Agent("./my_data", verbose=False)
print(agent.ask("Rank customers by churn risk."))
```

**Choose the backend/model in code** (overrides the environment):

```python
from guepard.tools.agent import Agent, LLMClient

client = LLMClient(backend="bedrock",
                   model="us.anthropic.claude-sonnet-4-5-20250929-v1:0")
agent = Agent("dbname=mydb host=localhost user=me password=secret", client=client)
print(agent.ask("Which drivers are most at risk of a DNF next race?"))
```

**`Agent(...)` options**

| argument | default | meaning |
|---|---|---|
| `source` | — | CSV/Parquet folder or file, or a Postgres connection string |
| `verbose` | `True` | stream the agent's progress to the terminal |
| `client` | auto | an `LLMClient` to control backend/model/region |
| `max_steps` | `40` | max reasoning/tool steps per question |
| `max_tokens` | `4096` | max tokens per model call |
| `pg_schema` | `None` | for Postgres, restrict to a specific schema |

`agent.ask(question: str) -> str` returns the final natural-language answer.

---

## Embedding in another app

RelML gives you three integration surfaces — pick by where the client lives.

### In-process (Python) — the `on_event` callback

Pass a callback to `Agent(...)` and receive every step as it happens — wire it to
your logs, a UI, or a progress bar:

```python
from guepard.tools.agent import Agent

def on_event(event: str, data: dict):
    # event: "text" | "tool_call" | "tool_result" | "error" | "connected"
    # data:  {"agent": "...", "name": <tool>, "text": "...", ...}
    my_logger.info("relml", event=event, **data)

agent = Agent("./data", on_event=on_event, verbose=False)   # verbose=False: don't also print
answer = agent.ask("Which customers will churn?")
```

`text` is the agent's reasoning/answer as it streams; `tool_call` / `tool_result`
mark each step it takes (`run_sql`, `train_model`, `predict`, …).

### Subprocess (any language) — `--json`

Emits **newline-delimited JSON** events on stdout, then a final `result`
(`stderr` is logs). Good for spawning from Node/Go/etc.:

```bash
relml-agent --json --source ./data "Which customers will churn?"
```

### Long-lived sidecar — `relml-serve`

A persistent **JSON-RPC service over stdin/stdout** (LSP-style
`Content-Length: N\r\n\r\n<json>` framing, `stderr` = logs). The host spawns it
once and drives it:

- **methods:** `initialize`, `predict`, `plot`, `infer`, `list_models`,
  `explain`, `delete_model`, `cancel`, `shutdown`
- **streaming `progress` notifications:** `{ requestId, event, … }` with
  `event ∈ connected | text | tool_call | tool_result | error`
- keeps a **warm session** (DB + model registry) across requests; supports
  **cancel**

`predict` / `infer` / `plot` run the LLM agent; `list_models` / `explain` /
`delete_model` are **deterministic** (no LLM) and read the persisted model
registry — so they can be served statelessly (see [Scaling](#scaling)).

---

## Scaling

RelML requests are heavy and long-running (an LLM agent loop **plus** C++ model
training). The scalable shape is a **queue-backed worker pool** with progress
fanned out over **pub/sub**, feeding a **shared model registry** that a separate
**stateless serve tier** reads.

- **Split train from serve.** `predict` / `ask` (LLM + training) → async jobs on
  an autoscaled **worker pool**. `list_models` / `explain` / prediction-by-model
  (no LLM) → **stateless replicas**. *Train once, serve many* — RelML fingerprints
  each task, so a repeat question reuses the trained model instead of retraining.
- **Externalize the registry.** Trained models persist under **`RELML_HOME`**
  (default `~/.relml`). Point it at **shared storage** (a shared volume / object
  store) so any replica loads any model — this is what makes the serve tier
  stateless.
- **One agent per process.** The orchestration is synchronous (GIL) — scale by
  process/container count, not threads. Set **`OMP_NUM_THREADS`** so the C++
  trainer's BLAS threads don't oversubscribe CPU when you pack workers.
- **Bound Bedrock concurrency.** It is your rate-limit and cost ceiling — cap the
  number of concurrent `predict` loops (queue concurrency).
- **Stream over pub/sub, not a direct socket.** Workers publish the
  `on_event` / `progress` stream to a topic keyed by `requestId`; a gateway
  relays it to the client over WebSocket/SSE. It survives worker restarts and
  fans out to multiple viewers.

```
 client ──POST /job──►  gateway ──enqueue──►  queue ──►  worker pool (N, autoscaled)
        ◄──WebSocket──   (stateless)                        Agent(on_event=publish)
              ▲                                                    │
              └──────────── pub/sub (per requestId) ◄─────────────┘
                                                     trained model ─► RELML_HOME (shared)
                                                                        │
                                       stateless serve tier ◄───────────┘  list_models / explain
```

---

## How it works

From one question, RelML runs a loop: **describe** your schema and key graph →
**explore** the data with read-only SQL → **frame** a supervised task (target,
features, train/validation split) → **train** a model → **evaluate** it against
held-out rows and leakage-free baselines → **iterate** until the gains are
marginal → **answer** you in plain language. Predictions can be written back as a
queryable table so you can inspect them with `/sql`.

---

## Troubleshooting

| symptom | fix |
|---|---|
| `error: externally-managed-environment` | you skipped the venv — see [Install](#install). |
| `no credentials found …` | set `AWS_BEARER_TOKEN_BEDROCK` (and `AWS_REGION`), or another backend's key. |
| Bedrock `AccessDenied` / model errors | enable the model in Bedrock → *Model access* for your region, and check `AWS_REGION`. |
| `No .csv/.parquet files found in …` | point `--source` at a folder that actually contains `.csv`/`.parquet` files, or at a single file. |
| Postgres connection fails | verify the DSN; the DB must be reachable and the first run needs network to fetch the `postgres` extension. |
| `command not found: relml-agent` | activate the venv where you installed it (`source .venv/bin/activate`). |

---

## License

MIT
