<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Belal Shafiq</title>
    <description>The latest articles on DEV Community by Belal Shafiq (@belalshafeq).</description>
    <link>https://dev.to/belalshafeq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4186769%2Fb3872f1a-9241-47b4-933d-11a079062486.jpg</url>
      <title>DEV Community: Belal Shafiq</title>
      <link>https://dev.to/belalshafeq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/belalshafeq"/>
    <language>en</language>
    <item>
      <title>How a Silent Agent Loop Cost Me $3k in API Bills (And How I Fixed It)</title>
      <dc:creator>Belal Shafiq</dc:creator>
      <pubDate>Mon, 09 Nov 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/belalshafeq/how-a-silent-agent-loop-cost-me-3k-in-api-bills-and-how-i-fixed-it-22ap</link>
      <guid>https://dev.to/belalshafeq/how-a-silent-agent-loop-cost-me-3k-in-api-bills-and-how-i-fixed-it-22ap</guid>
      <description>&lt;p&gt;The Technical Diagnosis: Why Retries Don't Work&lt;/p&gt;

&lt;p&gt;If you are using frameworks like LangGraph, CrewAI, or AutoGen, you probably have &lt;code&gt;max_retries&lt;/code&gt; configured. I did too.&lt;/p&gt;

&lt;p&gt;But a retry limit only triggers when an agent throws an error (like a 500, a timeout, or a malformed JSON response).&lt;/p&gt;

&lt;p&gt;An agent loop isn't an error. The LLM is successfully generating tokens. It is returning valid, perfectly formatted Pydantic output. The framework sees a successful handoff. The HTTP status is bash &lt;code&gt;200 OK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are two patterns that will drain your budget:&lt;/p&gt;

&lt;p&gt;The Repeated Loop:&lt;code&gt;A -&amp;gt; A -&amp;gt; A -&amp;gt; A&lt;/code&gt;. The model gets stuck on a single thought and repeats it indefinitely.&lt;/p&gt;

&lt;p&gt;The Cyclic Loop:&lt;code&gt;A -&amp;gt; B -&amp;gt; A -&amp;gt; B&lt;/code&gt;. Two agents get stuck validating each other's work forever.&lt;/p&gt;

&lt;p&gt;If you are only monitoring HTTP codes or infrastructure uptime, you will never catch this. The agents are healthy, they are just burning your runway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Naive Fix (And Why It Fails)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I realized what was happening, my first instinct was to write a manual loop counter.&lt;/p&gt;

&lt;p&gt;I wrote something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The Naive Counter
&lt;/span&gt;&lt;span class="n"&gt;execution_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;guarded_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;execution_count&lt;/span&gt;
    &lt;span class="n"&gt;execution_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;execution_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loop detected!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked for a single-agent setup. But it fell apart the moment I scaled to a multi-agent swarm.&lt;/p&gt;

&lt;p&gt;It doesn't catch cyclic loops. If Agent A calls Agent B, the counter keeps going up, but it's not catching the &lt;code&gt;A -&amp;gt; B -&amp;gt; A&lt;/code&gt; pattern, just the total number of executions.&lt;/p&gt;

&lt;p&gt;State resets break it. If an agent crashes and the graph resumes, the Python counter resets to zero, and the loop starts over.&lt;/p&gt;

&lt;p&gt;It's a nightmare to maintain. If you have 10 nodes, you have to manually pass and manage this counter across every single edge in your graph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Robust Fix: A Runtime Circuit Breaker&lt;/strong&gt;&lt;br&gt;
To actually stop runaway spend, you need a deterministic check that happens at the handoff layer, before the next API token is generated.&lt;/p&gt;

&lt;p&gt;You need to hash the payload.&lt;/p&gt;

&lt;p&gt;Every time an agent prepares to pass a message to another agent, you intercept that payload, serialize it, and run it through a &lt;code&gt;SHA-256&lt;/code&gt; hash.&lt;/p&gt;

