Skip to main content

Zero-dependency observability and runtime guards for AI agents

Project description

AgentGuard SDK (Python)

PyPI License: MIT

Zero-dependency observability and runtime guards for AI agents. Pure Python stdlib — nothing to audit, nothing that can break. Trace reasoning steps, catch loops, enforce budgets, and replay runs deterministically.

Install

pip install agentguard47

Quickstart

from agentguard import Tracer, LoopGuard, BudgetGuard, JsonlFileSink

sink = JsonlFileSink("traces.jsonl")
tracer = Tracer(
    sink=sink,
    service="my-agent",
    guards=[LoopGuard(max_repeats=3), BudgetGuard(max_cost_usd=5.00)],
)

with tracer.trace("agent.run") as span:
    span.event("reasoning.step", data={"thought": "search docs"})
    with span.span("tool.search"):
        pass  # your tool here
agentguard report traces.jsonl   # summary table
agentguard view traces.jsonl     # Gantt timeline in browser

Guards

from agentguard import LoopGuard, BudgetGuard, TimeoutGuard, FuzzyLoopGuard, RateLimitGuard

# Exact loop detection
guard = LoopGuard(max_repeats=3)
guard.check(tool_name="search", tool_args={"query": "agent loops"})

# Fuzzy loop detection (same tool, different args + A-B-A-B patterns)
fuzzy = FuzzyLoopGuard(max_tool_repeats=5, max_alternations=3)
fuzzy.check("search", {"q": "docs"})

# Budget enforcement with warning callback
budget = BudgetGuard(
    max_cost_usd=5.00,
    warn_at_pct=0.8,
    on_warning=lambda msg: print(f"WARNING: {msg}"),
)
budget.consume(tokens=150, calls=1, cost_usd=0.02)

# Wall-clock timeout
timeout = TimeoutGuard(max_seconds=30)
timeout.start()
timeout.check()

# Rate limiting
rate = RateLimitGuard(max_calls_per_minute=60)
rate.check()

Auto-Instrumentation

from agentguard import Tracer, patch_openai, patch_anthropic
from agentguard import trace_agent, trace_tool

tracer = Tracer()

@trace_agent(tracer)
def my_agent(query):
    return search(query)

@trace_tool(tracer)
def search(q):
    return f"results for {q}"

# Monkey-patch OpenAI/Anthropic (safe if not installed)
patch_openai(tracer)
patch_anthropic(tracer)

Async Support

from agentguard import AsyncTracer, JsonlFileSink
from agentguard import async_trace_agent, async_trace_tool, patch_openai_async

tracer = AsyncTracer(sink=JsonlFileSink("traces.jsonl"), service="my-agent")
patch_openai_async(tracer)

@async_trace_agent(tracer)
async def my_agent(query: str) -> str:
    return await search(query)

@async_trace_tool(tracer)
async def search(q: str) -> str:
    return f"results for {q}"

Evaluation as Code

from agentguard import EvalSuite

result = (
    EvalSuite("traces.jsonl")
    .assert_no_loops()
    .assert_tool_called("search", min_times=1)
    .assert_budget_under(tokens=50000)
    .assert_cost_under(max_cost_usd=1.00)
    .assert_completes_within(30.0)
    .assert_no_errors()
    .assert_no_budget_warnings()
    .run()
)
print(result.summary)

Replay

from agentguard import Recorder, Replayer

recorder = Recorder("runs.jsonl")
recorder.record_call("llm", {"prompt": "hi"}, {"text": "hello"})

replayer = Replayer("runs.jsonl")
resp = replayer.replay_call("llm", {"prompt": "hi"})

Production Features

# Metadata attached to every event
tracer = Tracer(
    sink=sink,
    metadata={"env": "production", "git_sha": "abc123"},
)

# Probabilistic sampling (emit 10% of traces)
tracer = Tracer(sink=sink, sampling_rate=0.1)

# HttpSink with gzip, retry, idempotency
from agentguard import HttpSink
sink = HttpSink(
    url="https://app.agentguard47.com/api/ingest",
    api_key="ag_...",
    compress=True,
    max_retries=3,
)

CLI

agentguard report traces.jsonl      # human-readable summary
agentguard view traces.jsonl        # Gantt trace viewer in browser
agentguard summarize traces.jsonl   # event-level breakdown
agentguard eval traces.jsonl        # run evaluation assertions
agentguard eval traces.jsonl --ci   # CI mode (stricter checks, exit code)

Export

from agentguard.export import export_json, export_csv

export_json("traces.jsonl", "traces.json")
export_csv("traces.jsonl", "traces.csv")

Benchmark

python -m agentguard.bench

Migration Guide (v0.5 → v1.0)

v0.5 v1.0
from agentguard.tracing import JsonlFileSink from agentguard import JsonlFileSink
from agentguard.instrument import trace_agent from agentguard import trace_agent
from agentguard.instrument import patch_openai from agentguard import patch_openai
budget.record_tokens(150) budget.consume(tokens=150)
(no async support) AsyncTracer, async_trace_agent, patch_openai_async
(no fuzzy loops) FuzzyLoopGuard, RateLimitGuard
(no budget warnings) BudgetGuard(warn_at_pct=0.8, on_warning=...)
(no sampling) Tracer(sampling_rate=0.1)
(no metadata) Tracer(metadata={"env": "prod"})
(no gzip) HttpSink(compress=True)

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

agentguard47-0.7.0.tar.gz (68.0 kB view details)

Uploaded Source

Built Distribution

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

agentguard47-0.7.0-py3-none-any.whl (43.8 kB view details)

Uploaded Python 3

File details

Details for the file agentguard47-0.7.0.tar.gz.

File metadata

  • Download URL: agentguard47-0.7.0.tar.gz
  • Upload date:
  • Size: 68.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agentguard47-0.7.0.tar.gz
Algorithm Hash digest
SHA256 59c5e4236788f88cfffdadf08ed2473477add70b28f158df64a7d9f23328e45d
MD5 702593da95b60102b38d12d5975686df
BLAKE2b-256 44809484af554a723f7da3e6182ff471240ddc1846e9a76cec45c8a3f2894b53

See more details on using hashes here.

File details

Details for the file agentguard47-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: agentguard47-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 43.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for agentguard47-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 77a15be3a37df197385717f32bde15a1a183d3ca7015e86d8fa244d0a25e1f59
MD5 4c624bd428e0b004e2ba33049730bf9b
BLAKE2b-256 0df6154368ab0ed731b0bbd618cd624f2327d1bad0089c3bcf1e8ef70975c3ca

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