Metadata-Version: 2.4
Name: ardenpy
Version: 0.4.1
Summary: AI Agent Warden - Keep your AI agents in check with policy enforcement and human oversight
Author-email: Arden Team <team@arden.dev>
License: MIT
Project-URL: Homepage, https://arden.sh
Project-URL: Documentation, https://arden.sh/docs
Project-URL: Repository, https://github.com/arden/ardenpy
Project-URL: Issues, https://github.com/arden/ardenpy/issues
Keywords: ai,agent,security,policy,approval,llm,safety
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 :: Security
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.24.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: typing-extensions>=4.0.0
Requires-Dist: packaging>=21.0
Requires-Dist: requests>=2.25.0
Provides-Extra: langchain
Requires-Dist: langchain>=0.1.0; extra == "langchain"
Provides-Extra: crewai
Requires-Dist: crewai>=0.28.0; extra == "crewai"
Provides-Extra: openai-agents
Requires-Dist: openai-agents>=0.0.3; extra == "openai-agents"
Provides-Extra: all
Requires-Dist: langchain>=0.1.0; extra == "all"
Requires-Dist: crewai>=0.28.0; extra == "all"
Requires-Dist: openai-agents>=0.0.3; extra == "all"
Dynamic: license-file

# ardenpy

**Policy enforcement and human approval for AI agent tool calls.**

Arden sits between your agent and its tools. Every call is checked against policies you configure in the dashboard — automatically allowed, blocked, or held for a human to approve.

## Install

```bash
pip install ardenpy
```

## Quick start

**1. Get your API key** from [app.arden.sh](https://app.arden.sh). You'll get two keys:
- `arden_test_...` — development, hits `api-test.arden.sh`
- `arden_live_...` — production, hits `api.arden.sh`

**2. Configure once**

```python
import ardenpy as arden
arden.configure(api_key="arden_live_...")
```

**3. Call your tools**

For **LangChain and CrewAI** — that's it. Arden auto-patches the framework at configure-time, so every tool call is intercepted without any wrapping:

```python
# LangChain — use tools normally, Arden intercepts everything
arden.configure(api_key="arden_live_...", tool_name_prefix="support")

agent = create_react_agent(llm, tools, prompt)  # no wrapping needed
# Tool names in the dashboard: "support.search_web", "support.send_email", etc.
```

For **custom agents with no framework**, wrap functions explicitly:

```python
def issue_refund(amount: float, customer_id: str) -> dict:
    return {"refund_id": "re_123", "amount": amount}

safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund)

result = safe_refund(150.0, customer_id="cus_abc")
# Arden checks policy first — allow, block, or wait for human approval
```

---

## How it works

Every tool call goes through a policy check before executing:

| Policy decision | What happens |
|----------------|-------------|
| `allow` | Function executes immediately |
| `block` | `PolicyDeniedError` raised, function never runs |
| `requires_approval` | Pauses until a human approves or denies on the dashboard |

**No policy configured?** The call is allowed automatically and logged — you get a full audit trail from day one and can add policies incrementally.

---

## Approval modes

When a tool requires approval, you choose how your code waits:

**`wait` (default)** — blocks until a human acts, then executes or raises `PolicyDeniedError`.

**`async`** — returns a `PendingApproval` immediately, background thread polls and calls your callback.

**`webhook`** — returns `PendingApproval` immediately, no polling. Arden POSTs to your endpoint when an admin decides.

```python
# wait (default)
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund)

# async
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund,
    approval_mode="async", on_approval=handle_approval, on_denial=handle_denial)

# webhook
safe_refund = arden.guard_tool("stripe.issue_refund", issue_refund,
    approval_mode="webhook", on_approval=on_approval, on_denial=on_denial)
```

For webhook setup (FastAPI, Flask, Django examples) see the [Library Reference](LIBRARY_REFERENCE.md#webhook-integration).

---

## Framework integrations

### LangChain and CrewAI — zero wrapping required

Arden automatically patches LangChain and CrewAI's base tool class when `configure()` is called. Every tool instance — including ones created after configure — has its calls intercepted.

```python
import ardenpy as arden

arden.configure(api_key="arden_live_...")
# All LangChain / CrewAI tool calls in this process are now intercepted.
# No protect_tools(), no guard_tool(), no boilerplate.
```

Tool names in the dashboard match each tool's `.name` attribute directly (e.g. `"issue_refund"`). The API key already scopes calls to your agent, so no prefix is needed.

Install the optional framework dependencies if you don't already have them:

```bash
pip install "ardenpy[langchain]"     # LangChain
pip install "ardenpy[crewai]"        # CrewAI
```

If you need per-tool approval mode overrides, `protect_tools()` is still available — see the [Library Reference](LIBRARY_REFERENCE.md#framework-integrations).

### OpenAI Chat Completions

```python
from ardenpy.integrations.openai import ArdenToolExecutor

executor = ArdenToolExecutor(tool_name_prefix="support")
executor.register("issue_refund", issue_refund_fn)
executor.register("send_email",   send_email_fn)

# In your loop:
result = executor.run(tc.function.name, json.loads(tc.function.arguments))
```

### OpenAI Agents SDK

```python
from ardenpy.integrations.openai import protect_function_tools

safe_tools = protect_function_tools([issue_refund, search], tool_name_prefix="support")
agent = Agent(name="SupportBot", tools=safe_tools)
```

```bash
pip install "ardenpy[openai-agents]"
```

See [examples/](examples/README.md) for runnable code for every integration.

---

## Error handling

```python
try:
    result = safe_refund(150.0, customer_id="cus_abc")
except arden.PolicyDeniedError:
    # blocked by policy, or denied by a human
except arden.ApprovalTimeoutError:
    # nobody approved within max_poll_time (wait mode)
except arden.ArdenError:
    # API/configuration error
```

---

## Links

- [Library Reference](LIBRARY_REFERENCE.md) — full API docs
- [Examples](examples/README.md) — runnable code
- [Dashboard](https://app.arden.sh)
- [PyPI](https://pypi.org/project/ardenpy/)
- [Support](mailto:team@arden.sh)
