> ## Documentation Index
> Fetch the complete documentation index at: https://refinehq.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tracing Agent Runs with @trace and traced_run

> Learn how to start and manage traced runs in AgentDbg using the @trace decorator and the traced_run context manager for scripts and notebooks.

AgentDbg gives you two ways to start a traced run: the `@trace` decorator for wrapping agent functions, and the `traced_run` context manager for scripts, notebooks, or dynamic workflows where a decorator doesn't fit. Both create an active run context that `record_llm_call`, `record_tool_call`, and `record_state` automatically attach to.

## `@trace` decorator

Apply `@trace` to any function to turn it into a traced run. When the function is called, AgentDbg emits a `RUN_START` event, runs the body, then emits `RUN_END`. If the function raises, AgentDbg emits `ERROR` followed by `RUN_END` with `status="error"` and re-raises the exception.

```python theme={null}
from agentdbg import trace

@trace
def run_agent():
    ...
```

You can pass arguments to configure the run name and enable guardrails:

```python theme={null}
from agentdbg import trace

@trace(
    name="support_agent",
    stop_on_loop=True,
    max_llm_calls=12,
    max_tool_calls=20,
    max_events=100,
    max_duration_s=30,
)
def run_agent():
    ...
```

### Parameters

<ParamField path="name" type="str | None" default="None">
  Run name shown in `agentdbg list` and the timeline UI. Defaults to the function name when not set.
</ParamField>

<ParamField path="stop_on_loop" type="bool" default="False">
  Abort the run when loop detection emits a `LOOP_WARNING` event. Raises `AgentDbgLoopAbort`.
</ParamField>

<ParamField path="stop_on_loop_min_repetitions" type="int" default="3">
  Minimum number of repeated pattern occurrences required before `stop_on_loop` triggers.
</ParamField>

<ParamField path="max_llm_calls" type="int | None" default="None">
  Abort after more than N LLM calls. Raises `AgentDbgGuardrailExceeded`.
</ParamField>

<ParamField path="max_tool_calls" type="int | None" default="None">
  Abort after more than N tool calls. Raises `AgentDbgGuardrailExceeded`.
</ParamField>

<ParamField path="max_events" type="int | None" default="None">
  Abort after more than N total events recorded. Raises `AgentDbgGuardrailExceeded`.
</ParamField>

<ParamField path="max_duration_s" type="float | None" default="None">
  Abort when elapsed run time reaches this limit in seconds. Raises `AgentDbgGuardrailExceeded`.
</ParamField>

***

## `traced_run` context manager

`traced_run` starts a traced run using a `with` block. Use it when you cannot or don't want to use a decorator — for example, in a Jupyter notebook cell, a script with a flat structure, or a dynamic workflow that assembles steps at runtime.

```python theme={null}
from agentdbg import traced_run, record_tool_call, record_llm_call

with traced_run(name="my_pipeline"):
    record_tool_call(name="fetch", args={"url": "..."}, result="...")
    record_llm_call(model="gpt-4", prompt="...", response="...")
```

Guardrails are available on `traced_run` as well:

```python theme={null}
from agentdbg import traced_run

with traced_run(
    name="react_debug",
    stop_on_loop=True,
    max_llm_calls=8,
    max_tool_calls=12,
    max_events=60,
    max_duration_s=20,
):
    ...
```

`traced_run` accepts the same parameters as `@trace`. See the parameter table above.

<Note>
  `traced_run` behavior is identical to `@trace`: if no run is already active it creates a new one; if a run is already active it attaches to it without creating nested run events.
</Note>

***

## `has_active_run`

`has_active_run()` returns `True` when a traced run is active in the current context — that is, inside a `@trace`-decorated function call or an open `traced_run` block.

```python theme={null}
from agentdbg import has_active_run

if has_active_run():
    print("Inside a traced run")
```

Use `has_active_run` when you are writing utility code or library integrations that should record events only when the caller has already started a run, rather than creating a new implicit one.

***

## Nested runs

Calling a `@trace`-decorated function from inside an already active run does **not** create a nested run or extra `RUN_START`/`RUN_END` events. All `record_*` calls inside the inner function still attach to the outer run.

```python theme={null}
from agentdbg import trace, record_llm_call

@trace
def inner():
    record_llm_call(model="gpt-4", prompt="inner prompt", response="inner response")

@trace
def outer():
    inner()   # attaches to the outer run — no second RUN_START emitted
```

This means you can safely add `@trace` to helper functions without worrying about polluting the timeline with spurious run boundaries.

***

## Implicit runs

By default, calling `record_llm_call`, `record_tool_call`, or `record_state` outside any traced run does nothing — the call is silently ignored.

If your script does not have a single top-level entrypoint you can wrap, set the environment variable:

```bash theme={null}
export AGENTDBG_IMPLICIT_RUN=1
```

With this set, the first recorder call that finds no active run automatically creates an implicit run. All subsequent recorder calls attach to it until the process exits, at which point AgentDbg finalizes and writes the run.

<Warning>
  Implicit runs capture everything in a single process-lifetime run. If your script calls multiple distinct agent workflows, consider using `traced_run` explicitly for each one so the timeline stays readable.
</Warning>
