Metadata-Version: 2.4
Name: prova-sdk
Version: 0.1.1
Summary: Agent-side SDK for the Prova AI control plane (ingest, gateway-check, register).
Project-URL: Homepage, https://prova.cobound.dev/docs/sdk
Project-URL: Documentation, https://prova.cobound.dev/docs/sdk
License: MIT
Keywords: agents,ai,audit,compliance,langgraph,llm,observability
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.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: cryptography>=42.0
Requires-Dist: httpx>=0.27
Provides-Extra: langgraph
Requires-Dist: langchain-core>=0.2; extra == 'langgraph'
Description-Content-Type: text/markdown

# prova-sdk (Python)

Agent-side SDK for the Prova AI control plane. Thin wrappers around:

- `POST /api/v1/audit/ingest`
- `POST /api/v1/gateway/check`
- `POST /api/v1/inventory`

Plus an Ed25519 receipt verifier and a one-shot migration tool that bulk-imports
existing LangSmith / Langfuse / OpenAI logs into the Audit Vault.

Separate from the legacy `prova` package (the reasoning-chain verifier).
See `/docs/sdk` for guidance on which one to install.

## Install

```sh
pip install prova-sdk
```

Requires Python 3.10+.

## Quick start

```python
from prova_cp import ProvaClient

prova = ProvaClient(api_key="prv_...")

prova.ingest({
    "kind": "model_call",
    "source": {"org_id": "YOUR_ORG", "framework": "langgraph", "app_id": "claims-orchestrator"},
    "model": {"provider": "openai", "name": "gpt-4o"},
    "payload": {"messages": messages, "response": response},
})

check = prova.gateway_check({"kind": "model_call", "payload": {"messages": messages}})
if check["action"] == "block":
    raise PolicyBlocked(check["findings"])
```

Pass `verify_receipts=True` to make the client verify every returned receipt's
Ed25519 signature against the published public key before returning.

## LangGraph / LangChain auto-instrumentation

Install the optional extra and drop the callback handler into any graph. Every
LLM call, node, and tool call is ingested as a signed receipt automatically. No
per-node code changes.

```sh
pip install "prova-sdk[langgraph]"
```

```python
from prova_cp import ProvaClient, ProvaCallbackHandler

prova = ProvaClient(api_key="prv_...")
handler = ProvaCallbackHandler(
    prova,
    app_id="claims-orchestrator",
    environment="production",
    framework="langgraph",
)

# LangGraph
graph.invoke(inputs, config={"callbacks": [handler]})

# LangChain
chain.invoke(inputs, config={"callbacks": [handler]})
```

The handler is fail-silent: a Prova outage logs at warning level and never
breaks the agent. LLM calls become `model_call` receipts, graph nodes become
`agent_step`, tool calls become `tool_call`.

## CrewAI

CrewAI has no LangChain-style callbacks; use its `step_callback` /
`task_callback` hooks instead.

```python
from prova_cp import ProvaClient, ProvaCrewAI

tap = ProvaCrewAI(ProvaClient(api_key="prv_..."), app_id="research-crew")
crew = Crew(agents=[...], tasks=[...],
            step_callback=tap.step_callback,
            task_callback=tap.task_callback)
```

Agent steps become `agent_step` receipts; completed tasks become `agent_run`.

## Raw OpenAI / Anthropic clients (no framework)

Wrap the vendor client once. Every completion is mirrored to a signed receipt.
The vendor response is returned unchanged and a Prova failure never raises.
Synchronous, `async` (`AsyncOpenAI`/`AsyncAnthropic`), and streamed
(`stream=True`) calls are all captured; for streams the receipt fires once
after the stream is fully consumed, with the chunk text reassembled.

```python
from openai import OpenAI
from prova_cp import ProvaClient, wrap_openai

client = wrap_openai(OpenAI(), ProvaClient(api_key="prv_..."), app_id="support-bot")
client.chat.completions.create(model="gpt-4o", messages=[...])  # auto-ingested
```

`wrap_anthropic` is identical for the Anthropic SDK (`messages.create`).

## Migrate existing logs

CLI:

```sh
PROVA_API_KEY=prv_... prova-migrate --source langsmith --file runs.ndjson
```

Programmatic:

```python
from prova_cp import ProvaClient, migrate
from prova_cp.migrate import read_ndjson

with ProvaClient(api_key="prv_...") as client, open("observations.ndjson") as f:
    result = migrate(client, "langfuse", read_ndjson(f))
    print(result)
```

Supported sources: `langsmith`, `langfuse`, `openai`. Idempotency keys are
derived from the source row id, so re-running the migration is safe.

## Verify a receipt offline

```python
from prova_cp import verify_receipt

verify_receipt(receipt, public_key_pem=PUBLIC_KEY_PEM)
```

Or fetch the public key from the deployment automatically:

```python
verify_receipt(receipt, base_url="https://api.prova.cobound.dev")
```
