AI Engineering

State, Memory and Resumable Agent Execution

Afzal AhmedFaz Ahmed
·13 September 2026·13 min read
AI AgentsStateMemorySQL ServerCheckpointsASP.NET CoreDurable Execution

Why This Matters

Separate model context, conversation, working state, checkpoints, long-term memory and authoritative business data for reliable agent execution.

The Agentic Leap — Part 4: State, Memory and Agent Execution

“Memory” is one of the most overloaded words in agent development. We can make it manageable by relating it to familiar .NET concepts. An HTTP request model, conversation transcript, SQL row and cache entry all hold information, but we would never treat them as interchangeable.

Store each kind of information according to its authority, lifetime and purpose.
Keep returning to one practical question: if the process stops now, what must be stored so another worker can continue safely?

Agent systems become unreliable when every piece of information is called “memory.” A conversation transcript, an execution checkpoint, a user preference and a project record have different owners, lifetimes and authority. Combining them in one prompt or vector store loses those distinctions.

1. Six concepts that must remain separate

ConceptPurposeAuthorityTypical lifetime
Model contextworking input for one inferenceassembled copyone call
Conversationuser/model interaction historysupporting recordthread
Working stateprogress of this executionorchestration recordrun
Checkpointresumable state snapshotdurable execution recordretention policy
Long-term memoryselected cross-session informationadvisory unless verifiedmultiple threads
Business dataproject facts and decisionsauthoritative system of recorddomain-defined
RAG evidence is another assembled input. It does not become authoritative merely because it is retrieved successfully.

2. Design execution state explicitly

Do not reconstruct important state from prose messages. Use a versioned record:

public sealed record AgentExecutionState(
    Guid ExecutionId,
    int SchemaVersion,
    Guid ProjectId,
    Guid ActingUserId,
    string Objective,
    AgentExecutionStatus Status,
    int CurrentStep,
    decimal CostUsed,
    IReadOnlyList<ObservationRef> Observations,
    PendingAction? PendingAction,
    long Version);

Store large documents and tool outputs separately; keep references, hashes, provenance and safe summaries in state. Otherwise checkpoints become expensive and can duplicate sensitive information.

3. SQL Server as a durable control record

A practical schema can use AgentExecutions, AgentSteps, AgentObservations, AgentApprovals and AgentOutbox. Apply tenant and project boundaries to every query. Use optimistic concurrency so two workers cannot advance the same execution silently.

UPDATE dbo.AgentExecutions
SET Status = @NextStatus,
    CurrentStep = @NextStep,
    StateJson = @StateJson,
    Version = Version + 1,
    UpdatedUtc = SYSUTCDATETIME()
WHERE ExecutionId = @ExecutionId
  AND TenantId = @TenantId
  AND Version = @ExpectedVersion;

Zero updated rows means concurrency conflict, not “try the same write until it succeeds.” Reload and decide whether the pending work is still valid.

4. Checkpoint at meaningful boundaries

Checkpoint after a completed observation, before waiting for approval, and after committing a command result. Avoid a checkpoint halfway through a non-idempotent side effect.

Decide -> authorise -> checkpoint intent -> execute idempotently
       -> record result + outbox -> checkpoint completed step

If the process fails after the external system accepted a command but before the local result was stored, reconcile using the idempotency key. “Run it again and hope” is not recovery.

5. Context is assembled, not accumulated

For each model call, build a context package from the current purpose:

  • stable developer instructions;
  • authenticated scope and permitted capabilities;
  • compact goal and working state;
  • only relevant recent turns;
  • selected evidence with provenance;
  • safe tool observations;
  • remaining budgets and stopping rules.
Use token budgets per section. Summarisation can reduce size, but summaries lose detail and must carry source references. Old messages should not automatically outrank current business data.

6. Conversation history is not business state

If a user says “Plot 18 now has approval,” the transcript records that statement; it does not update the project. The agent must retrieve the authoritative planning status or propose a controlled command.

Similarly, a model statement such as “I created the task” proves nothing. The command result and business audit record are the evidence.

7. Long-term memory needs consent and governance

Cross-session memory may store a user preference such as concise explanations. It should not casually retain health details, credentials, speculative judgements or project facts already owned by the business system.

Every memory class needs:

  • purpose and lawful basis;
  • namespace and tenant isolation;
  • writer and reader policy;
  • provenance and confidence;
  • expiry, correction and deletion;
  • protection against prompt-injected writes.
A useful design makes memory proposals reviewable. Application policy, not the model alone, decides what is retained.

8. Resume safely after interruption

On resume:

  1. Load the checkpoint by tenant and execution ID.
  2. Verify the authenticated user can continue it.
  3. Re-evaluate expired approval and current permissions.
  4. Reconcile any pending external command.
  5. Refresh authoritative data that may have changed.
  6. Continue from a defined state transition.
