Metadata-Version: 2.4
Name: soulpolicy
Version: 0.2.0
Summary: SoulPolicy Python SDK — LLM behavior trust primitives (drift / guardrail / snapshot / style)
Author: SoulPolicy
License: Apache-2.0
Project-URL: Homepage, https://soulpolicy.cc
Project-URL: Documentation, https://docs.soulpolicy.cc
Project-URL: Repository, https://github.com/vortwang/soulpolicy
Keywords: llm,ai-safety,drift-detection,guardrails,primitives
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-httpx>=0.30; extra == "dev"
Dynamic: license-file

# soulpolicy — Python SDK

LLM 行为可信度 primitive。一行集成，按调用计费。

## 安装

```bash
pip install soulpolicy
```

## 30 秒上手

```python
from soulpolicy import Client

sp = Client(api_key="sk_live_xxx")  # 或设 SOULPOLICY_API_KEY env

# 1) 用 5+ 条「健康输出」建一个 baseline
bl = sp.baselines.create(samples=[
    "Hello, thanks for contacting us. How can I help today?",
    "Hi there, I am happy to assist. Could you share more details?",
    "Apologies for the trouble. Let me look into that for you.",
    "Sure, I can check the status. One moment please.",
    "Thank you for your patience. I will follow up by email.",
])
print(bl.id, bl.fingerprint)

# 2) 对每次 LLM 输出做漂移判定
r = sp.drift_checks.check(text="Sure, let me help.", baseline=bl.id)
if r.severity == "critical":
    handle_drift(r)
print(r.score, r.severity, r.evidence["nearest_baseline_samples"])

# 3) 任何时刻可复现：用 reproducibility 包重算
replay = sp.drift_checks.replay(
    text="Sure, let me help.",
    baseline=bl.id,
    reproducibility=r.reproducibility,
)
assert replay.matched

# 4) 客户回标 — 帮助我们改进 precision/recall
sp.drift_checks.feedback(r.id, label="true_positive")
```

## 错误处理

```python
from soulpolicy import Client, AuthenticationError, IdempotencyError

try:
    sp.baselines.create(samples=["x"])  # 少于 3 条
except InvalidRequestError as e:
    print(e.code, e.message, e.param)
except AuthenticationError:
    print("api key invalid")
except IdempotencyError:
    print("idempotency key reused with different payload")
```

## Idempotency

POST 请求默认自动带 Idempotency-Key（`sdk-auto-<random>`）。手动指定：

```python
sp.drift_checks.create(text=..., baseline=..., idempotency_key="my-key-1")
```

## 自托管

```python
sp = Client(api_key="sk_local_xxx", base_url="https://soulpolicy.internal.example.com")
```

## 资源对照

| Method | Endpoint |
|---|---|
| `sp.baselines.create(...)` | `POST /api/v2/baselines` |
| `sp.baselines.retrieve(id)` | `GET /api/v2/baselines/{id}` |
| `sp.baselines.report(id)` | `GET /api/v2/baselines/{id}/report` |
| `sp.drift_checks.check(...)` | `POST /api/v2/drift_checks` |
| `sp.drift_checks.replay(...)` | `POST /api/v2/drift_checks/replay` |
| `sp.drift_checks.feedback(id, ...)` | `POST /api/v2/drift_checks/{id}/feedback` |
