Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To stop a TypeScript AI agent from calling the same tool forever, run it as a bounded state machine: validate every tool request, enforce a maximum turn count, detect repeated calls, apply per-call timeouts, and require approval before side effects. The loop must terminate on a final answer, refusal, typed error, cancellation, or a configured limit—not merely when the model appears to be finished.

Guardrails belong at the tool boundary. Checks before execution can block unsafe arguments and prevent side effects; checks after execution validate results and decide whether the model may continue. Agent-level checks alone are not enough when work is handed off between agents or coordinated by a manager.

What does a bounded TypeScript agent loop look like?

An agent loop is a sequence of explicit states, not an unconstrained conversation. Your application sends model input, receives either a final response or one or more tool calls, validates each call, executes permitted tools, appends tool results, and asks the model what to do next. The loop ends when the model returns a final answer, refuses, produces a typed terminal error, is cancelled, or reaches a configured limit.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Anthropic describes this client pattern as repeating while the response has a tool_use stop reason. The OpenAI Agents SDK for JavaScript instead raises MaxTurnsExceededError when its configured maxTurns is reached, unless that limit is explicitly set to null. These are framework behaviors, not substitutes for an application policy.

Popular on Amazon
Sale
Nicpro Mechanical Carpenter Pencils for Construction (Black, Red) With Case | Deep Hole Marker Pencil Set Includes Sharpener and 26 Refills, Comfortable Grip, Heavy Duty Woodworking Tools for Architect
  • Valued Carpenter Pencil Set: You will get 2 pcs solid carpenter pencils with 26 piece 2.8 mm refills, 1 replaceable sharpener, 1 plastic storage box.The complete carpenter pencils combination allows you to finish your work faster and more easily
  • Deep Hole Marker Pencil: The deep-hole construction pencils adopts 45mm elongated tip design, which is more convenient to mark in the small hole or in other tight areas that other carpenter markers cannot reach
  • Carpenter Pencils with Sharpener: The sharpener is screwed into the top of the work pencil, which won't get lost either. Built-in pencil sharpener that keep the lead with pointed and smooth to Improves line of sight in fine work
  • Stronger Solid Lead: This work pencil is matched with a 2.8 mm thick lead , which is much thicker and stronger during the drawing process of construction work, it will not break or damage easily
  • Marks on Various Surfaces: 3 colors solid construction pencil can marks on various surfaces,such as metal, plastic, wood, paper etc. Ideals for woodworkers, contractors, craftsmen, builders, merchants and masons

The states you should record

  • Input: the user request, identity, tenant, and allowed scope.
  • Model decision: response ID, stop reason, requested tool name, and raw arguments.
  • Validation: parsed arguments, schema result, authorization result, and approval status.
  • Execution: start time, end time, timeout or cancellation status, and tool-call ID.
  • Continuation: the normalized tool signature, returned result, and next turn number.
  • Terminal state: final output, refusal, typed error, approval pause, cancellation, or limit reached.

This state record lets an operator distinguish useful multi-step work from a loop that keeps producing the same request or error.

Where should guardrails run: before or after a tool?

Use both positions. A blocking input guardrail runs before execution to reject invalid arguments, disallowed scope, or a missing approval. An output guardrail runs after execution to validate the returned data and prevent malformed or unsafe results from being fed back into the model.

Input checks before execution

Parse model arguments with the tool’s schema, then authorize the parsed values against the current user, tenant, resource, and operation. Do not authorize the raw JSON string: equivalent values can have different formatting, and unparsed fields may hide an out-of-scope resource. If a check fails, return a bounded, structured error or terminate the run according to your policy. The tool must not run.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Output checks after execution

Validate the tool’s result before appending it to the conversation. Check required fields, maximum size, permitted status values, and data classifications. An output guardrail should be able to turn an invalid result into a typed error that the model can handle, or stop the run when continuing would be unsafe.

