Metadata-Version: 2.4
Name: cyberian-client
Version: 0.1.0
Summary: Python client for the Cyberian Systems verified-inference API
Author-email: Cyberian Systems <philippe@cyberiansystems.ai>
License: Proprietary
Project-URL: Homepage, https://cyberiansystems.ai
Project-URL: Documentation, https://cyberiansystems.ai/docs
Project-URL: Support, https://cyberiansystems.ai/docs
Keywords: ai,ml,verified-inference,merkle,embeddings,cyberian
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary 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: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: httpx<1.0,>=0.27.0
Requires-Dist: numpy<3.0,>=1.26.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"

# cyberian-client

Python client for the [Cyberian Systems](https://cyberiansystems.ai) verified-inference API.

Each call returns embeddings + a cryptographic receipt that proves an independent prover
re-executed a sample of your batch and got bitwise-identical results. The receipt is
self-verifying: any third party can validate it without access to the platform.

## Install

```bash
pip install cyberian-client
```

Requires Python 3.9+. Pulls in `httpx` and `numpy`.

## Get an API key

[https://cyberiansystems.ai/signup](https://cyberiansystems.ai/signup) — 14-day free
trial, no card required. The plaintext key is shown once at signup; save it. We store
only its SHA-256.

## Quickstart — one shot

```python
from cyberian import Client

client = Client(api_key="cyb_trial_…")  # or set CYBERIAN_API_KEY in env and pass it in

result = client.submit_and_wait(
    spec_yaml=open("spec.yaml").read(),
    input_texts=[
        "The property title search revealed no encumbrances.",
        "Quarterly compliance attestation per SOX 404.",
    ],
)

print("receipt_hash:", result.receipt["receipt_hash"])
print("verified:    ", result.verification["valid"])  # True
print("shape:       ", result.embeddings.shape)        # (2, 384) for BGE-small
print("first vec:   ", result.embeddings[0, :8])
```

## Step-by-step — when you need finer control

```python
job = client.submit_job(spec_yaml="spec.yaml", input_texts=["a", "b", "c"])

# Poll yourself, or use wait_for_completion:
final = client.wait_for_completion(job["id"], poll_interval_sec=2.0, timeout_sec=600)

receipt      = client.get_receipt(final["receipt_id"])
verification = client.verify_receipt(final["receipt_id"])
embeddings   = client.get_job_output(final["id"])  # numpy ndarray, float32
```

## Verification as a Service (VaaS)

You ran inference on your own infrastructure. Cyberian re-runs it and certifies the
SHA-256 commitment of your output matches. Useful for compliance — you keep the
inference, we provide independent auditable verification.

```python
import hashlib

# Your in-house inference output:
my_embeddings_bytes = my_pipeline.run(["text"]).astype("float32").tobytes()
my_commitment = hashlib.sha256(my_embeddings_bytes).hexdigest()

receipt = client.verify_outputs(
    spec_yaml="spec.yaml",
    input_texts=["text"],
    claimed_output_commitment=my_commitment,
)
# Raises VerificationFailedError if our prover's re-execution doesn't match yours.
```

Phase 2: VaaS is single-chunk only — `len(input_texts) <= spec.chunking.chunk_size`.

## Account management

```python
info = client.get_account()
print(info["tier"], info["effective_tier"], info["subscription_status"])
print(info["chunks_consumed_period"], "/", info["limits"]["chunks_per_period"])

# Mint an additional key (old one stays valid until you revoke it)
new_key = client.rotate_key()

# Revoke a specific key by its 12-char key_id (the prefix shown in /account)
client.revoke_key(key_id="a1b2c3d4e5f6")
```

## Error handling

Typed exceptions; catch the most specific one you care about.

```python
from cyberian import (
    Client,
    AuthError,            # 401, 403
    TrialExpiredError,    # 402 — email upgrade@cyberiansystems.ai
    QuotaError,           # 402 / 413
    RateLimitError,       # 429 — has .retry_after_sec
    ServiceBusyError,     # 503 — has .retry_after_sec
    JobFailedError,       # job ended in FAILED state during wait_for_completion
    VerificationFailedError,  # /verify returned valid=False
    ApiError,             # any other 4xx/5xx
    CyberianError,        # base of everything above
)

try:
    result = client.submit_and_wait(spec_yaml=…, input_texts=[…])
except RateLimitError as exc:
    time.sleep(exc.retry_after_sec)
    result = client.submit_and_wait(spec_yaml=…, input_texts=[…])
except TrialExpiredError:
    print("Email upgrade@cyberiansystems.ai for an extension or enterprise tier.")
    raise
```

## Trial limits (Phase 2)

| | trial (default) | free (post-trial) |
|---|---|---|
| Period | 14 days | 30 days |
| Chunks per period | 400 | 100 |
| Chunks per day | 100 | 25 |
| Requests per minute | 60 | 10 |
| Max chunks per request | 100 | 50 |
| Max input texts | 1000 | 500 |

A "chunk" is one ONNX inference unit, sized by your CES `chunking.chunk_size`. With
`chunk_size: 1` each input text is its own chunk; with `chunk_size: 100` a 1000-text
batch is 10 chunks. Counting chunks (not requests) means the quota tracks actual
compute consumption.

## Documentation

- API + SDK reference: <https://cyberiansystems.ai/docs>
- Trial terms: <https://cyberiansystems.ai/terms>
- Privacy: <https://cyberiansystems.ai/privacy>
- Issues / support: support@cyberiansystems.ai
- Upgrade / enterprise inquiries: upgrade@cyberiansystems.ai

## Patents

The verification mechanism (Canonical Execution Specification, Merkle receipts,
sample-and-replay verification with game-theoretic deterrence, the four-tuple binding)
is covered by a U.S. provisional patent. Use of this client does not grant any patent
license beyond what's needed to call the API as documented.
