Skip to main content

Unofficial Python SDK for the OPUS workflow automation platform

Project description

opus-aaico

Unofficial Python SDK for the OPUS workflow automation platform by AAICO.

PyPI version Python versions License: MIT


Overview

opus-aaico provides a type-safe, production-ready interface to the OPUS REST API. It covers all 64 API endpoints across 8 resource modules, with both synchronous and asynchronous clients.

Key capabilities:

  • Full API coverage -- all OPUS endpoints wrapped in typed Python methods
  • Sync and async -- OpusClient for scripts, AsyncOpusClient for high-throughput services
  • High-level orchestration -- workflows.run() handles the entire job lifecycle in one call
  • Type safety -- Pydantic v2 models for all requests and responses
  • Resilient -- automatic retry with exponential backoff on transient failures
  • Minimal footprint -- only two runtime dependencies (httpx, pydantic)

Installation

pip install opus-aaico

Requires Python 3.9 or later.

Quick Start

from opus_aaico import OpusClient

client = OpusClient(api_key="your-api-key")

# Run a workflow end-to-end: initiate, execute, poll, and return results
result = client.workflows.run(
    workflow_id="wf-123",
    payload={"query": {"value": "Analyze this document", "type": "str"}},
)

print(result.status)       # "COMPLETED"
print(result.outputs)      # Workflow output variables
print(result.execution_time)  # Seconds elapsed

Authentication

from opus_aaico import OpusClient

# Option 1: Pass directly
client = OpusClient(api_key="sk-...")

# Option 2: With workspace context
client = OpusClient(
    api_key="sk-...",
    workspace_id="ws-...",
)

# Option 3: From environment variables
# Set OPUS_API_KEY, OPUS_WORKSPACE_ID (optional), OPUS_BASE_URL (optional)
client = OpusClient()
Environment Variable Purpose
OPUS_API_KEY API key (required if not passed to constructor)
OPUS_WORKSPACE_ID Default workspace ID
OPUS_BASE_URL Override base URL for staging or self-hosted instances

Resources

The client organizes the API into resource namespaces:

Resource Description Key Methods
client.workflows Workflow management and orchestration get, list, generate, run, share, send_email
client.jobs Job lifecycle initiate, execute, get_status, get_results, poll, search
client.files File upload, download, and search upload, download, search, generate, multipart_upload
client.reviews Human review and task management initiate, list, get, pick, submit_result, submit_output
client.api_keys API key management create, list, rotate, revoke, delete
client.credits Credit balance and usage tracking get_balance, get_usage, record_usage
client.policies Organizational policy management upload, list, get, get_summary, set_active
client.users User and project lookups list, list_projects, get_projects

Usage Examples

Run a Workflow

from opus_aaico import OpusClient

client = OpusClient(api_key="sk-...")

# High-level: one call handles initiate -> execute -> poll -> results
result = client.workflows.run(
    workflow_id="wf-123",
    payload={
        "query": {"value": "Summarize this report", "type": "str"},
        "document": {"value": "https://files.opus.com/doc.pdf", "type": "file"},
    },
    title="Q1 Report Analysis",
    poll_interval=2.0,   # seconds between status checks
    timeout=300,         # max wait time in seconds
)

print(result.status)
print(result.job_id)
print(result.outputs)
print(result.execution_time)

Upload a File

# Upload a local file (handles presigned URL flow automatically)
file_url = client.files.upload("./report.pdf")

# Use it in a workflow
result = client.workflows.run(
    workflow_id="wf-123",
    payload={
        "document": {"value": file_url, "type": "file"},
    },
)

Low-Level Job Control

# Step-by-step control when you need it
job = client.jobs.initiate(
    workflow_id="wf-123",
    title="My Job",
    description="Processing data",
)

client.jobs.execute(
    job_execution_id=job.job_execution_id,
    payload={"query": {"value": "Analyze", "type": "str"}},
)

# Poll until complete
status = client.jobs.poll(job.job_execution_id, timeout=120)

if status.status.value == "COMPLETED":
    results = client.jobs.get_results(job.job_execution_id)
    audit = client.jobs.get_audit(job.job_execution_id)

Search and List

# Search jobs
jobs = client.jobs.search(
    workflow_id="wf-123",
    status=["COMPLETED", "FAILED"],
    start_date="2026-01-01",
    max_results=50,
)

# List workflows
workflows = client.workflows.list(
    query="onboarding",
    active=True,
)

Async Usage

import asyncio
from opus_aaico import AsyncOpusClient

async def main():
    async with AsyncOpusClient(api_key="sk-...") as client:
        # Run multiple workflows concurrently
        tasks = [
            client.workflows.run(
                workflow_id="wf-123",
                payload={"query": {"value": f"Task {i}", "type": "str"}},
            )
            for i in range(5)
        ]
        results = await asyncio.gather(*tasks)
        for r in results:
            print(f"{r.job_id}: {r.status}")