&lt;p&gt;If you keep a sliding window of the last 3 hashes, you can instantly detect loops:&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;hash_1 == hash_2 == hash_3&lt;/code&gt; , you have a Repeated Loop.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;hash_1 == hash_3 and hash_2&lt;/code&gt; is different, you have a Cyclic Loop.&lt;/p&gt;

&lt;p&gt;Instead of letting the agents keep talking, you throw a &lt;code&gt;422 Unprocessable Entity&lt;/code&gt; error back to the orchestrator, forcibly halting the session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enter AgentTrafficCop&lt;/strong&gt;&lt;br&gt;
After spending a weekend writing custom hashing logic and state trackers for my own projects, I realized how tedious this was.&lt;/p&gt;

&lt;p&gt;So we built AgentTrafficCop — a lightweight runtime middleware that sits between your agents and acts as a circuit breaker.&lt;/p&gt;

&lt;p&gt;We designed it so you don't have to rewrite your graph. If you are using LangGraph, integration is literally one line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agenttrafficcop&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;guarded_node&lt;/span&gt;

&lt;span class="c1"&gt;# Wrap your existing node
&lt;/span&gt;&lt;span class="nf"&gt;guarded_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_agent_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, AgentTrafficCop intercepts every handoff, hashes the payload, and kills the session if it detects a loop.&lt;/p&gt;

&lt;p&gt;But killing the process is only half the battle. If a loop happens, you need to know about it.&lt;/p&gt;

&lt;p&gt;When the middleware trips the circuit breaker, it instantly fires a webhook to your Slack or Discord, so your team knows exactly which session was killed before the bill spikes.&lt;/p&gt;

&lt;p&gt;We also built a dashboard that tracks Money Saved based on the number of loops prevented, along with a 7-day view of approved vs. rejected handoffs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Lesson: Monitor State, Not Uptime&lt;/strong&gt;&lt;br&gt;
In deterministic software, a bash &lt;code&gt;200 OK&lt;/code&gt; means everything is working. In probabilistic AI systems, a bash &lt;code&gt;200 OK&lt;/code&gt; just means the model successfully generated text. It doesn't mean the text was useful, and it certainly doesn't mean you aren't stuck in a loop.&lt;/p&gt;

&lt;p&gt;Stop relying on HTTP status codes to monitor your agent health. Monitor the state.&lt;/p&gt;

&lt;p&gt;If you want to stop writing custom loop counters and protect your API budget, AgentTrafficCop is live. The free tier protects up to 5 agents and 10,000 messages per month (no credit card required).&lt;/p&gt;

&lt;p&gt;You can install the SDK directly from PyPI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;agenttrafficcop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop letting your agents burn money in a &lt;code&gt;while(True)&lt;/code&gt; loop. Get your free API key at agenttrafficcop.com&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>architecture</category>
      <category>agents</category>
    </item>
    <item>
      <title>I got tired of watching AI agents burn money, so I built a runtime kill switch.</title>
      <dc:creator>Belal Shafiq</dc:creator>
      <pubDate>Sat, 31 Oct 2026 08:47:30 +0000</pubDate>
      <link>https://dev.to/belalshafeq/i-got-tired-of-watching-ai-agents-burn-money-so-i-built-a-runtime-kill-switch-4eb0</link>
      <guid>https://dev.to/belalshafeq/i-got-tired-of-watching-ai-agents-burn-money-so-i-built-a-runtime-kill-switch-4eb0</guid>
      <description>&lt;p&gt;I got paged at 3am last week by my bank, not by an alert.&lt;/p&gt;

&lt;p&gt;I looked at my dashboard and two agents had been stuck in a loop for six hours. Agent A asked Agent B a question. Agent B answered. Agent A hallucinated a reason to ask the exact same question again with slightly different wording. They weren't broken. They were perfectly obedient. They just had no idea they were stuck.&lt;/p&gt;

&lt;p&gt;I wrote about this exact failure mode a few weeks ago in my post about why you shouldn't trust agents when they say "done". The response was wild. Turns out everyone building agents is hitting this exact wall.&lt;/p&gt;

