Blog · · 11 min read

Agent state management for an existing product data model

Agent state management for an existing product data model

Agent state management breaks when a product treats every useful fact as agent memory. A checkpoint, chat transcript, customer record, retrieved document, and remembered preference do not have the same owner or lifecycle. Put them in one store and a resumed run can overwrite current product data, deleted information can survive in a summary, or a conversation can become an accidental system of record.

Classify each value before choosing its store. Keep product facts under product services. Use checkpoints only to resume execution, manage conversation continuity explicitly, rebuild working context when possible, and treat long-term memory as derived data with provenance and expiry. The sections below map those categories onto an existing product model, then work through the write path, recovery rules, and tests.

Separate five state classes before choosing storage

Product state and agent state can share infrastructure. They still need separate ownership rules:

State classTypical contentsAuthorityNormal lifetimeReplay behavior
Product domain stateOrders, tickets, accounts, permissions, subscriptionsExisting product serviceBusiness-definedRead again; never restore from agent state
Run checkpointCurrent node, pending tool call, retry count, intermediate outputsAgent runtimeOne run plus recovery windowResume the same run
Conversation stateUser and assistant messages, provider response IDs, summariesConversation serviceProduct retention policyContinue a conversation, not a transaction
Working contextSearch results, prompt assembly, temporary calculationsRun workerSeconds to hoursRecompute when practical
Long-term memoryPreferences, learned facts, prior outcomes, summariesMemory service with product policyExplicit expiry or revocationRetrieve as context, then verify

This separation matches the distinction in LangGraph's persistence documentation, which describes short-term memory through checkpointers and long-term memory through stores. That runtime distinction is useful, but an existing product needs another boundary: neither kind of agent memory replaces authoritative domain records.

A product record answers, "What is true now?" A checkpoint answers, "Where may this execution resume?" Conversation state answers, "What has been said?" Long-term memory answers, "What derived information might help later?" Those questions require different validation, retention, and deletion paths.

Why mixed state fails in existing products

Suppose a support agent remembers that a customer prefers annual billing. The customer later changes the plan, and the billing service records monthly billing. If the agent treats its memory as current product state, it can give the wrong answer or propose the wrong action. The preference can help with wording, but the subscription record decides what is true.

Checkpoints create a different risk. They let a run continue after a pause or failure. LangGraph documents checkpoints as snapshots organized into threads. Restoring one should recover execution position and intermediate run data. It should never roll an order, ticket, permission, or account back to an older value.

Retention is another boundary. Provider-managed conversation objects can behave differently from ordinary response objects. OpenAI's conversation-state guide documents several continuation methods and states that response objects are saved for 30 days by default, while conversation objects and their items are not subject to that 30-day time-to-live. That provider behavior does not define your product's retention policy. Your application still decides what it stores, for how long, and how deletion reaches each derived copy.

A thread ID without tenant and user scope is not a security boundary. Nor is a memory safe to reveal merely because semantic search found a close match. Every read needs the tenant, user, purpose, and permission checks that apply to the product action using it.

Framework terminology can also leak into the product model. Anthropic describes memory as one augmentation around an LLM, alongside retrieval and tools, and recommends tailoring those capabilities to the use case. Keep that memory behind a product-owned contract instead of exposing a framework's internal object as the domain model.

Map agent state management to explicit ownership

Keep product facts in product services

Orders belong to the order service. Permissions belong to the identity or policy service. Tickets belong to the support service. The agent may read and propose changes through narrow tools, but it should not maintain a competing copy that can become authoritative.

Store stable domain identifiers in agent state, not full mutable records. A run can keep order_id=ord_55; when it needs status or refund eligibility, it reads the current order through the product service. If a frozen view is required for audit, store an immutable snapshot labeled with its source version and capture time. Do not call that snapshot current state.

Use checkpoints to resume execution

A checkpoint should contain enough information to continue one execution safely:

  • run and workflow identifiers;
  • current step and pending operation;
  • normalized tool proposal;
  • retry and budget counters;
  • references to external product records;
  • last durable outcome;
  • code, prompt, tool, and policy versions needed to interpret the snapshot.

