Skip to Content
Core EnginereActLoop

reActLoop

Problem

A single LLM call is not enough for tasks that require multiple steps — like looking up data, using a tool result, then forming a final answer. Wiring that loop yourself means managing conversation history, step counters, tool routing, and exit conditions in every project.


Solution

reActLoop runs a full Reason → Act → Observe cycle for you. It calls your provider, checks if tools are needed, executes them, feeds results back into the conversation, and repeats — until the agent produces a final text answer or hits maxSteps.


Feature & Use-Case

Use reActLoop when:

  • Your agent needs to call tools to answer a question
  • The task requires multiple LLM steps (plan → act → respond)
  • You want automatic conversation history management across steps
  • You are building LangChain-powered agents with dynamic tool usage

Import

import { reActLoop } from "llm-layer-engine";

Function Signature

function reActLoop(options: ReActOptions): { run(): Promise<{ result: string; stats: { steps: number; toolCalls: number; errors: number; executionTime: { startTime: Date; endTime: Date; }; }; }>; }

Parameters (ReActOptions)

ParameterTypeRequiredDescription
configAgentConfigProvider + model + temperature config
providerLLMProviderYour LangChain-compatible LLM provider
messagesMessage[]Initial conversation to start the loop
toolsTool[]Array of tools the agent can call
maxStepsnumberMax iterations before stopping (default: 5)

Example — Agent With a Tool

import { reActLoop } from "llm-layer-engine"; import type { LLMProvider, Tool } from "llm-layer-engine"; import { ChatAnthropic } from "@langchain/anthropic"; // Provider setup const model = new ChatAnthropic({ model: "claude-3-5-sonnet-20241022" }); const provider: LLMProvider = { name: "anthropic", async run({ messages, config }) { const res = await model.invoke( messages.map((m) => ({ role: m.role, content: m.content })) ); return { content: res.content as string }; }, }; // Define a tool const weatherTool: Tool = { name: "get_weather", execute: async (input) => { const city = input.city as string; return { city, weather: "Clear skies, 28°C" }; }, }; // Run the loop const loop = reActLoop({ config: { provider, model: "claude-3-5-sonnet-20241022", temperature: 0.5, }, provider, messages: [ { role: "system", content: "You are a weather assistant. Use tools when needed." }, { role: "user", content: "What is the weather in Karachi?" }, ], tools: [weatherTool], maxSteps: 5, }); const { result, stats } = await loop.run(); console.log(result); // → "The weather in Karachi is clear skies at 28°C." console.log(stats); // → { steps: 2, toolCalls: 1, errors: 0, executionTime: { ... } }

How Steps Work

StepWhat Happens
1Provider receives initial messages
2If provider returns tool calls → tools execute, results added to conversation
3Provider runs again with updated conversation
4If provider returns plain text → loop ends, result returned
5+Repeats until isFinished or maxSteps reached

Stats Reference

FieldTypeDescription
stepsnumberTotal steps executed
toolCallsnumberTotal tool calls made across all steps
errorsnumberErrors caught during execution
executionTime.startTimeDateWhen the loop started
executionTime.endTimeDateWhen the loop ended

Conclusion

reActLoop is the core of any tool-using agent. Pass in your provider, your tools, and your messages — the loop handles the rest. Keep maxSteps reasonable (3–7) to avoid runaway loops and unnecessary token usage.

Last updated on