&lt;p&gt;The standard advice is max_iterations. But we all know that's a joke. Step count measures effort, not progress. An agent can loop 3 times and burn $20 doing nothing, or do 20 steps of actual work and get killed by the limit.&lt;/p&gt;

&lt;p&gt;So I built the fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dashboards don't stop the bleeding&lt;/strong&gt;&lt;br&gt;
The AI space is obsessed with "observability" right now. LangSmith, Langfuse, whatever. They are beautiful. They show you nice traces and graphs.&lt;/p&gt;

&lt;p&gt;But a dashboard is just watching the car crash in slow motion. If your agent is looping, a telemetry dashboard doesn't stop it. By the time you notice the spike and manually hit "Cancel," the money is gone.&lt;/p&gt;

&lt;p&gt;You can't prompt-engineer your way out of a state management problem. You need a hard stop outside the model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;meet AgentTrafficCop&lt;/strong&gt;&lt;br&gt;
I built AgentTrafficCop. It's a runtime interceptor that sits between your agents, or between an agent and its tools.&lt;/p&gt;

&lt;p&gt;Instead of running inside the agent's code (where the model can hallucinate a way around it), it sits on the "spend path." Every tool call has to pass through it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;how it works:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It diffs the state. It doesn't just count steps. It looks at the actual state. If an agent calls a tool, gets a response, and then 3 turns later calls the same tool with the same args without the underlying state changing, it knows the agent is spinning.&lt;/p&gt;

&lt;p&gt;It kills the execution. When it catches a loop, it doesn't just log a warning. It physically blocks the tool call and kills the run. The agents are forced to stop before they drain your API budget.&lt;/p&gt;

&lt;p&gt;It validates the payload. Before a tool call hits your db, it checks the schema. If the model hallucinates a parameter, the call is rejected before it touches your prod systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;what it doesn't do&lt;/strong&gt;&lt;br&gt;
im gonna be honest. AgentTrafficCop is not going to make your prompts smarter. It is not a magic AGI wrapper.&lt;/p&gt;

&lt;p&gt;It is a plumbing tool. It assumes the model will hallucinate, the api will timeout, and the agent will get stuck. It assumes things will break, and it puts a hard boundary around the damage they can do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;it's live&lt;/strong&gt;&lt;br&gt;
I just launched the beta. If you are building agents in prod and you are tired of surprise api bills, you can check it out here:&lt;/p&gt;

&lt;p&gt;👉 agenttrafficcop.com&lt;/p&gt;

&lt;p&gt;I'm building this in public and I want feedback. If you have a specific loop that your agents keep getting stuck in, drop it in the comments. Ill see if the middleware catches it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Stop Trusting Your AI Agents to Tell You They Are "Done"</title>
      <dc:creator>Belal Shafiq</dc:creator>
      <pubDate>Fri, 23 Oct 2026 12:45:36 +0000</pubDate>
      <link>https://dev.to/belalshafeq/stop-trusting-your-ai-agents-to-tell-you-they-are-done-1j3g</link>
      <guid>https://dev.to/belalshafeq/stop-trusting-your-ai-agents-to-tell-you-they-are-done-1j3g</guid>
      <description>&lt;p&gt;I spent three days last week watching two AI agents argue in a circle.&lt;/p&gt;

&lt;p&gt;Neither one was hallucinating. Neither one was broken. Both were being perfectly obedient to their prompts.&lt;/p&gt;

&lt;p&gt;Agent A (the coder) wrote a function. Agent B (the reviewer) said "change the variable name." Agent A changed it and passed it back. Agent B said "actually, change it back, the first name was more descriptive." Agent A changed it back.&lt;/p&gt;

&lt;p&gt;They did this for three days. The API bill was $42. The code was exactly what it was on hour one.&lt;/p&gt;

&lt;p&gt;This is the dirty secret of the current AI agent hype cycle. We are building incredibly complex, multi-agent swarms, giving them tools to interact with the real world, and then trusting them to tell us when the job is done.&lt;/p&gt;

&lt;p&gt;They cannot be trusted. Not because they are malicious, but because they are text predictors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Black Box With a Credit Card" Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most dangerous part of an AI agent isn't when it crashes. It's when it confidently says "Done!" and you have absolutely no way to replay the exact tool calls and state changes that led to that claim.&lt;/p&gt;

