AetherLab Python SDK
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.
- Website: https://aetherlab.co
- Dashboard (API keys & Policy Controls): https://app.aetherlab.co
- API base URL:
https://api.aetherlab.co
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)
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 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, or pass whitelisted_keywords / blacklisted_keywords with each
request. If neither 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/:
check_prompt.py— basic prompt checking with policiescheck_prompt_async.py— the same, using the async clientbatch_prompt.py— server-side prompt submission and NDJSON resultsbatch_media_async.py— async media batch with URL/file-ID inputserror_handling.py— handling every error class
Each reads AETHERLAB_API_KEY from the environment.
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 — usecheck_prompt().validate_content(),get_usage_stats(),get_logs(),get_audit_logs(), andanalyze_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. Usecheck_media()for media checks; view logs in the dashboard.
Contributing
See CONTRIBUTING.md. Bug reports and PRs are welcome in the issue tracker.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aetherlab-0.5.0.tar.gz.
File metadata
- Download URL: aetherlab-0.5.0.tar.gz
- Upload date:
- Size: 39.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19eb692416a71b13f3401e2b7a5842173ad3e5e6921396b92893eb17848e7c87
|
|
| MD5 |
41f5561dc22bccdb9714a4b6ae6965e1
|
|
| BLAKE2b-256 |
f8727bd5cdf7d9ac872d75bd6e145c27520fdf1a954952915eaba2e77575b011
|
File details
Details for the file aetherlab-0.5.0-py3-none-any.whl.
File metadata
- Download URL: aetherlab-0.5.0-py3-none-any.whl
- Upload date:
- Size: 27.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b16579a0dfa7fc803eda2c0e50e629c3e06a65fbe3ba2e1261bf85bfc700ba43
|
|
| MD5 |
bad655907b3ea66f616fb997ea77fd72
|
|
| BLAKE2b-256 |
10b64d539936c0517999c0895283df465535fca538486465c9fe7e010659af07
|