Orca Python SDK
Python client for the Orca Agent Engine API. Documentation lives at runorca.ai.
Installation
Install the SDK from PyPI:
pip install runorca
The distribution is named runorca, but the package you import is still orca.
Python 3.10 or later is required.
To install unreleased changes straight from this repository:
pip install "runorca @ git+https://github.com/orca-ae/orca-sdk-python"
Append @<tag or commit> to the URL to pin a version. If you previously installed
this SDK from Git as orca-sdk, uninstall that distribution before installing
runorca; both distributions install the same orca import package.
Note: do not run
pip install orca-sdk— that name belongs to an unrelated package on public PyPI.
Usage
import os
from orca import Orca
client = Orca(
api_key=os.environ.get("ORCA_API_KEY"),
base_url=os.environ.get("ORCA_BASE_URL"),
)
agent = client.agents.create(model="some-model", name="My First Agent")
print(agent.id)
Every method is available on an async client with the same signature:
import asyncio
from orca import AsyncOrca
client = AsyncOrca()
async def main() -> None:
agent = await client.agents.create(model="some-model", name="My First Agent")
print(agent.id)
asyncio.run(main())
Configuration
| Option | Environment variable | Default |
|---|---|---|
api_key |
ORCA_API_KEY |
— |
base_url |
ORCA_BASE_URL |
required |
timeout |
— | 600 seconds |
max_retries |
— | 2 |
base_url is the host root. The SDK writes the /v1/... and /apis/... prefixes
itself, so pass https://orca.example, not https://orca.example/v1. A trailing /v1,
/v1/registry, or /api/v1 is stripped with a deprecation warning.
There is no default host: this API is self-hosted, so a missing base URL raises rather than silently pointing somewhere unexpected.
Credentials
# A literal token
client = Orca(api_key="sk-...")
# Resolved per request -- the hook for short-lived or rotating tokens
client = Orca(api_key=lambda: read_current_token())
# No Authorization header, for a deployment behind an authenticating proxy
client = Orca(api_key=None)
The async client also accepts a coroutine function.
Pagination
List methods return a page that iterates across page boundaries automatically:
for agent in client.agents.list():
print(agent.id)
async for agent in client.agents.list():
print(agent.id)
To handle pages yourself:
page = client.agents.list(limit=20)
print(page.data, page.next_page)
Streaming
Session events arrive as server-sent events:
session = client.sessions.create(agent="agent_id", environment_id="env_id")
client.sessions.events.send(
session.id,
events=[{"type": "user.message", "content": [{"type": "text", "text": "Hello"}]}],
)
for event in client.sessions.events.stream(session.id):
if event.type == "session.status_idle":
break
Event names are not constrained by the SDK: every well-formed frame is yielded and you
discriminate on the payload's own type.
Working with one session
client.session(id) returns a handle that carries the session id for you:
handle = client.session("session_123")
handle.events.send(events=[{"type": "user.message", "content": [...]}])
for thread in handle.threads.list():
print(thread.id)
response = handle.files.download("file_123")
File uploads
metadata = client.files.upload(file=("hello.txt", b"hello\n", "text/plain"))
Anything accepted by FileTypes works: bytes, a file object, a path, or a
(filename, content, content_type) tuple.
Errors
from orca import Orca, OrcaError, APIError, NotFoundError, RateLimitError
try:
client.agents.retrieve("missing_id")
except NotFoundError as err:
print("not found:", err.status_code)
except RateLimitError as err:
print("rate limited; retry-after:", err.headers.get("retry-after"))
except APIError as err:
print(err.status_code, err.message)
except OrcaError as err:
print("client-side error:", err)
| Class | Status |
|---|---|
BadRequestError |
400 |
AuthenticationError |
401 |
PermissionDeniedError |
403 |
NotFoundError |
404 |
ConflictError |
409 |
UnprocessableEntityError |
422 |
RateLimitError |
429 |
InternalServerError |
5xx |
APIConnectionError |
network |
APIConnectionTimeoutError |
timeout |
ExtensionNotAvailableError |
client-side gate |
Policy and pricing extensions
Guardrail management and effective model pricing are exposed as top-level resources.
Like cloud methods, they check extension discovery first and raise
ExtensionNotAvailableError before issuing the business request when unavailable:
guardrail = client.guardrails.create(
name="Protect production",
phases=["tool_call"],
scope="explicit",
rule={"kind": "builtin", "builtin": "block_tools", "params": {"tools": ["shell"]}},
)
agent = client.agents.create(
model="some-model",
name="Guarded agent",
guardrail_ids=[guardrail.id],
extra_headers={"orca-beta": "managed-agents-2026-04-01"},
)
for price in client.model_prices.list():
print(price.provider, price.model_id, price.input_per_million_tokens)
guardrail_ids is optional on agent create/update and session-local agent
overrides. It is not supported by deployment APIs. The SDK probes the policy
extension only when the field is explicitly supplied.
Hosted extensions
Methods under client.cloud.* are served by the hosted extension group, which only the
hosted service serves; a self-hosted engine does not. On a deployment that does not serve
it, they raise before making any request:
from orca import ExtensionNotAvailableError
try:
providers = client.cloud.agents.providers.list()
except ExtensionNotAvailableError as err:
print(f"this deployment has no {err.group!r} extension installed")
To check first:
groups = client.discovery.groups()
if any(g.name == "cloud.sn.io" for g in groups.groups):
...
Retries and timeouts
Failed requests are retried twice by default, with exponential backoff honouring
retry-after. Connection errors, timeouts, 408, 409, 429, and 5xx are retried.
client = Orca(max_retries=3, timeout=30.0)
client.agents.list(timeout=5.0) # per request
Accessing the raw response
response = client.agents.with_raw_response.list()
print(response.headers.get("request-id"))
agents = response.parse()
with_streaming_response defers reading the body:
with client.agents.with_streaming_response.list() as response:
print(response.headers)
agents = response.parse()
Versioning
This package follows semantic versioning. Internal names prefixed with an underscore are not part of the public surface.
Contributing
Contributions are welcome. CONTRIBUTING.md covers the workflow, including the DCO sign-off every commit needs, and AGENTS.md holds the conventions every change follows. To get a working checkout:
./scripts/bootstrap
./scripts/test
./scripts/lint
Ask questions and share ideas in GitHub Discussions. Report SDK bugs in this repository's issues, and server behavior in the engine's issues.
Security
Please don't report security vulnerabilities in public issues. Use GitHub's private vulnerability reporting, or email security@runorca.ai.
License
The SDK's own code is licensed under the Apache License 2.0. It also
includes code under MIT, BSD-3-Clause, and MPL-2.0: NOTICE identifies the
covered code, and THIRD_PARTY_NOTICES contains the license
texts. The MPL-2.0 terms apply to src/orca/_utils/_utils.py, which contains copied
MPL code. Both the wheel and source distribution include these notices and that
source file.
Metadata
Release files for runorca 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| runorca-0.3.0.tar.gz | 317.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| runorca-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 591.8 kB
Release files / runorca-0.3.0.tar.gz
| Download URL | runorca-0.3.0.tar.gz |
|---|---|
| Size | 317.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b50b01fa1a3aee04be8081bb5d56e07de7cbc24840813cddb487eb81ccd53c4
|
|
BLAKE2b-256 checksum How to use checksums |
41f207d17a5b0c145712c04207ede27342406653d7775b666ac25f4d322df3b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / runorca-0.3.0-py3-none-any.whl
| Download URL | runorca-0.3.0-py3-none-any.whl |
|---|---|
| Size | 274.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c0a0d2a277ff704d5b6c30fd1cf419a57bd144eb0081851c96e932e621ece6c5
|
|
BLAKE2b-256 checksum How to use checksums |
53b683f5914df97fa0d78fae23eb0220ef75e770eac09b76f0197d1f0f1f3e7c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|