CODING CHALLENGE · N°66

Build Your Own Agent Loop

Medium AI EngineeringAgentsLoop Engineering

Strip an "AI agent" of its mystique and this is what is left: a loop. Read the model’s next move — a tool call or a final answer — run the tool, feed the result back as an observation, repeat until it answers or the step cap trips. This is the ReAct inner loop, and it is a pure, testable function.

The problem

Implement agent_loop(model_outputs, tools, max_steps). Each step consumes the next entry of model_outputs: either {"type": "final", "text": …} (the agent is done) or {"type": "tool", "name": …, "arg": …} (call a tool). tools is a lookup of {name: {arg: result}}. Execute a tool by looking up its result and appending it to observations; if the tool name is unknown append "unknown_tool", if the name is known but the arg is not append "unknown_arg". Stop on a final (status "answered") or when steps reaches max_steps or model_outputs runs out (status "max_steps", answer stays None). Return {"answer", "steps", "observations", "status"}.

EXAMPLE 1
Input model_outputs=[{"type":"tool","name":"search","arg":"cats"}, {"type":"final","text":"felis catus"}], tools={"search":{"cats":"felis catus"}}, max_steps=5
Output {'answer': 'felis catus', 'steps': 2, 'observations': ['felis catus'], 'status': 'answered'}
call the tool, observe the result, then answer — two steps
EXAMPLE 2
Input model_outputs=[{"type":"tool","name":"calc","arg":"2+2"}], tools={"calc":{"2+2":"4"}}, max_steps=1
Output {'answer': None, 'steps': 1, 'observations': ['4'], 'status': 'max_steps'}
the cap trips before a final answer ever arrives — no answer, loudly
EXAMPLE 3
Input model_outputs=[{"type":"tool","name":"web","arg":"x"}, {"type":"final","text":"done"}], tools={"search":{"a":"b"}}, max_steps=5
Output {'answer': 'done', 'steps': 2, 'observations': ['unknown_tool'], 'status': 'answered'}
a hallucinated tool name is observed as "unknown_tool" — the loop keeps going
CONSTRAINTS
  • One model_outputs entry is consumed per step; steps counts entries consumed (including the final).
  • Tool result: tools[name][arg] when both exist; "unknown_tool" if name is absent; "unknown_arg" if the name exists but the arg does not. Append it to observations in order.
  • A final ends the loop with status "answered" and answer set to its text.
  • Ending any other way — steps == max_steps OR model_outputs exhausted — is status "max_steps" with answer left as None.
SOLVE IT YOURSELF

Your turn — write it

Edit the stub, hit Run (or ⌘/Ctrl + Enter), and watch the hidden tests. Stuck? the hints are right above and Reveal solution is one click away.

YOUR TASK

Implement agent_loop(model_outputs, tools, max_steps) — step through the model’s moves, execute tools into observations, and stop on a final answer or the step cap. Return the full result dict.

HINTS — 4 IDEAS
  1. Loop while steps < max_steps AND steps < len(model_outputs). Read model_outputs[steps], then increment steps.
  2. On {"type": "final"}, set answer to its text, status "answered", and break.
  3. On a tool: check name in tools first ("unknown_tool"), then arg in tools[name] ("unknown_arg"), else tools[name][arg]. Append whichever to observations.
  4. If the loop ends without a final, answer stays None and status is "max_steps" — this covers both hitting the cap and running out of moves.
CPython · WebAssembly

Explore the topic

See this challenge alongside everything else on the same subject — handbooks, system designs, algorithms and tools, in one place.