DEV Community

Khushneet Singh
Khushneet Singh

Posted on

I built an observability tool to catch my AI agent in a 15-minute failure loop

When you hand a task off to an AI coding agent, you're essentially handing the keys to a black box. You wait ten minutes, and you either get a completed feature or a mangled codebase, with absolutely zero visibility into the retry loops, hallucinated file paths, and syntax errors that happened in between. I got tired of re-reading git diffs and terminal scrollback to figure out why an agent spent twenty minutes doing nothing, so I built a tool to trace it.

"Stuck" is a VS Code extension I built for the SigNoz hackathon. Instead of just accepting the black box, it instruments every file save, terminal command, and agent tool call as an OpenTelemetry span, ships it to a local SigNoz instance, and uses a local LLM to generate a postmortem report explaining exactly what went wrong (or right).

Here is exactly how I built it and how the pieces connect, using a real failure scenario I ran into.

The Use Case: The Pagination Disaster

Let’s say I ask the Antigravity agent to do something seemingly simple: "Add pagination to the /api/users endpoint."

I hit enter. The agent starts thinking. Five minutes pass. Ten minutes pass. Fifteen minutes later, the agent finally gives up and fails.


The Stuck extension in action, observing an active agent session.

Without observability, I’m left staring at a broken userController.ts file, trying to manually reverse-engineer a dozen git changes to figure out what the agent was actually attempting to do.

With "Stuck", the moment that session fails, the extension kicks into gear and connects the dots across four different layers of the editor.

1. Catching the Basics (VS Code APIs)

While the agent was spinning, the first layer of "Stuck" was quietly watching the standard VS Code APIs.

I wrote fileWatcher.ts to calculate byte deltas on the fly every time the agent saved a file. Simultaneously, terminalWatcher.ts hooked into the Shell Integration API to trace every npm run build command the agent ran, logging the exit codes.

All of this data was instantly formatted as OpenTelemetry spans and shipped via OTLP to a local SigNoz instance I had spun up using a simple Docker deployment (foundryctl cast -f casting.yaml).


The local SigNoz stack running effortlessly via foundryctl.

But just knowing what files changed isn't enough. I needed to know why the agent was changing them. I needed to see its tool calls.

2. Peering into the Black Box (The CDP Bridge)

There is no official API for observing what an Antigravity agent is actually doing under the hood. You can't just subscribe to an onDidExecuteTool event in VS Code.

To solve this, I built a bridge directly into the Chrome DevTools Protocol (CDP). Since the Antigravity agent runs inside a webview, you can launch the editor with --remote-debugging-port=9000 and attach to it. I used the chrome-remote-interface package in cdpBridge.ts to listen to the Network and Runtime domains.

When the agent decides to use a tool—say, searching for a file or editing code—the CDP bridge intercepts the JSON RPC payloads, classifies the action, and emits a custom cdp_tool_call span. Because this relies on heuristics (and future agent updates might break my parser), I added a cdp.inference_quality attribute (high/medium/low) to every span.

Now, in SigNoz, I could see the agent's exact thought process interleaved with the actual file saves and terminal commands.


Raw spans flowing into SigNoz in real-time, interleaving agent tool calls with terminal commands.

3. Catching the Loop (Loop Detection)

By combining the CDP tool calls with the terminal commands, "Stuck" caught exactly why the pagination task failed.

I built a loopDetector.ts module that tracks the targets of the agent's actions within a single session. During the pagination task, the agent edited userController.ts, ran npm run build, got a type error, and immediately tried the exact same edit again. It did this nine times.

The loop detector caught this. On the third repeated failure, the extension fired off a VS Code warning notification and tagged the telemetry span with cdp.retry_loop: true. I even wired up a retry-threshold-alert.yml for SigNoz to fire an alert when any session crossed a 5-retry threshold.

4. The Postmortem (Connecting the Trace to the LLM)

When the agent finally gave up (detected via a CDP task_end signal), the final piece of the puzzle activated: the postmortem engine.

The extension queried the local SigNoz instance (GET /api/v1/traces/{traceId}) to pull the entire trace tree of the 15-minute session. It then fed that raw timeline into a local LLM (Ollama running llama3) to figure out what happened.

The LLM parsed the 87 spans, saw the 9 retries, and generated a structured markdown report. It broke down the time spent (33% planning, 25% editing, 25% commands, 17% waiting) and, most importantly, generated a root cause hypothesis: the agent's pagination cursor type was incompatible with the existing query builder, and it lacked the context to fix it, causing a loop.


The generated postmortem in the Stuck UI, showing the 9 retries and the root cause.

If the task had succeeded, the UI cleanly shows the tool call list without the failure noise.


A successful session postmortem for comparison.

Takeaways

Building this taught me a lot about the fragility of AI agents and the power of observability.

1. The LLM formatting struggle:
Getting the LLM prompt right was easily the most frustrating part. The model constantly fought back, trying to write freeform narrative paragraphs instead of the parseable YAML/Markdown schema the UI needed. Worse, it would sometimes hallucinate tool calls that didn't exist in the trace data. I had to aggressively tune the system prompt to force it to act purely as a data-to-markdown transformer, strictly penalizing it for inventing context.

2. The SigNoz logs surprise:
The biggest surprise was how powerful the SigNoz logs integration turned out to be. Initially, I just saved the reports locally to .agent-reports/*.md to render them in the custom VS Code webview panel. But then I realized I could push the entire generated markdown report back to SigNoz as a log event, attached to the exact same trace ID. This meant the observability platform became the true source of truth. You could look at the raw spans, and right there attached to the trace was the human-readable AI explanation of what happened.

3. What I'd do differently:
If I had more time, I would build real-time session title inference and embed the SigNoz trace waterfall visualization directly into the VS Code postmortem panel, rather than just deep-linking to the dashboard.

Agents are only going to get faster and more autonomous. We need tools to keep them accountable when they veer off course.

Check out the repo here: github.com/ksploitx/stuck

Top comments (0)