Metadata-Version: 2.4
Name: psiguard
Version: 0.1.4
Summary: Real-time AI safety monitoring — detect hallucinations, drift, and anomalies in your AI responses.
Author-email: PsiGuard LLC <hello@psiguard.ai>
License: MIT
Project-URL: Homepage, https://psiguard.net
Project-URL: Repository, https://github.com/fivepillsofx/bumpr-ai-safety
Project-URL: Bug Tracker, https://github.com/fivepillsofx/bumpr-ai-safety/issues
Keywords: ai,safety,monitoring,hallucination,drift,llm,cognitive,anomaly-detection,psiguard
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.8
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 :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.8
Description-Content-Type: text/plain
Requires-Dist: requests>=2.28.0

# PsiGuard Python SDK

**Real-time AI safety monitoring.** Detect hallucinations, drift, and cognitive anomalies in your AI responses before they reach your users.

[![PyPI version](https://img.shields.io/pypi/v/psiguard.svg)](https://pypi.org/project/psiguard/)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

## Install

```bash
pip install psiguard
```

---

## Quick Start

```python
from psiguard import PsiGuard

# Initialize with your API key
pg = PsiGuard(api_key="pg_...")
# Or set PSIGUARD_API_KEY in your environment and call PsiGuard() with no args

# Monitor an AI response
result = pg.check(
    prompt="What is the capital of France?",
    response="The capital of France is Paris.",
    thread_id="session-abc123",   # use same ID across a conversation
)

if result.should_block:
    print("Blocked:", result.explanation)
else:
    print(f"Safe  |  risk={result.risk_score}/100  |  state={result.state}")
```

---

## API Reference

### `PsiGuard(api_key, base_url, timeout)`

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `api_key` | str | `PSIGUARD_API_KEY` env var | Your `pg_...` key from the dashboard |
| `base_url` | str | PsiGuard API | Override for testing |
| `timeout` | int | `15` | HTTP timeout in seconds |

---

### `.check(prompt, response, thread_id, risk_threshold) → CheckResult`

Monitor an AI response in real time.

```python
result = pg.check(
    prompt="Explain quantum tunneling.",
    response="Quantum tunneling is a phenomenon where...",
    thread_id="chat-session-42",
    risk_threshold=70,   # block if risk_score > 70 (default)
)
```

**CheckResult fields:**

| Field | Type | Description |
|-------|------|-------------|
| `should_block` | bool | `True` = suppress this response |
| `state` | str | `WARMING_UP`, `STABLE`, `ANALYZING`, `UNSTABLE`, `ANOMALY`, `DRIFT`, `CRITICAL`, `BLOCKED` |
| `risk_score` | int | 0–100. Higher = more risk |
| `confidence` | float | 0.0–1.0. Engine confidence in its verdict |
| `warnings` | list[str] | Human-readable warning messages |
| `explanation` | str | Plain-English explanation of the decision |
| `timestamp` | float | Unix timestamp from the server |

---

### `.thread_reset(thread_id) → bool`

Clear a thread's monitoring history. Call at the start of each new conversation.

```python
pg.thread_reset("chat-session-42")
```

---

### `.thread_summary(thread_id) → ThreadSummary`

Get aggregated risk stats for a conversation thread.

```python
summary = pg.thread_summary("chat-session-42")
print(f"Steps: {summary.total_steps}  |  Avg risk: {summary.mean_risk}  |  Peak: {summary.max_risk}")
```

**ThreadSummary fields:** `total_steps`, `mean_risk`, `max_risk`, `state_counts`

---

### Exceptions

| Exception | When |
|-----------|------|
| `PsiGuardAuthError` | Missing, invalid, or inactive API key |
| `PsiGuardRateLimitError` | Monthly limit reached (Playground plan) |
| `PsiGuardError` | Any other API or network error |

All exceptions expose a `.status_code` attribute with the HTTP status.

---

## Real-World Example

```python
import openai
from psiguard import PsiGuard, PsiGuardError

pg = PsiGuard()   # reads PSIGUARD_API_KEY from env
client = openai.OpenAI()

def safe_chat(user_message: str, session_id: str) -> str:
    ai_response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": user_message}],
    ).choices[0].message.content

    try:
        result = pg.check(
            prompt=user_message,
            response=ai_response,
            thread_id=session_id,
        )
        if result.should_block:
            return "I'm sorry, I can't help with that."
    except PsiGuardError as e:
        print(f"PsiGuard warning: {e}")  # fail open — don't break the app

    return ai_response
```

---

## Plans

| Plan | Checks/month | Price |
|------|-------------|-------|
| Playground | 50 | Free |
| Pro | Unlimited | [psiguard.ai/pricing](https://psiguard.ai/pricing) |

Get your API key at **[psiguard.ai](https://psiguard.ai)**

---

## License

MIT © PsiCo LLC
