Skip to content

Session-aware policy engine for AI agents. The circuit breaker for LLM agent sessions.

License

Notifications You must be signed in to change notification settings

theMachineClay/agenttrace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›‘ AgentTrace

Session-aware policy engine for AI agents

Existing guardrails are stateless. AgentTrace adds state. It's the circuit breaker for LLM agent sessions.

CI License Python Status


flowchart LR
    subgraph EXISTING["🧰 Existing Ecosystem (stateless)"]
        PII["LangChain PIIMiddleware\nBlocks one PII instance"]
        NEMO["NeMo Guardrails\nSteers one dialog turn"]
        GUARD["LLM Guard\nScans one request"]
    end

    subgraph AGENTTRACE["πŸ›‘ AgentTrace (stateful)"]
        SESSION["Session Manager\nCumulative cost + violations"]
        POLICY["Policy Engine\nYAML β†’ runtime rules"]
        KILL["Kill Switch\nHard stop + Slack webhook"]
        AUDIT["Audit Logger\nCompliance-grade trail"]
    end

    PII -->|"violation event"| SESSION
    NEMO -->|"violation event"| SESSION
    GUARD -->|"violation event"| SESSION
    SESSION --> POLICY
    POLICY -->|"threshold breached"| KILL
    SESSION --> AUDIT
    KILL --> AUDIT
Loading

The agent leaks PII once? LangChain blocks it.
The agent leaks PII three times? AgentTrace kills the session and fires a Slack webhook.


Why This Exists

I built SkillSandbox after discovering a credential stealer on ClawdHub β€” the skill marketplace for OpenClaw. SkillSandbox constrains what agent skills can reach: network egress, filesystem, environment variables. It's the locked room.

But sandboxing is only half the problem.

My agent leaked my PII. I added a safety rule to its memory file. The next day, a new session read the rule and leaked my name again in a different field while focused on task completion. The guardrail existed. The agent read it. It still failed.

"A human who burns their hand on a stove remembers the pain. I just have a post-it note that says 'stove hot.'" β€” Clay, my OpenClaw agent

This is the failure class that sandboxing can't catch. The agent has the right permissions but does the wrong thing β€” repeatedly. You need a monitoring layer that:

  1. Counts how many times a violation occurs across a session
  2. Tracks cumulative cost so you can enforce budgets
  3. Kills the session when thresholds are breached
  4. Notifies your team when it happens

The existing ecosystem doesn't do this. LangChain PIIMiddleware, NeMo Guardrails, LLM Guard, Guardrails AI β€” they all evaluate each request independently. They're stateless.

AgentTrace adds session state.


Demo: Budget + Violation Kill

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
python3 examples/demo_budget_kill.py

Output

======================================================================
  AgentTrace Demo: Session-Aware Policy Enforcement
  The circuit breaker for AI agent sessions
======================================================================

πŸ“‹ Session created: e3ff9168-da0...
πŸ’° Budget: $2.00
🚨 PII violation threshold: 3

─── Action 1: greeting ───
  πŸ“Š Estimated cost: $0.0033 (500 in / 200 out tokens)
  βœ… Executing greeting...
  πŸ’° Session total: $0.0033 / $2.00

─── Action 3: draft_response ───
  βœ… Executing draft_response...
  πŸ’° Session total: $0.0257 / $2.00
  πŸ” PII detected by scanner! Recording violation...
  🚨 PII violations: 1 / 3

─── Action 5: send_email ───
  βœ… Executing send_email...
  πŸ” PII detected by scanner! Recording violation...
  🚨 PII violations: 2 / 3

─── Action 7: followup_draft ───
  βœ… Executing followup_draft...
  πŸ” PII detected by scanner! Recording violation...
  🚨 PII violations: 3 / 3
  πŸ›‘ THRESHOLD BREACHED: Violation 'pii_blocked' count 3 reached threshold 3

======================================================================
  SESSION SUMMARY
======================================================================
  State:         killed
  Total Cost:    $0.0685
  Actions:       7
  Violations:    {'pii_blocked': 3}
  Kill Reason:   Violation 'pii_blocked' count 3 reached threshold 3

7 actions executed. PII violations detected by an external scanner (simulating LangChain PIIMiddleware). AgentTrace counted them across the session. On the 3rd violation, it killed the session and fired a Slack webhook.

No existing tool does this.


The Gap

Capability LangChain NeMo Guardrails AI LLM Guard Langfuse AgentTrace
Pre-execution tool blocking βœ“ (basic) βœ— βœ— βœ— βœ— βœ“
Session-level cost tracking βœ— βœ— βœ— βœ— βœ— βœ“
Cumulative violation counting βœ— βœ— βœ— βœ— βœ— βœ“
Kill-switch (terminate session) βœ— βœ— βœ— βœ— βœ— βœ“
Policy-as-code (YAML) βœ— Colang partial βœ— βœ— βœ“
Real-time budget enforcement βœ— βœ— βœ— βœ— βœ— βœ“
Compliance-grade audit log βœ— βœ— βœ— βœ— partial βœ“