Never trust a browser-supplied serialized checkpoint. The client may supply an opaque execution ID; the server loads the protected record.

9. Retention and observability

Execution records need retention based on operational and regulatory requirements. Logs are not a substitute for state, and state is not an excuse to log every prompt indefinitely. Redact or tokenize personal data, restrict trace access and record deletion.

Useful metrics include checkpoint size, resume success, stale-approval rejection, concurrency conflicts, memory reads/writes, context tokens by category and the age of evidence used.

10. Testing

Test crash recovery at every boundary: before a tool, after downstream success, during checkpoint write and while awaiting approval. Test two workers, permission revocation, expired evidence, schema migration and deletion requests. Verify that replay does not duplicate side effects.

Extended implementation review

11. Design state around invariants

An execution record should enforce facts that must remain true: one tenant owns the run; a step number never moves backwards; only one pending approval exists for a command; completed runs are immutable; and every observation identifies its source and creation time. Put these rules in application and database constraints rather than hoping the prompt preserves them.

Use optimistic concurrency with a version column. A worker loads version 12, calculates a transition and attempts to save version 13. If another worker has already advanced the run, the write fails and the first worker reloads rather than overwriting progress. Distributed locks can complement this for scarce work, but they should not be the only protection against lost updates.

Separate the execution summary from potentially large observations. Store references and hashes in state while evidence lives in an access-controlled store. This keeps checkpoint writes bounded and avoids copying personal data through every step.

12. Context assembly as a governed query

Context is not the transcript plus everything retrieved. Build it for a specific decision. A context assembler can allocate budgets to system rules, goal, recent state, evidence and tool definitions. It should rank by relevance and authority, remove duplicates and preserve citation identifiers.

Summaries reduce tokens but lose detail. Store the source range, summary version and generating model, and never promote a generated summary above its underlying business record. When a fact can be loaded deterministically, reload it rather than trusting an old conversation message.

Long conversations need compaction policy. Preserve current objective, accepted user constraints, unresolved questions, durable decisions and evidence references. Discard conversational pleasantries and stale tool payloads. Evaluate compaction with tasks that require an early constraint many turns later.

13. Memory write policy

Long-term memory should be opt-in, purposeful and correctable. Define which facts are eligible, who can read them, when they expire and how a user can view or delete them. A model suggestion such as “the user prefers weekly reports” is not a durable preference until policy accepts it and provenance is recorded.

Avoid storing sensitive inferences, temporary moods or facts copied from third-party documents as user memory. Prefer explicit preferences and stable workflow settings. At read time, label memory as advisory and revalidate anything that affects authority, money, safety or access.

Semantic retrieval is useful for recall but is not an authorisation system. Apply tenant and resource filters before similarity ranking. If the vector index cannot enforce those filters reliably, do not place mixed-tenant memories in it.

14. Checkpoint safety and replay

A safe checkpoint records the last committed state, pending operation and idempotency key. Choose boundaries so a node can be replayed without repeating an external consequence. Pure transformations are easy; command nodes need an outbox or downstream deduplication.

Consider a crash after the planning system accepts CreateTask but before the local checkpoint records success. On resume, the orchestrator queries by idempotency key. It either records the known task, retries safely if no task exists or enters reconciliation if the result cannot be established. It must not ask the model to guess.

Schema migrations need the same discipline as business data. Version checkpoint payloads, support upgrading old states and retain fixtures from deployed versions. A new release must either resume an old run correctly or terminate it with an explicit, supportable status.

15. Approval is time-sensitive state

Persist the exact proposal hash, acting user, authorised approver, evidence versions, policy version, expiry and decision. Resume should compare all of them. If access changed, evidence was replaced or the command body differs, invalidate approval and request a new decision.

The browser receives an opaque run ID and a display model, never a trusted checkpoint. Anti-forgery controls, authenticated APIs and resource authorisation protect the review path. Audit rejected and expired approvals as carefully as accepted ones; they reveal where the system asks for inappropriate action.

16. State privacy, retention and deletion

Map every state field to a purpose and retention class. Operational telemetry may need weeks, approval evidence may follow business-record policy, and raw prompts may not need persistence at all. Encrypt sensitive stores, restrict support access and avoid exporting full state to third-party tracing systems.

Deletion is harder when information appears in checkpoints, vector indexes, backups and logs. Maintain identifiers that allow governed deletion and document backup expiry. Where legal or audit requirements prevent erasure, explain the basis and minimise the retained content.

17. Recovery test matrix

Inject failure before and after every durable boundary. Restart workers while a model call is in flight, after a read, during an outbox write and after downstream acceptance. Test duplicate queue delivery, two resume requests, expired approval, permission revocation and a checkpoint created by the previous schema version.

