AgentRunCheckpoint
Interface: AgentRunCheckpoint
Defined in: src/core/runCheckpoint.ts:112
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:268
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:132
Wall-clock when the checkpoint was captured. Diagnostic only.
claimVerification?
readonlyoptionalclaimVerification?:ClaimVerificationState
Defined in: src/core/runCheckpoint.ts:187
Private, opt-in exact evidence and reservation counters. Unlike historical observations, this carrier can support later checks. A newest-version continuation must explicitly keep verification enabled, never discard it. Storage ownership/authenticity remains the checkpoint caller's obligation.
evidenceRecovery?
readonlyoptionalevidenceRecovery?:EvidenceRecoveryCheckpoint
Defined in: src/core/runCheckpoint.ts:139
The same request's bounded evidence repair. resumeOnError restores this
budget and any unsent feedback; run({ continueFrom }) adds a new human
turn and deliberately starts a fresh repair budget. Not conversation text.
Absent for checkpoints written before request-scoped recovery.
failurePoint?
readonlyoptionalfailurePoint?:object
Defined in: src/core/runCheckpoint.ts:272
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"|"unknown"|"llm"
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.
findingsLedger?
readonlyoptionalfindingsLedger?:FindingsLedger
Defined in: src/core/runCheckpoint.ts:180
The model's standings on its tool results (9.101.0) — the committed
AgentState.findingsLedger, carried so a continued conversation keeps
what the model already called a fact, left open, ruled out or dismissed,
instead of re-deriving it from results the store no longer serves whole.
Written only when the run's ledger is non-empty; absent on every
conversation whose agent never called .findings() and on any stored by
a runtime older than 9.101.0 — the folded rule: an optional field
is not a format change, and a runtime that has never heard of this key
reads the checkpoint, ignores it, and continues correctly. The rows are
plain records and arrays only (the shape recordFindings writes), so
they round-trip through JSON and structuredClone unchanged.
Version 1 still, by the same documented rule as folded / skillCursor.
folded?
readonlyoptionalfolded?: readonlyFoldedSpan[]
Defined in: src/core/runCheckpoint.ts:162
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:122
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:229
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:127
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:130
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:119
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:248
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.
turnNumber?
readonlyoptionalturnNumber?:number
Defined in: src/core/runCheckpoint.ts:207
The conversation TURN the stored history ends on — the stored run's
AgentState.turnNumber — carried while an honesty layer is armed.
Every ledger row filed while a layer is armed carries its turn, and the
answer's standing reads "this turn" by that stamp, so a stamp must never
repeat in one conversation. The count of user messages in history cannot
promise that: a window strategy or a compaction trims the stored history,
and the count repeats and goes backwards — an earlier turn's verdict would
then be folded as a later turn's. So the next run starts from this number:
run({ continueFrom }) is the turn after it, resumeOnError the same
turn again. Written by both carriers (checkpoint() and the crash
checkpoint), and only while a layer is armed — every other checkpoint
keeps its exact byte shape.
Version 1 still, by the same documented rule as folded / findingsLedger: an optional field is not a format change, and a runtime that has never heard of it continues the conversation correctly.
version
readonlyversion:1
Defined in: src/core/runCheckpoint.ts:114
Schema version. v1 = conversation-history-based.
