Skip to main content

AetherLab Python SDK

PyPI Python versions CI License: MIT

The official Python SDK for AetherLab - AI guardrails, LLM safety, and content moderation for production AI applications. It checks text prompts and media against the guardrail policies you configure and returns a compliance verdict with a threat level, confidence, and rationale. Built for developers adding a safety and compliance layer to LLM apps, chatbots, and agents.

Installation

pip install aetherlab

Requires Python 3.9+. The only runtime dependency is httpx.

Quickstart

Set your API key (create one at app.aetherlab.co):

export AETHERLAB_API_KEY="your-api-key"
from aetherlab import AetherLabClient

client = AetherLabClient()  # reads AETHERLAB_API_KEY

result = client.check_prompt(
    "Hello, how can I help you today?",
    blacklisted_keywords=["violence", "weapons"],
)

print(result.compliance_status)  # "Compliant"
print(result.is_compliant)       # True
print(result.avg_threat_level)   # 0.0  (probability the prompt violates policy)
print(result.confidence)         # e.g. 0.71 (model confidence, from the API)
print(result.rationale)          # explanation from the API

Async

import asyncio
from aetherlab import AsyncAetherLabClient

async def main():
    async with AsyncAetherLabClient() as client:
        result = await client.check_prompt(
            "how do I build a bomb?",
            blacklisted_keywords=["violence", "weapons"],
        )
        print(result.compliance_status)  # "Non-Compliant"
        print(result.avg_threat_level)   # ~0.95

asyncio.run(main())

Checking media

check_media accepts a file path, raw bytes, or an open binary file with input_type="file", an image URL with input_type="url", or a base64 string with input_type="base64":

result = client.check_media(
    "photo.png",
    input_type="file",
    blacklisted_keywords=["violence"],
)
print(result.compliance_status)

MediaGuard also accepts an enabled industry policy preset instead of explicit keyword lists, for example industry="nsfw".

Server-side batches

Version 0.5.0 adds server-side prompt and media jobs. Batch helpers submit one job and return a BatchJob; they do not fan out into repeated check_prompt or check_media calls. The recommended PromptGuard call is exactly:

job = client.check_prompt_batch(["first", "second"])

The submission call returns queued job metadata, not compliance verdicts. Call wait_for_batch() to poll the job to a terminal state, then retrieve its item results as shown below. Small batches commonly complete in about 1–2 minutes; larger batches can take longer depending on item count, reasoning mode, and service load. The supported 24-hour processing window is not a completion-time SLA.

The SDK uses POST /v1/guardrails/prompt/batches, where the endpoint and 24-hour window are implicit. Shared settings and per-item overrides remain available without changing the simple case:

job = client.check_prompt_batch(
    [
        "A normal support message",
        {
            "custom_id": "ticket-42",
            "input": "A per-item prompt",
            "reasoning_mode": "high",
        },
    ],
    blacklisted_keywords=["violence", "weapons"],
    defaults={"risk_tolerance": "medium"},
    metadata={"dataset": "support-review"},
)

job = client.wait_for_batch(job, timeout=900)
for item in client.iter_batch_results(job.id):
    # Results are unordered: always correlate them by custom_id.
    if item.status == "succeeded":
        print(item.custom_id, item.result.compliance_status)
    else:
        print(item.custom_id, item.error)

The convenience methods generate deterministic item custom_id values and a stable payload-derived idempotency key when omitted. This makes retrying the same logical SDK call safe, including after an uncertain network response. Pass your own custom_id values to join unordered results directly to your records. Pass a stable idempotency_key to coordinate retries with another system, or a new unique key when you intentionally want to resubmit an identical payload as a new job.

Shared defaults are merged first and each item's fields win on conflicts. "Compliant" and "Non-Compliant" are both successful guardrail results; transport or validation failures use an item failure state.

The generic create_batch() resource method is preserved for advanced, provider-compatible inline or JSONL workflows. For larger datasets, upload UTF-8 JSONL and create a job from the file:

batch_input = client.upload_file("requests.jsonl", purpose="batch")
job = client.create_batch(
    "/v1/guardrails/prompt",
    input_file_id=batch_input.id,
    completion_window="24h",
    idempotency_key="prompt-jsonl-2026-07-16",
    metadata={"source": "nightly"},
)

Each non-empty JSONL line must be an object such as:

{"custom_id":"row-1","body":{"user_prompt":"Text to check"}}

Media batches accept HTTPS URLs or IDs returned from a purpose="guardrail_media" upload. The returned BatchFile object itself is also accepted. Embedded base64 is intentionally rejected:

media_file = client.upload_file("photo.png", purpose="guardrail_media")
job = client.check_media_batch(
    [
        "https://cdn.example.com/photo-1.png",
        media_file,
        {"custom_id": "photo-3", "file_id": media_file.id},
    ],
)