Why agent-level guardrails are insufficient

In the OpenAI JavaScript Agents SDK, agent-level input guardrails run only on the first agent and agent-level output guardrails only on the final agent. A handoff or manager workflow can therefore execute intermediate tools without those checks. Put the authoritative policy on each custom function-tool invocation, then add agent-level checks as a second layer.

Blocking versus parallel guardrails

A blocking input check is the safest option when rejection must prevent model tokens and side effects. Parallel guardrail execution can reduce latency, but the model may already have consumed tokens or a tool may have started before the guardrail reports failure. Use parallel mode only when that race is acceptable and the tool itself remains safe under late cancellation.

How many turns or iterations should an agent be allowed?

Set a finite limit for every autonomous run. Choose it from the workflow’s maximum useful steps and cost budget, not from a universal “safe” number. Keep the limit independent of retry counts so a transient network retry cannot silently consume an unlimited number of model turns.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Framework or specification Published behavior How to use the information
OpenAI Agents SDK for JavaScript Raises MaxTurnsExceededError when maxTurns is reached; null disables that cap. Set an explicit finite value for production runs and handle the exception as a terminal state.
Microsoft Agent Framework LoopAgent Documents a default maximum of 10 agent invocations. Treat 10 as a framework example, not as a universal limit for every workflow.
Prompty specification Lists MAX_ITERATIONS = 10 and MAX_LLM_RETRIES = 3. Keep iteration and retry budgets as separate counters in your own implementation.

For a simple read-only lookup, a small cap may be enough. A workflow that searches, validates, and then writes data may need more turns, but it should still have a hard ceiling and an approval pause before the write.