&lt;p&gt;When you ask a LangChain or AutoGen agent to complete a task, it usually responds with something like: "I have successfully updated the database and emailed the client."&lt;/p&gt;

&lt;p&gt;But did it? Or did it just predict the most likely sequence of words that usually follows a task like that in its training data?&lt;/p&gt;

&lt;p&gt;If you cannot independently verify that the database write actually happened, and that the email payload actually left your server, you don't have an autonomous system. You have a black box with a credit card.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Naive Fix: max_iterations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The standard advice right now is to slap a step limit on your agent.&lt;/p&gt;

&lt;h1&gt;
  
  
  The "I hope this works" approach
&lt;/h1&gt;

&lt;p&gt;agent = create_agent(&lt;br&gt;
    model="gpt-4o",&lt;br&gt;
    tools=[search_tool, db_write_tool],&lt;br&gt;
    max_iterations=10&lt;br&gt;
)&lt;br&gt;
If you do this, you are going to have a bad time.&lt;/p&gt;

&lt;p&gt;max_iterations is the equivalent of a doctor telling you, "If the surgery takes more than 10 minutes, just stop and walk away."&lt;/p&gt;

&lt;p&gt;An agent can loop 5 times and burn $20 doing absolutely nothing.&lt;/p&gt;

&lt;p&gt;An agent can legitimately need 20 steps to solve a complex problem, but gets killed at step 10.&lt;/p&gt;

&lt;p&gt;Step count measures effort. It does not measure progress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Root Cause: State Desync&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why do agents loop? It's almost never because the model is "too dumb." It's because the state is desyncing.&lt;/p&gt;

&lt;p&gt;When an agent calls a tool and the tool fails (e.g., a 500 error, a malformed JSON response), what happens? If you are relying on the prompt to handle it, the model will usually say, "My apologies, let me try again," and call the exact same tool with the exact same arguments.&lt;/p&gt;

&lt;p&gt;The model thinks it is making progress because the conversation history is growing. The tokens are changing. But the actual state of the world hasn't changed at all.&lt;/p&gt;

&lt;p&gt;You end up with a "polite infinite loop." The agent keeps saying "sorry" and retrying a broken tool until it hits the max_iterations cap or drains your token budget.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The Real Fix: Move the Guardrails Outside the Model&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
You cannot fix a state problem with a better prompt. You have to move the enforcement out of the LLM and into a deterministic layer that wraps around it.&lt;/p&gt;

&lt;p&gt;If you are building agents for production, you need three things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; A Pre-Execution Validation Layer&lt;br&gt;
Never let the model execute a tool blindly. Before the tool call runs, validate the arguments against a strict schema. If the model hallucinates a parameter, reject the call and return a structured error. Don't let a malformed payload hit your API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; State-Change Diffing (The Loop Killer)&lt;br&gt;
If an agent calls search_flights("NYC", "LA") and gets a bad response, and then 3 steps later calls search_flights("NYC", "LA") again, your harness needs to catch that. If the same action is repeated without the underlying state changing, kill the execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Receiver-Side Idempotency&lt;br&gt;
If your agent is making network requests or writing to a database, the receiver must be idempotent. If the agent passes a unique idempotency key, the database knows to ignore the duplicate write, even if the agent retries 5 times because it didn't understand the first response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Brutal Truth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to stop obsessing over "smarter models." A 2-million token context window just gives an agent more room to get lost.&lt;/p&gt;

&lt;p&gt;The next wave of AI engineering isn't about better prompts. It's about better plumbing. It's about building harnesses that assume the model will hallucinate, the API will timeout, and the agent will get stuck.&lt;/p&gt;

&lt;p&gt;If you can't replay the exact tool calls and state changes that led to an agent saying "done," you don't have a system. You have a liability.&lt;/p&gt;

