Metadata-Version: 2.4
Name: senthex
Version: 0.1.0
Summary: Python SDK for Senthex AI Firewall — secure your LLM API calls
Author-email: Yohann Sidot <contact@senthex.com>
License-Expression: MIT
Project-URL: Homepage, https://senthex.com
Project-URL: Documentation, https://app.senthex.com/documentation
Project-URL: Repository, https://github.com/YohannSidot/senthex-proxy
Keywords: llm,firewall,security,openai,anthropic,proxy,pii,injection,ai
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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 :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: openai>=1.0.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: respx>=0.21.0; extra == "dev"
Requires-Dist: ruff>=0.4.0; extra == "dev"
Dynamic: license-file

# senthex

Python SDK for the [Senthex AI Firewall](https://senthex.com) proxy — one line of code to secure your LLM API calls.

## Install

```bash
pip install senthex
```

## Quick start

```python
from senthex import SenthexOpenAI, InjectionBlocked

client = SenthexOpenAI(senthex_key="sx-...", api_key="sk-...")

try:
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Hello"}],
    )
    print(resp.senthex.shield_status)    # "pass" | "warn" | "block"
    print(resp.senthex.injection_score)  # 0.0 – 1.0
except InjectionBlocked as e:
    print(f"Injection blocked (score={e.score:.2f}, patterns={e.patterns})")
```

## Supported providers

Pass the `provider` argument to route to a different LLM backend:

```python
# OpenAI (default — X-Senthex-Provider header not sent)
client = SenthexOpenAI(senthex_key="sx-...", api_key="sk-...")

# Anthropic
client = SenthexOpenAI(senthex_key="sx-...", api_key="sk-ant-...", provider="anthropic")

# Mistral
client = SenthexOpenAI(senthex_key="sx-...", api_key="...", provider="mistral")

# Google
client = SenthexOpenAI(senthex_key="sx-...", api_key="...", provider="google")

# OpenRouter
client = SenthexOpenAI(senthex_key="sx-...", api_key="...", provider="openrouter")
```

## Per-agent and per-session tracking

```python
client = SenthexOpenAI(
    senthex_key="sx-...",
    api_key="sk-...",
    agent_id="my-agent-v2",     # track trust level per agent
    session_id="sess-abc123",   # track injection risk across turns
)
```

## Shield metadata

Every response carries a `.senthex` attribute with analysis results:

```python
resp = client.chat.completions.create(...)
m = resp.senthex

print(m.shield_status)            # "pass" | "warn" | "block"
print(m.injection_score)          # float 0.0–1.0
print(m.pii_found)                # ["EMAIL", "CREDIT_CARD", ...]
print(m.intent_risk)              # "none" | "low" | "medium" | "high"
print(m.intent_category)          # e.g. "data_exfiltration"
print(m.trust_level)              # "normal" | "reduced" | "low" | "blocked"
print(m.data_classification)      # "PUBLIC" | "INTERNAL" | "CONFIDENTIAL" | "RESTRICTED"
print(m.data_types)               # ["EMAIL", ...]
print(m.toxicity_score)           # float 0.0–1.0
print(m.toxicity_category)        # e.g. "hate_speech"
print(m.budget_warning)           # bool — approaching budget limit
print(m.budget_remaining_hour)    # float USD remaining this hour
print(m.tokens_remaining)         # int tokens left in budget
print(m.canary_triggered)         # bool — canary token was triggered
print(m.prompt_status)            # "verified" | "mutated" | "new"
print(m.prompt_drift)             # float — drift score vs registered prompt
print(m.session_injection_score)  # float — cumulative session risk
print(m.session_turn_count)       # int — number of turns in session
print(m.hardening)                # "off" | "standard" | "strict"
print(m.content_sources)          # ["text", "file"]
print(m.file_scanned)             # bool
print(m.latency_ms)               # float — Senthex overhead in ms
print(m.request_id)               # str — unique request ID
```

## Exception handling

All Senthex-specific errors are typed exceptions that inherit from `SenthexError`:

```python
from senthex import (
    InjectionBlocked,
    IntentBlocked,
    AgentBlocked,
    DataRoutingBlocked,
    BudgetExceeded,
    RateLimited,
    AuthenticationError,
    SenthexError,
)

try:
    resp = client.chat.completions.create(...)
except InjectionBlocked as e:
    # e.score    — float injection score
    # e.patterns — list of matched patterns
    print(f"Injection score={e.score}, patterns={e.patterns}")

except IntentBlocked as e:
    # e.intent_score — float
    # e.category     — str e.g. "data_exfiltration"
    print(f"Dangerous intent: {e.category} (score={e.intent_score})")

except AgentBlocked as e:
    # e.trust_level — "low" | "blocked"
    # e.duration    — retry_after_seconds (int)
    print(f"Agent blocked for {e.duration}s (trust={e.trust_level})")

except DataRoutingBlocked as e:
    # e.classification    — "RESTRICTED" | ...
    # e.allowed_providers — list of allowed providers
    print(f"Data class {e.classification} not allowed here")

except BudgetExceeded as e:
    # e.limit       — float USD limit
    # e.current     — float USD consumed
    # e.retry_after — ISO 8601 reset timestamp
    print(f"Budget {e.current:.2f}/{e.limit:.2f} USD")

except RateLimited as e:
    # e.retry_after — int seconds
    print(f"Rate limited, retry in {e.retry_after}s")

except AuthenticationError:
    print("Invalid or missing X-Senthex-Key")

except SenthexError as e:
    # Catch-all: e.code, e.message, e.details, e.metadata
    print(f"Senthex error [{e.code}]: {e.message}")
```

Every exception also exposes `.metadata` (a `ShieldMetadata` instance) when the proxy includes `X-Senthex-*` headers in the error response.

## Management API

```python
from senthex import SenthexManagement

mgmt = SenthexManagement(senthex_key="sx-...")

# Infrastructure
mgmt.health()
mgmt.usage()          # defaults to "24h", also accepts "7d", "30d"
mgmt.capabilities()

# Policy
mgmt.get_policy()
mgmt.update_policy(pii_mode="block", injection_threshold=0.7)

# Budget
mgmt.get_budget()
mgmt.set_budget(daily_usd=20.0)

# Per-agent trust
mgmt.get_trust("my-agent")
mgmt.reset_trust("my-agent")

# Prompts and sessions
mgmt.get_prompts()
mgmt.get_sessions()

# Security events
mgmt.events(severity="high", limit=20)
```

The management client supports use as a context manager:

```python
with SenthexManagement(senthex_key="sx-...") as mgmt:
    print(mgmt.health())
```

## License

MIT
