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.1.tar.gz (98.2 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.1-py3-none-any.whl (51.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: agentguard47-1.2.1.tar.gz
  • Upload date:
  • Size: 98.2 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.1.tar.gz
Algorithm Hash digest
SHA256 06870ab7482962d4f4b58c57e4b740d647b4341ba25fe9bad911ee7f59b46505
MD5 0b55cf25fbd2e225e9379f3b3d95b229
BLAKE2b-256 16ec36f48f3f6957bbaddb3714a7f92620282718f9b7c271ac27efa74b696dae

See more details on using hashes here.

File details

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

File metadata

  • Download URL: agentguard47-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 51.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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 44e1a1bb2742e7fb0aef7b64d8054385179da6bf0426a415d0adf452e3148f90
MD5 516013a2ac12c387e5f6a087797ddcd2
BLAKE2b-256 b439cebfcb6c5c5043595ac6a2d4298cb754599279738e671666e53d96da37a6

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