Metadata-Version: 2.4
Name: chox-ai-sdk
Version: 0.1.0
Summary: Python SDK for Chox - AI governance proxy
Author: Chox
License: MIT
Project-URL: Homepage, https://chox.ai
Project-URL: Source, https://github.com/Deogan7/Chox
Keywords: chox,ai,governance,proxy,agent,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

# chox-sdk

Python SDK for [Chox](https://chox.ai) — AI governance proxy. Evaluate AI tool calls before execution to prevent unintended financial operations, data deletions, and other risky actions.

## Why Chox?

As AI agents gain access to external APIs (Stripe, Slack, SQL), they need governance. Chox sits between your agent and those APIs to:

- **Evaluate** every tool call (financial operations, data deletions, message sends, etc.)
- **Classify** the action type and risk level
- **Return a verdict** — allow, block, escalate, or warn — before the agent proceeds
- **Log** all activity for audit trails

This SDK wraps the `POST /api/v1/evaluate` endpoint with a clean API, automatic retry on network failures (fail-open), and precise type hints.

## Install

```bash
pip install chox-sdk
```

## Quickstart

```python
from chox import ChoxClient

chox = ChoxClient(
    base_url="https://chox.example.com",
    token="chox_token_...",
)

# Evaluate before a risky operation
verdict = chox.evaluate(
    tool="stripe.create_charge",
    arguments={"amount": 5000, "currency": "USD"},
    context={"user_id": "user_123"},
)

if verdict.verdict == "allow":
    # Safe to proceed
    stripe.Charge.create(amount=5000, currency="USD")
elif verdict.verdict == "block":
    raise ValueError(f"Action blocked: {verdict.reason}")
elif verdict.verdict == "escalate":
    # Requires human approval
    send_to_approval_queue(verdict.reason)
```

## Configuration

```python
chox = ChoxClient(
    base_url="https://chox.example.com",  # Required: Your Chox gateway URL
    token="chox_token_...",               # Required: Caller token or admin key
    fail_open=True,                       # Optional: Default True. If Chox is unreachable, return allow verdict
    timeout=5.0,                          # Optional: Default 5.0 seconds. Request timeout
)
```

### Authentication

- **Caller token** (`chox_token_...`): Use this in production. Tied to a specific AI system in Chox, can only evaluate with that token.
- **Admin key** (`chox_admin_...`): Use this for setup/testing. Can manage projects, integrations, and callers, but not recommended for ongoing agent evaluation.

## Verdicts

The `evaluate()` method returns an `EvaluateResponse` dataclass with these fields:

```python
from chox import EvaluateResponse

verdict: EvaluateResponse = chox.evaluate(...)

# Fields:
verdict.request_id          # Unique request ID for audit logging
verdict.verdict             # "allow" | "block" | "escalate" | "warn"
verdict.action_type         # "read" | "write" | "delete" | "financial" | "unknown"
verdict.risk_score          # 0 (safe) to 1 (critical)
verdict.reason              # Human-readable explanation
verdict.evaluated_at        # ISO 8601 timestamp
```

**Verdict meanings:**
- `allow` — Safe to proceed
- `block` — Blocked by policy; do not proceed
- `escalate` — Requires human approval (e.g., large transfer)
- `warn` — Proceed with caution; log prominently

## Error Handling

```python
from chox import ChoxClient, ChoxError, ChoxNetworkError

chox = ChoxClient(base_url="...", token="...")

try:
    verdict = chox.evaluate(tool="stripe.create_charge")
except ChoxError as e:
    # API returned non-2xx status
    print(f"Chox API error {e.status}: {e.body}")
except ChoxNetworkError as e:
    # Network timeout or unreachable
    print(f"Network error: {e}")
    if e.cause:
        print(f"Caused by: {e.cause}")
```

**Note:** If `fail_open=True` (default), network errors and timeouts return an allow verdict instead of raising, so your agent never gets blocked by Chox being temporarily down.

## API Reference

### Evaluate

```python
verdict = chox.evaluate(
    tool: str,                              # Dot-notation tool name, e.g., "stripe.create_charge"
    arguments: dict[str, Any] | None = None,  # Tool arguments as JSON
    caller_token: str | None = None,       # Optional override caller token
    context: dict[str, Any] | None = None, # Optional context (user_id, session, etc.)
)
```

### Projects

```python
chox.projects.create(name=..., slug=...)   # Create a project; returns raw admin key once
chox.projects.get()                        # Get authenticated project
```

### Callers (AI Systems)

```python
chox.callers.create(name=..., description="")  # Register an AI system; returns raw token once
chox.callers.list()                            # List all callers
chox.callers.delete(id)                        # Remove a caller
```

### Integrations

```python
chox.integrations.create(                  # Register an external API
    name="stripe",
    integration_type="http",              # "http" or "mcp"
    destination_url="https://api.stripe.com",
)
chox.integrations.list()                   # List all integrations
chox.integrations.delete(id)               # Remove an integration
```

### Logs

```python
chox.logs.list(                            # Query evaluation logs
    caller_id=None,
    integration=None,
    action_type=None,
    start=None,     # ISO 8601 timestamp
    end=None,       # ISO 8601 timestamp
    limit=None,
    offset=None,
)
chox.logs.get(id)                          # Get a specific log entry
```

### Stats

```python
chox.stats.actions(start=None, end=None)      # Breakdown by action type
chox.stats.hourly(start=None, end=None)       # Hourly activity counts
chox.stats.integrations(start=None, end=None) # Per-integration traffic
chox.stats.total()                            # Total request count
```

## Type Hints

This SDK is fully typed for use with `mypy`, `pyright`, and other type checkers.

```python
from chox import ChoxClient, EvaluateResponse

chox: ChoxClient = ChoxClient(base_url="...", token="...")
verdict: EvaluateResponse = chox.evaluate(tool="stripe.create_charge")

# Type checker catches mismatches:
if verdict.verdict == "invalid":  # ✗ mypy: Type '"invalid"' is not assignable to '"allow" | "block" | "escalate" | "warn"'
    pass
```

## License

MIT
