From a single JSON response to a full trace of every decision my AI agent made

I built a small AI agent, it answers questions by deciding on its own whether to use a calculator, search some notes, or check the time. The answers looked fine, but one query took eight seconds and another needed four tries to answer something a single tool call should've settled. All I had was a JSON response and a stopwatch. So I traced the whole decision loop with OpenTelemetry and SigNoz. Not just the request, every step inside it. In 30 minutes I could see exactly which iteration was slow, and caught the model calling my calculator with the same input three times in a row. Here's what I did.

The Agent

A ReAct-style loop: ask the model what to do, run a tool if it asks for one, feed the result back, repeat.

def run_agent(query: str) -> dict: