Loop Mechanics

By the Syncfusion DevTutorials team · Last updated

What happens inside one turn of the agent loop: input assembly, inference, tool execution and observation capture, plus iteration tracking, action evaluation and the three runtime logs.

Think about a cook following a recipe during a busy dinner service.

For every step, the cook follows the same process. They read the order and check what has already been completed. They decide what to do next, perform the action, then look at the result and make a quick note.

They keep repeating this process until the dish is ready. The steps are the same in every turn, even though the situation changes over time.

An agent loop works in exactly the same way. Each turn, called an iteration, follows the same sequence of steps.

The main idea: In each iteration, the agent prepares the input, asks the model what to do, performs the action, and saves the result. The next iteration starts with a little more history than before.

A Real-World Example

When the agent fixes the Brightgrid row count bug, it usually runs about five iterations. During iteration 3, the following happens:

  1. The application collects the goal and the results from iterations 1 and 2.
  2. It sends that information to the model.
  3. The model replies: "write_file web/format.js".
  4. The application runs the tool and saves the result: "Saved web/format.js".

Iteration 4 then starts with that saved result included in the history.

In simple words: One iteration means "collect, ask, do, save". The loop repeats this process until the goal is reached.

What You Will Learn

In this lesson, you will learn:

  1. The four parts of an iteration: input assembly, inference, tool execution, and observation capture.
  2. How the loop keeps track of iterations and updates its state.
  3. How to determine whether an action made progress.
  4. The three runtime logs: execution history, observation history, and decision records.

The Trace tab in the Agent Lab now includes an input viewer. Select any step to see the exact messages the brain received during that iteration. Notice how the input grows as more history is added with each step.

One iteration: assemble the input, ask the model, run the tool, and capture the observation. The observation is added to the history for the next iteration.

Execution Cycle

The execution cycle is the set of four parts that happen during a single iteration.

Input Assembly

Input assembly means building the messages that will be sent to the model. These messages usually include:

  • The system instructions and tool list.
  • The goal.
  • All previous actions and their results.

The model does not remember anything between calls. Because of this, the application must send the complete history every time. That is why the input becomes larger with each iteration.

The input grows every iteration

const system = "You are a coding agent. Tools: run_tests, read_file, write_file.";
const goal = "Make every test pass.";
const history = [
  { action: "run_tests", result: "1 passed, 2 failed" },
  { action: "read_file web/format.js", result: "return n + \" row\";" },
  { action: "write_file web/format.js", result: "Saved web/format.js" },
];

const tokens = (text) => Math.ceil(text.length / 4);

for (let i = 0; i <= history.length; i++) {
  const messages = [system, "Goal: " + goal];
  for (const h of history.slice(0, i)) messages.push(h.action, "Result: " + h.result);
  console.log("Iteration " + (i + 1) + ": " + messages.length + " messages, about " + tokens(messages.join("\n")) + " tokens");
}

Expected output:

Iteration 1: 2 messages, about 23 tokens
Iteration 2: 4 messages, about 33 tokens
Iteration 3: 6 messages, about 45 tokens
Iteration 4: 8 messages, about 59 tokens

Every iteration adds two messages: the action and its result. On long tasks, this growth becomes important. Lesson 13 explains how to keep the history small.

Inference

Inference means asking the model what to do next. The model reads the assembled input and returns a response that describes the next action.

The response is only text. The application must convert that text into a real action. If the response is invalid or incorrectly formatted, the application must detect the problem.

Turn the model's reply into an action

function readAction(reply) {
  const start = reply.indexOf("{");
  const end = reply.lastIndexOf("}");
  if (start < 0 || end < start) return { error: "no JSON in the reply" };
  try {
    return JSON.parse(reply.slice(start, end + 1));
  } catch {
    return { error: "the JSON could not be read" };
  }
}

const replies = [
  'Sure! {"tool": "run_tests", "args": {}}',
  '{"tool": "read_file", "args": {"path": "web/format.js"',
  "I think the bug is in the format file.",
];

for (const reply of replies) console.log(JSON.stringify(readAction(reply)));

Expected output:

{"tool":"run_tests","args":{}}
{"error":"no JSON in the reply"}
{"error":"no JSON in the reply"}

The first reply contains extra text, but the JSON inside it is valid. The second reply is incomplete because the closing brace is missing.

The third reply does not contain any JSON at all. The application detects both problems before running anything.

Tool Execution

Tool execution means the application runs the tool requested by the model. Before running the tool, the application verifies the tool name and checks the inputs, just as you learned in Lesson 3.

Observation Capture

Observation capture means saving the tool's result in a format that the model can use in the next iteration.

Two rules help create good observations:

  • Keep it short. Very large results make the input grow quickly, so long outputs should be shortened to a safe size.
  • Mark errors clearly. Start failures with "ERROR:" so the model can easily recognize them.

Capture a clean observation

function capture(result, maxChars) {
  if (!result.ok) return "ERROR: " + result.text;
  if (result.text.length > maxChars) return result.text.slice(0, maxChars) + "... (" + (result.text.length - maxChars) + " more characters)";
  return result.text;
}

