Expand description
Salvor runtime: the IO edge where core (replay), store, llm, and tools meet. Durable, resumable agent runs with hard budgets, in two tiers.
§The two tiers
- The substrate:
RunCtx. The library-first tier. A team that owns its control flow writes an ordinary async function againstRunCtx(recorded model calls, recorded tool dispatch,now,random, suspension) and gets durability, crash-exact replay, and the suspension protocol with no framework in the way. A runtime that sits under your loop is infrastructure; this type is that runtime. - The batteries:
Agent+Runtime.Agent::builderconfigures model, prompt, tools, budgets, pricing;Runtime::start/Runtime::recover/Runtime::resumedrive the single built-in loop. The loop is implemented entirely against the publicRunCtxsurface and doubles as its reference example; it holds no private hooks, by design and by test.
§Where this crate sits
The agent loop cannot live inside salvor-core: salvor-store and
salvor-tools both depend on
salvor-core, and the loop depends on both of them (plus salvor-llm),
so a loop in core would be a dependency cycle. This crate is the
resolution: core keeps the pure event model and replay engine with no
new dependencies, and salvor-runtime sits above all four crates as
the one place allowed to do IO. For the same reason this is the one
crate that may be tokio-bound: it is the IO edge, while core and store
stay executor-agnostic.
§Constraints this crate honors
The replay engine fixes the ground rules the runtime builds on:
- Budget checks are computed from replayed data (recorded usage,
recorded
nowobservations), so a crossing re-fires identically at the same position on replay (Budgets). - Suspension is
suspend+await_resume, and budget crossings park through the same protocol (RunCtx::suspend,RunCtx::await_resume,RunCtx::budget_exceeded). - Divergence detection is always on: every replayed step is compared structurally against the log, and a mismatch is a typed error, never a silent drift.
- Random values are raw recorded bits (
RunCtx::randomreturnsu64); richer values derive from the bits deterministically, which is how idempotency keys reproduce on replay. - Sequence numbers are 0-based and contiguous, with completions correlated to their intent’s position; the cursor enforces it and this crate persists exactly what the cursor emits, in order.
§Recorded wire shapes this crate defines
On top of the core event vocabulary, three shapes are contracts here:
the suspension sentinel and the structured tool-error object recorded in
tool-call completions (module docs of wire, exported constants
SUSPEND_SENTINEL_KEY / ERROR_SENTINEL_KEY), and the
budget-extension resume input (module docs of budgets). Error
compaction, what a failed tool call puts into the model’s context, is
specified and exported in compact.
Structs§
- Agent
- A built agent definition plus the client that executes its model calls.
Construct with
Agent::builder. - Agent
Builder - Builds an
Agent: - Budget
Extensions - The accumulated budget extensions granted by recorded resume inputs. See the module docs for the JSON shape they are parsed from.
- Budget
Observations - The replay-derived quantities a budget check consumes. The loop builds one of these at each iteration start, exclusively from recorded data.
- Budgets
- The limits an agent declares. Every dimension is optional; an absent dimension is never checked.
- Failure
Tracker - Tracks consecutive identical tool failures and produces the model-facing content for each dispatch result.
- Model
Turn - A model call’s result: the typed response plus the token usage recorded for it. Identical whether the call was executed live or replayed.
- Pricing
- Per-token pricing, in US dollars per million tokens. Required by the agent builder whenever a cost budget is declared.
- RunCtx
- The public durability substrate for one run. See the module docs.
- Runtime
- The batteries-included runtime. See the module docs for the three verbs.
- Tool
Failure - A tool failure as recorded in (and decoded from) a completion output.
Enums§
- Agent
Build Error - Why an agent could not be built.
- Loop
Outcome - How one drive of the loop ended: it produced a final output, or it parked and the process should stop driving it.
- Park
Reason - Why a run parked instead of completing.
- Resumption
- What
RunCtx::await_resumeproduced. - RunOutcome
- How a drive of a run ended.
- Runtime
Error - What can go wrong while driving a run.
- Tool
Call Result - A tool call’s result, decoded from the recorded completion output (the decoding is identical live and on replay, which is what keeps a resumed orchestration on the recorded path).
- Tool
Failure Kind - Which layer of the tool dispatch produced a recorded failure. Mirrors the
three
salvor_tools::ToolErrorvariants.
Constants§
- COMPACT_
HEAD_ CHARS - How many leading characters survive truncation.
- COMPACT_
MESSAGE_ CAP - The maximum length, in characters, of an error message handed to the model uncompacted.
- COMPACT_
TAIL_ CHARS - How many trailing characters survive truncation.
- DEFAULT_
MAX_ RESPONSE_ TOKENS - The default
max_tokenssent with each model request when the builder is not told otherwise. - ERROR_
SENTINEL_ KEY - The reserved key marking a completion output as a recorded tool failure.
- MAX_
LABELS - The most labels one run may carry.
- MAX_
LABEL_ KEY_ LEN - The longest a label key may be, in bytes.
- MAX_
LABEL_ VALUE_ LEN - The longest a label value may be, in bytes.
- MAX_
TOOL_ ATTEMPTS - The cap on total executions of one live tool call, counting the first
attempt. Applies only where
RetryPolicyallows retrying at all. - SUSPEND_
SENTINEL_ KEY - The reserved key marking a completion output as a recorded suspension.
Functions§
- canonical_
json - Renders a JSON value in the canonical form documented at module level: compact, with object keys recursively sorted in ascending byte order.
- clamp_
tokens - Narrows a provider-reported token count to the event log’s
u32, saturating rather than failing on a count that cannot occur in practice. - compact_
error_ message - Truncates a long error message, keeping head and tail around an elision
marker. Messages at or under
COMPACT_MESSAGE_CAPcharacters pass through unchanged. - content_
string - Renders a JSON value as the text handed to the model (an initial input or
a
tool_resultcontent string). - decode_
failure - Decodes a completion output that is the failure sentinel, if it is one.
- decode_
suspension - Decodes a completion output that is the suspension sentinel, if it is one.
- drive_
loop - Runs the built-in agent loop over an already-begun run, returning the final
output (a
LoopOutcome::Completed) or a park — but not recording the terminalRunCompleted. - encode_
failure - Encodes a tool failure as the sentinel completion output.
- encode_
suspension - Encodes a suspension as the sentinel completion output.
- error_
chain - Joins an error’s
Displaywith everysource()below it, separated by": ", so the recorded message keeps the informationthiserrorspreads across the chain. - event_
detail - The informative payload of one event, rendered as a single line. Picks the
fields that matter per kind: a tool call shows its name and effect, a model
completion its token usage, a suspension its reason. Hashes are shortened
and every payload is truncated, so no full input, output, or error text
reaches the progress stream;
salvor history --jsonis the escape hatch for the untruncated envelope. - event_
kind - The stable
kindlabel for one event, matching the enum variant name so it reads the same as the wire form’skindtag. - hash_
value - The content hash of a JSON value:
sha256:plus the hex SHA-256 of its canonical serialization. This is the exact string recorded inagent_def_hashandrequest_hashevent fields. - response_
value - Rebuilds the wire JSON of a response so the recorded value deserializes back
into an equal
MessageResponse. Built by hand because the response type is deserialize-only insalvor-llm. - sha256_
hex - Lowercase hex of the SHA-256 digest of
bytes. - usage_
of - The
TokenUsagea completion records forresponse: its input and output counts, each narrowed withclamp_tokens. This is the exactusagefield aModelCallCompletedcarries. - validate_
against_ schema - Validates
inputagainst the structural subset ofschemadocumented at module level. - validate_
extension_ input - Validates a resume input against the budget-extension shape documented
at module level. Applied by
Runtime::resumewhen the run parked on a budget crossing, before the input is recorded. - validate_
labels - Checks
labelsagainst the bounds documented at module level.
Type Aliases§
- ClockFn
- The injected clock: called once per persisted event (for the envelope
timestamp) and once per live
RunCtx::nowobservation. - Random
Fn - The injected random source: called once per live
RunCtx::randomobservation, returning 64 raw bits.