Uncaught API errors print their message again. The parsed provider payload
now travels on the condition as response_body; the previous field name,
body, is reserved by rlang for message bullets, and storing a list there
made top-level display fail with "body field must be a character vector
or a function" while hiding the provider's reason. Error headers now show
the raising call instead of the internal constructor, and the
model-params tip appears only for parameter errors, with the flagged
parameter named when the provider identifies one.
The audit log keeps its documented contract when include_messages = FALSE: generation parameters now land in a parameters field (the
request body minus its message-bearing fields), where previously nothing
of the body survived. A failed log write warns once and is counted;
llm_log_status() reports the count, since a silently unlogged call
defeats an audit log. The llm_hash() documentation states its
portability claim as the stable canonicalization it is (hash schema v1)
rather than as a promise about all machines forever.
API failures are classified against a catalog of each provider's documented
error codes (R/errors_catalog.R) rather than by HTTP status alone. A new
llmr_api_billing_error class marks empty balances and spend caps, and
call_llm_robust() fails fast on it instead of retrying: OpenAI's
insufficient_quota (a 429) is an account block, while DashScope's
same-named code is throttling, and Moonshot separates quota, rate limit,
and overload behind one 429. Ollama's bare-string errors and Voyage's
detail field now surface as the reason instead of falling back to raw
JSON, and the condition's code field carries the provider's code, type,
or status string when one is sent.
method argument is gone, and ten non-core helpers
are now internal.enable_structured_output()'s local bookkeeping
fields no longer enter the identity.llm_batch_submit(state_path = ) refuses to persist a job whose config
carries a literal API key; environment-variable handles round-trip as
before.json_output argument of call_llm_par() and the inert
.fields argument of the chat session's $send_structured() and
$send_tags(). llm_methods_text() is deprecated in favor of report()
and will be removed once the current 'LLMRagent' release no longer calls it."openrouter": chat, streaming, and structured output through
OpenRouter's OpenAI-compatible aggregator (model ids like
"openai/gpt-4o-mini"; key from OPENROUTER_API_KEY). OpenRouter has no
embeddings or batch API; its optional attribution headers can be set through
the req_builder hook.A bug-fix release; all changes are backward compatible.
llm_hash() no longer depends on the collation locale, so the same object
hashes identically on every machine; hashes recorded under the C locale are
unchanged.{column} reference) now fill every row; previously
rows 2..n were sent with NA content and rejected by providers.llm_mutate() appends its generated columns again (instead of moving them to
the front), and .before/.after now work on the embedding, structured,
tag, and row-batched paths.llm_usage() and llm_failures() work on llm_mutate_structured() and
llm_mutate_tags() results; config-side and log-side request hashes agree
after provider parameter renames.req_builder hook and the request timeout. Assorted smaller
fixes; see the commit log.call_llm_par(.request_hash =),
llm_add_request_hash(), llm_log_active(), llm_tool_signature(), and
llm_uuid().llm_agreement() gains ordinal and interval Krippendorff's alpha
(metric =); the nominal default is unchanged.anes_2024_personas: 100 participant profiles derived
from the ANES 2024 public release, the shared persona dataset of the LLMR
family.llm_persona_split(),
llm_persona_overview(), llm_persona_dictionary(),
llm_persona_demographic_fields(), llm_validate_persona_frame().transcript_as_messages() and ensure_alternating_messages(): build a
provider-safe, role-flipped message array from a multi-speaker transcript
(own turns become assistant, others become labeled user turns)..batch_size -> .rows_per_prompt, and kin);
the word "batch" is now reserved for the asynchronous provider Batch API.llm_log_read(): parse a JSONL call log into records plus a per-record
manifest with record and request hashes.llm_request_hash() canonicalizes message shape and keys on all generation
parameters, so a logged call and its config hash identically.reset() generic.llm_response_record() (one-row response record; a
failed call is a row, never a dropped call) and llm_request_hash() (stable
identity for a call).diagnostics() and report(), implemented by
the LLMR method packages.llm_batch_submit(),
llm_batch_status(), llm_batch_fetch(), llm_batch_cancel() (OpenAI,
Groq, Anthropic, Gemini).llm_log_enable()), a draft methods
paragraph (llm_methods_text()), and replication with agreement statistics
(llm_replicate(), llm_agreement()).llm_tool(), call_llm_tools()) and streaming
(call_llm_stream()).llm_logprobs()), canonical seed,
model_version and thinking on every response, prompt caching, and cost
estimates from a user-supplied price_table.llm_preview(): render exactly what a call would send, and flag problems,
without any API call.llm_usage() and llm_failures(): outcome counts, token totals, and
per-row failure listings for any result frame.NA, not 0; a bare environment-variable
name passed as api_key is always treated as a reference.llm_par_resume() re-runs only the failed rows; JSON array recovery and
embedding-dimension fixes..tags on llm_mutate(), plus
llm_mutate_tags(), llm_fn_tags(), and the tag parsers.llm_mutate() shorthand (answer = "{question}") and .structured = TRUE.call_llm() returns an llmr_response object; as.character(x) extracts
the text.llm_mutate().