Skip to main content

Crate salvor_runtime

Crate salvor_runtime 

Source
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 against RunCtx (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::builder configures model, prompt, tools, budgets, pricing; Runtime::start / Runtime::recover / Runtime::resume drive the single built-in loop. The loop is implemented entirely against the public RunCtx surface 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 now observations), 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::random returns u64); 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.
AgentBuilder
Builds an Agent:
BudgetExtensions
The accumulated budget extensions granted by recorded resume inputs. See the module docs for the JSON shape they are parsed from.
BudgetObservations
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.
FailureTracker
Tracks consecutive identical tool failures and produces the model-facing content for each dispatch result.
ModelTurn
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.
ToolFailure
A tool failure as recorded in (and decoded from) a completion output.

Enums§

AgentBuildError
Why an agent could not be built.
LoopOutcome
How one drive of the loop ended: it produced a final output, or it parked and the process should stop driving it.
ParkReason
Why a run parked instead of completing.
Resumption
What RunCtx::await_resume produced.
RunOutcome
How a drive of a run ended.
RuntimeError
What can go wrong while driving a run.
ToolCallResult
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).
ToolFailureKind
Which layer of the tool dispatch produced a recorded failure. Mirrors the three salvor_tools::ToolError variants.

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_tokens sent 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 RetryPolicy allows 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_CAP characters pass through unchanged.
content_string
Renders a JSON value as the text handed to the model (an initial input or a tool_result content 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 terminal RunCompleted.
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 Display with every source() below it, separated by ": ", so the recorded message keeps the information thiserror spreads 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 --json is the escape hatch for the untruncated envelope.
event_kind
The stable kind label for one event, matching the enum variant name so it reads the same as the wire form’s kind tag.
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 in agent_def_hash and request_hash event 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 in salvor-llm.
sha256_hex
Lowercase hex of the SHA-256 digest of bytes.
usage_of
The TokenUsage a completion records for response: its input and output counts, each narrowed with clamp_tokens. This is the exact usage field a ModelCallCompleted carries.
validate_against_schema
Validates input against the structural subset of schema documented at module level.
validate_extension_input
Validates a resume input against the budget-extension shape documented at module level. Applied by Runtime::resume when the run parked on a budget crossing, before the input is recorded.
validate_labels
Checks labels against 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::now observation.
RandomFn
The injected random source: called once per live RunCtx::random observation, returning 64 raw bits.