Metadata-Version: 2.4
Name: cyberian-client
Version: 0.2.6
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 attesting that the inference was
correctly executed and independently verified. The receipt is self-contained: 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

result = client.submit_and_wait(
    model="bge-large-v1.5",
    inputs=[
        "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, 1024) for BGE-large
print("first vec:   ", result.embeddings[0, :8])
```

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

```python
job = client.submit_job(model="bge-large-v1.5", inputs=["a", "b", "c"])

# Poll yourself, or use wait_for_completion:
final = client.wait_for_completion(job["id"], 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
```

## Models

Every job names a model (`model="..."`). The models enabled for your
account are listed on your [account dashboard](https://cyberiansystems.ai/account),
or programmatically:

```python
for m in client.list_models():
    print(m["id"], "—", m["name"])
```

`list_models()` returns a list of descriptors; the exact fields are stable
across releases but may grow over time, so dereference by name rather than
position.

Need a model that isn't enabled for you? Email
<support@cyberiansystems.ai> with the model reference (e.g. a Hugging
Face URL). Onboarding a new model is a configuration step on our
side — no code change on yours.

## Verification as a Service (VaaS)

You ran inference on your own infrastructure. Cyberian independently verifies the
output you computed and issues a receipt certifying it. Useful for compliance —
you keep the inference, we provide independent auditable attestation.

```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(
    model="bge-large-v1.5",
    inputs=["text"],
    claimed_output_commitment=my_commitment,
)
# Raises VerificationFailedError if our independent verification disagrees with
# the commitment you claimed.
```

VaaS is currently a single-call API. Per-request limits depend on your
account — the platform returns an `inputs_too_large` error with your
current cap if you exceed it.

## Receipt fields

The receipt your jobs / VaaS calls return is a self-contained, hash-chained object:

| Field                       | Meaning                                                           |
|-----------------------------|-------------------------------------------------------------------|
| `receipt_id`                | UUID of this receipt.                                             |
| `job_id`                    | UUID of the underlying job.                                       |
| `spec_hash`                 | SHA-256 commitment to the execution spec used.                    |
| `inputs_root`               | Merkle root over the inputs you submitted.                        |
| `outputs_root`              | Merkle root over the outputs that were produced.                  |
| `verification_attestation`  | Merkle root committing to the independent verification work.      |
| `executor_attestation_ids`  | Anonymized identifiers of the providers that executed the batch.  |
| `issued_at`                 | UTC ISO-8601 timestamp.                                           |
| `receipt_hash`              | SHA-256 of the entire receipt body — self-referential check.      |

## 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
    NetworkError,             # transport-level (no HTTP response); wait_for_completion retries automatically
    ApiError,                 # any other 4xx/5xx
    CyberianError,            # base of everything above
)

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

## Trial limits

| | 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 inputs per request | 1000 | 500 |

A "chunk" is the platform's internal billing unit (one batched inference). The
platform chooses how to group your inputs into chunks. Counting chunks (not raw
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
