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.6.0.tar.gz (56.1 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.6.0-py3-none-any.whl (36.2 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for agentguard47-0.6.0.tar.gz
Algorithm Hash digest
SHA256 3be1ade9c5c29425966b4c56cb05742f6dff3a81e452533c0f6bef9838540482
MD5 34dccf0681ed84f2e66e0d55e819f589
BLAKE2b-256 0b01acb4c4637b38e19e095924cb928d5b904eafc990ae17d9cea32d886cd77d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: agentguard47-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 36.2 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.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3e09ccb2ab37584192da3810e81fd8ecaecdbbf30b5db3e245fce25f472bde27
MD5 e2d0a3aa4b73e7d0ca4947315b28a9ee
BLAKE2b-256 66633f56277bdf17a1406f0b847f1e167d4e57dcc104af5ed67dc52d796e0330

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