The Five Patches That Turn a Chatbot Into an Agent
The difference between a chatbot and an agent is not model size—it is whether the model has tools, memory, and retrieval. Products like Claude Code and Cursor prove that wiring these five modules to a capable LLM produces a system that can execute multi-step work unattended, and the message-loop architecture with Promise.all concurrency is the difference between a demo and something that ships.
LLMs ship with five inherent defects: they are stateless, cannot execute actions, lack private knowledge, have a knowledge cutoff, and cannot orchestrate long tasks. An Agent fixes each one with a corresponding module—Memory, Tool use, RAG, MCP, and Skills—transforming a model that can only chat into one that can remember, act, retrieve, and plan. The formula is MECE: every gap gets exactly one patch, and together they cover the full distance from suggestion to execution.
The core mechanism is a relay-style message loop where the LLM itself acts as the dispatch center. When it decides a tool is needed, it stops generating text and emits a tool_calls list; the runtime executes the function and returns a ToolMessage keyed by tool_call_id. That ID is load-bearing—without it, an agent running multiple async tools cannot match results to requests, and the context collapses. A dependency analysis layer that groups independent tool calls into Promise.all turns a working agent into a fast one.
Claude Code validates the formula in production: it is simply LLM + fs + CLI, with the tool mechanism pushed to its limit. The tech stack to build your own—Node.js, NestJS, LangChain, LangGraph, and MCP/RAG/Skills—is mature and layered cleanly between traditional backend concerns and AI orchestration.
The claim that the five defects are MECE is a strong architectural assertion: it implies the formula is both necessary and sufficient, and any agent that works must implement all five modules in some form.
Making the LLM the dispatch center rather than a hard-coded router is a double-edged bet—it keeps the architecture simple but makes the system's reliability hostage to prompt and description quality, which are inherently brittle.
The tool_call_id mechanism is underappreciated. Most agent failures under concurrent tool calls trace back to ID mismanagement, not model intelligence.
Promise.all as a performance optimization is obvious in isolation, but the article's call for a dependency-analysis layer inside the tool-execution loop is a concrete engineering step most toy agents skip.