> ## 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.

# Record LLM Calls, Tool Calls, and State in AgentDbg

> Use record_llm_call, record_tool_call, and record_state to capture every event inside an AgentDbg traced run for inspection in the timeline.

AgentDbg captures the events that matter most in an agent loop — LLM calls, tool calls, and intermediate state — through three recording functions. Each function attaches its event to the active traced run; if no run is active, the call is silently ignored unless implicit runs are enabled. All three functions apply the same redaction and truncation rules before writing to disk.

## `record_llm_call`

Record a single LLM call event, including the prompt sent, the response received, token usage, and any metadata you want to attach.

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

record_llm_call(
    model="gpt-4",
    prompt="Summarize the search results.",
    response="Found 2 users.",
    usage={"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15},
    meta={"step": "summarize"},
    provider="openai",
    temperature=0.7,
    stop_reason="stop",
    status="ok",
    error=None,
)
```

### Parameters

<ParamField path="model" type="str" required>
  Model name, for example `"gpt-4"` or `"claude-3-opus"`. Required.
</ParamField>

<ParamField path="prompt" type="Any" default="None">
  Prompt sent to the model. Accepts a string, dict, or list (e.g. a chat messages array).
</ParamField>

<ParamField path="response" type="Any" default="None">
  Model response. Accepts the same types as `prompt`.
</ParamField>

<ParamField path="usage" type="dict | None" default="None">
  Token usage dictionary. Expected keys: `prompt_tokens`, `completion_tokens`, `total_tokens`.
</ParamField>

<ParamField path="meta" type="dict | None" default="None">
  Freeform metadata such as step labels, experiment tags, or any key-value pairs you want visible in the timeline.
</ParamField>

<ParamField path="provider" type="str" default="&#x22;unknown&#x22;">
  Provider name: `"openai"`, `"anthropic"`, `"local"`, etc.
</ParamField>

<ParamField path="temperature" type="float | None" default="None">
  Sampling temperature used for this call.
</ParamField>

<ParamField path="stop_reason" type="str | None" default="None">
  Why the model stopped generating: `"stop"`, `"length"`, etc.
</ParamField>

<ParamField path="status" type="str" default="&#x22;ok&#x22;">
  `"ok"` for a successful call, `"error"` if the call failed.
</ParamField>

<ParamField path="error" type="str | BaseException | dict | None" default="None">
  Error details when `status="error"`. Accepts an exception, a string message, or a dict.
</ParamField>

***

## `record_tool_call`

Record a tool call event: the tool name, its inputs, and either a result or an error. Typically called immediately after your tool function returns.

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

record_tool_call(
    name="search_db",
    args={"query": "active users"},
    result={"count": 42},
    meta=None,
    status="ok",
    error=None,
)
```

To record a failed tool call, catch the exception and pass it through `error`:

```python theme={null}
try:
    result = my_tool(args)
    record_tool_call(name="my_tool", args=args, result=result)
except Exception as e:
    record_tool_call(name="my_tool", args=args, status="error", error=e)
    raise
```

### Parameters

<ParamField path="name" type="str" required>
  Tool name as it appears in your agent code. Required.
</ParamField>

<ParamField path="args" type="Any" default="None">
  Arguments passed to the tool. Accepts any serialisable type.
</ParamField>

<ParamField path="result" type="Any" default="None">
  Return value from the tool.
</ParamField>

<ParamField path="meta" type="dict | None" default="None">
  Freeform metadata. Useful for tagging calls with step numbers, environment labels, or experiment identifiers.
</ParamField>

<ParamField path="status" type="str" default="&#x22;ok&#x22;">
  `"ok"` for a successful call, `"error"` if the tool raised.
</ParamField>

<ParamField path="error" type="str | BaseException | dict | None" default="None">
  Error details when `status="error"`.
</ParamField>

***

## `record_state`

Record a state-update event — a snapshot of your agent's internal state at a point in time. This is useful for capturing message history length, memory contents, or any structured data that helps you understand where the agent is in its reasoning.

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

record_state(
    state={"step": 3, "messages": ["..."]},
    meta={"label": "after_search"},
    diff=None,
)
```

### Parameters

<ParamField path="state" type="Any" default="None">
  State snapshot. Accepts any object or string that describes the agent's current state.
</ParamField>

<ParamField path="meta" type="dict | None" default="None">
  Freeform metadata.
</ParamField>

<ParamField path="diff" type="Any" default="None">
  Optional diff from the previous state, if you want to record only what changed.
</ParamField>

<Note>
  `record_state` does not increment the LLM or tool call counters used by guardrails. It is safe to call it as often as you like without affecting guardrail thresholds.
</Note>

***

## Full example: ReAct-style agent loop

The following example shows all three recording functions working together inside a ReAct-style loop that alternates between LLM reasoning and tool execution.

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

TOOLS = {"search": search_fn, "calculator": calc_fn}

@trace
def react_agent(question: str):
    messages = [{"role": "user", "content": question}]

    for step in range(10):
        response = llm_chat(messages)
        record_llm_call(
            model="gpt-4",
            prompt=messages,
            response=response,
            usage=response.get("usage"),
        )

        action = parse_action(response)
        if action is None:
            return response["content"]

        tool_fn = TOOLS[action["tool"]]
        result = tool_fn(**action["args"])
        record_tool_call(
            name=action["tool"],
            args=action["args"],
            result=result,
        )

        messages.append({"role": "assistant", "content": response["content"]})
        messages.append({"role": "tool", "content": str(result)})
        record_state(state={"step": step, "messages_count": len(messages)})

    return "Max steps reached"
```

After running, `agentdbg view` shows every LLM call, tool call, and state update in the order they occurred — making it straightforward to see where the agent went wrong or got stuck in a loop.

***

## Redaction and truncation

All three `record_*` functions apply the same data-safety rules before writing events to disk:

* **Redaction:** Dict keys matching configured patterns (such as `api_key`, `token`, or `password`) have their values replaced with `__REDACTED__`. This is applied recursively up to a depth of 10.
* **Truncation:** Strings longer than `AGENTDBG_MAX_FIELD_BYTES` (default: 20 000 bytes) are truncated and suffixed with `__TRUNCATED__`.

You can adjust these rules through environment variables or your project or user YAML config. Environment variables take precedence over YAML:

| Setting                  | Environment variable       | YAML key          |
| ------------------------ | -------------------------- | ----------------- |
| Redacted field names     | `AGENTDBG_REDACT_KEYS`     | `redact_keys`     |
| Enable/disable redaction | `AGENTDBG_REDACT`          | `redact`          |
| Max field size (bytes)   | `AGENTDBG_MAX_FIELD_BYTES` | `max_field_bytes` |
