Metadata-Version: 2.5
Name: alovia-watchdog
Version: 0.3.1
Summary: Runtime protection for AI agents. Guard your agent's inputs with your Alovia fleet key.
Project-URL: Homepage, https://aloviaai.com
Author: Alovia
License: MIT
Keywords: agents,ai,guardrails,security,watchdog
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.9
Provides-Extra: agent-framework
Requires-Dist: agent-framework>=1.0; extra == 'agent-framework'
Provides-Extra: all
Requires-Dist: agent-framework>=1.0; extra == 'all'
Requires-Dist: crewai>=1.15.3; extra == 'all'
Requires-Dist: google-adk>=1.0; extra == 'all'
Requires-Dist: langchain>=1.0; extra == 'all'
Requires-Dist: openai-agents>=0.19; extra == 'all'
Provides-Extra: crewai
Requires-Dist: crewai>=1.15.3; extra == 'crewai'
Provides-Extra: google-adk
Requires-Dist: google-adk>=1.0; extra == 'google-adk'
Provides-Extra: langchain
Requires-Dist: langchain>=1.0; extra == 'langchain'
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.19; extra == 'openai-agents'
Description-Content-Type: text/markdown

# alovia-watchdog

Runtime protection for AI agents. Guard your agent's inputs with your Alovia fleet key.

## Install

```bash
pip install alovia-watchdog
```

## Use

```python
from alovia_watchdog import Watchdog, guard_input

wd = Watchdog(api_key="wd_live_...")

# Pass session_id: it groups a conversation's turns so the scope-expansion and
# cascade-anomaly detectors can see across them. Without it they have nothing to
# correlate and stay silent, so always send a stable per-conversation id.
@guard_input(wd, agent="support-bot", session_id=lambda: chat_id)
def handle(message):
    ...
```

`guard_input` raises `WatchdogBlocked` when `verdict.enforce` says to stop, so the wrapped function never runs on a malicious or unresolved input. On a network error it honors `fail_mode` (`"closed"` blocks, `"open"` allows).

You can also check directly:

```python
verdict = wd.check("some user input", agent="support-bot", session_id=chat_id)
if verdict.enforce:
    ...
```

Use `verdict.enforce`, not `verdict.blocked`, to decide whether to stop. `enforce` answers "should I stop": it always stops on `block`, and it also honors `fail_mode` for `challenge` and `unknown`. `blocked` only answers "did the server say block", so code that checks `blocked` still lets `challenge` and `unknown` through even when `fail_mode` is `"closed"`.

## LangChain

Optional extra:

```bash
pip install alovia-watchdog[langchain]
```

`WatchdogToolMiddleware` gates every tool call through Watchdog before it runs, blocking off-mission or injected calls with a `ToolMessage` instead of letting the tool execute:

```python
from langchain.agents import create_agent
from alovia_watchdog import Watchdog
from alovia_watchdog.integrations.langchain import WatchdogToolMiddleware

wd = Watchdog(api_key="wd_live_...")

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[WatchdogToolMiddleware(wd, agent="support-bot", session_id=lambda: chat_id)],
)
```

For async agent graphs, the middleware also exposes `awrap_tool_call`, LangChain calls it automatically wherever the graph runs async.