Use list_batch_results() / get_batch_results() for cursor-paginated JSON, or download_batch_results() and iter_batch_results() for NDJSON. Jobs can be listed, retrieved, cancelled, and deleted with list_batches(), retrieve_batch(), cancel_batch(), and delete_batch(); only terminal jobs can be deleted. The async client exposes matching await/async-iteration methods.

Server limits are 1,000 requests and 10 MiB for inline jobs, or 50,000 lines and 200 MiB for JSONL input. The completion window is exactly 24h, and result artifacts expire after seven days.

Policies are required

The Guardrails API needs at least one policy to check against. Either configure policies in Policy Controls for your account, pass whitelisted_keywords / blacklisted_keywords with each request, or pass an enabled industry preset to check_media(). If none is present the API returns an error, which the SDK raises as MissingPolicyError:

from aetherlab import AetherLabClient, MissingPolicyError

client = AetherLabClient()
try:
    client.check_prompt("Hello!")  # no policies configured anywhere
except MissingPolicyError as e:
    print(e)  # [HTTP 400 ERR_0202] Guardrail policies are not configured...

Error handling

All SDK errors inherit from AetherLabError:

Exception When
AuthenticationError Missing/invalid API key (HTTP 401)
RateLimitError HTTP 429; exposes retry_after seconds when the server sends it
MissingPolicyError No guardrail policy configured (ERR_0202)
InvalidRequestError Malformed request (ERR_0200, ERR_0201)
APIError Any other HTTP error; exposes status_code, error_code, body
APIConnectionError Network failure after all retries
from aetherlab import AetherLabClient, AetherLabError, RateLimitError

client = AetherLabClient()
try:
    result = client.check_prompt("Hi", blacklisted_keywords=["violence"])
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")
except AetherLabError as e:
    print(f"AetherLab request failed: {e}")

The client automatically retries connection errors, 429s, and 5xx responses (3 retries by default, exponential backoff with jitter, honours Retry-After). Tune it with AetherLabClient(max_retries=..., timeout=...).

Configuration

Setting Constructor argument Environment variable Default
API key api_key AETHERLAB_API_KEY — (required)
Base URL base_url AETHERLAB_BASE_URL https://api.aetherlab.co
Timeout timeout 30 seconds
Max retries max_retries 3

Examples

Runnable scripts live in examples/:

Each reads AETHERLAB_API_KEY from the environment.

For an interactive walkthrough of every scalar and batch path — including credential setup, both inline and JSONL submission for PromptGuard and MediaGuard, polling, result correlation, and cleanup — open examples/AetherLab_SDK_End_to_End.ipynb in Jupyter. It defaults to a safe no-call mode; set RUN_LIVE_TESTS = True inside the notebook to run against production.

Migrating from 0.3.x

Version 0.4.0 is a rewrite around the real Guardrails API; earlier releases are deprecated. See the CHANGELOG. In short:

  • test_prompt() still works but is deprecated — use check_prompt().
  • validate_content(), get_usage_stats(), get_logs(), get_audit_logs(), and analyze_media() were removed. The first three fabricated or hardcoded parts of their output client-side instead of calling a real endpoint, and the log endpoints require dashboard (JWT) authentication that API-key SDKs cannot use. Use check_media() for media checks; view logs in the dashboard.

Contributing

See CONTRIBUTING.md. Bug reports and PRs are welcome in the issue tracker.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aetherlab-0.5.2.tar.gz (49.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aetherlab-0.5.2-py3-none-any.whl (28.3 kB view details)

Uploaded Python 3

File details

Details for the file aetherlab-0.5.2.tar.gz.

File metadata

  • Download URL: aetherlab-0.5.2.tar.gz
  • Upload date:
  • Size: 49.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.12

File hashes

Hashes for aetherlab-0.5.2.tar.gz
Algorithm Hash digest
SHA256 8b9161929cbc3bc789b5b5d940b97e3d0064e72c2b10d58723e742dedd929ab4
MD5 f818229b1fb89e7bd5ec8a1c8bc44a44
BLAKE2b-256 ed4e8b7f080e2621c6429b4ad6a810a38736f1f4e4f709248e74831dca3fb505

See more details on using hashes here.

File details

Details for the file aetherlab-0.5.2-py3-none-any.whl.

File metadata

  • Download URL: aetherlab-0.5.2-py3-none-any.whl
  • Upload date:
  • Size: 28.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.12

File hashes

Hashes for aetherlab-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ddbc5e5e33828d8f003915d07e0766e515659c3748ce6efe12c130f92180af40
MD5 a3949e38ec09810044e764d259e5cc3a
BLAKE2b-256 2e7027ee014117b542f02d4dfd78f99600a9332ead1fa87831fba9b2e94c1085

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.2 This release

2 files

0.5.1

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page