System Architecture
By the Syncfusion DevTutorials team · Last updated
The parts inside an agent program: the perception-action cycle, the runtime, inference engine, tool registry and state store, and the input, reasoning, execution and monitoring layers.
Think about a restaurant.
A waiter takes your order and makes sure the request is clear and valid. The chef decides how the food should be prepared.
The kitchen staff use tools such as stoves, ovens, and knives. A manager oversees the restaurant and makes sure everything runs smoothly and on schedule.
Each person has a specific responsibility. Together, they turn a customer's request into a completed meal.
An agent application works in a similar way. It is made up of several parts, and each part has a specific job.
The main idea: An agent works in a loop. A small program manages that loop using four main components: a runtime, an inference engine, a tool registry, and a state store.
A Real-World Example
In Lesson 1, the agent fixed the row count bug. It looked like a single intelligent action, but four different components were working together behind the scenes:
- The runtime managed the loop and tracked the number of steps.
- The inference engine asked the agent's brain to decide the next action.
- The tool registry managed the available tools and executed tools such as
run_testsandread_file. - The state store saved information from each step so the agent could remember what had happened.
When you build your own agent, you create these four components. Every agent framework includes these same concepts, even if different names are used.
In simple words: An agent application is a loop supported by four helpers: one runs the process, one thinks, one performs actions, and one remembers information.
What You Will Learn
In this lesson, you will learn:
- What happens during one complete cycle of the agent loop.
- The four main runtime components and their responsibilities.
- The four layers of an agent: input, reasoning, execution, and monitoring.
- How to build a simple agent runtime using these components.
The Agent Lab at the bottom of this page uses these same components. In this lesson, you will intentionally break some of them to see what happens. You will remove a tool from the registry and provide an empty goal to the input layer. The code examples use plain JavaScript to demonstrate the same concepts.
Perception-Action Cycle
The perception-action cycle describes one complete turn of the agent loop.
Perception means collecting information. Action means performing a task.
In Lesson 1, you learned the loop as look, think, act, and check. The perception-action cycle is the same process viewed from inside the application.
It contains four steps.
Input Processing
Input processing means validating and preparing incoming information before the agent uses it. The input may come from a user or from a tool result.
For example, input processing can:
- Remove extra spaces.
- Reject an empty goal.
- Shorten input that is excessively large.
Allowing invalid input to pass through this step can lead to confusing problems later in the process.
Clean and check the input first
function processInput(text) {
const clean = text.trim();
if (clean === "") return { ok: false, reason: "the goal is empty" };
if (clean.length > 60) return { ok: true, goal: clean.slice(0, 60) + "..." };
return { ok: true, goal: clean };
}
const inputs = [
" Make every test pass ",
"",
"Fix the bug on the ticket page where the row count text is wrong and add a test",
];
for (const text of inputs) {
const result = processInput(text);
console.log(result.ok ? "OK: " + result.goal : "REJECTED: " + result.reason);
}
Expected output:
OK: Make every test pass
REJECTED: the goal is empty
OK: Fix the bug on the ticket page where the row count text is w...
The first goal contains extra spaces, but input processing cleans it before the agent uses it. The empty goal is rejected before anything else runs. The long goal is shortened to a safe length before it reaches the agent.
Now try an empty goal in the Agent Lab.
Input Layer: An Empty Goal
The run stops at step 1 with the message "the goal is empty".
The agent's brain is never called because the problem is detected immediately. This saves processing time and, in real applications, can also reduce cost.
State Updates
A state update is the process of saving the result of each step into the agent's memory.
After each update, the state reflects the current situation.
For example, after run_tests finishes, the state changes from: "Tests have not been run" to "2 tests are failing".
Keeping the state updated helps the agent make decisions using the latest information.
Action Selection
Action selection is the reasoning stage you learned about in Lesson 2. The agent reviews the updated state and chooses the next action that should be performed.
Environment Feedback
Environment feedback is the result returned after an action is completed. This feedback becomes new input for the next cycle of the agent loop.
Because of this, the cycle keeps repeating:
- Feedback creates new input.
- New input leads to a new decision.
- The decision leads to a new action.
The cycle continues until a stopping condition is reached.
Four layers. The input layer validates incoming information. The reasoning layer chooses the next action. The execution layer runs tools. The monitoring layer tracks and observes every step.
Runtime Components
Inside an agent application, four components work together to make the cycle run.
Agent Runtime
The agent runtime is responsible for running and managing the agent loop.
It:
- Starts the agent run.
- Counts and tracks steps.
- Calls the other components in the correct order.
- Stops the loop when the task is complete or a limit is reached.
You can think of the runtime as the restaurant manager. The manager does not cook the food, but they ensure that every task happens in the correct order and at the correct time.
Inference Engine
The inference engine is the component that communicates with the model.
Inference means asking a trained AI model to generate a response.
The inference engine:
- Creates the message sent to the model.
- Sends the request.
- Receives the response.
- Converts the response into the next action.
In the Agent Lab, the scripted brain or the live model operates through this component.
Tool Registry
The tool registry is the collection of tools that the agent is allowed to use.
Each tool entry contains:
- A name
- A description
- Required inputs
- The code that performs the action
The tool registry has two important responsibilities:
- It tells the model which tools are available.
- It allows only registered tools to be executed.
A tool registry: register, list and run
function createRegistry() {
const tools = {};
return {
register(name, description, run) {
tools[name] = { description, run };
},
list() {
return Object.keys(tools);
},
call(name, input) {
if (!tools[name]) return "ERROR: no tool named " + name;
return tools[name].run(input);
},
};
}
const registry = createRegistry();
registry.register("read_file", "Read one file", (path) => "text of " + path);
registry.register("run_tests", "Run every test", () => "3 passed, 0 failed");
console.log("Tools: " + registry.list().join(", "));
console.log(registry.call("run_tests"));
console.log(registry.call("delete_file", "web/format.js"));
Expected output:
Tools: read_file, run_tests
3 passed, 0 failed
ERROR: no tool named delete_file
The registry runs run_tests because it is registered. It refuses delete_file because nobody registered it. The registry acts as a list of allowed tools.
Now see what happens when a tool the agent needs is missing from the registry.
A Registry Without run_tests
The agent asks to use run_tests, but the registry reports that the tool does not exist.
A well-designed agent stops and explains what it needs. It does not guess a solution when it cannot verify the result. Open the Tools tab to see the smaller registry.
State Store
The state store is where the agent keeps its memory. It stores the goal, every action taken, and every result returned during the run.
The inference engine reads information from the state store when preparing the next request. The runtime writes new information to the state store after every step.
A state store keeps every step
function createStateStore(goal) {
const steps = [];
return {
add(action, result) {
steps.push({ n: steps.length + 1, action, result });
},
last() {
return steps[steps.length - 1];
},
summary() {
return "Goal: " + goal + " | steps: " + steps.length;
},
};
}
const store = createStateStore("Every test passes");
store.add("run_tests", "1 passed, 2 failed");
store.add("read_file", "found the wrong word");
console.log(store.summary());
console.log("Last step: " + store.last().action + " -> " + store.last().result);
Expected output:
Goal: Every test passes | steps: 2
Last step: read_file -> found the wrong word
Easy Way to Remember: The runtime runs the process, the inference engine makes decisions, the tool registry provides access to tools, and the state store keeps track of information. In simple terms: run, think, act, and remember.
Build a Tiny Runtime
Now let's put all four components together.
The example below shows a complete but very small agent runtime. The "brain" uses a few fixed rules instead of AI, so the result is always the same every time you run it.
Four parts, one tiny agent runtime
const world = { text: "80,000 row" };
const registry = {
run_tests: () => (world.text === "80,000 rows" ? "pass" : "fail"),
read_file: () => world.text,
write_file: (text) => { world.text = text; return "saved"; },
};
const store = [];
function infer(history) {
const last = history[history.length - 1];
if (!last) return { tool: "run_tests" };
if (last.result === "pass") return { finish: true };
if (last.tool === "run_tests") return { tool: "read_file" };
if (last.tool === "read_file") return { tool: "write_file", input: last.result + "s" };
return { tool: "run_tests" };
}
for (let step = 1; step <= 6; step++) {
const action = infer(store);
if (action.finish) { console.log("Step " + step + ": finish"); break; }
const result = registry[action.tool](action.input);
store.push({ tool: action.tool, result });
console.log("Step " + step + ": " + action.tool + " -> " + result);
}
Expected output:
Step 1: run_tests -> fail
Step 2: read_file -> 80,000 row
Step 3: write_file -> saved
Step 4: run_tests -> pass
Step 5: finish
Find the four components in the code:
- The runtime is the
forloop. It counts the steps and stops after 6 iterations. - The inference engine is
infer. It reads the history and decides the next action. - The tool registry is the
registryobject. - The state store is the
storelist.
In a real agent, infer is usually replaced with a call to an AI model. The other three components often remain very similar.
Architecture Layers
Another way to understand an agent is through four layers.
A layer is a group of components that share the same responsibility. Each layer communicates only with the layers directly connected to it.
Input Layer
The input layer receives the goal and the results returned by tools. It validates, cleans, and prepares this information before it is used, just like the processInput example shown earlier.
Reasoning Layer
The reasoning layer decides what the agent should do next. It contains the inference engine and reads information from the state store to make decisions.
Execution Layer
The execution layer performs the selected action. It contains the tool registry.
This layer:
- Verifies that the requested tool exists.
- Checks that the inputs are valid.
- Enforces boundaries and access rules, such as allowing changes only within the
web/folder.
Monitoring Layer
The monitoring layer observes everything the agent does.
It records information such as:
- Which tool was used
- Whether the action succeeded or failed
- How long the action took
When an agent behaves unexpectedly, the monitoring log is usually the first place to investigate.
In the Agent Lab, the Trace tab represents the monitoring layer.
A monitoring layer sums up a run
const log = [
{ tool: "run_tests", ok: true },
{ tool: "read_file", ok: true },
{ tool: "write_file", ok: false },
{ tool: "write_file", ok: true },
{ tool: "run_tests", ok: true },
];
const errors = log.filter((entry) => !entry.ok).length;
const used = [...new Set(log.map((entry) => entry.tool))];
console.log("Steps: " + log.length);
console.log("Errors: " + errors);
console.log("Tools used: " + used.join(", "));
Expected output:
Steps: 5
Errors: 1
Tools used: run_tests, read_file, write_file
Three numbers can quickly tell a story. The agent completed 5 steps. One write operation failed, so the agent tried again.
| Layer | Responsibility | Component | Example in Agent Lab |
|---|---|---|---|
| Input | Validate and prepare incoming information | Input checks | An empty goal is rejected |
| Reasoning | Decide the next action | Inference engine, state store | The reasoning shown for each step |
| Execution | Perform actions safely | Tool registry, boundary checks | The Tools tab |
| Monitoring | Track and record activity | Log | The Trace tab |
Run the full agent one more time. Then open the Trace tab. The information shown there is the log created by the monitoring layer.
Watch Every Layer Work
Never skip the monitoring layer. Without logs, it can be difficult to understand why an agent failed. With logs, you can identify the exact step where the problem occurred.
Common Mistakes
| Mistake | Incorrect Understanding | Correct Understanding | What Can Go Wrong |
|---|---|---|---|
| No input validation | "The model can handle any input." | Validate and clean the input before sending it to the model. | Empty, invalid, or poorly formatted goals can waste model calls and create confusing results. |
| Running any tool requested by the model | "If the model asks for a tool, just run it." | Execute only tools that are registered and approved in the tool registry. | The agent may try to use tools that do not exist or tools that should never be allowed. |
| No state store | "The model will remember everything." | Store the results of every step and provide them again when needed. | The agent forgets previous actions and repeats the same work. |
| One large function for everything | "It is easier to put everything in one place." | Keep the runtime, inference engine, tool registry, and state store as separate components. | The system becomes difficult to test, maintain, update, and debug. |
| No monitoring or logging | "It worked before, so it will work again." | Record and monitor every step of the agent's activity. | When something fails, it becomes difficult to find the cause of the problem. |
Exercises
Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.
What to Remember
- One complete cycle of an agent is called the perception-action cycle: input, state update, action, and feedback.
- An agent application is built using four main components: the runtime, inference engine, tool registry, and state store.
- The runtime manages the loop, the inference engine decides what to do next, the tool registry provides access to approved tools, and the state store keeps track of information and results.
- The four architecture layers are input, reasoning, execution, and monitoring.
- Always validate input before sending it to the model, allow only registered tools to run, and record every step using logs.
Next: State Machines, the named states an agent moves through and the rules for moving between them.