Back to Blog
Agent Decomposition

Conversation history is not workflow state

Why transcripts cannot safely coordinate agent workflows, and how explicit state, version checks, and durable checkpoints close the gap.

31 min read
Shubh ShuklaMember of Technical Staff
agentsarchitectureorchestrationworkflow-statedurability

Part 4 defined what crosses an agent boundary. Now the coordinator has several contracts in flight: a network diagnostic, a technician hold, a billing result, a user approval, and external operation references. It needs to know where the workflow stands even when the last chat message is ambiguous or execution stops.

Conversation history helps. It can be conversational state, evidence, and an input to checkpoint creation. It may be the best record of tone, user wording, and unresolved nuance. The claim of this post is narrower: history alone is insufficient for reliable workflow coordination.

Key takeaways

  • Conversation history is valuable conversational state and evidence, but it does not by itself provide a reliable workflow ledger.
  • Explicit state names goals, active work, dependencies, holds, approvals, external references, and a version.
  • Models and specialists may propose transitions; trusted application or runtime code validates and commits authority-sensitive state.
  • Parallel results need stale-write protection, usually a version check or equivalent concurrency control chosen for the workload.
  • A persisted runtime checkpoint can preserve progress, not exactly-once external effects; receipts, idempotency, and reconciliation remain separate.

A transcript is useful but insufficient

A transcript answers a conversational question: what was said, in what order, and often by whom. Workflow coordination asks different questions: which tasks are active, which dependency is satisfied, which hold expires next, which approval applies to which proposed action, which result version was committed, and which external effect remains unconfirmed.

Sometimes those answers can be inferred from messages. Inference is the problem. The same sentence may be a proposal, a report, a correction, or a commitment. “I found a 6:30 appointment” does not tell the runtime whether the slot was merely listed, held, confirmed, expired, or superseded. “Yes, do it” does not safely identify the approved operation if two choices are pending.

A model can reread the transcript and make a plausible reconstruction. That is useful for conversation repair. It is not equivalent to a deterministic state transition. Another model, prompt version, context window, or summarization pass may reconstruct a different board.

History also omits application events that never became chat. A lease expired. A provider acknowledged a request after the user disconnected. A policy version changed. A parallel worker returned against an old snapshot. A temporary hold expired. If the user was not told about the event, the transcript cannot contain it.

Conversely, a transcript contains statements that should not become committed state. Users speculate, correct themselves, quote old messages, and paste untrusted content. Agents explain intentions before tools run. A sentence saying “the credit is applied” is not an authorization grant or provider receipt.

Architecture recommendation: preserve useful history, but coordinate with an explicit workflow record whose transitions are validated by trusted code. The record can cite messages and artifacts as evidence. It should not require a model to rediscover control state from prose on every turn.

This distinction does not mean “chat is stateless.” History can be the complete state for a low-risk conversation whose only output is more conversation. The need for a separate workflow record grows with parallelism, interruption, consequential effects, expiry, external lifecycle, and the cost of a wrong resume.

Three tests expose the limit quickly. First, ask whether two readers can derive the same pending work without model judgment. Second, ask whether a new process can resume safely if the last assistant message was never delivered. Third, ask whether a late specialist result can be accepted or rejected without replaying the whole chat. If any answer depends on “the model will understand,” explicit workflow state is probably missing.

Summarization does not solve the underlying problem. A good summary can preserve the customer's goal and recent events while reducing tokens. It still chooses what to omit, may blur proposal and commitment, and usually lacks concurrency semantics. Store summaries as derived conversational artifacts, not as an unversioned replacement for committed task state.

Tool-call messages help but are not automatically a ledger. A call can be attempted without reaching the provider, a result can arrive after cancellation, and framework history can be filtered before the next run. Durable coordination needs application-defined meanings for attempt, acknowledgement, confirmation, and unknown outcome.

Five layers that are easy to conflate

Precise vocabulary prevents design arguments where two people use “state” for different things.

Message history is the ordered record of user, assistant, tool, and system messages retained by an application or framework. It may be complete, filtered, summarized, or truncated. It is evidence of an interaction, subject to the integrity and retention properties of its store.

Model-visible context is what a specific model invocation can see now. It may include some message history, system instructions, retrieved facts, tool schemas, summaries, and generated briefs. It is an assembled input, not necessarily the durable record.