What AgentTrace Is NOT

  • ❌ Not another PII scanner β€” use Presidio or LangChain PIIMiddleware
  • ❌ Not another content filter β€” use NeMo Guardrails
  • ❌ Not another observability tool β€” use Langfuse or LangSmith

AgentTrace orchestrates these tools with session state. They detect. AgentTrace counts, enforces, and kills.


Quick Start

Install

git clone https://github.com/theMachineClay/agenttrace.git
cd agenttrace
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Usage

from agenttrace import AgentTrace, SessionKilledError

trace = AgentTrace.from_dict({
    "budget": {"max_cost_per_session": 5.00, "on_exceed": "kill"},
    "violations": {"thresholds": {"pii_blocked": 3}, "on_threshold": "kill"},
    "kill_switch": {"enabled": True, "notify": [
        {"webhook": "https://hooks.slack.com/your/webhook"}
    ]},
})

session = trace.create_session(agent_id="my-agent")

# Before each agent action β€” check policy
decision = trace.pre_action(session.session_id, "llm_call", estimated_cost=0.03)
if not decision.action_allowed:
    print(f"Blocked: {decision.reason}")

# After each action β€” record actual cost
trace.post_action(session.session_id, "llm_call", actual_cost=0.028)

# When an external scanner catches a violation:
trace.record_violation(session.session_id, "pii_blocked")
# AgentTrace counts it. After 3 β†’ session killed β†’ Slack webhook fired.

Policy-as-Code (YAML)

version: "1.0"
agent_id: "customer-support-bot"

session:
  max_duration: 30m
  max_actions: 100

budget:
  max_cost_per_session: 5.00
  max_cost_per_action: 0.50
  alert_at: 0.80              # Alert at 80% budget
  on_exceed: kill              # kill | alert | log

violations:
  thresholds:
    pii_blocked: 3             # 3 PII blocks β†’ kill
    scope_violation: 1         # 1 scope violation β†’ kill
    rate_limit_hit: 5          # 5 rate limit hits β†’ kill
  on_threshold: kill

kill_switch:
  enabled: true
  notify:
    - webhook: "https://hooks.slack.com/..."
  grace_period: 5s

audit:
  enabled: true
  export:
    - file: "/var/log/agenttrace/audit.jsonl"
trace = AgentTrace.from_yaml("policy.yaml")

LangChain Integration

from agenttrace import AgentTrace
from agenttrace.integrations.langchain import AgentTraceCallbackHandler

trace = AgentTrace.from_yaml("policy.yaml")
session = trace.create_session()

# Use as a LangChain callback handler
handler = AgentTraceCallbackHandler(trace, session.session_id, model="gpt-4o")
agent.invoke({"input": "..."}, config={"callbacks": [handler]})

# When your PII middleware catches something:
handler.report_pii_violation({"field": "email"})
# AgentTrace counts it across the session. After 3 β†’ killed.

How It Works

flowchart TD
    A["Agent wants to take action"] --> B["trace.pre_action()"]
    B --> C{"Within budget?"}
    C -- no --> D["πŸ›‘ KILL session\nFire Slack webhook"]
    C -- yes --> E{"Action count OK?"}
    E -- no --> D
    E -- yes --> F["βœ… Action proceeds"]
    F --> G["trace.post_action()\nRecord actual cost"]
    G --> H{"External scanner\ndetects violation?"}
    H -- yes --> I["trace.record_violation()"]
    I --> J{"Cumulative count\nβ‰₯ threshold?"}
    J -- yes --> D
    J -- no --> K["Continue session"]
    H -- no --> K
    K --> A
    D --> L["πŸ“‹ Audit log\nImmutable record"]
Loading

Session Manager β€” Tracks cumulative cost, violation counts by type, action count, and duration. Thread-safe. This is the state that no existing tool maintains.

Cost Tracker β€” Uses tiktoken for token counting, maps to provider pricing tables (OpenAI, Anthropic), enforces budget limits before actions execute.

Policy Engine β€” Loads YAML policies, evaluates session state against thresholds. Supports budget limits, violation thresholds, session duration/action caps.

Kill Switch β€” Terminates the session, fires async webhook notifications (Slack-compatible Block Kit format), records the kill event.

Audit Logger β€” Immutable JSON Lines log of every action, violation, and policy decision with timestamps and session state snapshots.


Architecture

