AgentRunCheckpoint
Interface: AgentRunCheckpoint
Defined in: src/core/runCheckpoint.ts:75
JSON-serializable checkpoint of an in-progress agent run. Persist
to ANY durable store (Redis / Postgres / S3 / disk / queue) and
resume hours / days / deploys later via agent.resumeOnError(...).
Stable shape — the version field guards forward compat. v1
→ v2 transitions will be supported via a migration helper.
Properties
agent?
readonlyoptionalagent?:object
Defined in: src/core/runCheckpoint.ts:179
WHICH agent recorded this conversation — present only when that agent was
given an explicit Agent.create({ id }) (9.2.0).
A conversation is a transcript, and a transcript can be replayed on any agent. Usually that is the point: a deploy that adds a tool or edits a prompt must still be able to continue yesterday's conversations, so the runtime cannot refuse on "the agent changed". But replaying the BILLING agent's conversation on the SUPPORT agent is a different mistake, and it used to be accepted in silence.
The rule is the one the embedder fingerprint already uses: ids decide
only when BOTH sides named themselves. A default id ('agent') is not
naming yourself, so the majority of callers — who never pass one — are
never refused. Two sides that both chose a name and chose different ones
are refused, by name.
Version 1 still, for the same reason as the two fields above.
id
readonlyid:string
checkpointedAt
readonlycheckpointedAt:number
Defined in: src/core/runCheckpoint.ts:95
Wall-clock when the checkpoint was captured. Diagnostic only.
failurePoint?
readonlyoptionalfailurePoint?:object
Defined in: src/core/runCheckpoint.ts:183
Where the failure happened. Diagnostic — surfaces in oncall triage so you can tell "LLM 500 mid-iteration" from "tool threw" from "validation kept failing".
iteration
readonlyiteration:number
phase
readonlyphase:"tool"|"iteration"|"llm"|"unknown"
stage?
readonlyoptionalstage?:string
What was OPEN when it threw — 'call-llm' for the model call, or the
declared name of the tool that was running (8.14.0).
Absent when nothing was open (a failure between brackets), which is the honest answer rather than a guess.
Never a URL, never a credential, never request or response content.
Only the literal string 'call-llm' or a tool name the app itself
declared. A checkpoint is persisted to Redis / Postgres / S3 and read by
whoever is on call; nothing that could carry a secret goes in it. Do not
"improve" this field into carrying the endpoint.
folded?
readonlyoptionalfolded?: readonlyFoldedSpan[]
Defined in: src/core/runCheckpoint.ts:118
Every span this conversation folded into a summary, oldest first — what makes a compacted conversation still a provable one after the process that compacted it is gone.
Written by .compaction(); absent on a conversation that never folded,
and absent on one stored by a runtime older than 8.2. Under the default
retain: 'conversation' each span carries the folded messages verbatim;
under retain: 'discard' the span is still here, naming what left, and
only messages is absent.
Join a summary in history to its span with foldedSpanFor(...) —
by content fingerprint, never by index, because a later fold moves every
index after it.
Version 1 still, deliberately. An optional field is not a format
change: a runtime that has never heard of folded reads this checkpoint,
ignores it, and continues the conversation correctly — the summary is an
ordinary message in history either way. Bumping the version would make
an older deployment REFUSE a session it can serve perfectly well, which is
the opposite of what the version field is for.
history
readonlyhistory: readonlyLLMMessage[]
Defined in: src/core/runCheckpoint.ts:85
Conversation history at the LAST completed iteration boundary (LLM messages). The next iteration retries from here.
identity?
readonlyoptionalidentity?:MemoryIdentity
Defined in: src/core/runCheckpoint.ts:140
WHO this conversation belongs to — the identity the stored run was
given, carried so that continuing it lands in the same namespace it
started in (9.2.0).
Before this field, continuing a conversation re-seeded identity from the
resuming run's own id: every continued turn wrote its memory under a
FRESH conversationId, so turn two's facts were stored somewhere turn
three could not read them. Nothing threw, and the only symptom was an
agent that kept forgetting — the same class of failure as a store that
silently forgot everything looking exactly like a new user.
Absent on a conversation stored before 9.2.0, and absent when the run
never got an explicit identity (the default is derived from a runId, and
carrying THAT forward would pin a whole conversation to one run's id).
An explicit identity on the continuing call always wins.
Version 1 still, on the same reasoning as folded: an optional field is not a format change, and a runtime that has never heard of it continues the conversation correctly.
lastCompletedIteration
readonlylastCompletedIteration:number
Defined in: src/core/runCheckpoint.ts:90
Index of the last completed iteration in the FAILING run
(diagnostic — not consumed on resume). The resumed run restores
this history but re-seeds its own iteration counter at 1 with a
full maxIterations budget.
originalInput
readonlyoriginalInput:object
Defined in: src/core/runCheckpoint.ts:93
Original input message. Surfaces in observability + lets the consumer correlate checkpoint to the user's request.
message
readonlymessage:string
runId
readonlyrunId:string
Defined in: src/core/runCheckpoint.ts:82
runId of the FAILING run — lets the consumer correlate a
persisted checkpoint back to the original run's observability.
NOT reused on resume: resumeOnError starts a fresh run with a
fresh runId (only the conversation history is restored).
skillCursor?
readonlyoptionalskillCursor?:string
Defined in: src/core/runCheckpoint.ts:159
WHERE the conversation's skill graph stood when the stored turn ended — the graph cursor, carried so a continued conversation can default its next turn's start to it (SG-C, 9.17.0).
Written ONLY when the recording agent's graph declared
continuity: 'conversation'; under the default 'turn' the field is
never written and the byte shape of every checkpoint is unchanged. On
the continuing side it is honored only under the same declaration, and
the RouteTurn cascade still judges it against the new message — an
inherited cursor is a sticky DEFAULT, not a lock. An id the continuing
graph does not know is dropped and recorded
(turn_routed.droppedResume), never silently parked.
Version 1 still, by the same documented rule as folded / identity / agent: an optional field is not a format change — an older runtime ignores it and continues correctly.
version
readonlyversion:1
Defined in: src/core/runCheckpoint.ts:77
Schema version. v1 = conversation-history-based.