Application context is local data and capabilities available to runtime code: authenticated identity, tenant binding, database handle, policy client, feature flags, credential references, and tracing facilities. It need not be shown to the model.

Workflow state is the explicit application record of goals, agenda, lifecycles, dependencies, decisions, holds, pending work, references, and versioned transitions. It answers “where is the work?” without asking a model to interpret the transcript.

Runtime checkpoint is a capture that lets a particular execution resume or replay from a known point. Depending on the framework, it may include workflow data, executor position, pending requests, and framework internals. Persistence and durability depend on the checkpoint store: an in-memory checkpoint does not survive a process restart, while a checkpoint in durable storage can. A checkpoint is one mechanism for preserving progress; it is not synonymous with the domain workflow model.

Framework behavior (OpenAI Agents SDK): sessions provide a persistent memory layer for conversation items across runs. The context guide separates local runtime context from context visible to the model. Those features are valuable, but an application still decides whether and how to represent domain workflow state.

Framework behavior (Microsoft Agent Framework): the workflow state documentation exposes shared-state APIs for a workflow execution. It also warns that reusing one workflow instance across tasks can unintentionally share state, and that executor instances reused across workflow builds share their internal mutable state. Applications must create fresh instances or otherwise provide the documented isolation. Its checkpoint documentation captures execution state for restore. These framework surfaces support explicit state; they do not make one universal schema correct for every application.

The layers can reference one another. A workflow task can cite the user message that created it. A model-visible brief can be derived from workflow state. A checkpoint can serialize the current workflow projection. Keeping the layers distinct makes those transformations reviewable.

The transformations should be one-way where authority matters. Message history can propose a goal update; a validator commits it to workflow state. Workflow state can generate a scoped model brief; the model does not receive the state store handle. A checkpoint can capture a committed version; restoring it does not let old runtime data overwrite a newer record.

This vocabulary also prevents accidental retention coupling. Removing a message from model-visible context does not necessarily delete it from the durable history store. Expiring a checkpoint does not necessarily close the domain workflow. Closing a workflow does not prove external providers deleted their resources. Each layer needs an explicit lifecycle and owner.

A production trace should say which layer a value came from. “Customer requested after-hours approval” belongs to message evidence. “Gate gate-14 is pending for hold-208” belongs to workflow state. “Executor paused before node confirm_visit” belongs to checkpoint metadata. That precision makes incident review far less dependent on inference.

The minimum explicit workflow-state model

Start small. A useful state model does not need to mirror every message or every provider object. It needs enough structure to make coordination decisions deterministic and auditable.

At minimum, record:

  • Identity and scope references: workflow ID, authenticated principal and tenant references, and relevant policy version. These are references to trusted runtime facts, not model assertions.
  • Goal and agenda: the user's current goal, decomposed intents, active item, paused items, and dependencies.
  • Task lifecycle: task ID, contract reference, assignee, lifecycle state, result extent, reason, and the state version from which the task began.
  • Decisions and gates: what decision is pending, which exact action it governs, who may decide, and when it expires.
  • Produced values: named slots and artifact references that downstream work consumes.
  • External references: provider task IDs, hold IDs, operation IDs, receipts, and last independently observed status.
  • Concurrency metadata: monotonically increasing version or another comparison token, plus timestamps where expiry matters.
  • Checkpoint metadata: the resumable runtime reference and the workflow version it represents.

Do not serialize credentials, API keys, session cookies, or secret material into this record. Store a stable reference that trusted runtime code resolves under current identity and policy. Durable state is copied, logged, inspected, backed up, and sometimes replayed; it is the wrong place for raw secrets.

The workflow-state model should encode invariants, not only fields, and the trusted commit path should enforce them. A task cannot be both terminal and pending input. A downstream task cannot be ready until its named dependencies are committed. A gate must reference one concrete action or a clearly bounded action set. A hold past expires_at cannot remain actionable. Every mutation advances the version or equivalent concurrency token.

Separate canonical state from convenient projections. The canonical record may contain normalized task and gate objects. A user-facing projection can say “waiting for your appointment approval.” A Billing brief can include only the verified outage duration and account reference. Rebuilding projections from the canonical record is safer than letting each view become another independently mutable truth.

