Conventions
Four things hold everywhere in the SDK.
Async-only
Section titled “Async-only”Every call is a coroutine; there is no synchronous twin. It drops into an async service without a thread pool in the middle.
In an async framework (FastAPI, Starlette, aiohttp) await it from the handler directly. In a
synchronous entry point, wrap it once with asyncio.run(main()).
Cancelling the task awaiting a call raises asyncio.CancelledError as usual. For chat() that
stops your waiting only — the turn keeps running server-side until you call cancel().
Every list_* reads all pages
Section titled “Every list_* reads all pages”A list_* method returns the whole collection, not the server’s first page — it keeps reading
until it has everything.
projects = await aura.list_projects() # all of themfiles = await aura.list_files(WorkspaceFiles(project_id=project_id)) # all of themThis avoids a class of silent bug: a deploy prunes remote files by diffing a listing, so a short read would delete files that are still there.
Everything returned is a pydantic model
Section titled “Everything returned is a pydantic model”Response models are generated from the backend’s OpenAPI spec, so they validate at the boundary: a
response that does not match the contract fails there, loudly, rather than surfacing as an
AttributeError three calls later.
They serialise back out cleanly, which is what you want when a response is on its way to your own API or a queue:
snapshots = await aura.list_snapshots(project_id)payload = [s.model_dump(mode="json") for s in snapshots]Four exception types, one base
Section titled “Four exception types, one base”AuraApiError (the call was rejected), AuraResponseError (the answer was unreadable),
AuraTurnCancelledError (a turn stopped early) and AuraTurnTimeoutError (your wait elapsed) all
inherit AuraError, so one except covers everything and the specific types let you branch
without string matching. Errors has the detail.
Snapshots are the only container writes can’t reach
Section titled “Snapshots are the only container writes can’t reach”upload_file / delete_file write through the same FileContainer you already pass to
list_files / read_file: a workspace or deployment container accepts the write, a snapshot
container rejects it — a run’s captured state has to stay retrievable. Prefer asking the agent in
a turn to change a project’s inputs; reach for these methods directly for out-of-band writes, like
staging a dashboard file. See File containers for when to
use which container.