Working Memory
By the Syncfusion DevTutorials team · Last updated
How an agent keeps track of what it knows during a task: a scratchpad, facts versus assumptions, updates, compression, sliding windows with pinned facts, and memory budgets.
Think about a detective working on a case.
The detective carries a small notebook. At the top is the main question: who took the painting?
Below that are the clues collected so far, the facts that are confirmed, the ideas that still need checking, and the actions already taken.
The detective does not write down every word from every witness. That would fill many notebooks and bury the important clues. Instead, they keep only what matters, remove information that proved wrong, and keep the notebook small enough to review quickly.
An agent needs the same kind of notebook.
The main idea: Working memory is what the agent keeps in mind during a task. Good working memory keeps important information, removes unnecessary details, and stays small enough to fit within the model's limits.
A Real-World Example
The Brightgrid agent is fixing the row count text. After seven steps, its complete history contains:
- Two full test results, including every PASS and FAIL line.
- The full contents of
web/format.js. - Two file updates, each containing the entire file.
- Every thought generated along the way.
The model has to read all of that again at every step. In Lesson 9, you saw how the input grows with each iteration.
To decide the next action, however, the agent needs only a small part of that information. It needs the goal and the rules. It needs the latest test failures, the latest version of the file, and a record of the changes it has already made.
In simple words: Remember what is needed for the next decision, not everything that has ever happened.
What You Will Learn
In this lesson, you will learn:
- What a scratchpad is and what information belongs in it.
- The difference between facts, assumptions, observations, and decisions.
- How to keep memory relevant as the task changes.
- How to summarize, prune, and compress older steps.
- How sliding windows and state summaries work.
- How to fit memory within a token budget by priority.
The Agent Lab includes a new Memory tab. It shows the agent's scratchpad after any step, the information the brain will see next, and how many tokens the input uses. Try the three scenarios for this lesson, then open the Memory tab.
Three ways to remember. Full history keeps everything. A small window forgets important evidence. A window plus pinned facts stays small while keeping what matters.
Scratchpad
A scratchpad is a short, structured note that the agent keeps updated throughout a task. It uses fixed sections so the agent, and anyone reviewing it, always knows where to find information.
Goal Tracking
The goal stays at the top of the scratchpad and never changes during the run. Every decision is checked against it: does this step move the agent closer to the goal?
Evidence Collection
Evidence is information the agent has seen that supports a conclusion. For a bug fix, the strongest evidence is usually the latest failing test message, such as expected "80,000 rows", got "80000 row".
Constraint Management
Constraints are rules the agent must follow, such as:
- "Change only files in
web/." - "Never change a test file."
- "Stay under 2,000 tokens."
These rules come from the configuration you learned about in Lesson 5. They must remain in memory throughout the entire run, even if older history is removed.
A scratchpad with fixed sections
const pad = {
goal: "Make every test pass",
constraints: ["Change only files in web/"],
evidence: [],
decisions: [],
};
pad.evidence.push('FAIL formats a big number: expected "80,000 rows", got "80000 row"');
pad.decisions.push("Step 3: add commas in web/format.js");
for (const [section, value] of Object.entries(pad)) {
console.log(section + ": " + (Array.isArray(value) ? value.join(" | ") : value));
}
Expected output:
goal: Make every test pass
constraints: Change only files in web/
evidence: FAIL formats a big number: expected "80,000 rows", got "80000 row"
decisions: Step 3: add commas in web/format.js
Knowledge Management
Not everything in the agent's memory should be treated the same way. Keeping different kinds of information separate prevents the agent from treating a guess as a confirmed fact.
Fact Tracking
A fact is something the agent has verified. For example, "web/format.js has 4 lines" is a fact because the agent actually read the file and confirmed it.
Assumption Handling
An assumption is something the agent believes might be true but has not yet proven. For example, "The bug is in web/format.js because the failing test points there" is an assumption.
It becomes a fact only after the agent verifies it. If the tests pass after changing that file, the assumption was correct. If they do not, the assumption was wrong and should be removed from the notes.
Observation Storage
An observation is a raw result returned by a tool, as you learned in Lesson 9.
Observations are the source of facts and evidence. They are also usually the largest part of memory, so they are often the first thing that gets summarized or shortened when memory needs to be reduced.
Decision Recording
A decision records what the agent chose to do and why it chose to do it.
Recording decisions helps prevent the agent from repeating the same change multiple times. It also allows a person reviewing the run to understand the reasoning behind each action.
An assumption becomes confirmed, or stays unproven
const assumptions = [
{ text: "The bug is in web/format.js", file: "web/format.js", status: "unproven" },
{ text: "The bug is in api/limits.js", file: "api/limits.js", status: "unproven" },
];
const changed = "web/format.js";
const testsPassAfter = true;
for (const a of assumptions) {
if (a.file === changed) a.status = testsPassAfter ? "confirmed" : "wrong";
}
for (const a of assumptions) console.log(a.status.padEnd(9) + " " + a.text);
Expected output:
confirmed The bug is in web/format.js
unproven The bug is in api/limits.js
The Scratchpad Across a Run
Run it with Step by step and keep the Memory tab open. After step 1, the evidence contains two FAIL lines. After step 3, a decision is added.
After step 4, the evidence changes: the comma issue is fixed, but "row" is still incorrect. At the end of the run, the assumption is marked as confirmed.
Context Updates
Information Updates
An update replaces an older note with a newer one. When the tests run again, the latest result replaces the previous evidence. Keeping both would leave the agent with two conflicting results.
Relevance Assessment
Relevance asks: does this note still help with the next decision?
The first test result is no longer relevant once a newer result exists. The contents of a file are no longer relevant once the agent has rewritten that file.
Memory Optimization
Summarization
Summarization replaces many details with a short summary. Seven steps might become: "Commas fixed at step 3. Plural fixed at step 5. All tests pass."
Pruning
Pruning means removing notes that are no longer relevant, such as old test results or thoughts from many steps ago.
Compression
Compression keeps information but makes it smaller. A test result with 20 lines can be reduced to a summary line plus the FAIL lines. The PASS lines rarely help with the next decision.
Compress a test result
const result = [
"1 passed, 2 failed",
"PASS free plan limit",
'FAIL formats a big number with commas: expected "80,000 rows", got "80,000 row"',
'FAIL formats a small number: expected "12 rows", got "12 row"',
].join("\n");
function compress(text) {
const lines = text.split("\n");
return [lines[0], ...lines.slice(1).filter((l) => l.startsWith("FAIL"))].join("\n");
}
const tokens = (t) => Math.ceil(t.length / 4);
console.log("before: " + tokens(result) + " tokens");
console.log("after: " + tokens(compress(result)) + " tokens");
console.log(compress(result).split("\n").length + " lines kept");
Expected output:
before: 46 tokens
after: 40 tokens
3 lines kept
Here only one PASS line was dropped. In a real project with 200 passing tests, compression removes 200 lines and keeps only the few lines that matter.
Context Windows
Sliding Windows
A sliding window keeps only the most recent steps. When a new step is added, the oldest step falls out of the window. This keeps the input size the same no matter how long the run becomes.
A sliding window of 2 steps
const steps = ["run_tests: 1 failed", "read_file web/format.js", "write_file web/format.js", "run_tests: 0 failed"];
const keep = 2;
steps.forEach((_, i) => {
const seen = steps.slice(0, i + 1).slice(-keep);
console.log("after step " + (i + 1) + ": " + seen.join(" | "));
});
Expected output:
after step 1: run_tests: 1 failed
after step 2: run_tests: 1 failed | read_file web/format.js
after step 3: read_file web/format.js | write_file web/format.js
after step 4: write_file web/format.js | run_tests: 0 failed
After step 3, the first test result is gone. The window stays the same size, but it removes whatever is oldest.
The danger is that a sliding window does not know what is important. It removes the oldest step even when that step contains the only test result.
Sliding Window of 1 Step
The window keeps only the most recent step. At step 2, the agent reads the file. At step 3, it can see only the file contents.
The test result has already fallen out of memory, so the agent runs the tests again. Then it reads the file again. It repeats this cycle until it runs out of steps, and the fix is never written.
State Summaries
A state summary solves this problem. Alongside the sliding window, the application keeps a few pinned items: the latest test result (in compressed form) and the latest version of each file.
Pinned items never fall out of memory. Everything else can.
Window of 1 Step, with Pinned Facts
This uses the same window size of 1, but with pinned facts. The agent finishes in 5 steps, just as it does with full history. It uses 1,677 tokens instead of 1,886 because older steps are removed or compressed.
The saving is small in this example because the run is short. In a 40-step run, full history grows with every step. A sliding window plus pinned facts stays nearly the same size.
Memory Budgeting
Token Budgets
A token budget for memory is the maximum number of tokens the agent may spend on remembered context at each step. It is part of the total run budget you learned about in Lesson 10.
Priority Allocation
Priority allocation decides what information is included when everything cannot fit. Assign a priority to each kind of note. Add notes from the highest priority down and stop when the budget is full.
A good priority order for a coding agent is:
- Goal and constraints (always included)
- Latest evidence (the failing tests)
- Latest text of the files being changed
- Decisions made so far
- The most recent steps
- Everything else
Fill a memory budget by priority
const notes = [
{ what: "goal and rules", priority: 1, tokens: 60 },
{ what: "old test result", priority: 6, tokens: 120 },
{ what: "latest failures", priority: 2, tokens: 40 },
{ what: "file text", priority: 3, tokens: 50 },
{ what: "decisions", priority: 4, tokens: 30 },
{ what: "last 2 steps", priority: 5, tokens: 90 },
];
function fill(budget) {
const kept = [];
let used = 0;
for (const n of [...notes].sort((a, b) => a.priority - b.priority)) {
if (used + n.tokens <= budget) { kept.push(n.what); used += n.tokens; }
}
return used + " tokens: " + kept.join(", ");
}
console.log(fill(200));
console.log(fill(300));
Expected output:
180 tokens: goal and rules, latest failures, file text, decisions
270 tokens: goal and rules, latest failures, file text, decisions, last 2 steps
With a 200-token budget, the agent keeps the four highest-priority notes. With a 300-token budget, the last two steps fit as well. The old test result never makes it into memory, and it should not.
Easy Way to Remember: a good memory is a notebook, not a recording. Keep the goal, the rules, and the latest evidence. Update notes when information changes. Summarize or remove the rest.
Never remove constraints to save tokens. An agent that forgets "change only files in web/" is an agent that can no longer reliably follow that rule.
Common Mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Keep everything | "More context is always better." | Keep only what helps with the next decision. | Tokens and costs grow every step, and important clues get buried. |
| Plain window | "The last few steps are enough." | Pin the latest evidence and file contents. | The agent forgets the test result and loops. |
| Guess as fact | "The bug must be in this file." | Treat it as an assumption until a check confirms it. | The agent keeps changing the wrong file. |
| Two versions of the truth | "Keep both test results." | Replace old evidence with newer evidence. | The agent reads results that contradict each other. |
| Rules removed to fit | "The rules are long, so cut them." | Constraints must always stay in memory. | The agent breaks a rule because it can no longer see it. |
Exercises
Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.
What to Remember
- Working memory is a notebook, not a recording.
- Keep a scratchpad with fixed sections: goal, constraints, evidence, facts, assumptions, and decisions.
- Replace old evidence with newer evidence, and treat guesses as assumptions until they are confirmed.
- Summarize, prune, and compress old information to keep memory useful and manageable.
- A plain sliding window can forget important information. Pin the items that must stay available.
- Fill the memory budget by priority. The goal and constraints always come first.
Next: State Persistence, how an agent saves its progress so it can stop, crash, and carry on later.