Avoid mirroring the entire remote provider inside local state. Keep the fields needed for orchestration: remote task reference, last observed status, observed time, expiry, and receipts. The provider remains authoritative for its own inventory or booking. The local record describes what the coordinator knows and what it must check next.

Continue the outage from Part 4. The six scenes below keep a deliberately short conversation beside explicit state. Each scene says what changed, what remains pending, and what the visible history still cannot establish.

Outage workflow: history beside state

Conversation history

Customer

Internet has been down since last night. Restore it, book the earliest technician if needed, and apply any credit. Ask before a visit after 5 p.m.

Workflow state

Workflow

Version
1
Changed
Goal
Restore service and resolve fallbacks
Changed

Agenda

Active
Diagnose service
Pending
Pending
Technician fallback; outage credit
Pending

Authority

After-hours rule
Approval required after 5 p.m.
Changed
Service binding
Not yet resolved
Pending

Triggering event

The customer submits one compound outage request.

Changed: the goal, agenda, and stated time constraint. Pending: identity-bound service resolution and all work. History cannot establish the authenticated service or grant tool authority.

Scene 1 of 6: 1 · Request. Event: The customer submits one compound outage request.

Notice what the structured state does not try to do. It does not preserve every sentence. It preserves coordination facts: versions, task lifecycles, named dependencies, a gate bound to one action, expiry, and evidence references. The transcript remains beside it for human meaning and conversational continuity.

Models propose; trusted code commits

State ownership needs a write policy. A coordinator model can propose that the diagnostic completed, that the next two tasks are ready, or that a user message looks like approval. A specialist can return a structured result. Neither output should directly commit authority-sensitive state merely because it matches a schema.

Trusted application or runtime code should validate at least four things: the actor may propose this transition; the prior state permits it; referenced facts and result schemas are valid; and policy or approval conditions are satisfied. Only then does it commit the next version.

Architecture recommendation: use one narrow commit path for workflow state. The example below is deliberately framework-neutral. Optimistic concurrency is shown as a production recommendation, not SDK-mandated behavior.

commit-specialist-result.tsts
async function commitSpecialistResult(input) {  const result = await dataStore.transaction(async tx => {    const current = await tx.loadWorkflow(input.workflowId);    if (current.version !== input.basedOnVersion) {      return { accepted: false, reason: "stale_version" };    }     const candidate = reducer(current, input.proposal);    const validated = validateTransition(current, candidate);    authorizeStateChange(input.actor, current, validated);     const next = { ...validated, version: current.version + 1 };    const updated = await tx.compareAndSwap({      workflowId: input.workflowId,      expectedVersion: current.version,      next,    });     if (!updated) {      return { accepted: false, reason: "stale_version" };    }     await tx.insertOutbox({      id: createEventId(),      topic: "workflow_state_committed",      workflowId: input.workflowId,      version: next.version,    });     return { accepted: true, state: next };  });   return result;}

Begin one datastore transaction, load the current record through it, and compare the version with the snapshot the specialist saw. A mismatch returns a disposition without writing state or an event.

The sketch omits domain details and retry policy to keep the commit rule visible. Its framework-neutral transaction requires one datastore capable of atomically updating workflow state and inserting the outbox row. AWS's transactional-outbox pattern describes that atomic unit and explains the separate obligation: publishers can deliver an outbox event more than once, so consumers must be idempotent.

The reducer should be deterministic for the same current state and validated proposal. That makes state changes testable without calling a model. It can mark one task complete, open dependent tasks, or create a pending gate according to declared rules. If a transition requires ambiguous semantic judgment, the model can produce that judgment as a proposal with evidence; the reducer still owns the committed shape.

Validation and authorization are different checks. Validation may confirm that hold_ref, expiry, and reason code are present. Authorization decides whether this actor may commit a gate for this tenant and whether current policy permits the eventual action. A schema-valid model response can fail authorization.

The outbox insert also has a narrow meaning. It prevents a committed workflow transition from permanently losing its publication record. It does not guarantee a consumer handles the event once, nor that an external provider executes once. Event IDs, consumer deduplication, effect idempotency, and reconciliation still matter.

Approval is another proposal-to-commit boundary. The model may classify “yes” as approval and attach the likely gate ID. Trusted code must verify identity, bind the response to the exact pending action, check expiry and policy, and then commit the gate transition. Detailed approval mechanics are the subject of a later part.