Also popular on Amazon
Sale
DEWALT 20V MAX Drill and Impact Driver (DCK240C2) | Includes 2 Batteries, Charger and Bag (
  • Ergonomically Designed: Work in tight areas with a compact design that gets into tough spots
  • Both tools are designed to fit into difficult to reach spaces
  • Complete a wide range of applications with a high-performance motor that delivers up to 300 UWO, and an impact driver delivering up to 1,400 in-lbs of torque
  • Both the DEWALT impact driver and drill driver feature integrated LED work lights with a convenient 20-second delay, ensuring enhanced visibility in dimly lit or challenging work areas
  • One-Handed Loading - Keep one hand free with a 1/4 in. hex chuck that accepts 1 in. bit tips

Reset forced tool choice

If your SDK allows a forced or named tool choice, reset it after the tool call. The OpenAI Agent configuration’s resetToolChoice option defaults to true; its stated purpose is to prevent an infinite loop of tool usage. Leaving a forced choice active can cause the model to request the same function on every turn even after it has returned a result.

How do I detect the same tool call repeating?

Count repetition in application state, not just identical text. Normalize the tool name and arguments, then compare that signature with recent calls. Also consider whether the relevant state changed and whether the same error was returned.

Build a normalized signature

Sort object keys, remove insignificant whitespace, canonicalize case only where the schema says values are case-insensitive, and exclude volatile fields such as request IDs. Hash or serialize the result with the tool name. Never remove fields that affect authorization or the operation’s meaning.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a circuit breaker

  • Increment a counter for each normalized signature.
  • Increment a separate counter when the relevant state remains unchanged after execution.
  • Count repeated identical error results, including validation and permission errors.
  • Stop or pause for review when a signature reaches the configured threshold.

A repetition threshold is an application policy, not a published standard. A read-only tool might tolerate two identical calls; a payment, deletion, or shell tool should normally pause after the first suspicious repeat.

What TypeScript policy can I implement at the tool boundary?

The following policy combines a turn cap, repetition breaker, schema validation, timeout, and approval hook. The numbers are illustrative choices; tune them to latency, task complexity, and risk.

const MAX_TURNS = 8;
const MAX_SAME_CALL = 2;
const TOOL_TIMEOUT_MS = 15_000;

type ToolContext = {
  signal: AbortSignal;
  turn: number;
  callId: string;
};

type ToolResult =
  | { ok: true; value: unknown }
  | { ok: false; code: string; message: string };

async function runToolWithPolicy(
  tool: ToolDefinition,
  rawArgs: unknown,
  ctx: ToolContext,
  state: RunState,
): Promise<ToolResult> {
  if (ctx.turn >= MAX_TURNS) {
    return { ok: false, code: "max_turns", message: "Run limit reached." };
  }

  const parsed = tool.inputSchema.safeParse(rawArgs);
  if (!parsed.success) {
    return { ok: false, code: "invalid_arguments", message: "Arguments failed validation." };
  }

  const signature = normalizeSignature(tool.name, parsed.data);
  const repeats = state.signatureCounts.get(signature) ?? 0;
  if (repeats >= MAX_SAME_CALL) {
    return { ok: false, code: "repeated_call", message: "Repeated tool request blocked." };
  }
  state.signatureCounts.set(signature, repeats + 1);

  if (!isAllowed(tool.name, parsed.data, state.identity)) {
    return { ok: false, code: "not_authorized", message: "Requested scope is not allowed." };
  }

  if (tool.hasSideEffects && !(await requestApproval(tool.name, parsed.data))) {
    return { ok: false, code: "approval_denied", message: "Approval was not granted." };
  }

  const timeout = AbortSignal.timeout(TOOL_TIMEOUT_MS);
  const signal = AbortSignal.any([ctx.signal, timeout]);
  try {
    const value = await tool.execute(parsed.data, { ...ctx, signal });
    const checked = tool.outputSchema.safeParse(value);
    if (!checked.success) {
      return { ok: false, code: "invalid_output", message: "Tool output failed validation." };
    }
    return { ok: true, value: checked.data };
  } catch (error) {
    if (signal.aborted) {
      return { ok: false, code: "timeout_or_cancelled", message: "Tool did not finish." };
    }
    return { ok: false, code: "tool_error", message: "Tool failed." };
  }
}

In a real SDK integration, use the signal supplied by the runner when one exists. If the SDK requires a particular timeout result shape, return that schema-compatible object rather than an arbitrary exception string.

How do I timeout and cancel a tool call in Node.js?

Give every tool invocation a positive timeout and propagate the resulting AbortSignal into the operation. A timeout is useful only when the underlying HTTP client, database driver, subprocess, or SDK actually listens for cancellation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Create or receive an abort signal for the run.
  2. Combine it with a per-call timeout, such as AbortSignal.timeout(15_000).
  3. Pass the combined signal to the tool and down into fetch, the database client, or the child-process API.
  4. When the signal aborts, release sockets, streams, locks, and temporary files.
  5. Return either a structured timeout result or raise an exception, according to the tool policy.

The OpenAI JavaScript tool API supports a timeoutMs setting and two behaviors: error_as_result, which gives the model a recoverable structured result, and raise_exception, which sends control to application error handling. Use the first when the model can safely choose an alternative; use the second when continuing would be misleading or dangerous.

Also popular on Amazon
Sale
Push to Unlock,Katerk 6pcs 1/4 inch Hex Shank Aluminum Alloy Screwdriver Bit Holder Light-Weight Quick-Change Extension Bar Keychain Drill Screw Adapter Portable,Black Carabiner,Tool Gifts for Men
  • 【Great Compatibility】This Katerk 1/4 inch hex shank bit holder is specifically designed for 1/4 inch hex shank drill bits. It's compatible with most 1/4 fast hex handles, hex sockets, various electric screwdrivers, and handheld screwdrivers. The bit holder makes it a valuable addition for any handyman.
  • 【Secure and Safe】Built with a secure backup nut design, each drill bit holder securely locks onto your bits, ensuring they stay firmly in place. Additionally, our bit holder incorporates a high-quality steel ball rolling design that holds up to several kilograms of weight, ensuring your various drill bits don't fall off.
  • 【Easy One-Handed Operation】The bit holder for impact driver allows you to change bits single-handedly, simplifying your workflow. Its multi-color design further allows for quick identification of the drill bit you need.
  • 【Compact and Convenient】Thanks to its compact size, this 1/4 inch bit holder is easy to carry around. The bit holder allows for easy attachment to various tools, making this a convenient addition to your construction accessories. The Katerk bit holder is cast from high-quality alloy material, promising a long product lifespan. Despite its rugged strength, the bit holder remains lightweight, making it portable.
  • 【Cool Christmas Gift For Men Stocking Stuffers】 This screwdriver bit holder, driver bit holder, impact bit holder, can be given as a gift to your loved one, especially for anyone involved in construction or electrical work. It's a must-have for stocking stuffers for men and women, tools gifts for dad, tech gadgets for men, gifts for dad, gifts for him, gifts for husband, gifts for boyfriend, cool gadgets for men, and cool gifts for dad.

Do not treat a timeout as a successful empty result. Make the failure code explicit so the model cannot claim that an operation completed when it did not.

How should schemas and errors be handled?

Validate both directions of the tool contract. Input schemas constrain what the model may request; output schemas constrain what your code feeds back into the next model turn.

  • Reject unknown or extra fields when they could alter authorization or execution.
  • Set maximum lengths for strings, arrays, and uploaded content.
  • Use enums for operations and resource types instead of accepting free-form commands.
  • Return stable error codes such as invalid_arguments, not_authorized, timeout, and conflict.
  • Keep sensitive stack traces in logs, not in model-visible messages.

OpenAI’s JavaScript tool API supports an outputSchema. Its documentation also requires schema-compatible error handlers when timeout errors are returned as results. That requirement matters: an error object that violates the declared result schema can trigger a second failure and encourage unproductive retries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When should a human approve a tool call?

Pause for approval before cancellations, edits, shell commands, deletion, external messages, financial actions, sensitive MCP operations, and any other irreversible side effect. Approval should identify the exact tool, normalized arguments, target resource, and expected consequence.

A safe approval sequence

  1. Validate and authorize the request without executing it.
  2. Display a concise human-readable summary and the exact scope.
  3. Record who approved, denied, or allowed the request to expire.
  4. Resume with the same call ID only after approval; do not ask the model to reconstruct arguments.
  5. Re-check authorization and resource version at execution time to prevent a stale approval from changing a different object.

OpenAI’s API guidance describes approvals as a pause-and-resume path for sensitive tool calls. Treat a denial as a terminal or recoverable typed result, not as a reason to retry the same side effect automatically.

How do I separate retries from loop limits?

Use independent budgets. A retry handles a transient failure such as a rate limit or temporary network disconnect; a loop limit handles repeated reasoning steps. Each retry must still consume time and may need its own cap, backoff, and idempotency key.

For writes, require idempotency keys and detect ambiguous outcomes. If a request times out after the server may have accepted it, do not blindly issue the write again. Query status or send the same idempotency key so the service can safely return the original result.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What should I log to diagnose a runaway loop?

Persist enough information to reconstruct the state machine without storing unnecessary secrets.

Also popular on Amazon
Sale
2 Pack Carpenter Pencils Mechanical Pencils with 12 Refills, (2 Colors) | Construction Pencils with Built-in Sharpener, Long Nib Deep Hole Pencil Marker, Heavy Duty Woodworking Pencil for Architect
  • Long Nib and Deep Hole Marker: Our mechanical carpenter pencil with 45mm nib is designed for easy marking of deep holes or narrow areas. These construction pencils are the great choice for woodworking tools, construction tools, carpenter tools, contractor tools, wood carpentry tools and architect tools
  • Extra Refills in 2 Colors for Versatile Marking: The construction mechanical pencil comes with 12 extra 2.8mm refills, including 6 red and 6 black refills. The black refill is suitable for light surfaces, while the red wax is perfect for dark surfaces. Our carpenter mechanical pencil makes sure that you'll have an ample supply for extended use
  • Built-in Sharpener: Our construction pencil comes with a built-in sharpener to ensure the mechanical pencil tip is always sharp and ready for use. Never buy an extra pencil sharpener again. A great tool for any woodworker pencil, contractor pencils. The refill can easily be extended or retracted with a simple click of the pencils mechanical, allowing you to work more efficiently and accurately
  • Portable Clip Design: Our deep hole construction pencil features a portable clip design, easy to carry and attach to your pocket or tool box, so that you can keep the carpenter pencils mechanical close at hand, making it a convenient tool to have on the go. Great gifts choice for carpenters
  • Stronger Pencil Lead: The black refills are made of lead, sturdy and smooth. The red refills are made of wax, clear and light. These marking pencils are much thicker and stronger than normal pencils during the marking process of construction work, suitable for various surfaces, such as glasses, metal, boards, floors, walls, furniture, etc. The written marks can be easily wiped with a wet paper towel when needed
  • Run ID, parent workflow ID, agent name, tenant, and deployment version.
  • Turn number, model response ID, stop reason, and total elapsed time.
  • Tool-call ID, normalized tool signature, schema version, and authorization decision.
  • Start and end timestamps, timeout or cancellation cause, and retry count.
  • Approval request ID and decision for side-effecting calls.
  • Terminal reason: final answer, refusal, typed error, max turns, repeated call, timeout, or cancellation.

Redact credentials and personal data before logs leave the trust boundary. Metrics should expose counts of terminal reasons and average turns, while traces should retain the per-call sequence needed to explain one failed run.

How do I choose guardrail settings for different workflows?

Match strictness to side effects and uncertainty rather than applying one profile to every tool.

Workflow Turn policy Tool policy Human involvement
Read-only lookup Small finite cap; stop on repeated signature Short timeout, strict output schema Usually none
Multi-step analysis Higher cap with unchanged-state breaker Separate retry budget and larger result limits Review only unusual scope
Record edit Finite cap with no automatic repeat after conflict Idempotency key, version check, output validation Approve before mutation
Shell or external command Very small cap and one-command policy Allowlist executable, arguments, environment, and working directory Approve every sensitive command

Concurrency is another limit. If the model emits several tool calls in one turn, cap the number executed at once and apply the same authorization, timeout, and repetition checks to each call. Parallel execution should never bypass the global turn budget or approval gate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What happens when a guardrail trips?

Make the outcome deterministic and visible. A recoverable validation or timeout error can be returned as a typed tool result with a short message; the model may then choose a permitted alternative. A maximum-turn, repeated-call, denied-approval, or unsafe-scope event should normally end the autonomous run or pause it for a person.

Never silently drop a tool result, silently retry a denied operation, or let the model infer success from the absence of an error. The terminal record should state exactly which policy stopped the run.

Frequently Asked Questions

Can a system prompt alone prevent an agent from looping?

No. Prompt instructions can explain when to stop, but they cannot enforce a maximum, cancel a hung process, or prevent a tool from receiving an unsafe argument. Runtime limits and tool-boundary checks must remain authoritative.

Does aborting a Node.js signal automatically undo a database write?

No. Abortion stops cooperative work; it does not roll back a write that already committed. Use database transactions, idempotency keys, and status checks when a timeout could occur after the server accepts the operation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should parallel tool calls share one repetition counter?

Use a global run budget plus a per-signature counter. This prevents a model from avoiding a breaker by issuing equivalent calls concurrently while still allowing genuinely independent read operations.

What is the safest behavior after an approval request expires?

Treat expiration as a denial and discard the pending execution context. If the user wants to proceed later, create a new approval using freshly validated arguments and current resource state.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.