Metadata-Version: 2.4
Name: decision-os-sdk
Version: 0.1.0
Summary: Official Python SDK for Decision OS — AI decision governance platform
Project-URL: Homepage, https://decisionos.com
Project-URL: Documentation, https://decisionos.com/docs
Project-URL: API Reference, https://decisionos.com/docs
Project-URL: Integration Guides, https://decisionos.com/integrations
Project-URL: Changelog, https://decisionos.com/changelog
Author-email: Decision OS <support@decisionos.com>
License: MIT
Keywords: agents,ai,audit,decision,governance,ledger,llm
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Description-Content-Type: text/markdown

# decision-os-sdk

Official Python SDK for [Decision OS](https://decisionos.com) — the AI governance platform that logs, audits, replays, and monitors AI agent decisions.

## Install

```bash
pip install decision-os-sdk
```

Requires Python 3.9+.

## Quickstart

```python
import os
from decision_os import DecisionOS

dos = DecisionOS(
    api_key=os.environ["DECISION_OS_API_KEY"],
    agent_id=os.environ["DECISION_OS_AGENT_ID"],
)

result = dos.log_decision(
    context="Route support ticket: API key rotation broke our integration",
    options=["engineering", "billing", "security"],
    chosen="engineering",
    confidence=0.91,
)
print(result.decision_id)
```

## Environment variables

| Variable | Required | Description |
|---|---|---|
| `DECISION_OS_API_KEY` | Yes | API key from Settings → API Keys. Starts with `dos_live_` or `dos_test_`. |
| `DECISION_OS_AGENT_ID` | Recommended | Agent ID from your workspace. Can also be passed per-call. |

Generate an API key at **decisionos.com → Settings → API Keys**.

## `log_decision`

Writes an immutable decision to the governance ledger.

```python
result = dos.log_decision(
    context="Route support ticket",
    options=[
        {"key": "engineering", "label": "Engineering", "probability": 0.91},
        {"key": "billing",     "label": "Billing",     "probability": 0.06},
        {"key": "security",    "label": "Security",    "probability": 0.03},
    ],
    chosen="engineering",
    confidence=0.91,
    model="gpt-4o",
    runner="support_routing_v1",
    prompt_version="v1.0",
    constraints=["SLA: < 4 hours", "Tier: enterprise"],
    trace_id="otel-trace-id",
    run_id="run-id",
    request_id="ticket_abc123",   # idempotency key
    run_policy_eval=True,         # evaluate against active governance policy
)

print(result.decision_id)         # "dec_abc..."
print(result.status)              # "logged"

if result.policy_eval:
    if not result.policy_eval.ok:
        print(f"Policy evaluation failed: {result.policy_eval.error}")
    elif result.policy_eval.diff and result.policy_eval.diff.get("changed"):
        print("Active policy would have chosen differently — drift detected")
```

### Parameters

| Parameter | Type | Description |
|---|---|---|
| `context` | `str` | **Required.** The decision prompt, question, or situation. |
| `options` | `list[str \| dict]` | Options the agent considered. String or `{"key", "label"?, "probability"?}`. |
| `chosen` | `str` | Key of the selected option. |
| `confidence` | `float` | Agent confidence, 0–1. |
| `constraints` | `list[str]` | Constraints active at decision time. |
| `assumptions` | `list[str \| dict]` | Assumptions. String or `{"text", "confidence"?}`. |
| `model` | `str` | Model used, e.g. `"gpt-4o"`. |
| `runner` | `str` | Runner identifier. |
| `prompt_version` | `str` | Prompt version for audit traceability. |
| `parameters` | `dict` | Runner parameters (temperature, top_p, etc.). |
| `trace_id` | `str` | OpenTelemetry / LangSmith trace ID. |
| `run_id` | `str` | Run or thread ID. |
| `span_id` | `str` | OTel span ID. |
| `parent_span_id` | `str` | OTel parent span ID. |
| `request_id` | `str` | Idempotency key — duplicate calls with the same ID return the original decision. |
| `agent_id` | `str` | Override the agent ID set in the constructor. |
| `run_policy_eval` | `bool` | Run inline policy evaluation and return the diff in `result.policy_eval`. Default: `False`. |

### Returns: `LogDecisionResult`

| Field | Type | Description |
|---|---|---|
| `decision_id` | `str` | Unique decision ID. |
| `status` | `str` | Decision status, e.g. `"logged"`. |
| `policy_eval` | `PolicyEvalResult \| None` | Policy evaluation result when `run_policy_eval=True`. |

### `PolicyEvalResult`

| Field | Type | Description |
|---|---|---|
| `ok` | `bool` | Whether policy evaluation passed. |
| `replay_id` | `str \| None` | ID of the replay run. |
| `policy_version_id` | `str \| None` | Policy version evaluated against. |
| `diff` | `dict \| None` | Diff between agent decision and policy recommendation. |
| `error` | `str \| None` | Error message if evaluation failed. |

## `capture_snapshot`

Attaches runtime evidence to an existing decision — model telemetry, tool call traces, eval results.

```python
result = dos.capture_snapshot(
    decision_id="dec_abc...",
    snapshot={
        "prompt": "Route this support ticket...",
        "response": "engineering",
    },
    model_usage={"input_tokens": 312, "output_tokens": 8},
    timings={"latency_ms": 420},
    eval_score=0.95,
    eval_pass=True,
)
print(result.snapshot_id)
```

## Error handling

All SDK errors inherit from `DecisionOSError`. Catch the base class to ensure governance logging never blocks agent execution:

```python
from decision_os import DecisionOS, DecisionOSError

dos = DecisionOS(api_key=os.environ["DECISION_OS_API_KEY"], agent_id="your-agent-id")

try:
    result = dos.log_decision(context="My agent decision")
except DecisionOSError as exc:
    # Non-blocking: log the failure and continue
    print(f"[decision-os] logging failed: {exc}")
    # exc.status_code — HTTP status (int or None for network errors)
```

Specific error types:

| Exception | HTTP | When |
|---|---|---|
| `AuthenticationError` | 401 | Invalid or missing API key. |
| `NotFoundError` | 404 | Agent not found in this workspace. |
| `PlanLimitError` | 402 | Monthly decision quota reached. |
| `RateLimitError` | 429 | Rate limit exceeded. Has `.retry_after` attribute. |
| `ValidationError` | 400/422 | Missing required field or invalid input. |
| `ServerError` | 5xx | Unexpected server error (automatically retried). |

## Idempotency

Pass `request_id` to make calls idempotent. If you retry after a timeout, the same `request_id` returns the original decision without creating a duplicate:

```python
result = dos.log_decision(
    context="Route support ticket",
    chosen="engineering",
    request_id=ticket_id,   # e.g. your system's ticket ID
)
```

## Policy evaluation

When `run_policy_eval=True`, Decision OS evaluates the decision synchronously against the active governance policy and returns whether the policy would have chosen differently:

```python
result = dos.log_decision(
    context="Approve loan application",
    chosen="approve",
    run_policy_eval=True,
)

if result.policy_eval and result.policy_eval.diff:
    if result.policy_eval.diff.get("changed"):
        alert_compliance_team(result.decision_id)
```

## LangGraph integration

See [`examples/langgraph_route_node.py`](examples/langgraph_route_node.py) for a complete LangGraph routing agent example that logs decisions and captures model telemetry.

## Context manager

The client can be used as a context manager to ensure the connection pool is closed:

```python
with DecisionOS(api_key=os.environ["DECISION_OS_API_KEY"], agent_id="...") as dos:
    result = dos.log_decision(context="My decision")
```

## Constructor options

| Parameter | Default | Description |
|---|---|---|
| `api_key` | — | **Required.** Your Decision OS API key. |
| `agent_id` | `None` | Default agent ID (can be overridden per-call). |
| `base_url` | `https://decisionos.com` | API base URL. |
| `timeout` | `10.0` | HTTP timeout in seconds. |
| `retries` | `2` | Number of automatic retries on 5xx errors. |

## Security

Never commit your API key to source control. Use environment variables or a secrets manager:

```bash
export DECISION_OS_API_KEY="dos_live_..."
```

Rotate keys at any time in **Settings → API Keys**.

## License

MIT
