Skip to main content

AI Agent Warden - Keep your AI agents in check with policy enforcement and human oversight

Project description

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

pip install ardenpy

Quick start

1. Get your API key from 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

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:

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

agent = create_react_agent(llm, tools, prompt)  # no wrapping needed
# Tool names in the dashboard match each tool's .name attribute directly

For custom agents with no framework, wrap functions explicitly:

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.

# 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.


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.

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:

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.

OpenAI Chat Completions

from ardenpy.integrations.openai import ArdenToolExecutor

executor = ArdenToolExecutor()
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

from ardenpy.integrations.openai import protect_function_tools

safe_tools = protect_function_tools([issue_refund, search])
agent = Agent(name="SupportBot", tools=safe_tools)
pip install "ardenpy[openai-agents]"

See examples/ for runnable code for every integration.


Session tracking

Attach a session ID to group all tool calls from a single conversation in the action log:

import ardenpy as arden
import uuid

arden.configure(api_key="arden_live_...")

# Set once per request — all guard_tool and auto-patched calls carry it automatically
arden.set_session(str(uuid.uuid4()))

Uses contextvars.ContextVar — safe for concurrent async requests. Fully optional.


Error handling

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ardenpy-0.5.0.tar.gz (43.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ardenpy-0.5.0-py3-none-any.whl (26.5 kB view details)

Uploaded Python 3

File details

Details for the file ardenpy-0.5.0.tar.gz.

File metadata

  • Download URL: ardenpy-0.5.0.tar.gz
  • Upload date:
  • Size: 43.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for ardenpy-0.5.0.tar.gz
Algorithm Hash digest
SHA256 487a4ae28a7f554389344fb8539da105b4aa9b3f23ee34ddada18722e740ffb1
MD5 7299d48c49e3f1c6ad0f08cc7b2530ac
BLAKE2b-256 47eb59ce497076bc4715c09129c181096896610c1bce6a6f3e5c8fdb70b1e992

See more details on using hashes here.

File details

Details for the file ardenpy-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: ardenpy-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 26.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for ardenpy-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a6764e112a8b0c9237ad0e492549682612c8e1ebe4e0c4d77cf8a6b1d99a27ba
MD5 b454e24899fa7792d10946215460db00
BLAKE2b-256 fe39262ef81e5164ea27cae558c5ae3b2a12a360a26d3f1ebf4b90dda23d5445

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page