Python SDK for the Agent on Demand API
Project description
aod-sdk
Python SDK for the Agent on Demand HTTP API. Covers every
endpoint in docs/openapi.yaml with typed pydantic
models, sync and async clients, and a typed SSE event stream.
Install
pip install aod-sdk
Quickstart
Sync
from aod import Client
with Client(base_url="https://aod.example", token="aod_...") as client:
env = client.environments.create(
name="prod",
packages={"apt": ["jq"], "npm": ["typescript"]},
env_vars={"OPENAI_API_KEY": "sk-..."},
networking={"type": "limited", "allowed_hosts": ["api.github.com"]},
)
agent = client.agents.create(
name="my-agent",
model="claude-sonnet-4-5",
runtime="claude-code",
system="You are a careful software engineer.",
environment_id=env.id,
)
ack = client.sessions.create(
agent_id=agent.id,
prompt="implement the feature in TODO.md",
resources=[
{"type": "github_repository", "url": "https://github.com/me/repo"},
],
)
with client.sessions.stream(ack.id) as events:
for event in events:
print(event.type, event.extra)
Async
import asyncio
from aod import AsyncClient
async def main():
async with AsyncClient(token="aod_...") as client:
agents = await client.agents.list()
for agent in agents:
print(agent.name)
asyncio.run(main())
Configuration
base_url and token can be passed to the constructor or read from the
AOD_API_URL and AOD_API_TOKEN environment variables. base_url defaults
to http://localhost:8777.
Errors
Non-2xx responses raise a typed subclass of AodHTTPError:
| Status | Exception | When |
|---|---|---|
| 401/3 | AuthError |
Missing/invalid token |
| 404 | NotFoundError |
Resource missing |
| 409 | ConflictError |
Archived row, terminal session, or stale version |
| 422 | ValidationError |
Server-side pydantic validation failure |
| 429 | RateLimitError |
Per-user concurrent session limit reached (.limit, .active) |
| 5xx | ServerError |
All share .status_code, .detail, .method, .url.
Optimistic concurrency
agents and environments require the current version on update. A stale
version raises ConflictError:
agent = client.agents.get(agent_id)
client.agents.update(agent.id, version=agent.version, name="renamed")
Streaming
client.sessions.stream(session_id, since=None) is a context manager that
yields a StreamEvent iterator. Pass since to resume after a specific event
id. Event types: start, turn_start, output, stage, exit, error,
terminated, stale. Everything except the discriminator (type) and
id lands in event.extra.
Pretty-printing agent output
aod.pretty holds optional, runtime-scoped formatters that turn an
agent's raw stdout into human-readable display lines. Runtime output formats
are not part of the AoD API, so these helpers live under a separate namespace
— the core SDK stays runtime-agnostic.
Currently shipped:
| Formatter | Runtime | Input format |
|---|---|---|
aod.pretty.claude.ClaudeFormatter |
claude-* |
Claude CLI stream-json lines |
from aod import Client
from aod.pretty.claude import ClaudeFormatter
fmt = ClaudeFormatter()
with client.sessions.stream(session_id) as events:
for event in events:
for line in fmt.consume(event): # filters to output/stdout
print(line)
for line in fmt.flush(): # drain any unterminated buffer
print(line)
.consume(event) is the event-oriented entry point. .feed(chunk) and
.flush() are available for lower-level integrations that already extracted
the stdout bytes themselves.
Development
cd clients/python
uv pip install -e ".[dev]"
pytest
ruff check
mypy
Releases (maintainers)
Published to PyPI via GitHub Actions using Trusted
Publishing — no API tokens to
manage. Two workflows live in .github/workflows/:
sdk-release.yml— fires on GitHub Release creation with tagaod-sdk-v<version>, publishes to pypi.org/p/aod-sdk.sdk-release-test.yml— manualworkflow_dispatch, publishes to test.pypi.org/p/aod-sdk for dry-run validation.
One-time setup
-
Reserve the name on PyPI (and TestPyPI). On both pypi.org and test.pypi.org, add a pending trusted publisher:
Field Value Project name aod-sdkOwner ravi-hqRepository agent-on-demandWorkflow sdk-release.yml(PyPI) /sdk-release-test.yml(TestPyPI)Environment pypi/testpypi -
(Recommended) Create protected GitHub environments. In Settings → Environments, create
pypiwith required reviewers, andtestpypiwith no protections.
Cutting a release
-
Bump the version in both
clients/python/pyproject.tomlandclients/python/src/aod/__init__.py(the workflow verifies the pyproject value matches the tag). PR + merge tomain. -
(Recommended) Run
sdk-release-test.ymlagainstmainandpip install -i https://test.pypi.org/simple/ aod-sdk==<version>in a throwaway venv to confirm the wheel installs and imports cleanly. -
Tag and create a GitHub Release:
gh release create aod-sdk-v0.2.0 \ --title "aod-sdk v0.2.0" \ --notes "..." \ --target main
sdk-release.ymlfires onpublished, verifies the tag matchespyproject.toml, runs the tests, builds sdist + wheel, and uploads to PyPI.
Project details
Release history Release notifications | RSS feed
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 aod_sdk-0.1.0.tar.gz.
File metadata
- Download URL: aod_sdk-0.1.0.tar.gz
- Upload date:
- Size: 67.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
685ca70335f81ba100b4420d29a8970012fdd600bb753ca9cedb3b2977f9eb64
|
|
| MD5 |
342feaedfdc1b36ff8c962ba263229d9
|
|
| BLAKE2b-256 |
b8a4a23232030e549ff06b4a6d7dc8c7d1e82367cb528b5c9aaeb033b805c967
|
Provenance
The following attestation bundles were made for aod_sdk-0.1.0.tar.gz:
Publisher:
sdk-release.yml on ravi-hq/agent-on-demand
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aod_sdk-0.1.0.tar.gz -
Subject digest:
685ca70335f81ba100b4420d29a8970012fdd600bb753ca9cedb3b2977f9eb64 - Sigstore transparency entry: 1356231512
- Sigstore integration time:
-
Permalink:
ravi-hq/agent-on-demand@621aafc7f99d018f234f5ebc239c8e985105bf42 -
Branch / Tag:
refs/tags/aod-sdk-v0.1.0 - Owner: https://github.com/ravi-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-release.yml@621aafc7f99d018f234f5ebc239c8e985105bf42 -
Trigger Event:
release
-
Statement type:
File details
Details for the file aod_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aod_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdbd77f1e9678c845e66a235118ea835b58e3b756d4a2bc94ac04f9583d576f1
|
|
| MD5 |
bbd68945e45938df7e5339b19133e94a
|
|
| BLAKE2b-256 |
11bf1dc63e61764126d35d90425170a3931bccf1a62b40f0f04a2334d5c5976a
|
Provenance
The following attestation bundles were made for aod_sdk-0.1.0-py3-none-any.whl:
Publisher:
sdk-release.yml on ravi-hq/agent-on-demand
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aod_sdk-0.1.0-py3-none-any.whl -
Subject digest:
bdbd77f1e9678c845e66a235118ea835b58e3b756d4a2bc94ac04f9583d576f1 - Sigstore transparency entry: 1356231520
- Sigstore integration time:
-
Permalink:
ravi-hq/agent-on-demand@621aafc7f99d018f234f5ebc239c8e985105bf42 -
Branch / Tag:
refs/tags/aod-sdk-v0.1.0 - Owner: https://github.com/ravi-hq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-release.yml@621aafc7f99d018f234f5ebc239c8e985105bf42 -
Trigger Event:
release
-
Statement type: