# Ezop Python SDK

Ezop tracks the lifecycle of your AI agents — registrations, versions, and runs — so you have full observability across every deployment.

## Installation

```bash
pip install ezop
```

## Configuration

```bash
export EZOP_API_KEY=your-ezop-api-key-here
export EZOP_API_URL=https://api.ezop.ai
```

---

## Usage

### Initialize the agent

```python
from ezop import Agent

agent = Agent.init(
    name="customer-support-bot",
    owner="growth-team",
    version="v0.3",
    runtime="langchain",
    description="Handles tier-1 customer support tickets",
    default_permissions=["read:tickets"],
    permissions=["read:tickets", "write:replies"],
    changelog="Switched to new retrieval pipeline",
)
```

Call `Agent.init()` once at startup. It is safe to call on every deployment:

- If the agent does not exist, it will be created on the platform.
- If the agent already exists, registration returns the existing agent.
- If a new `version` is provided, the platform registers it as a new version under the same agent. If the version already exists, version registration is also a no-op.

### Track runs

Wrap each invocation of your agent with `start_run()` / `end_run()`:

```python
agent.start_run()

try:
    result = agent.run(user_input)
    agent.end_run(
        status="completed",
        total_tokens=result.usage.total_tokens,
        total_cost=result.cost,
        metadata={"user_id": user_id},
    )
except Exception as e:
    agent.end_run(status="failed", message=str(e))
    raise
```

---

## API Reference

### `Agent.init()`

Registers the agent and its version with the Ezop platform, and returns an `Agent` instance.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | `str` | Yes | Agent name. Together with `owner`, uniquely identifies the agent on the platform. |
| `owner` | `str` | Yes | Team or user that owns the agent. |
| `version` | `str` | Yes | Version string (e.g. `"v1.2.0"`). A new version is registered if it does not exist yet. |
| `runtime` | `str` | Yes | Runtime or framework used (e.g. `"langchain"`, `"crew"`, `"custom"`). |
| `description` | `str` | No | Human-readable description of the agent. |
| `default_permissions` | `list[str]` | No | Permissions granted to all versions of this agent by default. |
| `permissions` | `list[str]` | No | Permissions granted to this specific version. |
| `changelog` | `str` | No | Description of what changed in this version. |

---

### `agent.start_run()`

Creates a new run record with status `running`. Call this at the start of each agent invocation.

```python
agent.start_run()
```

---

### `agent.end_run()`

Ends the current run and records its outcome.

```python
agent.end_run(
    status="completed",
    total_tokens=350,
    total_cost=0.007,
    message=None,
    metadata={"user_id": "u-123"},
)
```

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | `str` | Yes | Final status of the run. Typically `"completed"` or `"failed"`. |
| `total_tokens` | `int` | No | Total number of tokens consumed. |
| `total_cost` | `float` | No | Total cost of the run in USD. |
| `message` | `str` | No | Human-readable message describing the outcome, e.g. a failure reason. |
| `metadata` | `dict` | No | Any arbitrary JSON-serialisable data you want to attach to the run (e.g. user context, request identifiers, feature flags). |

---

## Logging

The SDK uses Python's standard `logging` module under the `ezop` namespace. To enable logs in your application:

```python
import logging
logging.getLogger("ezop").setLevel(logging.DEBUG)
```