Keep the checkpoint write atomic with the transition it records. If the run publishes a task to another worker, use an outbox or equivalent durable dispatch so the checkpoint and task cannot disagree. On resume, re-read current product state before executing a write. The checkpoint can prove what the agent intended earlier, not that the action is still valid now.

Give conversation state its own contract

Conversation state is useful for continuity, but it should not carry hidden transactional truth. Record who owns the conversation, which tenant it belongs to, its channel, retention class, and any provider identifiers. If you use previous_response_id or a provider conversation object, keep a product-owned conversation ID as the stable public reference.

Messages can contain claims that are stale, incorrect, or unverified. Tag tool outputs and confirmed product facts separately from user statements and model text. When a later turn needs the current order status, load it again rather than trusting a sentence from ten messages ago.

Rebuild working context when possible

Working context includes retrieval results, selected documents, calculated values, prompt fragments, and temporary plans. Most of it should expire with the run. Persist only what is needed for debugging, audit, or deterministic replay, and redact sensitive text before it reaches general logs.

Record source references and retrieval versions when a decision must be explainable. Otherwise, prefer recomputation over keeping large context blobs forever. This reduces stale data and makes deletion practical.

Treat long-term memory as derived data

A memory needs a subject, scope, source, observed time, expiry, and confidence or verification state. It also needs a revocation path. Separate user-provided preferences from model-inferred summaries, because they deserve different trust.

Use long-term memory to select context or personalize an interaction. Before it drives a consequential action, verify the relevant fact against an authoritative service. A remembered shipping preference can shape a draft. A shipping address used for fulfillment must come from the current account or order record.

Implement a product-owned state schema

A framework-neutral schema can keep runtime state and product authority separate:

agent_run:
  id: run_482
  tenant_id: tenant_42
  actor_id: user_18
  workflow: support_refund_v3
  status: waiting_for_approval
  current_step: propose_refund
  checkpoint_ref: checkpoint_009
  conversation_id: conv_71
  product_refs:
    order_id: ord_55
    ticket_id: tic_90
  versions:
    workflow: 3
    tool_registry: 12
    policy: refund_policy_8
  budgets:
    turns_used: 4
    tool_calls_used: 2
  last_outcome: needs_human

conversation:
  id: conv_71
  tenant_id: tenant_42
  owner_id: user_18
  provider_conversation_ref: optional_external_id
  retention_class: support_90_days
  summary_version: 6

memory:
  id: mem_204
  tenant_id: tenant_42
  subject_type: user
  subject_id: user_18
  kind: communication_preference
  value: prefers concise status updates
  source_type: explicit_user_statement
  source_ref: message_993
  observed_at: 2026-07-20T08:15:00Z
  expires_at: 2027-01-20T00:00:00Z
  verification: user_supplied

The agent_run refers to ord_55; it does not contain a second editable order record. The conversation points to an external provider object only as an implementation reference. The memory includes provenance and expiry instead of presenting a model summary as timeless fact.

Implement the write path in this order:

  1. Authenticate the actor and resolve tenant scope outside model input.
  2. Create a product-owned conversation and run record.
  3. Read current domain records through authorized product services.
  4. Assemble working context from current records, permitted retrieval, conversation history, and scoped memory.
  5. Persist the next checkpoint before dispatching asynchronous work.
  6. Treat model output as a proposal and validate it through product rules.
  7. Execute changes through the owning product service with idempotency protection.
  8. Record the durable outcome, then update conversation summaries or derived memory.

Update memory only after the product write succeeds. Otherwise, the memory can record a false history. Likewise, do not advance a checkpoint until the side effect has a durable outcome. A worker that resumes between those writes may repeat or skip the action. Define those transitions across the run record, action record, and product service.

Work through a refund example

A customer asks, "Can you refund the duplicate charge from yesterday?"

The conversation stores the request and subsequent messages. The run checkpoint stores that the workflow has identified a candidate charge and is waiting for approval. The payment and order services remain authoritative for charge status, refund eligibility, amount, and destination. Working context contains the search result that matched the duplicate charge plus the policy excerpt used during the proposal. Long-term memory might contain the customer's stated preference for email receipts.

If an operator approves the refund two hours later, the resumed run must reload the charge. It checks whether another operator already refunded it, whether the amount changed, and whether the approval still matches the current proposal. The old checkpoint explains why the run paused; it does not prove that the refund remains valid.

