OpenRouter

OpenRouter's Tool-Calling Loop: Where Your Stop Conditions Belong

OpenRouter's TypeScript tutorial shows why the iteration cap, not the model, decides when an agent loop ends.

OpenRouter's Tool-Calling Loop: Where Your Stop Conditions Belong — article cover
On this page6 SECTIONS
  1. The model asks, your code decides
  2. Three stop conditions, three different failures
  3. Failures belong in the tool result
  4. What the example run shows
  5. Where this fits
  6. Sources

The model asks, your code decides

A tool-calling agent loop looks simple: send the conversation and tool definitions, run whatever the model requests, append the results, repeat. The interesting part is that the model never decides when to stop. Your application does.

OpenRouter’s TypeScript tutorial walks through building that loop against the OpenRouter SDK, using local weather data so the example runs without a second service. The control flow is the point, not the weather.

Three stop conditions, three different failures

The tutorial names three ways the loop ends: the model returns no tool calls, the same call repeats past a limit, or an iteration cap fires.

Each covers a distinct failure. A model that keeps searching for a better answer never returns empty tool calls. A model stuck on a failed call repeats the same fingerprint. And a model that keeps requesting tools on the final permitted iteration would have its results executed with no chance to reach the model — so the tutorial checks the cap after the response and before any tool runs. Running tools there creates side effects nothing can report on.

The cap check uses equality against maxIterations, which is why the example rejects anything that is not a positive safe integer before the first request. A value like 0, 1.5, or NaN would never match, and the loop would run until the model stopped asking. Number.isSafeInteger() also rejects values above Number.MAX_SAFE_INTEGER, where iteration++ stops producing distinct values.

The repeat counter stops a run after the same tool and argument string appears three times. The tutorial explains the threshold: two would kill a model that retries once after an empty or transient result, while three allows that single retry and still stops a stuck model quickly. Both the threshold and the default cap are application choices, not OpenRouter defaults.

Failures belong in the tool result

Tool arguments arrive as a JSON string, so parsing sits inside the handler’s try block. Invalid JSON, an unknown function name, or a failed lookup becomes a tool result rather than a crash. The model can then change its arguments, pick another tool, or explain the failure.

Each result carries the original call ID as toolCallId, which is how the model matches results to requests. One response can contain several calls, and each needs its own result. The tutorial keeps request-level errors — authentication, network — outside that path so the surrounding application still sees them.

Two smaller details matter more than they look. Tool definitions go on every request, including follow-ups after tool results, because the model needs them to judge whether another tool helps. And the assistant message is appended before the tool results, preserving the full turn.

What the example run shows

The tutorial’s sample run against the API returned two get_weather calls in a single first iteration, which the loop executed in parallel, then a second iteration with no tool calls and a text answer. Latency was roughly 3.9 seconds then 1.4 seconds. The tutorial notes your run may differ in iteration count, wording, and latency.

That parallel execution is where concurrency choices start to matter, and the tutorial flags it as a separate control from the stop conditions. Model fallback handles provider errors; the ordered models list gives fallback, and Auto Exacto reorders providers on tool-calling requests by default.

Where this fits

The tutorial’s argument is that you do not need an agent framework to build or understand this control flow, and that a small implementation stays useful even if you later move the loop into a library. That framing matches a pattern worth watching across agent tooling: the harness around the model carries more of the reliability work than the model choice does, as Cooley’s IPO agent work illustrated in this earlier post.

If you are starting today, the practical next step is to run the tutorial’s local weather version end to end, then replace the handler with a real service and watch which stop condition fires first. The supplied material does not cover what changes when tools have side effects beyond the note about the final iteration — that is the part you will have to design yourself.

Sources

AI-assisted summary compiled from the sources above, reviewed by a human before publishing.

FOUND_THIS_USEFUL?

Support more practical AI articles, tutorials, and build notes.

BUY_ME_A_COFFEE
SHAREXEMAIL