Assertions should cover both outcome and absence of harm: no duplicate task, no cross-tenant evidence, no completed status with an unresolved command, and no resumed run using stale authority. Recovery behaviour is part of the product contract, not merely an infrastructure concern.

18. Worked resume scenario

Suppose a reviewer approves a task proposal at 14:00, a worker crashes at 14:01 and project access is revoked at 14:02. The restarted worker loads the checkpoint, but it must not execute simply because an approval exists. It re-authenticates the acting context, rechecks project policy, compares the proposal digest and verifies evidence freshness. The revoked permission moves the run to a denied or review-required state.

If access remains valid and the downstream API received the command before the crash, the local record may still say Dispatching. The worker queries by idempotency key, finds the created task, stores its identifier and advances to Completed. It does not send a second command. This one scenario connects concurrency, approval freshness, reconciliation and audit.

19. Review questions

  • Can support determine current truth without reading a raw prompt?
  • Can two workers advance a run without losing an update?
  • Can every command be reconciled after a timeout?
  • Does resume repeat policy checks rather than replay old authority?
  • Can a user inspect and correct durable memory?
  • Can retained state be located and deleted according to policy?
  • Can this release resume checkpoints from the previous one?
If an answer is uncertain, a larger context window or vector store will not solve the underlying state problem.

State design should also distinguish freshness from correctness. A recent observation can still be wrong, while an older approved record may remain authoritative. Store both source version and observation time. When context is rebuilt, the assembler can detect changed business versions and invalidate derived assessments. This prevents a resumed run from combining a current permission check with an obsolete recommendation.

Operators need safe inspection tools. Show a redacted timeline of transitions, tool outcomes and evidence references, with controls for retry, cancel and reconcile based on current state. Do not provide a generic “set status” control that bypasses invariants. Administrative recovery is another command surface and deserves authentication, authorisation, idempotency and audit.

Production checklist

  • Model context, conversation, execution state, memory and business data are distinct.
  • State has a schema version and optimistic concurrency.
  • Side effects use idempotency and reconciliation.
  • Context is purpose-built with explicit budgets.
  • Long-term memory has consent, retention and provenance.
  • Resume rechecks identity, policy and freshness.
  • Sensitive prompts and observations are not logged indiscriminately.
  • Crash recovery is tested, not assumed.

20. Continue the series

Our local tools now have clear state and authority. Part 5 examines MCP as an interoperability boundary for discovering tools, resources and prompts without confusing discovery with trust.

A C# execution store, one small step at a time

Expose valid state transitions rather than generic checkpoint updates:

public interface IAgentExecutionStore
{
    Task<AgentExecution> LoadAsync(
        Guid tenantId,
        Guid executionId,
        CancellationToken cancellationToken);

    Task<bool> TryAdvanceAsync(
        AgentExecution current,
        AgentTransition transition,
        CancellationToken cancellationToken);
}

TryAdvanceAsync uses an EF Core concurrency token. If two workers load version 12, only one commits version 13. The other reloads rather than overwriting progress.

public sealed class AgentExecutionRow
{
    public Guid Id { get; init; }
    public Guid TenantId { get; init; }
    public string Status { get; set; } = "Created";
    public string StateJson { get; set; } = "{}";

    [Timestamp]
    public byte[] RowVersion { get; set; } = [];
}

Store references rather than large document bodies in StateJson. The evidence service reloads protected content with tenant and project filters. This keeps checkpoints small and avoids copying sensitive evidence into every version.

Mapping the design to Azure

Azure SQL is a natural authoritative store here because approvals and transitions need transactional guarantees. Azure Service Bus delivers work to stateless workers. Duplicate delivery is expected, so workers use stored versions and idempotency keys rather than assuming a message arrives once.

Azure AI Search is a retrieval index, not the business system of record. Semantic relevance does not establish truth or permission. Blob Storage can hold large protected artifacts, Key Vault protects secrets, managed identity authenticates workloads, and Application Insights receives redacted traces.

Microsoft Foundry conversation state can support its runtime features, but BuildEstate Pro should still persist the domain state needed to authorize, reconcile and audit business actions.

Before writing long-term memory, complete this sentence: “We need to remember this because…” Then define who can correct it, when it expires and what decisions may rely on it. An explicit preference for concise weekly reports may be suitable memory. A model’s guess that a user “usually approves ecology tasks” is not.

Primary references

Applied learning context

This production-minded educational design uses BuildEstate Pro as a realistic case study; it does not claim that an autonomous agent is deployed in the live project.

View BuildEstate Pro →
Afzal Ahmed

Faz Ahmed

Senior Full Stack Engineer & Technical Lead

A hands-on engineer with 15+ years in commercial software. I publish what I am studying, revising and testing so visitors can see both established experience and learning still in progress.

How would you approach this problem? I'd love to hear your thoughts or continue the discussion.

Connect on LinkedIn →