&lt;p&gt;Build the hard stop. Build it outside the model.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>automation</category>
      <category>llm</category>
    </item>
    <item>
      <title>The Coder Agent and the Reviewer Agent Have Been Arguing for Three Days</title>
      <dc:creator>Belal Shafiq</dc:creator>
      <pubDate>Fri, 16 Oct 2026 08:11:53 +0000</pubDate>
      <link>https://dev.to/belalshafeq/the-coder-agent-and-the-reviewer-agent-have-been-arguing-for-three-days-51k8</link>
      <guid>https://dev.to/belalshafeq/the-coder-agent-and-the-reviewer-agent-have-been-arguing-for-three-days-51k8</guid>
      <description>&lt;p&gt;I set up a Coder agent and a Reviewer agent last week. Simple loop. Coder writes code, Reviewer gives feedback, Coder fixes it. I went to bed at midnight.&lt;/p&gt;

&lt;p&gt;They were still going when I woke up.&lt;/p&gt;

&lt;p&gt;Not crashed. Not erroring. Just talking. Coder kept fixing the same thing. Reviewer kept asking for the same change. Both doing exactly what I told them to.&lt;/p&gt;

&lt;p&gt;The only thing that stopped them was me killing the process.&lt;/p&gt;

&lt;p&gt;Here's what nobody tells you.&lt;/p&gt;

&lt;p&gt;Every framework has a step limit. LangGraph, CrewAI, all of them. Mine did too. It didn't help.&lt;/p&gt;

&lt;p&gt;Because from the step counter's point of view, message 47 is a brand new step. Message 46 was different. It ran. It produced output. The counter ticked up.&lt;/p&gt;

&lt;p&gt;It has no way of knowing that message 47 is byte-for-byte identical to message 45.&lt;/p&gt;

&lt;p&gt;Step limits catch agents that never stop. They don't catch agents that stop every single time, then immediately start again with the same message.&lt;/p&gt;

&lt;p&gt;The shift that fixed it&lt;br&gt;
A loop isn't repeated steps. It's repeated content.&lt;/p&gt;

&lt;p&gt;So I stopped counting steps and started counting fingerprints.&lt;/p&gt;

&lt;p&gt;Every message gets hashed. Store the hashes in a small window per session. Same hash showing up too many times? Loop. Short pattern cycling? A→B→A→B ping-pong.&lt;/p&gt;

&lt;p&gt;The whole thing is about fifteen lines of code.&lt;/p&gt;

&lt;p&gt;The bug that almost killed it&lt;br&gt;
One thing will silently break this if you're not careful.&lt;/p&gt;

&lt;p&gt;If you serialize a payload to a string before hashing it (and you have to), the order of the keys matters.&lt;/p&gt;

&lt;p&gt;{"a": 1, "b": 2} and {"b": 2, "a": 1} are the same dict. But json.dumps gives you two different strings. Two different hashes. As far as your detector knows, two different messages.&lt;/p&gt;

&lt;p&gt;Your loop detector fires zero times. Ever. And you never notice, because on the surface everything looks fine.&lt;/p&gt;

&lt;p&gt;The fix is sort_keys=True. That's it. But if you don't know to add it, you write the whole thing, ship it, and it does nothing.&lt;/p&gt;

&lt;p&gt;What I still can't catch&lt;br&gt;
Honest list:&lt;/p&gt;

&lt;p&gt;Different words, same meaning. Hashes don't see that. Needs embeddings.&lt;/p&gt;

&lt;p&gt;Genuinely new message every round. That's a step limit problem, not a loop problem.&lt;/p&gt;

&lt;p&gt;One malformed message crashing the next agent. Schema problem.&lt;/p&gt;

&lt;p&gt;The fingerprinting catches one specific thing — two agents saying the same thing to each other until someone notices. That's the one that costs the most money.&lt;/p&gt;

&lt;p&gt;Takeaway&lt;br&gt;
If you're running agents in production without payload fingerprinting, you don't have loop detection. You have a step limit, or you have a bill.&lt;/p&gt;

&lt;p&gt;Hash the payload. Watch for repeats. Watch for cycles. Trip early.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>agents</category>
      <category>python</category>
    </item>
  </channel>
</rss>
