🚧 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_KEY is 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.