The agent hype is still on the rise but the quality and efficiency of agentic systems are far from production-ready. As people scramble to come up with agentic system architectures, I saw Humanlayer dropping this tongue-in-cheek principle:
Factor 12 - Make your agent a stateless reducer!
If we [...] accept that "an AI Agent is basically a for loop", then what's the lispy version of this? And AI agent is a foldL where the accumulator is a context window, and the reducer is an LLM DetermineNextStep + a switch statement on how to handle it.
As a functional programming lover, I'm drooling over that diagram:
+---------+ +-----------+ +-----+ +-----+ +-------------------+
| Context | --> | Determine | --> | |-->| | --> | whatever you want |
+---------+ | Next | +-----+ +-----+ +-------------------+
^ | Step | +-----+ +-----+ |
| +-----------+ | |-->| | |
| +-----+ +-----+ |
| +-----+ +-----+ |
| | |-->| | |
| +-----+ +-----+ |
| Handle Next Step |
| |
+-----------------------------------------------------------+
Does this look familiar to you as a frontend developer? It should. This is essentially the Flux pattern that many popular frontend frameworks are based on. It is a really good "divide and conquer" strategy that modularizes state management into pure functional components and compose them in a conflict-free manner. Not surprisingly, we can model most Human-Computer interactions as a React render loop:
+---------+ +-----------+ +-----+ +-----+ +---------------------+
| UI | --> | Next | --> | |-->| | --> | whatever user wants |
+---------+ | Human | +-----+ +-----+ +---------------------+
^ | Action | +-----+ +-----+ |
| +-----------+ | |-->| | |
| +-----+ +-----+ |
| +-----+ +-----+ |
| | |-->| | |
| +-----+ +-----+ |
| Effects and callbacks |
| |
+-----------------------------------------------------------+
But can we take it a step further? React is good at managing the state of this human-initiated interaction loop. What if we use an agent to interpret the user's goal and perform the most relevant actions that a real human would perform? Can we keep using React as the state management layer for the rest of the system?
Let's start with a classic counter app:
function MyApp() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount((c) => c + 1), []);
const decrement = useCallback(() => setCount((c) => c - 1), []);
return (
<div>
<div>Count: {count}</div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
To agentify it, let's replace useState
with useAgentState
, useCallback
with useAgentTool
. Then call agent.run
with the intention of the user.
function MyAgent() {
const agent = useAgent({ apiKey });
const [person, setPerson] = useAgentState("Person", { name: "John", age: 24 });
useAgentTool(
`Update the person's age to be older or younger`,
z.number().describe("the delta of age, positive to grow older, negative to grow younger"),
(update) => setPerson((prev) => ({ ...prev, age: prev.age + update.delta }))
);
const growMuchYounger = agent.run("Grow much younger");
const growYounger = agent.run("Grow younger");
const growOlder = agent.run("Grow older");
const growMuchOlder = agent.run("Grow much older");
return (
<div>
<div>
{userProfile.name} is currently {userProfile.age} years old
</div>
<button onClick={growMuchYounger}>Grow much younger</button>
<button onClick={growYounger}>Grow younger</button>
<button onClick={growOlder}>Grow older</button>
<button onClick={growMuchOlder}>Grow much older</button>
</div>
);
}
You can BYO OpenAI API key to try this live.
I think this is a powerful idea for engineers, designers, and product managers.
Technical merits
- You can compose an entire application with declarative states and tools just as you would do in a well-architected React app.
- Developers fully control the implementation of tool use. Correctness and efficiency are in your hands.
- Agents are only used as tool choosers and parameter fillers. This means much faster response and less room for hallucination.
- Agent actions affect UI immediately and deterministically, using the well-understood
UI = f(State)
rendering model.
HCI merits
- The human user is steering the agent by just clicking and navigating around, because those actions cause the agent state and tool availability to change.
- As state and tool availability change, the agent's context window is automatically aligned with the most relevant task based on the UI.
- Both the human user and the agent share the entire UI state and tools to interact with it. The I/O is much richer than the prevailing prompt-driven approach.
- Good UI Information Architecture automatically becomes good Agent Cognitive Architecture. Many UX laws translate well into AI Psychology.
Business merits
- In-place enhancement for existing React applications. It's not a rewrite. It's incremental agentification.
- A good React developer automatically becomes a good Agent developer, maximizing skill transfer.
- It paves a smooth path for UI to disappear. You can imagine at some point in the future, we set
display: none
on the entire UI and what's left is a fully functional agent. Ultimately, the React app could become a stateful MCP server.
If you want to build your own agentic app with React, I've implemented the ideas in this post into the react-agent-hooks library. I hope that would give you a head start. I look forward to seeing what you build with it.
*Footnote: The title is word play on ReAct and Attention is All You Need. It's almost poetic that ReAct and React are finally meeting each other here.