Skip to main content

Versioned formats

Published Rust APIs follow the crate release's semantic version. Persisted documents carry an explicit envelope, and an old or unknown version refuses rather than being coerced.

FormatCarried by
llm.turn/3Persisted neutral requests without controls
llm.turn/4Persisted neutral requests carrying controls (thinking, parallel tool calls, advisory hints)
llm.outcome/4Persisted neutral outputs
llm.binding/1Provider/account/endpoint/model declarations
llm.catalog/1TOML routing catalogs
llm.routes/1YAML model routes: endpoints by base URL, protocol and secret reference, routes as <endpoint>/<model-id>; expands into llm.catalog/1 (guide)
llm.provider-description/1TOML provider descriptions: inference URL template, wires, authentication and pinned control-plane operations
llm.prices/1Price books, TOML or JSON
llm.usage/2Attributed usage observations; refuses v1
llm.cost/2Derived accounting reports
llm.budget/1The SQLite budget journal

These versions ship in llm's releases. They are not yet a published contract with a compatibility policy (planned, see Status): until it is, a release may change a version, and the change is named in the changelog.

What a version is, and is not​

An unversioned Rust value is an in-process value. It is not a claim of a stable vendor wire format, and a derived inspection view or an in-process command is not an independently versioned wire.

An unsupported addition needs a version change before it is accepted. Nothing is silently widened.

Bounds​

InputBound
Routes document2 MiB, as a catalog
Price book, observations1 MiB and 4096 entries each
Provider description64 KiB
Provider-description instance name1 through 48 bytes of [a-z0-9]
Price-book source description2048 bytes, non-blank Unicode, no control characters
Secret adapter bindings4096 per adapter
Concurrent blocking OS credential reads8
Local secret file read1 MiB
Budget outstanding reservations1 through 65,536
Moneyu64 nanounits; max 18446744073.709551615 currency units

Provider descriptions​

An llm.provider-description/1 document is what every consumer reads about one provider. ProviderDescription::parse in llm-providers refuses unknown fields in every table.

TableCarries
[provider]id and category
[inference]base_url_template, protocols (non-empty, no repeats), auth_kind (anonymous, bearer or api-key, with api_key_header exactly when api-key)
[control_plane], optionalopenapi_url (HTTPS), document_sha256 (64 lower-case hex digits), server_url (HTTPS), auth_kind
[control_plane.operations]the operationId of create_instance, list_instances, get_instance and delete_instance, all four distinct

The template holds {instance} exactly once, inside the host's first label, and a fixed domain follows that label, so no instance can name a single-label host. inference_base_url(instance) accepts only 1 through 48 bytes of [a-z0-9], so an instance cannot change the host, the path or the scheme. subscription-oauth is refused: a description is API access. Parsing does no I/O. It never fetches the OpenAPI document and never checks the digest against it; that is the reader's job.

The crate ships Runpod's description as llm_providers::descriptions::runpod(): https://{instance}-8000.proxy.runpod.net/v1/ serving Chat Completions, Messages and Responses with a bearer key, and the Runpod REST control plane with CreatePod, ListPods, GetPod and DeletePod. These values are checked against fixtures only. No live Runpod pod or control-plane call has qualified them.

Identity digests​

Two digests appear in output and both are SHA-256 over validated canonical data:

  • Configuration digest identifies a validated routing catalog. Row order and equivalent decimal spellings do not change it; a changed declared fact does.
  • Binding revision hashes one complete validated binding — endpoint URL, upstream model, auth reference and capabilities. Secret bytes and credential generations are excluded, so rotating the same reference does not invalidate a continuation, while repointing an id does.

The capabilities output_streaming (default true) and input_during_output (default false) are left out of the canonical data at their defaults, so a document written before those fields keeps both digests.

A local SecretVersion is a third digest, but it is redacted, non-serializable and must never be logged or used as a public fingerprint.