Skip to main content

Overview

The prebuilt ReAct agent implements a classic pattern:
  • Reason/Plan with an LLM planner step
  • Act by executing a tool requested by the LLM
  • Repeat until you have a final answer
In Coevolved, react_agent(...) is built on top of agent_loop(...), so it supports checkpointing, budgets, and interrupts.

Required state shape

ReAct expects state to be either a dict or a Pydantic model with fields that behave like:
  • messages: list of chat messages (recommended)
  • llm_response: the last LLMResponse from the planner
  • tool_name, tool_args, tool_call_id: metadata for the current tool call
  • tool_result: output of the tool
  • final: final assistant text (used as the stop signal)

Planner (LLM step)

The planner must be a step created by llm_step(...) and should attach an LLMResponse into state (default key: llm_response). When tool specs are present in LLMConfig.tools, the provider can return tool calls in LLMResponse.tool_calls.

Tools (tool steps)

Tools must be steps created via tool_step(...) (annotation kind="tool"). At runtime, the agent:
  • Validates that all tools are Steps and are marked as tools
  • Resolves tool calls by tool name
  • Executes exactly one tool call per iteration (first call in the list)

Loop behavior and termination

ReAct stops when final is not None. If the LLM requests a tool that does not exist, ReAct raises a KeyError. If a tool runs but does not set tool_result (or your configured result key), ReAct raises an error so you can fix the tool wrapper.

Next steps