Most agent projects hit the same wall. A request arrives that the agent cannot handle, so someone writes a new tool. Then it happens again. The cost of keeping up grows with the number of requests, and requests combine combinatorially, so you never catch up.
The fix is not a better framework. The fix is recognizing that autonomous composition is not one mechanism. It is a stack of composition types plus two layers of glue. A real agent layers all of them and reaches for whichever one the task needs, instead of betting that a single mechanism solves everything.
Four kinds of composition
Sequential. Thought → Action → Observation, where each result decides the next step. This is the ReAct loop, and it is the base layer. It works well for a few steps where semantics drive the path. It works badly at bulk.
Batch and compute. N rows, filtered, joined, aggregated. Do not make the model pick tools one per round. Let it write code that calls the primitives, loop included, and run that code once. Standard tool-calling cannot express a for loop. Code execution can.
Decomposition. Hand a large piece of work to a sub-agent with its own context, and get back a summary. The value is context isolation and narrowed attention. The cost is orchestration and debugging, so do not pay for complexity the task does not have.
Knowledge. Make retrieval a tool that the loop calls when the loop decides it needs one. The retrieval method is itself a sub-choice: plain vector RAG, graph RAG for global or multi-hop questions, or tree navigation for long documents.
ReAct is the base layer. Code execution, sub-agents, and retrieval are all tools hanging off it. Without that “decide, call, observe, decide” loop driving them, they are inert functions lying around.
Two layers of glue
The stack only composes because of two things underneath it.
A unified tool schema. Local tools, MCP endpoints, sub-agents, and code execution all look like the same function-call schema to the model, so the model can mix them freely within one turn. Adding a capability means registering one more schema, and the loop logic does not change.
State and memory. Multi-step composition needs results to carry across steps: a scratchpad within a task, a workspace within a session, and durable memory across sessions.
The discipline is to let no single mechanism swallow everything. ReAct orchestrates, code execution computes, sub-agents decompose, and retrieval fetches. Doing this moves the combinatorial explosion off your maintenance backlog and onto the model’s runtime. Your cost drops from one unit per request to one unit per primitive.