Skip to main content

Zero-dependency observability and runtime guards for AI agents — loop detection, budget enforcement, cost tracking, and structured tracing

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-1.2.2.tar.gz (86.5 kB view details)

Uploaded Source

Built Distribution

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

agentguard47-1.2.2-py3-none-any.whl (42.7 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for agentguard47-1.2.2.tar.gz
Algorithm Hash digest
SHA256 50ea4dfdebb392a1a9e3172730f941bbb14babb7afb6b905b61f5e76deb5ed39
MD5 cc2e0e17088e4a995ffeea3031a9ac5f
BLAKE2b-256 92b56002ac776ce96aacf1e88927761752eba13d9d7913a834a7ab86bd77767a

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for agentguard47-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d898c4280d6147c8a95ca63c78327c5c1a9186c2b8eda0d49db6617bda9a4356
MD5 fa5fff7ba8156982dff3f53ac7c7910e
BLAKE2b-256 02c28e33f232f338d17343d9a894310a3ffbe805aab00ee7648c778c15e652bc

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