State Persistence
By the Syncfusion DevTutorials team · Last updated
How an agent saves its progress so it survives a crash: serialization, snapshots, recovery points, restoring, integrity checks and drift.
Think about a long video game.
You have been playing for two hours when the power suddenly goes out.
If you never saved your progress, you have to start again from the beginning. If you saved at the last checkpoint, you can continue from there and lose only a small amount of progress.
Now imagine that someone else used your save file and spent all your coins while you were away.
If the game loads that save without checking it, your notes might say "500 coins" while the game actually has 0. You would make plans based on information that is no longer true.
A well-designed game saves progress regularly and validates saved data before trusting it.
An agent needs the same two habits.
The main idea: State persistence means saving an agent's progress so it can recover after a crash. A good saved state is easy to restore, stored regularly, and validated before it is used.
A Real-World Example
The Brightgrid agent has already run the tests, read web/format.js, and written a fix. Then the browser tab crashes.
The fix is safe because it has already been written to the file. However, the agent's memory is gone. Its memory contained information such as which test failed, what files it read, and what changes it made.
Without a saved state, the agent must start again from the beginning. With a saved state, it can reload its previous steps, verify that the project still matches what it expects, and continue directly with "run the tests again".
In simple words: Save progress regularly and verify it before trusting it.
What You Will Learn
In this lesson, you will learn:
- How to convert an agent's state into text and back again through serialization.
- What a snapshot is and when it should be created.
- What recovery points are and why they matter.
- How to restore an agent from a saved snapshot.
- How an integrity check detects a corrupted or outdated save.
- How to handle drift when the world changes while the agent is not running.
The Agent Lab includes three crash scenarios. In each one, the process stops after step 3. Compare what happens with no save, with a valid save, and with an outdated save. The Memory tab shows the size and fingerprint of each snapshot.
Save after every step. After a crash, validate the snapshot against the current files. Restore it if it matches. Reject it and start fresh if it does not.
State Saving
State Serialization
Serialization converts data in memory into text so it can be stored or transferred. Deserialization converts that text back into data. In JavaScript, JSON.stringify performs serialization and JSON.parse performs deserialization.
Be careful because not every data type survives serialization correctly. A Set or a Map becomes an empty object {}. Plain objects, arrays, strings, numbers, and boolean values are safe to serialize.
What survives JSON and what doesn't
const state = {
goal: "Make every test pass",
steps: [{ n: 1, tool: "run_tests" }],
readFiles: new Set(["web/format.js"]),
};
const text = JSON.stringify(state);
const back = JSON.parse(text);
console.log(text);
console.log("steps kept: " + back.steps.length);
console.log("readFiles kept: " + JSON.stringify(back.readFiles));
Expected output:
{"goal":"Make every test pass","steps":[{"n":1,"tool":"run_tests"}],"readFiles":{}}
steps kept: 1
readFiles kept: {}
The Set becomes empty when it is restored. The agent would lose track of which files it has already read. Instead, store it as an array using [...readFiles].
Snapshot Creation
A snapshot is a saved copy of the agent's state at a specific point in time. A good snapshot contains:
- a version number, so older saves can be identified
- the goal
- the step number when the snapshot was created
- the steps completed so far (the agent's memory)
- a hash of the project files
A hash is a short fingerprint of some text. If even a single character changes, the fingerprint changes as well. You will use this fingerprint later during the integrity check.
A tiny hash: one character changes everything
function hash(text) {
let h = 5381;
for (let i = 0; i < text.length; i++) h = ((h * 33) ^ text.charCodeAt(i)) >>> 0;
return h.toString(16);
}
console.log(hash('return n + " rows";'));
console.log(hash('return n + " rows";'));
console.log(hash('return n + " row";'));
Expected output:
b4d6ac48
b4d6ac48
bfa9707b
The same text always produces the same hash. Removing even one letter creates a completely different hash.
Recovery Points
A recovery point is a moment that the agent can safely return to after a failure. The Agent Lab creates a snapshot after every step. If a crash happens, the agent loses at most one step of work.
Saving more often adds a small amount of overhead. Saving less often increases the amount of work that could be lost after a crash.
How much work does a crash lose?
function lostSteps(saveEvery, crashAfter) {
const lastSave = Math.floor(crashAfter / saveEvery) * saveEvery;
return crashAfter - lastSave;
}
for (const every of [1, 3, 5]) console.log("save every " + every + " steps, crash after step 7: lose " + lostSteps(every, 7));
Expected output:
save every 1 steps, crash after step 7: lose 0
save every 3 steps, crash after step 7: lose 1
save every 5 steps, crash after step 7: lose 2
Saving after every step means the most recently completed step is always safe.
A Crash with No Snapshot
The agent writes the fix at step 3, and then the process crashes.
Because nothing was saved, the run ends with an error. The fix still exists in the file, but there is no record showing whether the fix was checked.
State Recovery
State Restoration
State restoration means loading a snapshot back into memory. After restoring the snapshot, the agent continues from the next step as if the interruption never happened.
Integrity Checks
An integrity check asks a simple question: can this snapshot be trusted?
It checks three things:
- Can the snapshot be read? (Is it valid JSON?)
- Is it a version the agent understands? (The version number.)
- Does it still match the current state of the world? (Does the file hash still match the current files?)
Check a snapshot before trusting it
function hash(text) {
let h = 5381;
for (let i = 0; i < text.length; i++) h = ((h * 33) ^ text.charCodeAt(i)) >>> 0;
return h.toString(16);
}
function check(snapText, filesNow) {
let snap;
try { snap = JSON.parse(snapText); } catch { return "REJECT: not valid JSON"; }
if (snap.version !== 1) return "REJECT: unknown version " + snap.version;
if (snap.hash !== hash(filesNow)) return "REJECT: files changed since the save";
return "OK: restore from step " + snap.step;
}
const files = 'return n.toLocaleString("en-US") + " rows";';
const good = JSON.stringify({ version: 1, step: 3, hash: hash(files) });
console.log(check(good, files));
console.log(check(good, "// Reviewed by Sam.\n" + files));
console.log(check('{"version":1,"step":3', files));
console.log(check(JSON.stringify({ version: 2, step: 3 }), files));
Expected output:
OK: restore from step 3
REJECT: files changed since the save
REJECT: not valid JSON
REJECT: unknown version 2
The second file gained only a comment, but that is enough to change the hash. The snapshot no longer matches the current state of the files.
Crash, restore the snapshot, carry on
After the crash at step 4, the snapshot passes the integrity check. The agent knows it already wrote the fix, so step 5 runs the tests and step 6 finishes. It completes the task in 6 steps instead of starting over from the beginning.
Drift Handling
Drift means the world changed while the agent was not running. A teammate may have edited a file, a branch may have been merged, or a new test may have been added.
When drift is detected, the agent has two safe options:
- Reject the snapshot and take a fresh look. Run the tests again and reread the files. This is the safest option.
- Re-check only the changed parts. Keep the snapshot, but reread every file whose hash changed. This is faster, but it requires a separate hash for each file.
The unsafe option is to load the old snapshot and continue as if nothing changed.
The Files Changed: Reject the Snapshot
While the process was down, a teammate added a comment to web/format.js. The hash no longer matches, so the snapshot is rejected. The agent clears its saved memory and starts with a fresh test run.
The tests now pass because the fix from step 3 is still present in the file. The agent finishes in 6 steps without trusting outdated state information.
Find exactly which files drifted
function hash(text) {
let h = 5381;
for (let i = 0; i < text.length; i++) h = ((h * 33) ^ text.charCodeAt(i)) >>> 0;
return h.toString(16);
}
const saved = { "web/format.js": hash("A"), "web/ticket.html": hash("B"), "api/limits.js": hash("C") };
const now = { "web/format.js": "A2", "web/ticket.html": "B", "api/limits.js": "C" };
const drifted = Object.keys(now).filter((path) => hash(now[path]) !== saved[path]);
console.log("re-read: " + drifted.join(", "));
console.log("still trusted: " + Object.keys(now).filter((p) => !drifted.includes(p)).join(", "));
Expected output:
re-read: web/format.js
still trusted: web/ticket.html, api/limits.js
A hash for each file tells the agent exactly which files need to be checked again. Everything else in the snapshot can still be trusted.
Easy Way to Remember: save often, check before you load. A save that has not been checked is only a guess about the past.
Never restore a snapshot without an integrity check. An agent using out-of-date notes can overwrite a teammate's work.
Common Mistakes
| Mistake | Wrong Idea | Correct Idea | What Goes Wrong |
|---|---|---|---|
| No saves | "Crashes are rare." | Save after every step. | A single crash loses the entire task. |
| Sets in JSON | "JSON saves everything." | Convert a Set to an array before saving. | Important state silently disappears after restoration. |
| No version number | "The format will never change." | Include a version in every snapshot. | An old snapshot may be restored incorrectly. |
| No integrity check | "The save is ours, so it must be safe." | Verify the hash before restoring. | The agent works from outdated information. |
| Ignoring drift | "Nobody changed the files." | Compare file hashes after restarting. | The agent overwrites a teammate's changes. |
Exercises
Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.
What to Remember
- Save often, check before you load.
- Serialize using plain data types. A
SetorMapshould be converted to an array before saving. - A good snapshot includes a version number, the goal, the current step, the recorded steps, and a file hash.
- An integrity check catches invalid data, unsupported versions, and drift between the snapshot and the current files.
- When drift is detected, either reject the snapshot or re-read the files that changed before continuing.
Next: Errors and Fallbacks, how an agent notices a fault, recovers, and never leaves you with nothing.