🚧 Developer Preview — v0.1.0
AgentSentinel is functional, installable scaffolding. The Python and TypeScript SDKs work as documented below. Features marked roadmap are not yet implemented. Follow the repo for progress.
License Activation
1) Find your license key
Your key is sent after purchase from contact@agentsentinel.net and looks like
as_pro_xxxxxxxxxxxxxxxx.
2) Set the environment variable
# Linux / macOS
export AGENTSENTINEL_LICENSE_KEY="as_pro_your_key_here"
# Windows (PowerShell)
$env:AGENTSENTINEL_LICENSE_KEY="as_pro_your_key_here"
# .env
AGENTSENTINEL_LICENSE_KEY=as_pro_your_key_here
3) Verify activation and troubleshoot
Run your first protected tool call. If your key is valid, AgentSentinel initializes without license errors.
- License key not found: ensure
AGENTSENTINEL_LICENSE_KEYis set in the same shell/process. - Invalid key: copy the full key exactly from your email (no extra spaces/quotes).
- Still stuck? contact contact@agentsentinel.net.
Installation
# Requires Python 3.10+
pip install agentsentinel-core
The Python SDK has zero runtime dependencies — it uses only the Python standard library.
The TypeScript SDK likewise has no runtime dependencies and targets ES2020 / Node.js 18+.
Note: PyPI and npm packages are not yet published. In the meantime, install directly from the repository:
pip install git+https://github.com/ordocaelum/agentsentinel-landing.git#subdirectory=python
Quick Start
from agentsentinel import AgentGuard, AgentPolicy, ApprovalRequiredError, BudgetExceededError
# 1. Define a policy
policy = AgentPolicy(
daily_budget=10.0,
hourly_budget=2.0,
require_approval=["send_email", "delete_*"],
rate_limits={"search_web": "10/min"},
audit_log=True,
)
# 2. Create a guard
guard = AgentGuard(policy=policy)
# 3. Protect your tools
@guard.protect(tool_name="search_web", cost=0.01)
def search_web(query: str) -> str:
return f"Results for: {query}"
@guard.protect(tool_name="send_email")
def send_email(to: str, subject: str, body: str):
print(f"Sending to {to}: {subject}")
# 4. Use your tools — guardrails are applied automatically
result = search_web("AI safety") # ✓ allowed
try:
send_email("user@example.com", "Hi", "Test")
except ApprovalRequiredError as e:
print(f"Blocked: {e}") # ⏸ requires approval
Examples
The examples/ directory contains
runnable demos for each SDK:
Python quickstart
examples/python_quickstart.py
Demonstrates all features: budget, approvals, rate limits, and audit logging.
cd python && pip install -e .
python ../examples/python_quickstart.py
TypeScript quickstart
examples/typescript_quickstart.ts
Parallel TypeScript demo — same features as the Python example.
cd typescript && npm install && npm run build
npx ts-node ../examples/typescript_quickstart.ts
API Reference
AgentPolicy
Configuration dataclass (Python) / class (TypeScript) for all safety controls. Pass to AgentGuard.
| Parameter | Type | Description |
|---|---|---|
daily_budget |
float | Max cumulative cost (USD) per day. Default: unlimited. |
hourly_budget |
float | Max cumulative cost (USD) per rolling hour. Default: unlimited. |
require_approval |
list[str] | Tool name patterns requiring human approval. Supports fnmatch wildcards like delete_*. Default: empty. |
rate_limits |
dict[str, str] | Per-tool rate limit strings. Keys support wildcards. Values: "10/min", "100/hour". |
audit_log |
bool | Enable audit logging. Default: True. |
alert_channel |
str | Alert destination. Currently: "console". Slack/webhook on roadmap. Default: "console". |
cost_estimator |
callable | None | Optional (tool_name, kwargs) → float function. Used when no explicit cost= is provided. |
AgentGuard
Main guard class. Wraps tools with all policy enforcement.
AgentGuard(policy, approval_handler=None, audit_logger=None)
Construct a guard. Optionally supply an ApprovalHandler and/or AuditLogger. Defaults to DenyAllApprover and ConsoleAuditSink.
guard.protect(func=None, *, tool_name=None, cost=None)
Decorator that enforces all policy rules. Supports three forms:
# Form 1: plain decorator (tool_name = function name)
@guard.protect
def my_tool(): ...
# Form 2: with options
@guard.protect(tool_name="my_tool", cost=0.05)
def my_tool(): ...
# Form 3: wrap an existing function
protected = guard.protect(existing_fn, tool_name="existing_fn")
guard.daily_spent / guard.hourly_spent
Read-only properties returning cumulative cost (USD) for the current day / hour.
guard.reset_costs()
Reset all cost accumulators to zero. Useful in tests.
Errors
All errors inherit from AgentSentinelError.
BudgetExceededError
Raised when a tool call would exceed the daily or hourly budget. Has .budget and .spent attributes.
ApprovalRequiredError
Raised when a tool matches a require_approval pattern and the approval handler denies or raises. Has .tool_name.
RateLimitExceededError
Raised when a tool exceeds its configured rate limit. Has .tool_name and .limit.
Audit
Every invocation produces an AuditEvent broadcast to all registered AuditSink instances.
AuditEvent
Fields: timestamp, tool_name, status, cost, decision, metadata.
Decision values: allowed · blocked_budget · blocked_rate_limit · approval_required · approved · error
ConsoleAuditSink
Prints a one-line summary of each event to stdout. Default sink.
InMemoryAuditSink
Accumulates events in .events list. Ideal for tests.
sink = InMemoryAuditSink()
logger = AuditLogger(sinks=[sink])
guard = AgentGuard(policy=policy, audit_logger=logger)
# ... run some tools ...
for event in sink.events:
print(event.tool_name, event.decision)
AuditLogger
Manages a list of sinks. Use .add_sink() / .remove_sink() to configure dynamically. Implement AuditSink for custom destinations (file, database, HTTP).
Approval
Approval handlers decide whether a tool matching require_approval may proceed.
DenyAllApprover (default)
Raises ApprovalRequiredError for every request. Use this in production until a real approval channel is configured.
InMemoryApprover(approved_tools=set())
Pre-approves specific tool names. Call .approve(name) / .revoke(name) dynamically.
approver = InMemoryApprover(approved_tools={"send_email"})
guard = AgentGuard(policy=policy, approval_handler=approver)
ApprovalHandler (interface)
Implement request_approval(tool_name, **kwargs) → bool to add Slack/email/webhook approval flows.
RateLimiter
Sliding-window per-tool rate limiter. Configured via AgentPolicy.rate_limits; used automatically by AgentGuard.
Rate limit string format
"10/min" — 10 calls per minute
"100/hour" — 100 calls per hour
"5/sec" — 5 calls per second
"*" key — applies to all tools not matched by a more specific pattern
Framework Integrations
AgentSentinel ships first-class integrations for all major AI agent frameworks. None of the integrations require the target framework to be installed at import time — the dependency is only needed when you actually call the integration.
LangChain
Wraps every tool in a LangChain AgentExecutor or a bare list of tools.
from agentsentinel import AgentGuard, AgentPolicy
from agentsentinel.integrations.langchain import protect_langchain_agent
policy = AgentPolicy(daily_budget=5.0, require_approval=["send_email"])
guard = AgentGuard(policy=policy)
executor = protect_langchain_agent(executor, guard)
executor.invoke({"input": "..."})
AutoGen
Wraps AutoGen function_map dicts and individual callables.
from agentsentinel import AgentGuard, AgentPolicy
from agentsentinel.integrations.autogen import AutoGenGuard
policy = AgentPolicy(daily_budget=5.0)
ag_guard = AutoGenGuard(AgentGuard(policy))
# Protect a function_map
safe_map = ag_guard.protect_function_map({
"run_sql": run_sql,
"send_email": send_email,
})
CrewAI
Protect an entire Crew or wrap individual tools with the @crewai_guard.tool decorator.
from agentsentinel import AgentGuard, AgentPolicy
from agentsentinel.integrations.crewai import CrewAIGuard, protect_crew
policy = AgentPolicy(daily_budget=5.0, require_approval=["send_email"])
guard = AgentGuard(policy)
crewai_guard = CrewAIGuard(guard)
# Option 1: decorator
@crewai_guard.tool(cost=0.01)
def search_web(query: str) -> str:
return search(query)
# Option 2: protect a whole Crew
protected_crew = protect_crew(crew, guard=guard)
result = protected_crew.kickoff()
LlamaIndex
Protect LlamaIndex agents, FunctionTool objects, and QueryEngine instances.
from agentsentinel import AgentGuard, AgentPolicy
from agentsentinel.integrations.llamaindex import LlamaIndexGuard, protect_query_engine
policy = AgentPolicy(daily_budget=10.0, model_budgets={"gpt-4o": 5.0})
guard = AgentGuard(policy)
llama_guard = LlamaIndexGuard(guard)
@llama_guard.tool(model="gpt-4o", cost=0.02)
def query_knowledge_base(query: str) -> str:
return kb.query(query)
# Wrap a QueryEngine
protected_engine = protect_query_engine(engine, guard=guard)
OpenAI Assistants API
Wrap function maps used in the OpenAI Assistants API run loop with full policy enforcement.
from agentsentinel import AgentGuard, AgentPolicy
from agentsentinel.integrations.openai_assistants import protect_function_map
policy = AgentPolicy(daily_budget=20.0, require_approval=["send_email"])
guard = AgentGuard(policy)
protected = protect_function_map(
{"get_weather": get_weather, "send_email": send_email},
guard=guard,
default_model="gpt-4o",
)
# In your run loop:
result = protected[fn_name](**fn_args)
Anthropic Claude Tools
Protect tool_use handler maps for Anthropic's Claude model family.
from agentsentinel import AgentGuard, AgentPolicy
from agentsentinel.integrations.anthropic_tools import protect_tool_handlers
policy = AgentPolicy(daily_budget=15.0, model_budgets={"claude-3-5-sonnet": 10.0})
guard = AgentGuard(policy)
handlers = protect_tool_handlers(
{"get_weather": get_weather, "search_web": search_web},
guard=guard,
model="claude-3-5-sonnet",
)
# In your message loop:
for block in response.content:
if block.type == "tool_use":
result = handlers[block.name](**block.input)
| Framework | Guard class | One-liner |
|---|---|---|
| LangChain | LangChainGuard |
protect_langchain_agent(executor, guard) |
| AutoGen | AutoGenGuard |
protect_function_map(fn_map, guard) |
| CrewAI | CrewAIGuard |
protect_crew(crew, guard=guard) |
| LlamaIndex | LlamaIndexGuard |
protect_agent(agent, guard=guard) |
| OpenAI Assistants | OpenAIAssistantsGuard |
protect_function_map(fns, guard=guard) |
| Anthropic Tools | AnthropicToolsGuard |
protect_tool_handlers(handlers, guard=guard) |
What's Next
v0.2 — Adapters
- • Slack approval handler
- • Webhook / HTTP sink
- • LangChain tool adapter
v0.3 — Cost tracking
- • Auto token-count estimation (OpenAI, Anthropic)
- • UTC midnight daily counter reset
- • Persistent file audit sink
v0.4 — Frameworks
- • AutoGen function wrapper
- • CrewAI task guard
- • LlamaIndex tool wrapper
v1.0 — Dashboard
- • Local audit review UI
- • PyPI + npm package publication
- • Self-hosted server option
Want to influence the roadmap? Drop us a line or open a discussion on GitHub.