Parallel results need stale-write protection

Parallel specialists make implicit state especially dangerous. Network Operations completes first, then Field Service and Billing both start from version 3. Billing returns quickly and commits version 4. Field Service returns later with a useful hold. If it writes a full snapshot based on version 3, it can erase the credit result or reopen the diagnostic.

One option is optimistic locking: each result declares based_on_version, and the store commits only if that version is still current. DynamoDB's optimistic locking guidance documents the compare-version pattern and its tradeoffs.

Architecture recommendation: use a version check, compare-and-swap, or an equivalent concurrency strategy wherever parallel writers can touch overlapping state. This is not universal framework behavior. It adds conflicts and retry or merge work, and high-contention systems may prefer serialized commands, partitioned ownership, or database transactions.

A stale result is not automatically useless. Trusted code can reload current state and decide whether to reject, revalidate, or apply a narrow commutative patch. Billing's independent receipt may merge cleanly while an appointment proposal tied to an expired gate may not. The merge policy belongs to the application, not to a model improvising over two snapshots.

Partitioning can reduce conflicts. If Billing exclusively owns its task result and Field Service exclusively owns its own, each can append a result event while one coordinator reducer derives the combined agenda. That design trades fewer write conflicts for more projection logic. A single versioned document is simpler at low contention; event or command streams can be better when ordering and independent ownership dominate.

Do not respond to every version conflict by blindly rerunning a specialist. Its external call may already have caused an effect, and the result may still contain a receipt worth recording. First classify whether the stale work was read-only, effectful, superseded, or independently mergeable. Redispatch only after checking operation references and current state.

Version metadata should travel with tasks and results. based_on_version: 3 lets the commit path identify the snapshot a specialist saw. A result without that fact can still be treated as untrusted evidence, but it should not silently rewrite a versioned record. Time alone is not a safe ordering rule when clocks, queues, and retries differ.

Keep result dimensions separate during the merge. A specialist's lifecycle state does not determine the coordinator disposition. A completed specialist task can arrive after cancellation and be recorded as no_return or superseded. A needs_input result can be accepted as useful partial work and open a gate. An external operation can remain unknown even when local task processing completed successfully.

Author inference: version checks are often the smallest reliable default for moderate-contention coordinator records because they make races visible. That is an engineering judgment to validate against workload contention, merge cost, latency, and datastore guarantees—not a claim that every agent system requires the same mechanism.

Checkpoint and resume without pretending exactly once

A checkpoint answers: where can this runtime continue? It may capture executor position, workflow data, pending interruptions, and framework metadata. That is more precise than replaying the transcript and asking a model what probably happened.

Framework behavior (Microsoft Agent Framework): checkpoints can preserve workflow execution state for restoration. Its Durable Functions integration adds durable execution capabilities. Applications still define their domain state and external-effect policy.

Framework behavior (Temporal): a Workflow Execution is durable and can continue through failures, while a Workflow Definition must obey determinism constraints for replay. Temporal offers a stronger execution model than a generic agent transcript, but it still distinguishes workflow code from external activities and effects.

A checkpoint does not prove exactly-once external effects. Consider a process that sends a booking request, the provider commits it, and the worker crashes before recording the response. A checkpoint may know execution reached the activity; it cannot infer whether the provider acted.

External effects therefore need separate controls:

  • idempotency keys enforced by the provider or an effect-owning broker;
  • stable operation and provider references;
  • receipts or acknowledgement records;
  • read-after-write verification where the provider supports it;
  • reconciliation for unknown outcomes;
  • compensation when a later part of the workflow invalidates a confirmed effect.

Stripe's idempotent-request documentation shows a concrete provider-enforced model. An application-local key without downstream enforcement does not create the same guarantee.

Resume versus redispatch remains contextual. Resume is attractive when the checkpoint is durable, code-compatible, observable, and the retained state can be revalidated. Redispatch may be safer when a clean task context is cheap, a provider hold expired, or old context could drive a new effect. Neither should be a universal default.

On restore, compare the checkpoint's workflow version with the current committed record. Revalidate identity, policy, approvals, expiry, remote task state, and external references before any consequential effect. A checkpoint restores progress; it does not freeze the outside world.

