A minimal, bring-your-own-LLM ReAct (Reason + Act) agent loop for TypeScript
react-agent-loop is a tiny, dependency-free control loop for building
tool-using LLM agents. The model reasons, acts by calling tools,
observes the results, and repeats until the task is done — while every
external concern (which LLM, which tools, how to persist) stays yours.
Implement one method, complete(), over OpenAI, Anthropic, a local model, or a mock. No SDK is bundled.
Register tools with a name, description, JSON-schema parameters, and an async handler. That's it.
beforeToolCall is the seam for a loop detector, policy engine, or budget guard — block or rewrite actions before they run.
No vendor lock-in, no hidden network calls, no global state. Strict TypeScript with full .d.ts types.
npm i github:Princeu3/react-agent-loop
npm registry release coming soon.
import { runReActLoop } from "react-agent-loop";
import type { LlmClient, Tool } from "react-agent-loop";
const getWeather: Tool = {
name: "get_weather",
description: "Get the current weather for a city.",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
handler: async (args) => `It is 22°C and sunny in ${args.city}.`,
};
const llm: LlmClient = {
async complete({ system, messages, tools }) {
const res = await callYourProvider({ system, messages, tools });
return { text: res.text, toolCalls: res.toolCalls };
},
};
const result = await runReActLoop({
llm,
tools: [getWeather],
system: "You are a weather assistant. Call task_done when finished.",
initialMessages: [{ role: "user", content: "Weather in Lisbon?" }],
hooks: {
beforeToolCall(call) {
if (call.name === "delete_everything")
return { block: true, reason: "Blocked by policy." };
},
},
});
console.log(result.stopped); // "task_done" | "shouldStop" | "maxTurns"
console.log(result.finalSummary); // the agent's closing summary
beforeToolCall / shouldStop).beforeToolCall).Distilled and authored by Prince Upadhyay. The control-flow architecture is inspired by the MIT-licensed Conway-Research/automaton agent loop, re-authored as a clean, framework-agnostic library with all project-specific coupling removed.