In the previous chapter, Interactive CLI & State Management, we built the dashboard (the body) of our application. We created a way to see what the agent is doing.
Now, we need to build the Brain.
Most simple programs follow a straight line: Step A -> Step B -> Step C. But an AI Agent is different. It doesn't know the steps ahead of time. It has to figure them out as it goes.
This chapter explains the Recursive Agent Loopβthe core engine that allows Dexter to "think," act, observe the results, and think again.
Imagine a detective trying to solve a mystery.
Dexter works like the Good Detective. We don't hard-code steps; we give Dexter a Loop.
The "Brain" of Dexter is implemented in src/agent/agent.ts. It doesn't just run once; it runs in a cycle called ReAct (Reason + Act).
Let's look at how this loop solves a simple financial question.
User Query: "What is the stock price of Apple?"
financial_search("AAPL price")."{ ticker: 'AAPL', price: 150.00 }".
Let's look at the code in src/agent/agent.ts. We will simplify it to focus on the logic.
The core logic lives in the run() method of the Agent class.
1. The Setup We start a loop that will run until we have an answer or we hit a limit (so we don't loop forever).
// src/agent/agent.ts
async *run(query: string) {
// We keep track of the conversation context
const ctx = createRunContext(query);
// We build the very first prompt for the AI
let currentPrompt = this.buildInitialPrompt(query);
// THE LOOP starts here
while (ctx.iteration < this.maxIterations) {
ctx.iteration++;
// ... logic continues below ...
}
}
Explanation: ctx holds our variables. maxIterations is usually set to 10 to prevent infinite loops if the agent gets confused.
2. Asking the Brain Inside the loop, we send the current situation to the AI model.
// Inside the while loop...
// 1. Ask the AI what to do
const { response } = await this.callModel(currentPrompt);
// 2. Check if the AI wants to use a tool
if (!hasToolCalls(response)) {
// If NO tools are called, we are done!
yield* this.generateFinalAnswer(ctx);
return;
}
Explanation: callModel sends the text to the LLM. If the LLM returns text (e.g., "Hi there"), hasToolCalls is false, and we exit the loop.
3. Executing Tools If the AI does want to use a tool, we execute it and stay in the loop.
// Inside the while loop (continued)...
// 3. The AI wants to use a tool. Let's run it.
// This executes the function (e.g., searching the web)
yield* this.toolExecutor.executeAll(response, ctx);
// 4. Update the Prompt
// We take the tool results and add them to the prompt for the next turn
currentPrompt = buildIterationPrompt(
query,
ctx.scratchpad.getToolResults() // The "Evidence"
);
// The loop now repeats with the new evidence!
Explanation: This is the recursive part. We take the result of the tool, stick it into currentPrompt, and go back to the top of the while loop. Next time we call callModel, the AI will "see" the tool's result.
You might wonder: How does the agent know what it did in the previous step?
It's all in the Prompt.
In src/agent/prompts.ts, we have a function buildIterationPrompt. Every time the loop runs, we reconstruct the prompt to look like this:
Iteration 1 Prompt:
User Query: "Apple Stock Price"
Iteration 2 Prompt:
User Query: "Apple Stock Price"
>
Data retrieved from tool calls:
Tool: financial_search
Result: {"price": 150}
When the AI sees the Iteration 2 prompt, it knows it has the data, so it stops asking for tools and gives the answer.
In this chapter, we built the engine that powers Dexter:
while loop that allows the agent to try multiple times to solve a problem.hasToolCalls to see if we need to work (run a tool) or talk (answer the user).However, a detective is only as good as their gadgets. Right now, our agent knows how to call tools, but it doesn't have any specific skills yet.
In the next chapter, we will give Dexter specialized abilities.
Next Chapter: Skills System
Generated by Code IQ