After the payment service confirms success, the run records the refund ID and marks the action complete. The conversation receives a verified tool outcome. The memory service may retain the receipt preference, but it should not store "this charge is refundable" as a durable customer fact.

Keep business invariants in product domain records. Agent state can reference those records, explain a decision, and resume work around them.

Handle failure and recovery without restoring stale truth

If no checkpoint is available, mark the run as requiring recovery instead of reconstructing execution from chat text. Re-read domain state, inspect the action ledger, and either create a new run or resume from the last verified checkpoint.

If the provider conversation is missing, start another provider conversation under the same product-owned conversation when policy permits. Rebuild context from retained messages and verified summaries. An external conversation ID should not be the only key for customer history.

When memory contradicts product state, prefer the product service. Quarantine or expire the memory and record the conflict. If it came from an explicit user statement, ask whether the user wants to update the authoritative record through the normal product flow.

For a side effect with an unknown outcome, query the product service or external provider with the stable action ID. The model's final message does not prove success. Replay the write only after the action ledger says retry is safe.

Deletion and scope changes must reach conversation items, summaries, embeddings, and memories derived from the affected data. Checkpoints retained for audit need a defined legal and security basis, restricted access, and redaction. Tenant transfers, account merges, and role changes should trigger the same scope review.

Keep schema and workflow versions with checkpoints and memories. A new worker should either understand the stored version through an explicit migration or refuse to resume it. Silent reinterpretation is harder to detect than a stopped run.

Verify the state boundaries

Run tests that prove ownership and lifecycle, not only that storage calls succeed.

  1. Put a stale order status in conversation history and memory. Confirm the agent reads the current status from the order service before proposing an action.
  2. Resume the same checkpoint twice. Confirm both attempts converge on one product action and one recorded outcome.
  3. Reuse a conversation or memory query across two tenants. Confirm the second tenant receives no messages, embeddings, summaries, credentials, or tool results from the first.
  4. Delete a user conversation. Confirm the deletion reaches provider references, local messages, summaries, vector entries, and derived memories according to policy.
  5. Ask where a remembered fact came from. Confirm the system can return its source type, source reference, observed time, and verification state.
  6. Try to resume a checkpoint after changing the workflow schema. Confirm the runtime migrates the known version or stops with an actionable error.
  7. Interrupt the worker after the product service accepts a write but before the run records success. Confirm recovery queries the action ledger instead of issuing the write again.
  8. Revoke the actor's access while a run is paused. Confirm resume performs a fresh authorization check and does not trust the old checkpoint.

Also inspect traces for large prompt snapshots, unscoped thread IDs, and memory writes without provenance. These are signs that state categories have collapsed even when functional tests pass.

Common state-management mistakes

Chat history is not a database. Messages explain an interaction, but they do not enforce uniqueness, permissions, transaction rules, or current business state.

Do not copy complete domain objects into checkpoints. Store identifiers and the minimum immutable evidence needed for recovery, then reload mutable records before decisions and writes.

Semantic similarity does not grant authorization. A close memory match still needs tenant, user, purpose, and permission filters.

Summaries need source links. A compact summary is convenient until a user corrects or deletes the underlying information. Provenance makes repair possible.

Provider retention is an implementation constraint, not product policy. Your application owns user-visible retention, export, and deletion rules.

One status field cannot describe the product workflow, agent run, tool outcome, and approval decision. Model them separately and define how their transitions relate.

What to do next

Take one existing agent workflow and list every value it reads or writes. Assign each value to product state, checkpoint, conversation, working context, or long-term memory. For each row, name the owner, scope, retention rule, update authority, and replay behavior. Any value without one clear owner is the first state boundary to fix.

References

  • LangGraph persistence - Supports the distinction between checkpointer-backed short-term state, threads, checkpoints, and store-backed long-term memory.
  • OpenAI conversation state - Documents conversation continuation methods and the different default storage behavior of response and conversation objects.
  • Anthropic, Building effective agents - Frames memory as an LLM augmentation that should be tailored to the use case rather than treated as a product domain model.

Be first in line.

Join the waitlist and we'll email you the moment it's ready. No sales call.

Try the demo →
or talk to us