What is ReAct?
First, we’re not talking about the ui library React.js - today we are learning about the ReAct agent pattern.
ReAct is really just a while() loop - it’s a looping structure where the model alternates between Reasoning, Acting, and observing. The way I think about it is that the model is iteratively thinking about the task, calling a tool, and ingesting the tool call results in order to build a high quality output. This pattern enables an agent to continually refine its plan as tools provide more context.
How can I build agents using the ReAct pattern?
Here’s a quick example that uses hashbrown (with Angular) to implement the react pattern using an agent.
First, let’s create a small TaskService
@Injectable({ providedIn: 'root' })
export class TaskService {
private readonly _tasks = signal<string[]>([
'Write ReAct blog post',
'Ship hashbrown v0.4',
]);
readonly tasks = computed(() => this._tasks());
addTask(title: string) {
this._tasks.update((tasks) => [...tasks, title]);
}
}Now, let’s build some tools to list and add tasks using my TaskService
import { inject } from '@angular/core';
import { createTool } from '@hashbrownai/angular';
import { s } from '@hashbrownai/core';
import { TaskService } from './task.service';
export const listTasks = createTool({
name: 'listTasks',
description: 'List the current user tasks',
handler: () => {
const tasks = inject(TaskService).tasks();
return { tasks };
},
});
export const addTaskTool = createTool({
name: 'addTask',
description: 'Add a new task to the user list',
schema: s.object('Add task input', {
title: s.string('Short description of the task to add'),
}),
handler: ({ title }) => {
inject(TaskService).addTask(title);
return { success: true };
},
});Next, let’s build our chat agent:
import { Component, signal } from '@angular/core';
import { chatResource } from '@hashbrownai/angular';
import { listTasks, addTaskTool } from './task.tools';
@Component({
selector: 'app-agent-chat',
imports: [Field],
template: `
<section class="chat">
<h2>Task Agent (ReAct)</h2>
<form (submit)="onSubmit($event)" class="chat-input">
<label>
<span>Ask the agent</span>
<input
type="text"
[field]="chatInputForm.message"
placeholder="Ask for help planning or updating your tasks"
/>
</label>
<button type="submit" [disabled]="!chatInputForm().valid()">
Send
</button>
</form>
<div class="messages">
@for (message of chat.value(); track $index) {
<p [class.user]="message.role === 'user'">
{{ message.content }}
</p>
}
</div>
</section>
`,
})
export class AgentChatComponent {
chatInputModel = signal({
message: '',
});
chatInputForm = form(this.chatInputModel);
chat = chatResource({
model: 'gpt-5',
debugName: 'task-react-agent',
tools: [listTasks, addTaskTool],
system: `
You are a task-planning assistant that follows a Reason–Act–Observe loop.
REASON:
- Think step-by-step about what the user wants.
- Write your reasoning as short, clear natural language.
ACT:
- When you need data or should modify tasks, call a tool:
- listTasks: to inspect current tasks.
- addTask: to add a new task the user will see.
OBSERVE:
- After each tool call, look at the result and reconsider your plan before deciding what to do next.
Continue looping Reason, Act, and Observe until you can give a concise, helpful final answer to the user.
`,
});
onSubmit(event: Event) {
event.preventDefault();
const f = this.chatInputForm();
if (!f.valid()) return;
const message = f.message().value.trim();
if (!message) return;
this.chat.sendMessage({ role: 'user', content: message });
this.chatInputModel.set({ message: '' });
}
}Let’s review the code above.
First, I’m using Angular’s experimental signal forms. Ohhh nice.
We then define a new
chatResource()that connects to the gippity 5 model and exposes two strongly typed tools:listTasks()andaddTask().The system message provides the instructions to the model to use the ReAct pattern.
Hashbrown loops over each tool call and send the results to the model.
Finally, the resource
value()signal is updated as the model streams the text result into the template.
Tell me a funny joke about React and ReAct
React and ReAct are pair-programming.
React says, “I render components.”
ReAct says, “I render decisions.”
React sighs. “Can you just pick a button color?”
ReAct pauses, reasons for eight steps, calls a tool, observes the result, and finally says:
“I’ve concluded the real button was the friends we made along the way.”
(and, yes, I asked gippity to write this one for me)
Bites
The engineering team at Anthropic wrote about the cost reductions and performance improvements of using code execution with MCP.
Today is the OpenRAG summit (by the langflow folks).
Angular version 21 drops next week. Cheers!
Want to learn more about ReAct? Check out this free tutorial on how to build agents from scratch.
