A request hash identifies the question asked. It keys on provider, model, the
canonical role/content turns, and the generation parameters
(model_params minus transport and internal knobs), plus any explicit tool,
response-format, or schema signature. It is the key the archive layer uses for
deduplication and replay, and the value to record when reproducibility of a
specific call matters.
Usage
llm_request_hash(
config = NULL,
messages = NULL,
provider = NULL,
model = NULL,
tools = NULL,
response_format = NULL,
schema = NULL,
extra = NULL
)Arguments
- config
An
llm_config()(itsprovider,model, and the answer-relevant entries ofmodel_paramsare used), orNULLto supplyprovider/modeldirectly and the generation parameters throughextra$params.- messages
The messages or prompt sent. A character scalar, a named character vector of roles, or a list of
list(role=, content=)turns – whatever was passed tocall_llm(). Canonicalized to a provider-neutral list of role/content turns before hashing, so the message shape (a bare string vs a named vector vs a turn list) does not change the hash; only the roles and text do.- provider, model
Provider and model ids. Taken from
configwhen it is given; supply them directly (withextra$params) when hashing a call read from an audit log, where there is noconfig.- tools
Optional tool definitions (as passed to
call_llm()/bind_tools()). Their signature is included when present.- response_format
Optional response-format directive (e.g. a JSON-mode flag or object) that constrains the output.
- schema
Optional JSON Schema used for structured output.
- extra
Optional named list folded into the hashed object. The log side passes the call's generation parameters here as
extra$params(a named list), which are consumed into the param key exactly as a config'smodel_paramswould be; a config, when given, takes precedence overextra$params. Any other entries are hashed as-is, to add identity-relevant fields the standard arguments do not cover.
Value
A 64-character lowercase SHA-256 hex string (see llm_hash()).
Details
The hash is built over a canonical object and passed to llm_hash(), so it
inherits that convention: construction order and S3 class do not matter, and
the value does not depend on R's serialization format. API keys and volatile
fields (timestamps, request ids) are never part of the input. Transport and
internal knobs in model_params (see the source for the full list – e.g.
req_builder, response_modifier, timeout, api_url, max_tries,
request_modifier, cache, use_responses_api, vertex) are excluded,
since they change how a call is issued, not what is asked.
Scope
The hash keys on the canonical turns and generation parameters. It is designed
so a call described by an llm_config() and the same call read from a logged
provider request body agree for the common chat/completions path. It does
not attempt to reconstruct every provider's exact translated body: calls
that differ only in features outside this key – the OpenAI Responses API
(input/instructions), full tool-call transcripts, or provider-injected
defaults – may hash the same across the config and log sides. The archive
layer's collision detection is the backstop for those cases: it flags when one
replay key gathers records whose stored request hashes disagree.
Examples
cfg <- llm_config("openai", "gpt-4.1-mini", temperature = 0)
h1 <- llm_request_hash(cfg, "Hello")
# message order/content matters; temperature matters:
cfg2 <- llm_config("openai", "gpt-4.1-mini", temperature = 1)
identical(h1, llm_request_hash(cfg2, "Hello"))