Metadata-Version: 2.5
Name: rai-control-plane-sdk
Version: 0.1.0
Summary: Official Python SDK for the RAI Control Plane governance API
Project-URL: Homepage, https://github.com/ztechnium/rai-python-sdk
Project-URL: Documentation, https://github.com/ztechnium/rai-python-sdk#readme
Project-URL: Repository, https://github.com/ztechnium/rai-python-sdk
Project-URL: Issues, https://github.com/ztechnium/rai-python-sdk/issues
Project-URL: Changelog, https://github.com/ztechnium/rai-python-sdk/blob/main/CHANGELOG.md
Author-email: ZTechnium <opensource@ztechnium.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: control-plane,governance,rai,responsible-ai,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: respx>=0.21.0; extra == 'dev'
Requires-Dist: twine>=4.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# RAI Control Plane Python SDK

Official Python client for the RAI Control Plane stable `/sdk/v1` governance API.

**Never execute a consequential side effect before RAI returns ALLOW.**

## Requirements

- Python **3.10** or newer (3.10–3.13 supported in CI)
- A RAI Control Plane deployment and runtime agent credentials

## Installation

```bash
pip install rai-control-plane-sdk
```

## Minimal usage

```python
from rai_sdk import RAIClient

client = RAIClient(
    base_url="https://rai.example.com",
    api_key="rai_...",
    integration_id="...",
)

client.heartbeat()

session = client.start_session(
    external_session_id="session-001",
    channel="application",
)

session.observe_input("Create an order")

decision = session.authorize_action(
    tool="create_order",
    parameters={
        "amount": 100,
        "currency": "USD",
    },
)

if decision.allowed:
    # Execute the application's side effect here.
    decision.report_execution(
        client,
        status="SUCCEEDED",
    )

session.end()
client.close()
```

Or use a context manager:

```python
with RAIClient(base_url="...", api_key="...", integration_id="...") as client:
    client.heartbeat()
```

## Authorization decisions

`authorize_action` returns a `Decision`. Check `decision.decision` (or `decision.allowed`
for the ALLOW case):

| Decision | Meaning | Application action |
| -------- | ------- | ------------------ |
| `ALLOW` | Action is permitted | Execute the side effect, then call `report_execution` |
| `DENY` | Action is blocked | Do **not** execute; surface `human_message` / `reason_code` as needed |
| `REQUIRE_APPROVAL` | Human approval required | Do **not** execute until approved; use `approval_request_id` |
| `MONITOR` | Observed / audited without blocking | Follow your product policy; still do not treat as unconditional ALLOW unless `decision.allowed` is true |

Only `decision.allowed` (`decision == "ALLOW"`) means it is safe to perform a
consequential side effect.

## Fail-closed behavior

By default (`fail_closed=True`), network errors, timeouts, and unreachable control-plane
endpoints raise `RAIError` with code `RAI_UNAVAILABLE`. Treat the control plane as
unavailable and **do not** execute consequential side effects — retry or abort according
to your integration policy.

HTTP error responses from the control plane (4xx/5xx with a structured body) raise
`RAIError` with the server-provided error code and message.

## Idempotency

`authorize_action` accepts an optional `idempotency_key`. When supplied, the SDK sends
it as both the JSON `idempotency_key` field and the `Idempotency-Key` HTTP header so
retries of the same authorization request can be safely deduplicated by the server.

If you omit `idempotency_key`, the SDK generates a unique key for the JSON body only
(no `Idempotency-Key` header).

## Runtime credentials

Construct `RAIClient` with:

- `base_url` — your RAI Control Plane base URL
- `api_key` — runtime agent key (sent as `X-RAI-Agent-Key`)
- `integration_id` — integration identifier for heartbeat and sessions

Store secrets in environment variables or a secrets manager. Never commit API keys.
`RAIClient.__repr__` never includes the API key; error messages redact it when echoed.

## Session lifecycle

```text
heartbeat / health
  → start_session
  → observe_input
  → authorize_action   (ALLOW | DENY | REQUIRE_APPROVAL | MONITOR)
  → report_execution   (after ALLOW, when a side effect runs)
  → observe_output
  → end_session
```

## API compatibility

This SDK targets the stable `/sdk/v1` HTTP contract (`API_RANGE = ">=1.0.0,<2.0.0"`).
Your control-plane deployment must expose compatible `/sdk/v1` endpoints.

## Error handling

```python
from rai_sdk import RAIClient, RAIError

try:
    client.heartbeat()
except RAIError as exc:
    # exc.code, exc.message, exc.retryable, exc.status_code, exc.details
    if exc.code == "RAI_UNAVAILABLE":
        # Fail closed: do not execute side effects
        raise
```

## Async client

`AsyncRAIClient` is **not included in 0.1.0**. Async support is deferred to a future
release. For asyncio applications today, run the synchronous `RAIClient` in a thread pool
(`asyncio.to_thread`) or call the REST API directly.

## Development

See [CONTRIBUTING.md](CONTRIBUTING.md).

```bash
pip install -e ".[dev]"
pytest
python -m build
twine check dist/*
```

## Links

- [Repository](https://github.com/ztechnium/rai-python-sdk)
- [Changelog](CHANGELOG.md)
- [Security policy](SECURITY.md)

## License

Apache-2.0 — see [LICENSE](LICENSE).
