Tracing

Learn how to use the @trace and @span decorators to instrument your AI agents and capture the full execution flow.

The @trace Decorator

The @trace decorator creates a new trace for each function invocation. Use it on your top-level agent functions:

from mindreef import trace

@trace
async def customer_support_agent(message: str) -> str:
    """Handle a customer support request."""
    # Your agent logic here
    return response

Trace Options

Customize trace behavior with options:

@trace(
    name="support-agent",     # Custom trace name
    capture_input=True,         # Log function inputs
    capture_output=True,        # Log function outputs
    tags={"team": "support"}  # Custom tags
)
async def customer_support_agent(message: str) -> str:
    ...

The @span Decorator

The @span decorator creates child spans within an existing trace. Use it for operations you want to track separately:

from mindreef import trace, span

@trace
async def research_agent(query: str):
    # Each of these creates a child span
    context = await search_knowledge_base(query)
    analysis = await analyze_results(context)
    response = await generate_response(analysis)
    return response

@span(name="search", span_type="retrieval")
async def search_knowledge_base(query: str):
    # Search logic here
    ...

@span(name="analyze")
async def analyze_results(context: str):
    # Analysis logic here
    ...

@span(name="generate", span_type="llm")
async def generate_response(analysis: str):
    # LLM call here
    ...

Manual Span Creation

For more control, create spans manually using the context manager:

from mindreef import trace, Span

@trace
async def complex_agent(query: str):
    with Span(name="preprocessing") as span:
        span.set_attribute("query_length", len(query))
        processed = preprocess(query)

    with Span(name="main_logic") as span:
        result = await process(processed)
        span.set_attribute("result_type", type(result).__name__)

    return result

Adding Attributes

Add custom attributes to spans for richer debugging:

from mindreef import get_current_span

def process_order(order_id: str):
    span = get_current_span()
    span.set_attribute("order_id", order_id)
    span.set_attribute("order_value", 99.99)

    # Process the order...

Recording Events

Log discrete events within a span:

from mindreef import get_current_span

def handle_request(request):
    span = get_current_span()

    # Log an event
    span.add_event("validation_complete", {
        "valid": True,
        "checks_passed": 5
    })

    # Process request...

Error Handling

Exceptions are automatically captured and associated with the current span:

@trace
async def risky_agent(query: str):
    try:
        result = await process(query)
        return result
    except Exception as e:
        # Error is automatically recorded on the span
        raise  # Re-raise to preserve stack trace

Async Support

Both @trace and @span work seamlessly with async functions:

@trace
async def async_agent(queries: list[str]):
    # Parallel execution - each task gets its own span
    tasks = [process_query(q) for q in queries]
    results = await asyncio.gather(*tasks)
    return results

@span
async def process_query(query: str):
    # This span is correctly parented to the trace
    ...

Next Steps