Checkpoint compatibility deserves an explicit policy. Code, prompt, tool schema, and state schema may change while work is paused. Record the relevant versions and decide which combinations can resume in place, which require migration, and which must redispatch a bounded task. Deserializing old bytes successfully does not prove the restored workflow is semantically safe.

Restoration should be observable. Emit which checkpoint was loaded, which workflow version it represented, which newer events were reconciled, and which facts were revalidated. Do not log secrets or unnecessary customer data. The goal is to explain why the runtime resumed at a state, not to duplicate the entire serialized payload into logs.

Multiple checkpoints can exist for one workflow. Treat them as runtime artifacts linked to committed state, not competing canonical records. If a stale worker restores an older checkpoint after another process advanced the workflow, the version check must stop it from committing an old projection.

Holds, pending work, references, expiry, and revalidation

Interruptions are normal workflow states. The customer may need time to decide. An OAuth flow may require authentication. A remote agent may request input. A provider may place a temporary hold. Treating every interruption as failure throws away valuable work; treating it as success hides unfinished obligations.

A pending record should identify the exact object of the interruption:

  • gate_id and the action or proposal it governs;
  • reason, such as approval, authentication, or missing information;
  • requested_from, which principal or system can satisfy it;
  • created_at, expires_at, and the policy version used;
  • dependent tasks blocked by the gate;
  • stable hold, provider task, or artifact references;
  • revalidation steps required before continuation.

needs_input is an interruption, not necessarily failure or terminal success. In the outage, Field Service completed useful option search and created a hold, but appointment confirmation remains open. The coordinator can communicate the partial result without pretending the agenda is done.

The A2A v1.0 specification provides task states and artifacts that can represent remote progress and input requests. Those values are remote-reported evidence. They do not reveal the remote agent's private workflow state or prove its internal external effects. Store the protocol task ID, agent identity, observed status, artifacts, and any independent provider receipt.

Expiry changes meaning. An approval for hold-208 cannot authorize a different replacement hold unless the approval contract explicitly says so. A late “yes” may still be conversationally clear, but trusted code must reject or reframe it when its bound object expired.

Pending work should be queryable without reading messages. An operator should be able to list workflows waiting on a user, holds expiring soon, remote tasks with unknown outcomes, and checkpoints that cannot resume under current code. That operational view is one of the clearest returns on explicit state.

An interruption can also carry partial results. If the appointment search found three options but needs accessibility information, preserve the options, provider references, and their observed times. The next step can ask one precise question. A binary success/failure model either discards useful work or misrepresents completion.

Revalidation is targeted, not a ritual restart. Recheck facts that may have changed or protect an effect: principal access, approval binding, policy, resource expiry, price, inventory, and provider status. Stable completed facts, such as a verified historical outage interval, need not be recomputed unless their source or integrity is in doubt.

Travel makes portability visible without changing the model. A flight hold and hotel option each have provider references, prices, expiry, and separate authority. If the flight changes, the hotel dependency must be invalidated or revalidated. The transcript may explain why; explicit state identifies exactly which downstream item is now stale.

Isolate state, define retention, and keep secrets out

Agent or subagent isolation is a topology and context choice. It is not data authorization. A fresh context can still receive data the caller was not allowed to disclose. A shared state store can be safe only when every read and write is scoped and enforced.

Architecture recommendation: bind workflow records to authenticated tenant and principal references, enforce access in the state service, and scope each specialist projection to its purpose. Do not depend on a prompt telling an agent to ignore fields it should never have received.

Separate the canonical record from model-visible projections. Network Operations may receive service and telemetry facts. Billing may receive account, plan, and verified outage duration. Field Service may receive address, equipment, and scheduling constraints. The coordinator can own the combined agenda without forwarding the combined dataset to every specialist.

Retention should follow purpose and evidence needs, not “save everything.” Message history, workflow records, checkpoints, traces, and external receipts may need different retention windows. Deletion also has dependency semantics: a checkpoint that references a deleted transcript slice must remain understandable, and an audit record may need a non-sensitive digest rather than raw content.

Do not put credentials, access tokens, private keys, raw payment data, or session cookies in serialized workflow state or checkpoints. Store a stable secret reference. Resolve it just in time through trusted runtime code, under current identity and policy, and make it possible to rotate or revoke without rewriting historical state.