asyncio.run(main())

Error Handling

All errors inherit from OpusError. Catch specific exceptions or the base class:

from opus_aaico import (
    OpusClient,
    AuthenticationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
    PermissionDeniedError,
    OpusError,
)

try:
    result = client.workflows.run("wf-123", payload={...})
except AuthenticationError:
    # 401 -- invalid API key
    pass
except NotFoundError:
    # 404 -- workflow does not exist
    pass
except RateLimitError as e:
    # 429 -- retry after e.retry_after seconds
    pass
except ValidationError:
    # 400 -- invalid request parameters
    pass
except PermissionDeniedError:
    # 403 -- insufficient permissions
    pass
except OpusError as e:
    # Any other API error
    print(f"{e.message} (status={e.status_code})")

Error hierarchy:

OpusError
├── AuthenticationError       (401)
├── PermissionDeniedError     (403)
├── NotFoundError             (404)
├── ValidationError           (400)
├── RateLimitError            (429)  -- includes retry_after
├── APIError                  (5xx)
├── TimeoutError              (request or polling timeout)
└── ConnectionError           (network failure)

The SDK automatically retries on 429 and 5xx errors with exponential backoff (up to 3 retries by default).

Configuration

client = OpusClient(
    api_key="sk-...",              # required (or set OPUS_API_KEY)
    workspace_id="ws-...",         # optional default workspace
    base_url="https://operator.opus.com",  # override for staging
    timeout=30.0,                  # request timeout in seconds
    max_retries=3,                 # retries on transient failures
)

Both OpusClient and AsyncOpusClient support context managers for proper connection cleanup:

with OpusClient(api_key="sk-...") as client:
    result = client.workflows.run("wf-123", payload={...})

Architecture

src/opus_aaico/
├── __init__.py              # Public API: OpusClient, AsyncOpusClient, errors
├── _client.py               # HTTP layer: auth, retry, request handling
├── _sync.py                 # OpusClient (synchronous)
├── _async.py                # AsyncOpusClient (asynchronous)
├── _exceptions.py           # Typed error hierarchy
├── _constants.py            # Base URL, defaults, version
├── _cli.py                  # CLI entry point (opus-aaico command)
├── resources/               # One module per API resource
│   ├── workflows.py         # Workflow CRUD + run() orchestrator
│   ├── jobs.py              # Job lifecycle + polling
│   ├── files.py             # File upload/download + multipart
│   ├── reviews.py           # Human review management
│   ├── api_keys.py          # API key CRUD
│   ├── credits.py           # Credit tracking
│   ├── policies.py          # Policy management
│   └── users.py             # User and project lookups
├── types/                   # Pydantic v2 models for all DTOs
│   ├── enums.py             # JobStatus, ReviewType, etc.
│   ├── shared.py            # Base model, UserDetails, etc.
│   ├── workflows.py         # Workflow, WorkflowRunResult, etc.
│   ├── jobs.py              # JobAudit, JobSearchItem, etc.
│   └── ...                  # One file per resource
└── _utils/
    ├── polling.py           # Exponential backoff polling
    └── files.py             # Presigned URL upload helpers

Design principles:

  • Resource-based namespacing following the OpenAI/Stripe SDK pattern
  • Async-first internals with sync wrapper using httpx's dual transport
  • camelCase to snake_case conversion handled automatically by Pydantic aliases
  • Minimal dependencies -- only httpx and pydantic at runtime

Development

See CONTRIBUTING.md for setup instructions and development workflow.

Changelog

See CHANGELOG.md for release history.

License

MIT License. See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

opus_aaico-0.4.0.tar.gz (41.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

opus_aaico-0.4.0-py3-none-any.whl (35.2 kB view details)

Uploaded Python 3

File details

Details for the file opus_aaico-0.4.0.tar.gz.

File metadata

  • Download URL: opus_aaico-0.4.0.tar.gz
  • Upload date:
  • Size: 41.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for opus_aaico-0.4.0.tar.gz
Algorithm Hash digest
SHA256 7edfe21a7d65669472d1994e37df2df16f0024ad1f809c35630460b11b73f0f5
MD5 8e28c0267cfd596b54c61a71a10fc0b3
BLAKE2b-256 58da2b98f3bc767e392868acd60255317c1e673d67649bd20a336fab47b06c4e

See more details on using hashes here.

File details

Details for the file opus_aaico-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: opus_aaico-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 35.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for opus_aaico-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 492e5a9c71682b7ca1f11fc61b729698e67972a0542cf82afafe9ca5ec764b8f
MD5 cb532d8c1a9c290ec545db9ed0c0d52f
BLAKE2b-256 38879083e313b5946f8b36c165f06cee538aef4cbd91fbba42d78ff94fae5d0c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page