
I watched the same two web searches run again. Then again. Then again.
The gateway was not crashing. The provider was not timing out. Every request came back with HTTP 200, complete with a fresh response ID. From the API’s point of view, everything was working beautifully.
From my point of view, my agent had become a very expensive parrot.
It repeated roughly the same step nine times in about two minutes: the same short preamble, the same two tool calls, and the same results coming back into the conversation. Only a manual stop ended it.
That incident gave me a much better definition of “healthy.” A successful request is not the same thing as a successful workflow.
A green status code answers a very small question
HTTP 200 means the server accepted a request and produced a valid response. It does not mean the response moved the task forward. It does not mean the model understood the tool result. It definitely does not mean the agent is making progress toward my goal.
That distinction matters with agentic systems because one task is really a chain of requests. The model chooses a tool, the tool returns data, the result is added to the conversation, and the model decides what to do next. Every link can be syntactically valid while the chain goes nowhere.
At first, a repeated tool call looks like an ordinary retry. Maybe the network dropped the result. Maybe the provider duplicated a response. Maybe a timeout caused the harness to resend the last request.
The logs ruled those out. Each provider response had a unique ID, so these were fresh generations rather than one response being replayed by the transport. The tool results were already present between calls. The model was seeing a continuation turn and independently choosing the same action again.
That is not a retry storm. It is a reasoning loop.
The transcript was the real debugging tool
The most useful evidence was not the error log, because there was no error. It was the sequence of assistant messages and tool results.
The repeated preamble was almost identical. The tool names and arguments matched. The returned search data was visible before the next request. OpenClaw even logged loop warnings as the pattern accumulated, but the run continued until I stopped it.
Once I lined those events up, the failure moved from the vague category of “the new model is acting weird” into a much narrower question: what information did the model receive on a tool-continuation turn?
That question led to the replay path.
Reasoning models have a replay contract
Kimi’s current K3 documentation says that multi-turn conversations and tool calls must pass the complete assistant message back to the API as-is, including both reasoning_content and tool_calls.
That requirement is easy to underestimate. In a normal chat, preserving the visible answer can seem sufficient. In a reasoning-and-tools loop, the assistant message contains more than prose. It also records the plan that produced the tool call and the structured call itself. Remove part of that state and the next turn may no longer be a continuation in the model’s eyes.
When I inspected my local integration, the strongest clue was that the replay path did not preserve the earlier reasoning content cleanly. The model received the tool result, but not necessarily the full reasoning state that led to the tool request. Faced with what looked like the same unfinished decision, it planned the step again and landed on the same calls.
I cannot prove that one replay detail explains every loop. Tool-call markup and serialization may also contribute, and a more robust model might recover instead of repeating itself. But the observed behavior matches the documented contract closely enough that I would not dismiss it as random model stubbornness.
The harness is part of the model now. If it loses state between turns, the smartest endpoint in the world can still look forgetful.
Did my patch cause it?
This was the uncomfortable question because the loop appeared after I enabled K3’s maximum-thinking path locally.
My answer is: the patch exposed the problem, but it did not create the replay mechanism that appears to be responsible.
Before the patch, that reasoning mode was not being exercised through this integration. Turning it on sent traffic through a path with a stricter continuation contract. The bug was waiting there; my change finally stepped on it.
That is still useful accountability. “The patch only revealed it” is not permission to ignore the result. A feature is not working for me if enabling it makes routine tool work unreliable, regardless of which layer deserves the bug report.
Guardrails need to measure progress
The immediate lesson was to enable loop detection explicitly. OpenClaw’s current documentation describes rolling detectors for repeated calls and ping-pong patterns, with warnings first and blocking when a no-progress pattern persists. My incident produced warnings without a stop, so configuration and version clearly matter more than assuming the guard is active.
Detection also needs more than a call count. Polling a job ten times can be perfectly healthy if the status changes. Calling the same search twice can be broken if the arguments and results are identical. A useful detector compares the tool, its arguments, and the outcome, then asks whether anything changed.
I was lucky that the repeated tools were read-only searches. If the same pattern hits a tool that sends a message, creates a record, or changes a setting, a silly loop becomes a real incident. Side-effecting tools need their own protections because model-level loop detection is the last guardrail, not the first.
I also want a visible kill switch and bounded runs for tool-heavy experiments. If a new model or reasoning mode is under evaluation, I would rather stop a suspicious sequence early, inspect it, and continue deliberately than burn through tokens while every dashboard stays green.
Success is forward motion
This changed the first question I ask during an agent failure.
I used to start with, “Did the API call succeed?” Now I start with, “What changed after it succeeded?”
Status codes tell me whether the transport worked. Transcripts tell me whether the agent understood the state. Repeated tool signatures tell me whether the workflow is making progress. I need all three before I can call a run healthy.
An agent can fail loudly with a 429 or a timeout. The more dangerous failure is the one that keeps returning 200 while doing the same thing forever. If every step is green but the goal is standing still, what exactly succeeded?



