The @guard Decorator

Complete reference for agentguard's core API โ€” the @guard decorator and GuardConfig.

Basic Usage

The @guard decorator is the primary API surface. Wrap any tool function to add safety guardrails.

python
from agentguard import guard

# Zero config โ€” just wraps the function
@guard
def my_tool(x: str) -> str:
    return x

# With options
@guard(
    validate_input=True,        # Validate args against type hints
    validate_output=True,       # Validate return value
    detect_hallucination=True,  # Multi-signal hallucination detection
    max_retries=3,              # Retry on failure
    timeout=30.0,               # Kill after 30 seconds
    record=True,                # Write traces to the configured store
    trace_backend="sqlite",     # Production default backend
    trace_dir="./traces",       # SQLite parent directory or JSONL directory
    session_id="my-session",    # Group traces by session
)
def my_tool(x: str) -> dict:
    ...

GuardConfig Reference

For reusable configuration across multiple tools, use GuardConfig:

python
from agentguard import guard, GuardConfig
from agentguard.config import CircuitBreakerConfig, RateLimitConfig, BudgetConfig

config = GuardConfig(
    validate_input=True,
    max_retries=2,
    timeout=10.0,
    circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
    rate_limit=RateLimitConfig(calls_per_minute=60),
    budget=BudgetConfig(max_cost_per_session=5.00),
)

@guard(config=config)
def tool_a(x: str) -> str: ...

@guard(config=config)
def tool_b(y: int) -> int: ...

Configuration Fields

FieldTypeDefaultDescription
validate_inputboolFalseValidate arguments against type hints
validate_outputboolFalseValidate return value against return type
detect_hallucinationboolFalseEnable multi-signal hallucination detection
max_retriesint0Maximum retry attempts on failure
timeoutfloatNoneTimeout in seconds
recordboolFalseRecord traces to the configured store
trace_dirstr"./traces"SQLite parent directory or JSONL directory
trace_backendstr"sqlite"Trace backend: sqlite or jsonl
trace_db_pathstrNoneOptional explicit SQLite database path
session_idstrautoSession identifier for trace grouping
circuit_breakerCircuitBreakerConfigNoneCircuit breaker configuration
rate_limitRateLimitConfigNoneRate limiter configuration
budgetBudgetConfigNoneBudget enforcement configuration
retryRetryConfigNoneDetailed retry configuration
before_callCallableNoneHook called before tool execution
after_callCallableNoneHook called after tool execution
custom_validatorslistNoneCustom validator instances

Retry & Timeout

Configure detailed retry behavior with RetryConfig:

python
from agentguard.config import RetryConfig

@guard(
    retry=RetryConfig(
        max_retries=5,
        initial_delay=0.5,      # First retry after 500ms
        backoff_factor=2.0,     # Double delay each retry
        max_delay=30.0,         # Cap at 30s between retries
        jitter=True,            # Add randomness to prevent thundering herd
        retry_on=(TimeoutError, ConnectionError),  # Only retry these
    ),
    timeout=60.0,               # Hard timeout per attempt
)
def unreliable_api(query: str) -> dict:
    return requests.get(f"https://api.example.com?q={{query}}").json()
๐Ÿ’ก Timeout applies per attempt

The timeout setting applies to each individual attempt, not the total time across all retries. A function with max_retries=3 and timeout=10.0 could take up to 30+ seconds total.

Custom Validators

Extend validation logic with your own validator classes:

python
from agentguard import guard, Validator, ValidationResult

class ContentSafetyValidator(Validator):
    name = "content_safety"

    def validate(self, result, context):
        # Check the tool output for unsafe content
        text = str(result)
        if any(word in text.lower() for word in self.blocked_words):
            return ValidationResult(
                valid=False,
                message="Response contains blocked content"
            )
        return ValidationResult(valid=True)

@guard(custom_validators=[ContentSafetyValidator(blocked_words=["password", "secret"])])
def query_database(sql: str) -> list:
    return db.execute(sql)

Lifecycle Hooks

Run code before or after every guarded tool call:

python
def log_call(func_name, args, kwargs):
    print(f"Calling {{func_name}} with {{args}}")

def log_result(func_name, result, elapsed_ms):
    print(f"{{func_name}} returned in {{elapsed_ms:.1f}}ms")

@guard(before_call=log_call, after_call=log_result)
def my_tool(x: str) -> str:
    return x.upper()
Edit this page on GitHub