Metadata-Version: 2.4
Name: cluster-sdk
Version: 0.1.0
Summary: Python SDK for Cluster Protocol — Decentralized AI Inference Gateway
Project-URL: Homepage, https://clusterprotocol.ai
Project-URL: Repository, https://github.com/clusterprotocol/cluster-sdk-python
Project-URL: Documentation, https://docs.clusterprotocol.ai/sdk/python
Author-email: Cluster Protocol <dev@clusterprotocol.ai>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai,cluster,decentralized,inference,llm,openai
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
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: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0
Requires-Dist: typing-extensions>=4.7
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-httpx>=0.22; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Description-Content-Type: text/markdown

# Cluster Protocol Python SDK

Python SDK for the [Cluster Protocol](https://clusterprotocol.ai) Decentralized AI Inference Gateway. OpenAI-compatible API with typed responses, automatic retries, and async support.

## Installation

```bash
pip install cluster-sdk
```

## Quick Start

```python
from cluster_sdk import ClusterClient

client = ClusterClient(api_key="cp_your_key_here")

response = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V3",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
```

## Streaming

```python
stream = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V3",
    messages=[{"role": "user", "content": "Write a poem"}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")
```

## Embeddings

```python
result = client.embeddings.create(
    input="The quick brown fox jumps over the lazy dog",
    model="BAAI/bge-large-en-v1.5",
)
print(f"Dimensions: {len(result.data[0].embedding)}")

# Batch embedding
result = client.embeddings.create(
    input=["First sentence", "Second sentence"],
    model="BAAI/bge-large-en-v1.5",
)
for emb in result.data:
    print(f"[{emb.index}] {len(emb.embedding)}d vector")
```

## Dataset Marketplace

```python
# Browse datasets
listing = client.datasets.list(search="sentiment", category="nlp")
for ds in listing.datasets:
    print(f"{ds.name} — {ds.pricingType} — {ds.downloadCount} downloads")

# Get dataset details
dataset = client.datasets.get("imdb-reviews-v2")
print(f"{dataset.name}: {dataset.description}")

# Purchase a dataset
receipt = client.datasets.purchase(dataset.id)
print(f"Purchase status: {receipt.status}")

# Check access
access = client.datasets.check_access(dataset.id)
print(f"Has access: {access.hasAccess}")
```

## Async Client

```python
import asyncio
from cluster_sdk import AsyncClusterClient

async def main():
    async with AsyncClusterClient(api_key="cp_your_key_here") as client:
        # Chat
        response = await client.chat.completions.create(
            model="deepseek-ai/DeepSeek-V3",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        print(response.choices[0].message.content)

        # Embeddings
        emb = await client.embeddings.create(
            input="Hello world",
            model="BAAI/bge-large-en-v1.5",
        )
        print(f"Embedding dim: {len(emb.data[0].embedding)}")

        # Datasets
        listing = await client.datasets.list(search="finance")
        print(f"Found {listing.pagination.total} datasets")

asyncio.run(main())
```

## Models & Balance

```python
# List models
for model in client.models.list():
    print(f"{model.id}: {model.owned_by}")

# Check balance
balance = client.balance.get()
print(f"${balance.usd:.2f}")

# Usage history
usage = client.usage.get()
print(f"Total cost: ${usage.total_cost:.4f}")
```

## Error Handling

```python
from cluster_sdk import ClusterClient
from cluster_sdk.exceptions import (
    AuthenticationError,
    InsufficientBalanceError,
    RateLimitError,
    ModelNotFoundError,
)

try:
    response = client.chat.completions.create(
        model="deepseek-ai/DeepSeek-V3",
        messages=[{"role": "user", "content": "Hello"}],
    )
except AuthenticationError:
    print("Invalid API key — check your cp_ key")
except InsufficientBalanceError:
    print("Top up your balance at clusterprotocol.ai")
except RateLimitError as e:
    print(f"Rate limited: {e}")  # Auto-retried with Retry-After header
except ModelNotFoundError:
    print("Model not found — check client.models.list()")
```

Rate-limited (429) and server error (5xx) requests are automatically retried with exponential backoff. The SDK respects the `Retry-After` header when present.

## Configuration

| Parameter | Env Variable | Default |
|-----------|-------------|---------|
| `api_key` | `CLUSTER_API_KEY` | — |
| `base_url` | `CLUSTER_BASE_URL` | `https://api.clusterprotocol.ai` |
| `timeout` | — | `60s` |
| `max_retries` | — | `3` |

## License

Apache-2.0
