Skip to main content

Orca Python SDK

CI

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)

Source distribution for runorca 0.3.0
File Size Uploaded
runorca-0.3.0.tar.gz 317.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for runorca 0.3.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page