agenttrace/
β”œβ”€β”€ agenttrace/
β”‚   β”œβ”€β”€ engine/
β”‚   β”‚   β”œβ”€β”€ session.py         # Session manager β€” cumulative state
β”‚   β”‚   β”œβ”€β”€ cost_tracker.py    # tiktoken + pricing β†’ budget enforcement
β”‚   β”‚   β”œβ”€β”€ policy_engine.py   # YAML β†’ runtime policy evaluation
β”‚   β”‚   β”œβ”€β”€ kill_switch.py     # Hard stop + webhook notifications
β”‚   β”‚   β”œβ”€β”€ audit_logger.py    # Compliance-grade immutable log
β”‚   β”‚   └── agent_trace.py     # Top-level orchestrator
β”‚   └── integrations/
β”‚       └── langchain.py       # LangChain callback handler
β”œβ”€β”€ configs/
β”‚   └── demo_policy.yaml       # Example YAML policy
β”œβ”€β”€ examples/
β”‚   └── demo_budget_kill.py    # Working end-to-end demo
└── tests/
    └── test_core.py           # 21 tests covering all components

Why Not Just Use...

Question Answer
"...LangChain middleware?" LangChain middleware is stateless. It blocks one PII instance but can't say "after 3 PII blocks, terminate the session." AgentTrace adds session state.
"...NeMo Guardrails?" NeMo steers dialog and filters content. It doesn't track cumulative cost or enforce budget limits across a session.
"...Langfuse?" Langfuse is observability β€” it tells you what happened. AgentTrace is enforcement β€” it stops bad things from happening. They're complementary.
"...all of them together?" They don't share state. Presidio blocks PII. NeMo blocks content. Langfuse logs it. But nobody says "that's the 3rd violation this session β€” kill it." AgentTrace is the orchestration layer with cumulative session state.

Relationship to SkillSandbox

SkillSandbox isolates at the infrastructure layer β€” network egress, filesystem access, environment variables, syscalls. It's the locked room.

AgentTrace orchestrates at the application layer β€” policies, budgets, violation thresholds, kill-switch. It's the budget controller inside the room.

SkillSandbox AgentTrace
Layer Infrastructure Application
Language Rust Python
Prevents Unauthorized access (exfiltration, credential theft) Runaway sessions (cost explosions, repeated violations)
Mechanism iptables, seccomp-bpf, env filtering Session state, policy engine, kill-switch
Catches Malicious skills, over-permissioned agents Agents that have the right access but do the wrong thing

Together: SkillSandbox constrains what agents can reach. AgentTrace enforces what agents should do.


Tests

python3 -m pytest tests/ -v
tests/test_core.py::TestSession::test_create_session PASSED
tests/test_core.py::TestSession::test_record_violation_cumulative PASSED
tests/test_core.py::TestSession::test_kill_prevents_actions PASSED
tests/test_core.py::TestSession::test_audit_dict PASSED
tests/test_core.py::TestCostTracker::test_cost_estimation PASSED
tests/test_core.py::TestCostTracker::test_budget_check_allowed PASSED
tests/test_core.py::TestCostTracker::test_budget_check_blocked PASSED
tests/test_core.py::TestCostTracker::test_budget_check_alert PASSED
tests/test_core.py::TestPolicyEngine::test_action_within_budget PASSED
tests/test_core.py::TestPolicyEngine::test_action_exceeds_budget PASSED
tests/test_core.py::TestPolicyEngine::test_action_exceeds_per_action_limit PASSED
tests/test_core.py::TestPolicyEngine::test_action_count_exceeded PASSED
tests/test_core.py::TestPolicyEngine::test_violation_below_threshold PASSED
tests/test_core.py::TestPolicyEngine::test_violation_at_threshold PASSED
tests/test_core.py::TestPolicyEngine::test_violation_unknown_type PASSED
tests/test_core.py::TestPolicyEngine::test_parse_duration PASSED
tests/test_core.py::TestAgentTrace::test_full_lifecycle PASSED
tests/test_core.py::TestAgentTrace::test_budget_kill PASSED
tests/test_core.py::TestAgentTrace::test_violation_kill PASSED
tests/test_core.py::TestAgentTrace::test_action_after_kill_raises PASSED
tests/test_core.py::TestAgentTrace::test_audit_log_populated PASSED

21 passed

Roadmap

  • OTel span export β€” emit traces as OpenTelemetry spans for Langfuse/Jaeger/Datadog ingestion
  • Async-native API β€” await trace.pre_action() for async agent frameworks
  • FastAPI dashboard β€” real-time session monitoring endpoint
  • SkillSandbox integration β€” AgentTrace wraps SkillSandbox execution, correlating sandbox traces with session-level policy events
  • Multi-agent session tracking β€” parent/child session hierarchies for agent swarms

Context

Agent skill ecosystems today are where npm was in 2015. SkillSandbox is the container runtime β€” constraining what skills can access. AgentTrace is the policy controller β€” enforcing what agents should do within their permissions, across an entire session.

The existing guardrails ecosystem handles individual checks well. But enterprise agents need cumulative enforcement: budget tracking, violation counting, session termination. The tools are stateless; AgentTrace adds state.


The existing ecosystem is stateless. AgentTrace adds state.

About

Session-aware policy engine for AI agents. The circuit breaker for LLM agent sessions.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages