# How to Extract Tool Usage Patterns from ADR chat_history Using AgentEvent

> Learn to extract tool usage patterns from ADR chat_history using AgentEvent. Discover how to access tool information efficiently with our guide.

- Repository: [Uber Open Source/ADR](https://github.com/uber/ADR)
- Tags: how-to-guide
- Published: 2026-08-07

---

**Extract tool usage patterns from ADR `chat_history` by iterating over `AgentEvent` objects and reading the `"tool"` key from each event's `metadata` dictionary, using either the `ADRBaselineAgent` class or the `extract_tool_usage()` helper function.**

The Uber ADR framework structures conversation histories as `AgentEvent` dataclasses that capture metadata about external tool invocations. When you need to extract tool usage patterns from ADR `chat_history`, you analyze these events to identify which tools (such as `webfetch`, `search`, or custom agents) were invoked during the interaction. According to the uber/ADR source code, the framework provides dedicated extraction utilities in [`adr_baseline.py`](https://github.com/uber/ADR/blob/main/adr_baseline.py) that transform raw event sequences into actionable frequency counts.

## Understanding AgentEvent and Tool Metadata Structure

The foundation of tool usage extraction lies in the `AgentEvent` dataclass defined in [`Detection/guardrail/adr_agent/events.py`](https://github.com/uber/ADR/blob/main/Detection/guardrail/adr_agent/events.py). This structure represents a single turn in a conversation with four key fields:

- **`timestamp`**: When the event occurred
- **`role`**: Either `"user"` or `"assistant"`
- **`content`**: The raw text content of the message
- **`metadata`**: A dictionary containing optional additional information

When an assistant invokes an external tool, the `metadata` dictionary contains a `"tool"` key identifying the specific utility called. For example, an event representing a `webfetch` call would include `metadata={"tool": "webfetch"}`.

## Methods to Extract Tool Usage Patterns from chat_history

The [`Detection/guardrail/adr_agent/adr_baseline.py`](https://github.com/uber/ADR/blob/main/Detection/guardrail/adr_agent/adr_baseline.py) file implements two approaches for aggregating these tool calls from a list of `AgentEvent` objects.

### Using the ADRBaselineAgent Class

The `ADRBaselineAgent` class provides a stateful interface for processing chat history. Instantiate it with a list of events, then call the `run()` method to populate a `patterns` dictionary mapping tool names to call counts.

```python
from adr_agent.events import AgentEvent
from adr_agent.adr_baseline import ADRBaselineAgent

# chat_history is a list of AgentEvent objects

agent = ADRBaselineAgent(chat_history)
tool_counts = agent.run()  # Returns {'webfetch': 2, 'search': 1}

```

The `run()` method iterates through `self.events` and executes the extraction logic: `tool_name = ev.metadata.get("tool")`. If the tool name exists, it increments the counter in the `patterns` dictionary. After processing, call `summary()` to generate a human-readable report sorted by frequency.

### Using the extract_tool_usage Helper Function

For one-off analyses without class instantiation, use the standalone `extract_tool_usage()` function. This helper mirrors the counting logic of `ADRBaselineAgent.run()` but operates as a pure function.

```python
from adr_agent.events import AgentEvent
from adr_agent.adr_baseline import extract_tool_usage

# Returns the same dictionary format as the class method

counts = extract_tool_usage(chat_history)

```

Both approaches normalize tool names by reading the `"tool"` key directly from `ev.metadata`, ensuring consistent counting across the event stream.

## Complete Implementation Examples

### Example 1: Class-Based Extraction with Summary

Process a conversation history and generate a formatted report showing tool usage frequency:

```python
from adr_agent.events import AgentEvent
from datetime import datetime
from adr_agent.adr_baseline import ADRBaselineAgent

chat_history = [
    AgentEvent(timestamp=datetime.now(), role="assistant", content="Fetching data...", metadata={"tool": "webfetch"}),
    AgentEvent(timestamp=datetime.now(), role="assistant", content="Searching...", metadata={"tool": "search"}),
    AgentEvent(timestamp=datetime.now(), role="assistant", content="Fetching more...", metadata={"tool": "webfetch"}),
]

agent = ADRBaselineAgent(chat_history)
patterns = agent.run()
print(agent.summary())

```

**Output:**

```text
Tool usage summary:

- webfetch: 2 calls
- search: 1 calls

```

### Example 2: Functional Extraction in Data Pipelines

Integrate tool usage analysis into monitoring or logging workflows using the functional approach:

```python
from adr_agent.adr_baseline import extract_tool_usage

def analyze_conversation(events):
    """Directly obtain frequency counts for telemetry or guardrails."""
    return extract_tool_usage(events)

# Usage in a larger ADR workflow

tool_metrics = analyze_conversation(chat_history)
assert tool_metrics.get("webfetch", 0) < 10, "Rate limit exceeded"

```

## Summary

Extracting tool usage patterns from ADR `chat_history` requires analyzing the `metadata` field of `AgentEvent` objects to identify invoked tools:

- **Source files**: [`Detection/guardrail/adr_agent/events.py`](https://github.com/uber/ADR/blob/main/Detection/guardrail/adr_agent/events.py) defines the `AgentEvent` dataclass, while [`Detection/guardrail/adr_agent/adr_baseline.py`](https://github.com/uber/ADR/blob/main/Detection/guardrail/adr_agent/adr_baseline.py) provides extraction logic
- **Extraction logic**: Access `ev.metadata.get("tool")` to retrieve tool identifiers from each event
- **Two approaches**: Use `ADRBaselineAgent` for stateful processing with summary generation, or `extract_tool_usage()` for functional, one-off analyses
- **Output format**: Both methods return a `Dict[str, int]` mapping tool names to call frequencies

## Frequently Asked Questions

### What is the structure of the metadata field in AgentEvent?

The `metadata` field is an optional `Dict[str, Any]` that stores additional information about the event. When a tool is invoked, this dictionary contains a `"tool"` key with a string value identifying the utility (e.g., `"webfetch"`, `"search"`). The field defaults to `None` if no metadata is provided, so extraction code must handle missing keys gracefully using `.get()` methods.

### How does ADRBaselineAgent handle events without tool calls?

The `run()` method safely skips events that lack tool metadata. During iteration, it executes `tool_name = ev.metadata.get("tool")`—if the key is missing or `metadata` is `None`, `tool_name` becomes `None`, and the counter increment is bypassed. Only events with explicit tool identifiers contribute to the frequency count.

### What is the difference between ADRBaselineAgent and extract_tool_usage?

`ADRBaselineAgent` is a class that maintains internal state (the `self.patterns` dictionary) and provides the `summary()` method for formatted output. The `extract_tool_usage()` function performs identical counting logic but operates as a pure function without class instantiation, making it suitable for lightweight analytics or functional programming patterns. Both use the same underlying extraction mechanism from [`Detection/guardrail/adr_agent/adr_baseline.py`](https://github.com/uber/ADR/blob/main/Detection/guardrail/adr_agent/adr_baseline.py).

### Can I extract other metadata fields besides the tool name?

While the standard implementation specifically targets the `"tool"` key, you can extend the extraction logic by modifying the dictionary access pattern. The `AgentEvent` structure supports arbitrary metadata, so you could adapt the counting logic in [`adr_baseline.py`](https://github.com/uber/ADR/blob/main/adr_baseline.py) to aggregate values from other keys such as `"duration"`, `"status"`, or custom identifiers relevant to your specific ADR implementation.