executeStep
Problem
Inside a ReAct loop, each individual step — calling the provider, checking for tool calls, executing tools, and updating the conversation — has to be coordinated carefully. Doing this manually in every agent adds complexity and breaks separation of concerns.
Solution
executeStep handles one complete step of the agent loop. It calls your provider, detects tool calls, runs the matching tools, appends results to the conversation, and tells the loop whether the agent is finished or needs another step.
You typically do not call this directly. reActLoop calls it internally on every iteration. But it is exported so you can use it in custom loop implementations.
Feature & Use-Case
Use executeStep directly when:
- You are building a custom agent loop with special exit conditions
- You need step-level control — pause between steps, inspect conversation state, or log per-step output
- You want to wrap each step with your own retry or permission logic
Import
import { executeStep } from "llm-layer-engine";Function Signature
async function executeStep(input: StepInput): Promise<{
conversation: Message[];
toolCalls: number;
errors: number;
isFinished: boolean;
finalResult: string;
}>Parameters (StepInput)
| Parameter | Type | Required | Description |
|---|---|---|---|
provider | LLMProvider | ✅ | Your LangChain-compatible provider |
config | AgentConfig | ✅ | Model name, temperature, provider ref |
tools | Tool[] | ✅ | Tools the provider can call (pass [] if none) |
conversation | Message[] | ✅ | Full current conversation history |
Return Value
| Field | Type | Description |
|---|---|---|
conversation | Message[] | Updated conversation after this step |
toolCalls | number | How many tool calls happened in this step |
errors | number | 1 if the step threw an error, else 0 |
isFinished | boolean | true when agent has a final text answer |
finalResult | string | The agent’s final answer (empty if not finished) |
Example — Custom Loop with Step Inspection
import { executeStep } from "llm-layer-engine";
import type { LLMProvider, Message, Tool, AgentConfig } from "llm-layer-engine";
const config: AgentConfig = {
provider: myProvider,
model: "claude-3-5-sonnet-20241022",
temperature: 0.6,
};
let conversation: Message[] = [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Search for the latest Node.js version." },
];
const tools: Tool[] = [searchTool];
let stepCount = 0;
const maxSteps = 6;
while (stepCount < maxSteps) {
const step = await executeStep({
provider: myProvider,
config,
tools,
conversation,
});
// Inspect mid-loop
console.log(`Step ${stepCount + 1} — toolCalls: ${step.toolCalls}`);
conversation = step.conversation;
stepCount++;
if (step.isFinished) {
console.log("Final Answer:", step.finalResult);
break;
}
}Conclusion
executeStep is the atomic unit of the ReAct loop. For most use-cases, let reActLoop manage it. Reach for executeStep directly only when you need fine-grained control over loop behavior — custom pause logic, per-step logging, or conditional early exits.