Untrusted content needs integrity treatment even when it is useful. A pasted provider email or remote artifact can be retained as evidence without becoming an authoritative transition command. OWASP Cornucopia AAI2, updated July 17, 2026, provides a current primary threat-modeling resource for agentic applications. Its existence does not substitute for application-specific authorization and data-flow analysis.

State APIs should expose purpose-specific commands rather than unrestricted document writes where risk warrants it. record_specialist_result, open_approval_gate, and mark_hold_expired give trusted code a smaller surface to validate than “replace workflow JSON.” This is an application design option, not a requirement to build a large event-sourcing system.

Backups and analytics are part of the data flow. Tenant scoping at the primary API is insufficient if exports, traces, or warehouse tables later combine records without equivalent controls. Keep sensitive values out when references or aggregates answer the operational question, and test deletion and retention behavior across derived stores.

Agent isolation still helps with context quality and accidental disclosure. A fresh Field Service context is less likely to anchor on billing details it never received. The caveat is that isolation supports least exposure; authorization still comes from the state, policy, identity, and tool services that enforce the boundary.

A state-ownership matrix, then human approvals

The final design artifact is a state-ownership matrix. It prevents “shared state” from becoming “everyone can mutate everything.”

State surfaceMay proposeValidates and commits
User goal and agendaCoordinator model; user correctionCoordinator runtime after intent and identity checks
Specialist task lifecycleAssigned specialist or remote agentWorkflow runtime against contract and current version
Produced slots and artifactsSpecialist structured resultSchema validator and dependency reducer
Approval gateCoordinator classification of user responseApproval service bound to principal, action, policy, and expiry
Authorization and credential scopeNo model or specialist may grant itTrusted identity, policy, and tool boundary
External-operation evidenceTool, provider, or remote agent reportsOperation ledger plus receipt or reconciliation logic
Workflow versionNo caller chooses the next valueState store during an atomic commit
Checkpoint referenceRuntime checkpoint subsystemRuntime store linked to a committed workflow version

The matrix separates conversational ownership from commit ownership. A coordinator can own the user-facing conversation without having unilateral authority to post credits or confirm visits. A specialist can own a bounded task without being allowed to rewrite the global agenda. Topology does not determine these permissions one-to-one.

Turn the matrix into tests. A Billing result cannot mutate Field Service state. A coordinator proposal cannot increase its credential scope. A user response cannot close a gate for another principal or expired action. A restored checkpoint cannot decrement the workflow version. A provider report can update observed evidence but cannot retroactively become proof of an unobserved internal effect.

The matrix also clarifies human escalation. An operator may be allowed to resolve an ambiguous provider outcome but not alter the original receipt. A support agent may cancel a pending gate but not fabricate approval. A security process may revoke a credential reference while preserving the historical fact that it was once used. “Human in the loop” still needs scoped state authority.

Keep the model out of mechanical commit work. It does not need to choose version numbers, enforce compare-and-swap, calculate expiry, or decide whether a receipt cryptographically verifies. Spend model reasoning on ambiguous intent, explanations, and domain judgment; use deterministic code for invariants that must hold every time.

Check your understanding

After restoring a checkpoint, the transcript ends with the customer saying “yes,” but the referenced appointment hold has expired. What should happen?

After restoring a checkpoint, the transcript ends with the customer saying “yes,” but the referenced appointment hold has expired. What should happen?

History remains important at the end of this design. It preserves the customer's language, explains why constraints exist, and gives a resumed agent the conversation needed to respond naturally. It can be conversational state, evidence, and checkpoint input. It simply should not be the only source of truth for active tasks, committed decisions, authority, expiry, and external effects.

The next part of the series moves from pending gates to human approvals: how to bind approval to a specific action, pause safely, handle changed proposals, and revalidate before execution. Later parts will cover retry and recovery, compensation, observability, and deeper A2A trust. Those mechanics are intentionally deferred here.

The foundation is now complete. Parts 1–3 chose and tested the system shape. Part 4 defined the contracts at justified boundaries. Part 5 gave the coordinator an explicit, versioned record that survives parallel work and interruption without confusing a plausible transcript reconstruction for a committed workflow transition.

Primary sources

Building something difficult?

Bring us the constraint, the failure mode, or the system that should exist next.

Work with us