Skip to content

About

Python client for the Orca Agent Engine (OMA) Registry API

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

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 [email protected].

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.

About

Python client for the Orca Agent Engine (OMA) Registry API

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages