Metadata-Version: 2.5
Name: ai-decisions
Version: 0.2.0
Summary: Official Python SDK for the AI DECISIONS Compliance API
Project-URL: Homepage, https://aidecisions.ai
Project-URL: Documentation, https://aidecisions.ai/docs
Project-URL: Repository, https://github.com/ai-decisions
License-Expression: MIT
Requires-Python: >=3.9
Requires-Dist: requests>=2.28
Description-Content-Type: text/markdown

# AI DECISIONS Python SDK

Official Python client for the AI DECISIONS Compliance API.

## Installation

```bash
pip install ai-decisions
```

## Quick Start

```python
from ai_decisions import AiDecisionsClient

client = AiDecisionsClient(api_key="your-api-key")

# Address screening — the billed unit
# (RESEARCH 25/mo free, ANALYST 500/mo, ENTERPRISE 10,000/mo)
verdict = client.screen("ethereum", "0x8589427373D6D84E98730D7795D8f6f8731FDA16")

print(verdict["risk_score"])      # 0.0 - 1.0 (None on unserved chains)
print(verdict["risk_tier"])       # 1 - 5
print(verdict["category"])        # e.g. "mixer", "exchange", "personal"
print(verdict["sanctions_hit"])   # True on OFAC SDN addresses
print(verdict["mixer_exposure"])  # {"direct": ..., "mixer_names": [...], ...}

# Chains: ethereum, tron, bitcoin, arbitrum, base, gnosis

# Similar wallets (ENTERPRISE) — guilt-by-association over GNN embeddings
similar = client.similar("ethereum", "0x8589427373D6D84E98730D7795D8f6f8731FDA16", top_k=5)
print(similar["neighbours"])      # [{"address", "chain", "similarity", "label", "category"}]

# Transaction risk scoring
result = client.transaction_check(
    amount=150_000,
    sender="Acme Corp",
    receiver="Shell Ltd",
    sender_jurisdiction="US",
    receiver_jurisdiction="CY",
    currency="USD",
)

print(result["risk_score"])       # 0.0 - 1.0
print(result["risk_level"])       # "low" | "medium" | "high" | "critical"
print(result["risk_factors"])     # [{"rule": ..., "detail": ..., "severity": ...}]
print(result["recommendation"])   # "APPROVE" | "REVIEW" | "ESCALATE" | "BLOCK"

# AI-agent detection
detection = client.agent_detection([
    {"timestamp": "2026-01-15T10:00:00", "amount": 500, "sender": "w1", "receiver": "w2"},
    {"timestamp": "2026-01-15T10:01:00", "amount": 500, "sender": "w1", "receiver": "w3"},
    {"timestamp": "2026-01-15T10:02:00", "amount": 500, "sender": "w1", "receiver": "w4"},
])

print(detection["agent_probability"])  # 0.0 - 1.0
print(detection["classification"])     # "likely_human" | "likely_agent"
print(detection["indicators"])         # [{"indicator": ..., "detail": ..., "score": ...}]
```

## Error Handling

The SDK raises typed exceptions for common HTTP errors:

```python
from ai_decisions import (
    AiDecisionsClient,
    AiDecisionsError,
    AuthenticationError,
    RateLimitError,
    ValidationError,
)

client = AiDecisionsClient(base_url="https://api.example.com", api_key="key")

try:
    result = client.transaction_check(amount=100, sender="A", receiver="B")
except AuthenticationError:
    # 401 - invalid or missing API key
    print("Check your API key")
except RateLimitError as exc:
    # 429 - rate limit exceeded (after automatic retries)
    print(f"Rate limited. Retry after {exc.retry_after}s")
except ValidationError:
    # 422 - invalid request payload
    print("Check request parameters")
except AiDecisionsError as exc:
    # Any other API error
    print(f"API error (HTTP {exc.status_code}): {exc}")
```

## Configuration

| Parameter     | Type   | Default | Description                              |
| ------------- | ------ | ------- | ---------------------------------------- |
| `base_url`    | `str`  | -       | API base URL                             |
| `api_key`     | `str`  | `""`    | API key (sent as `X-API-Key`)            |
| `timeout`     | `int`  | `30`    | Request timeout in seconds               |
| `max_retries` | `int`  | `3`     | Max retries on 429 Too Many Requests     |

## Retry Behavior

The SDK automatically retries requests that receive a `429 Too Many Requests` response.
It respects the `Retry-After` header if present, otherwise uses exponential backoff
(`2^attempt` seconds). After `max_retries` attempts, a `RateLimitError` is raised.