console.log(capture({ ok: true, text: "3 passed, 0 failed" }, 40));
console.log(capture({ ok: false, text: "No file named web/fromat.js" }, 40));
console.log(capture({ ok: true, text: "x".repeat(100) }, 40));

Expected output:

3 passed, 0 failed
ERROR: No file named web/fromat.js
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx... (60 more characters)

The long result is shortened, and the note shows how much content was removed. The error begins with "ERROR:", making it easy for the next thought to recognize and respond to the failure.

Now run an agent and open the Trace tab. Select step 1 and then step 5 in the input viewer.

Inside each iteration

Step 1's input contains only the instructions and the goal. Step 5's input contains the instructions, the goal, and all previous actions and results. This shows how input assembly grows from one iteration to the next.

Easy Way to Remember: Every iteration follows collect, ask, do, save. Collect the input, ask the model, run the tool, and save the observation.

Loop Progression

Iteration Tracking

Iteration tracking means counting the turns in the loop. The count is used for the step limit and for logs. It also helps communicate progress, such as "the agent is on step 4 of a maximum of 8 steps."

State Updates

A state update changes what the agent knows after each iteration. For example: "tests run: yes" or "failing: 2".

The state should only be updated from real observations. Never update the state based on what the model thinks or expects happened.

Action Evaluation

Action evaluation means asking: "Did that action move us closer to the goal?" A simple way to measure this is to compare a value before and after the action, such as the number of failing tests.

Track iterations, update the state, evaluate each action

const state = { iteration: 0, failing: 2 };
const results = [2, 2, 1, 1, 0];

for (const failingNow of results) {
  state.iteration++;
  const change = state.failing - failingNow;
  const verdict = change > 0 ? "progress" : failingNow === 0 ? "done" : "no change";
  state.failing = failingNow;
  console.log("Iteration " + state.iteration + ": failing " + failingNow + " (" + verdict + ")");
}

Expected output:

Iteration 1: failing 2 (no change)
Iteration 2: failing 2 (no change)
Iteration 3: failing 1 (progress)
Iteration 4: failing 1 (no change)
Iteration 5: failing 0 (progress)

Not every iteration makes progress. Reading files does not reduce the number of failures, and that is fine.

However, if many iterations in a row produce no progress, it can be a warning sign. Lesson 10 turns this idea into a rule.

Runtime Logs

A runtime log is a record that the agent writes while it is running. Good agents keep three types of logs.

Execution History

The execution history records what the agent did. It usually includes the step number, the tool that was used, and whether the action succeeded.

Observation History

The observation history records the results returned by each tool.

Decision Records

The decision records record why the agent chose each action. This is the agent's thought or reasoning for that step.

These three logs answer three important questions:

  • What did the agent do?
  • What did the agent see?
  • Why did the agent do it?

Three logs answer three questions

const executionLog = [];
const observationLog = [];
const decisionLog = [];

function record(step, tool, ok, observation, thought) {
  executionLog.push({ step, tool, ok });
  observationLog.push({ step, observation });
  decisionLog.push({ step, thought });
}

record(1, "run_tests", true, "1 passed, 2 failed", "I need to find what is broken.");
record(2, "read_file", true, "return n + \" row\";", "The failure points to web/format.js.");
record(3, "write_file", false, "ERROR: BLOCKED", "I fix the word.");

const failed = executionLog.find((e) => !e.ok);
console.log("What failed: step " + failed.step + ", " + failed.tool);
console.log("What it saw: " + observationLog.find((o) => o.step === failed.step).observation);
console.log("Why it tried: " + decisionLog.find((d) => d.step === failed.step).thought);

Expected output:

What failed: step 3, write_file
What it saw: ERROR: BLOCKED
Why it tried: I fix the word.

With all three logs, a person can understand the cause of a failure in seconds. The Trace tab in the Agent Lab displays all three logs together in a single table.

Never log secrets, passwords, or private customer information. Logs are often viewed by many people and stored for a long time. Remove or mask sensitive values before writing them to a log.

Common Mistakes

MistakeWrong IdeaCorrect IdeaWhat Goes Wrong
Sending only the most recent step"The model remembers everything else."Send the full history in every iteration.The agent forgets information learned earlier.
Running an invalid reply"The model always returns valid JSON."Parse and validate the reply before using it.The application crashes or performs the wrong action.
Huge observations"More details are always better."Trim long results to a safe size.The input becomes too large and more expensive to process.
Hidden errors"The model will notice the problem."Start failures with "ERROR:".The agent behaves as if the action succeeded.
No decision log"The tool log is enough."Record the reasoning behind every step.Nobody can understand why the agent made a decision.

Exercises

Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.

What to Remember

  • Each iteration follows the same pattern: collect, ask, do, save.
  • The input grows with every iteration because the complete history is sent to the model each time.
  • Always validate the model's reply before running any action.
  • Keep observations short and make errors easy to identify by clearly marking them.
  • Maintain three types of logs: what was executed, what observations were returned, and why each decision was made.

Next: Loop Control and Governance, how to decide when the loop should stop, and how to keep it inside a budget.