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.8.0.tar.gz (69.3 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.8.0-py3-none-any.whl (44.6 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for agentguard47-0.8.0.tar.gz
Algorithm Hash digest
SHA256 3e7e8ef07ced972b1b9da409d2d7811a161283d8018f2bb3de9b100da25da815
MD5 5f21fb689f384742b8054ab71f26d25d
BLAKE2b-256 99becd146ad0ffc0eafa88f5d62bbb6bc3659a16b939db012bace20e6dfc35e5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: agentguard47-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 44.6 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.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 248d771d4f0346fbd7b236a415d660214cef6ec1aeed4dc9a6158f568a1178b0
MD5 21e2c609e652724ae880a451dc9c10d2
BLAKE2b-256 372d9810651da12810c454b70626f972f8d325055757334f52a40065f8cff363

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