LangChain Integration
Auditail works as a wrapper around LangChain tools. Add guardrails to any existing tool in one line.
Python (LangChain)
import os
from langchain.agents import tool
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.prompts import ChatPromptTemplate
from auditail import Auditail, rules
# Initialize Auditail once
aegis = Auditail(api_key=os.environ["AUDITAIL_API_KEY"])
aegis.add_rules([
rules.no_external_email(),
rules.no_data_deletion(),
])
# Wrap LangChain tools with aegis.guard()
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""Send an email to a recipient."""
result = aegis.guard(
action="send_email",
payload={"to": to, "subject": subject, "body": body},
agent_id="langchain-email-agent",
)
if not result.approved:
return f"[Auditail] Action blocked: {result.reason}"
# Your actual email sending logic here
# email_client.send(to=to, subject=subject, body=body)
return f"Email sent to {to}"
@tool
def execute_sql(query: str) -> str:
"""Execute a SQL query against the database."""
result = aegis.guard(
action="execute_query",
payload={"query": query},
agent_id="langchain-db-agent",
)
if not result.approved:
return f"[Auditail] Action blocked: {result.reason}"
# Your actual DB execution logic here
# return db.execute(query)
return f"Query executed: {query[:50]}..."
# Build the agent as normal
llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [send_email, execute_sql]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant. Use the tools provided."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_openai_tools_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Run — Auditail will intercept any dangerous actions
agent_executor.invoke({"input": "Send the Q3 report to client@externalco.com"})
TypeScript (LangChain.js)
import { ChatOpenAI } from '@langchain/openai';
import { DynamicStructuredTool } from '@langchain/core/tools';
import { AgentExecutor, createOpenAIToolsAgent } from 'langchain/agents';
import { z } from 'zod';
import { Auditail } from 'auditail-sdk';
const aegis = new Auditail({ apiKey: process.env.AUDITAIL_API_KEY! });
aegis.addRule(Auditail.rules.noExternalEmail());
aegis.addRule(Auditail.rules.noDataDeletion());
const sendEmailTool = new DynamicStructuredTool({
name: 'send_email',
description: 'Send an email to a recipient.',
schema: z.object({
to: z.string().email(),
subject: z.string(),
body: z.string(),
}),
func: async ({ to, subject, body }) => {
const result = await aegis.guard({
action: 'send_email',
payload: { to, subject, body },
agentId: 'langchain-agent',
});
if (!result.approved) {
return `[Auditail] Action blocked: ${result.reason}`;
}
// await emailClient.send({ to, subject, body });
return `Email sent to ${to}`;
},
});
CrewAI Integration
from crewai import Agent, Task, Crew
from auditail import Auditail, rules
aegis = Auditail(api_key=os.environ["AUDITAIL_API_KEY"])
aegis.add_rule(rules.no_external_email())
def guarded_send_email(to: str, body: str) -> str:
result = aegis.guard(
action="send_email",
payload={"to": to, "body": body},
agent_id="crewai-outreach-agent",
)
if not result.approved:
return f"Blocked: {result.reason}"
return f"Sent to {to}"
outreach_agent = Agent(
role="Outreach Specialist",
goal="Send personalized emails to leads",
backstory="You are an expert at writing personalized outreach.",
tools=[guarded_send_email],
)
Why Wrap at the Tool Level?
Wrapping at the tool level (rather than the LLM call level) means:
- The LLM decides what to do — Auditail doesn't interfere with reasoning.
- Only the action is blocked — the agent can recover gracefully.
- The audit trail is precise — you know exactly what action was attempted, with what parameters.