AuraClient
Async client for the Strangeworks Aura public /api/v1 surface.
Authenticates with a company API key (sk-aura-…). Every method is a coroutine;
there is no synchronous variant. chat follows a turn live over the project
WebSocket and falls back to polling when the socket cannot be held open, hiding both
behind a single await.
Owns HTTP connections, so use it as an async context manager, or call aclose:
async with AuraClient(api_key=key) as aura: project = await aura.create_project(name="demo", from_deployment="acme/vrp")Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
— | A company API key, minted in Company settings → API keys. |
base_url |
str |
DEFAULT_BASE_URL |
Root of the Aura deployment. Defaults to production; point it at http://localhost:3000 for a local just dev stack. |
timeout |
float |
DEFAULT_TIMEOUT |
Per-request HTTP timeout in seconds. This bounds one call, not a whole agent turn — see chat’s own timeout. |
transport |
httpx.AsyncBaseTransport | None |
None |
Optional httpx transport, for tests that serve responses in-process instead of over the network. |
websocket_factory |
WebSocketFactory |
default_websocket_factory |
Opens the project event socket; tests pass a scripted fake. |
Methods
Section titled “Methods”aclose()
Section titled “aclose()”async def aclose() -> NoneClose the underlying HTTP connections.
create_deployment()
Section titled “create_deployment()”async def create_deployment(name: str) -> DeploymentResponseCreate an empty deployment for your company.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | Deployment name, unique within the company. |
Returns
Section titled “Returns”The created deployment.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
The name is invalid or already taken. |
list_deployments()
Section titled “list_deployments()”async def list_deployments() -> list[DeploymentResponse]List every deployment your company owns, following pagination.
Returns
Section titled “Returns”All deployments, in server order.
get_deployment()
Section titled “get_deployment()”async def get_deployment(name: str) -> DeploymentResponseFetch one deployment by name.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | The deployment’s name. |
Returns
Section titled “Returns”The deployment.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
No such deployment. |
delete_deployment()
Section titled “delete_deployment()”async def delete_deployment(name: str) -> DeploymentDeleteResponseDelete a deployment: purge its files and free its name for reuse.
Irreversible — there is no undelete, and a new deployment claiming the same name starts empty. Projects already seeded from this deployment keep their own copy of the workspace and are left alone.
Requires an admin, which every API key satisfies.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | The deployment’s name. |
Returns
Section titled “Returns”The handle, how many files were purged, and how many projects had been seeded from it.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
No such deployment. |
check_deployment()
Section titled “check_deployment()”async def check_deployment(name: str) -> DeploymentCheckResponseAsk the server whether a deployment satisfies the run contract.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | The deployment’s name. |
Returns
Section titled “Returns”ok, plus the missing paths and warnings behind that verdict.
upload_file()
Section titled “upload_file()”async def upload_file(container: FileContainer, path: str, body: bytes | str, content_type: str) -> FileEntryUpload one file to a container.
Three steps behind one await: plan the upload, PUT the bytes to the URL the plan names, then complete it. The byte PUT carries only the plan’s own headers, never your API key.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
container |
FileContainer |
— | Which files to write to. A SnapshotFiles is rejected server-side; a snapshot is immutable by design. |
path |
str |
— | Destination path within the container, e.g. run/solve.py. |
body |
bytes | str |
— | File contents. A str is encoded as UTF-8. |
content_type |
str |
— | MIME type recorded for the file. |
Returns
Section titled “Returns”The stored file’s entry.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
The plan, the byte upload, or the completion failed, or the server planned a multipart upload, which this SDK does not implement. |
list_files()
Section titled “list_files()”async def list_files(container: FileContainer, path_prefix: str | None = None) -> list[FileEntry]List a container’s files, following pagination.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
container |
FileContainer |
— | Which files to list. |
path_prefix |
str | None |
None |
Restrict the listing to paths under this prefix. |
Returns
Section titled “Returns”All matching file entries.
read_file()
Section titled “read_file()”async def read_file(container: FileContainer, path: str) -> FileContentResponseRead one file from a container.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
container |
FileContainer |
— | Which files to read from. SnapshotFiles reads a run’s frozen copy, which later runs cannot have overwritten. |
path |
str |
— | The file’s path, e.g. solutions/out.json for a run’s solution. |
Returns
Section titled “Returns”The file’s contents: text for text files, base64 for binary ones.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
No such file in that container. |
delete_file()
Section titled “delete_file()”async def delete_file(container: FileContainer, path: str) -> DeleteResponseDelete one file from a container.
Not recursive — pass a file path, not a directory.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
container |
FileContainer |
— | Which files to delete from. A SnapshotFiles is rejected server-side; a snapshot is immutable by design. |
path |
str |
— | The file’s path within the container. |
Returns
Section titled “Returns”What the server deleted.
create_project()
Section titled “create_project()”async def create_project(name: str, *, from_deployment: str | None = None, short_description: str | None = None, description: str | None = None) -> ProjectResponseCreate a project, optionally seeded from a published deployment.
A project seeded from a deployment lands directly in run mode, so the run agent is usable on it immediately.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
— | Human-readable project name. |
from_deployment |
str | None |
None |
A deployment handle, "<company>/<name>". The wire field is from, which is a reserved word in Python. |
short_description |
str | None |
None |
One-line summary. |
description |
str | None |
None |
Longer description. |
Returns
Section titled “Returns”The created project.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
The deployment handle is unknown or fails its run contract. |
list_projects()
Section titled “list_projects()”async def list_projects() -> list[ProjectSummary]List your projects, following pagination.
Returns
Section titled “Returns”A summary of every project you can see.
get_project()
Section titled “get_project()”async def get_project(project_id: str) -> ProjectResponseFetch one project.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Returns
Section titled “Returns”The project.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
No such project, or it is not yours. |
delete_project()
Section titled “delete_project()”async def delete_project(project_id: str) -> NoneDelete a project and everything in it.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
No such project, or it is not yours. |
list_conversations()
Section titled “list_conversations()”async def list_conversations(project_id: str) -> list[ConversationResponse]List a project’s conversations, following pagination.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Returns
Section titled “Returns”All conversations in the project.
create_conversation()
Section titled “create_conversation()”async def create_conversation(project_id: str, title: str | None = None) -> ConversationResponseStart a new conversation in a project.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
title |
str | None |
None |
Optional title; the server names it otherwise. |
Returns
Section titled “Returns”The created conversation.
delete_conversation()
Section titled “delete_conversation()”async def delete_conversation(project_id: str, conversation_id: str) -> NoneDelete one conversation.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
conversation_id |
str |
— | The conversation’s id. |
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
No such conversation in that project. |
send_message()
Section titled “send_message()”async def send_message(project_id: str, content: str, *, conversation_id: str | None = None, client_msg_id: str | None = None) -> ChatResponseDispatch a message without waiting for the agent’s reply.
Use this when you want to poll get_conversation_state yourself; chat is
the one-await version.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
content |
str |
— | The message text. |
conversation_id |
str | None |
None |
Target conversation. Defaults to the project’s active one. |
client_msg_id |
str | None |
None |
Your own idempotency key for the dispatch. |
Returns
Section titled “Returns”The dispatch result, including the stored user message and its sequence.
get_conversation_state()
Section titled “get_conversation_state()”async def get_conversation_state(project_id: str, conversation_id: str | None = None) -> ConversationSyncResponseRead an atomic snapshot of a conversation: its messages plus turn state.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
conversation_id |
str | None |
None |
Which conversation. Defaults to the project’s active one at the time of the call. |
Returns
Section titled “Returns”The messages the server has stored and whether a turn is in flight.
chat()
Section titled “chat()”async def chat(project_id: str, content: str, *, conversation_id: str | None = None, client_msg_id: str | None = None, poll_interval: float = DEFAULT_POLL_INTERVAL, timeout: float = DEFAULT_TURN_TIMEOUT, on_delta: Callable[[str], None] | None = None, on_tool_activity: Callable[[ToolActivityData], None] | None = None) -> ChatMessageResponseSend a message and wait for the agent’s reply, following the turn live.
The turn is followed over the project WebSocket, so the wait is event-driven —
turn-end comes from the authoritative stream_end rather than from polling — and
on_delta / on_tool_activity see the turn as it happens. When the socket cannot
be opened, or dies mid-turn, this degrades silently to polling /chat/sync: the
reply is unaffected, only the callbacks stop.
The returned message always comes from a /chat/sync reconcile, never from the
accumulated deltas. Deltas carry no sequence numbers, so a dropped frame is
undetectable; the stream is liveness and the stored row is truth.
On the polling path the reply is the first assistant message whose sequence
exceeds the dispatched one, accepted only once the turn reads idle and the message
is unchanged across two reads. Comparing sequences rather than counting messages
is what makes the wait attributable to this caller, and immune to the newest-N
window /chat/sync returns.
The wait is pinned to the conversation the dispatch resolved to, so creating or activating another conversation mid-turn cannot redirect it.
Cancelling the task awaiting this coroutine raises asyncio.CancelledError as
usual and stops only the waiting — the turn keeps running server-side. Call
cancel to stop the turn itself.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
content |
str |
— | The message text. |
conversation_id |
str | None |
None |
Target conversation. Defaults to the project’s active one. |
client_msg_id |
str | None |
None |
Your own idempotency key for the dispatch. |
poll_interval |
float |
DEFAULT_POLL_INTERVAL |
Seconds between polls, on the fallback path. |
timeout |
float |
DEFAULT_TURN_TIMEOUT |
Seconds to wait before giving up. |
on_delta |
Callable[[str], None] | None |
None |
Called with each chunk of assistant text, in order. |
on_tool_activity |
Callable[[ToolActivityData], None] | None |
None |
Called for each tool start, completion, or failure. |
Returns
Section titled “Returns”The agent’s completed reply.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraTurnCancelledError |
The turn stopped before finishing, so the reply is partial. partial_content carries what the agent managed. |
AuraTurnTimeoutError |
timeout elapsed. The turn is still running server-side; conversation_id is what to pass to cancel. |
AuraApiError |
A call failed, or the turn died before streaming. |
AuraResponseError |
The turn finished but its reply was not in the sync window. |
cancel()
Section titled “cancel()”async def cancel(project_id: str, conversation_id: str | None = None) -> boolStop a running agent turn.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
conversation_id |
str | None |
None |
Restrict cancellation to this conversation. Without it, any running turn in the project is cancelled. |
Returns
Section titled “Returns”Whether anything was actually cancelled.
get_agent_status()
Section titled “get_agent_status()”async def get_agent_status(project_id: str) -> AgentStatusResponseReport whether a turn is in flight, without inferring it from messages.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Returns
Section titled “Returns”The project’s current agent status.
list_executions()
Section titled “list_executions()”async def list_executions(project_id: str) -> list[ExecutionResponse]List the project’s solve executions, most recent first.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Returns
Section titled “Returns”Every execution, following pagination.
get_execution()
Section titled “get_execution()”async def get_execution(project_id: str, execution_id: str) -> ExecutionResponseFetch one solve execution.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
execution_id |
str |
— | The execution’s id. |
Returns
Section titled “Returns”The execution, including its status and timing.
list_snapshots()
Section titled “list_snapshots()”async def list_snapshots(project_id: str) -> list[SnapshotResponse]List a project’s snapshots, following pagination.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Returns
Section titled “Returns”Every snapshot taken in the project.
get_snapshot()
Section titled “get_snapshot()”async def get_snapshot(project_id: str, ref: str) -> SnapshotDetailResponseFetch one snapshot, including its file list.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
ref |
str |
— | A snapshot id or a tag name. |
Returns
Section titled “Returns”The snapshot and its files.
list_tags()
Section titled “list_tags()”async def list_tags(project_id: str) -> list[SnapshotTagResponse]List a project’s snapshot tags, following pagination.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
Returns
Section titled “Returns”Every tag and the snapshot it points at.
set_tag()
Section titled “set_tag()”async def set_tag(project_id: str, name: str, snapshot_id: str) -> SnapshotTagResponsePoint a tag at a snapshot, creating or moving it.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
name |
str |
— | The tag name. |
snapshot_id |
str |
— | The snapshot the tag should name. |
Returns
Section titled “Returns”The tag as stored.
checkout()
Section titled “checkout()”async def checkout(project_id: str, source: str, conversation_id: str | None = None) -> WorkspaceBasisResponseReset the project’s workspace to a deployment or snapshot.
The server dispatches on source’s segment count: one segment is a snapshot
id or tag name, two is a <group>/<name> deployment handle, three is a
<group>/<project>/<name> in-project snapshot tag.
Parameters
Section titled “Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
project_id |
str |
— | The project’s id. |
source |
str |
— | What to check out, as described above. |
conversation_id |
str | None |
None |
Conversation to attribute the checkout to. |
Returns
Section titled “Returns”The workspace’s new basis.
Throws
Section titled “Throws”| Exception | When |
|---|---|
AuraApiError |
source does not resolve to anything checkout-able. |