Metadata-Version: 2.4
Name: reef-sdk
Version: 0.3.0
Summary: Server-side Python SDK for the Reef agentic product runtime
Author-email: FluxOS contributors <dev@fluxtopus.com>
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx<1,>=0.25.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"

# Reef Python SDK

Server-side Python client for Reef. Product servers authenticate with an InkPass API key or
service credential. Provider credentials remain inside Reef.

## Install

```bash
pip install reef-sdk
```

## Create a typed decision

The decision client accepts choice, score, and noul questions in one request. Use the rolling
Jev alias to follow the latest release, or use a pinned model ID when reproducibility matters.

```python
import os

from reef_sdk import DecisionCreateRequest, ReefClient, ReefConfig


request: DecisionCreateRequest = {
    "state": {
        "ticket": "I upgraded to Pro, still see Free, and was charged.",
    },
    "questions": {
        "route": {
            "type": "choice",
            "instructions": "Choose the team that should handle this ticket.",
            "criteria": {
                "billing": "Billing, subscription, or charge issue",
                "technical": "Technical product malfunction",
                "account": "Account access or identity issue",
            },
        },
        "urgency": {
            "type": "score",
            "instructions": "Score the urgency of this ticket.",
            "criteria": ["low", "medium", "high"],
        },
        "billing_related": {
            "type": "noul",
            "instructions": "Does this ticket concern billing?",
        },
    },
    "requested_model": "~typesafe/jev-latest",
    "model_policy_id": "decision_model_default",
}

with ReefClient(
    ReefConfig(
        "https://reef.example.com",
        os.environ["REEF_SERVICE_API_KEY"],
        credential_kind="service",
    )
) as reef:
    decision = reef.decisions.create(
        "support-product",
        request,
        idempotency_key="ticket-4821-routing-v1",
    )

if decision["status"] == "completed":
    route = decision["answers"]["route"]
    if route["type"] == "choice":
        print(route["choice"], route["confidence"])
```

`DecisionResponse` is a status-discriminated union. Completed responses require typed answers,
provider metadata, and usage. The SDK rejects a malformed successful response instead of passing
an untyped dictionary to application code.

## Runtime requirements

- Call the SDK from a product backend. Do not expose Reef credentials to browser code.
- The principal needs `agent_decision:execute`.
- The product needs an active OpenRouter provider configuration and an execution policy whose
  model policy requires the `decisions` capability.
- Reuse an idempotency key only for the same request. Reef returns the stored result without a
  second provider call.

See [Reef decision requests](../../apps/reef/docs/decisions.md) for policy setup, the HTTP
contract, errors, accounting, and production verification evidence.

The client also exposes configuration, prompts, conversations, files, runs, approvals, tools,
usage, memory, and evidence. Mutations require caller-owned idempotency keys. The SDK never
accepts provider credentials and does not retry mutations outside Reef.
