Call Params
Every field accepted by call(), cachedCall(), and their defaults
call() takes a single CallParams<T> object. userContent is the only required field; everything
else is optional or inherits a default.
const result = await llm.call({
systemPrompt: 'You are a helpful assistant.',
userContent: 'Summarize this text.',
temperature: 0.7,
maxTokens: 500,
});cachedCall uses the same call shape, except reserveUsage and refundUsage belong at the
cachedCall top level. Its top-level signal controls that caller's cancellation lifecycle.
jsonMode/schema selection works the same way for cachedCall's return type as it does for
call.
Content
userContent
string | ContentBlock[], required. The current user message. Supports text and image
blocks. See Multimodal Input.
systemPrompt
string, optional. The system message. Omit to use the provider's default behavior.
history
ConversationTurn[], optional. Prior conversation turns, excluding userContent. See
Multi-turn Conversations.
For multimodal input, pass an array of text and image blocks:
const result = await llm.call({
userContent: [
{
type: 'text',
text: 'Describe this image.',
},
{
type: 'image',
mimeType: 'image/png',
data: imageBase64,
},
],
});Supported image MIME types are image/png, image/jpeg, image/gif, and image/webp. Image data
is base64-encoded without a data: URL prefix.
history must follow VernLLM's conversation ordering rules. Invalid history fails with
LLMError('validation') before a provider request is made. See Multi-turn Conversations.
Tool calling
tools
ToolDefinition[], optional. Tools the model may call. Changes the return type to
CallWithToolsResult<T>. See Tool Calling.
toolChoice
'auto' | 'none' | 'required' | { name: string }, optional. Defaults to 'auto' when
tools is set. 'none' narrows the return type further, to ContentResult<T> instead of
CallWithToolsResult<T> — see the callout in Tool Calling.
tools must not be an empty array. toolChoice requires tools, and { name } must reference a
declared tool.
VernLLM validates returned tool calls. Contract failures such as unknown_tool and
duplicate_tool_call_id are surfaced as LLMError('api') values with a machine-readable code.
See Tool Calling for the complete workflow and Error Handling for failure behavior.
Streaming
stream
boolean, default false. Returns { chunks, finalResult } when true. See Streaming.
chunkIdleTimeoutMs
number, optional. Overrides the instance value for stream: true. Pass 0 or Infinity to
disable the idle timeout for this call. See Per-chunk idle timeout.
stream: true combines with tools and schemas. See the streaming overload note for the TypeScript overload requirement.
Model & generation
| Field | Type | Default | Notes |
|---|---|---|---|
model | string | Instance model | Overrides the model for this call. |
temperature | number | null | Instance defaultTemperature, otherwise 0.2 | Pass null to omit temperature and use the provider's default. |
maxTokens | number | Instance defaultMaxTokens, otherwise 1000 | Maximum response length. |
reasoningEffort | 'minimal' | 'low' | 'medium' | 'high' | null | Instance defaultReasoningEffort, otherwise not sent | Native on OpenAI compatible clients, converted on others. See below. |
budgetTokens | number | null | Instance defaultBudgetTokens, otherwise not sent | Native on Anthropic and Gemini, except on adaptive-only Claude models, where it's converted into Anthropic's own effort parameter instead (see below). Converted on OpenAI compatible clients, forwarded only for Claude models on Bedrock. |
Pass null to either field to explicitly skip an instance-level defaultReasoningEffort/
defaultBudgetTokens for one call, the same way temperature: null opts a call out of
defaultTemperature above. Omitting the field entirely (undefined) defers to the instance
default instead, null is the only way to say "not for this call" once an instance default is
set. Useful for a call using a forced toolChoice, since Anthropic rejects any reasoning
alongside one, see the warning below.
Anthropic rejects budgetTokens/reasoningEffort combined with a toolChoice that forces tool
use (a specific tool, or 'required'), a call that tries throws LLMError('invalid_params')
before any request is sent, both on fromAnthropic and on Claude models called through
fromBedrock. This also applies implicitly whenever jsonSchema forces a single synthetic tool
call to emulate structured output on a model without native support, even with no toolChoice of
your own set. Use toolChoice: 'auto' (or omit it), or pass budgetTokens: null/
reasoningEffort: null for that specific call.
Claude Opus 4.7 and later, Claude Opus 5, and every Claude 5 tier model (Sonnet 5, Fable 5,
Mythos 5) reject temperature (and top_p/top_k) on a non-default value with a 400 error.
Omit temperature entirely for those models, or pass null, and describe the desired behavior
in the prompt instead.
Separately, Anthropic rejects temperature alongside any thinking mode, manual or adaptive,
on every model that supports thinking at all, not just the models above. fromAnthropic and
fromBedrock both drop temperature from the request automatically whenever budgetTokens or
reasoningEffort is set, so you don't need to handle this yourself, it's called out here so the
omission isn't a surprise if you're inspecting the request.
Each adapter reads its own native field first. Anthropic and Gemini use budgetTokens directly.
OpenAI compatible clients use reasoningEffort directly. Bedrock forwards a budget only for Claude
models, other Bedrock models get neither.
When only the other field is set, it is converted using a shared table: minimal is 1024,
low is 4096, medium is 16000, high is 32000. A value strictly between two tiers rounds up to
the next tier it's still <=, e.g. 4097 lands in medium, not low. This is a reasonable guess,
not a provider guarantee. Set budgetTokens directly for a precise number on a specific model.
Claude Opus 4.7 and later, and every Claude 5 tier model, also reject manual, budget-based
thinking (thinking: { type: 'enabled', budget_tokens }) outright, with a 400 error, separate
from the temperature restriction above. fromAnthropic and fromBedrock detect these models and
send adaptive thinking plus Anthropic's own effort parameter (low/medium/high/xhigh/
max) instead, converting reasoningEffort/budgetTokens onto the nearest effort level
automatically. xhigh and max have no equivalent in VernLLM's four-tier reasoningEffort and
aren't reachable through this conversion.
On Gemini 2.5 series models, 0 disables thinking and -1 requests automatic budgeting via
thinkingConfig.thinkingBudget. Both are passed through unchanged rather than run through the
conversion table above.
Gemini 3 series models use a different control, thinkingConfig.thinkingLevel
(MINIMAL/LOW/MEDIUM/HIGH), not thinkingBudget. fromGemini detects Gemini 3 and later
models (a version threshold, so 3.1, 3.5, and every future 3.x release are covered automatically)
and sends thinkingLevel there instead. reasoningEffort maps onto it directly, no conversion
table needed, VernLLM's four tiers line up exactly with Gemini's own four levels. budgetTokens
alone is converted to the nearest tier first, through the same table used everywhere else, then
mapped onto thinkingLevel. 0 and -1 have no thinkingLevel equivalent and both collapse to
MINIMAL, the closest available approximation of "off", which several Gemini 3 models can't be
fully disabled on anyway, MINIMAL still requires thought signatures rather than genuinely
turning thinking off, unlike thinkingBudget: 0 on Gemini 2.5. Pass thinkingLevelModels as part
of fromGemini's second argument to mark an additional model as using thinkingLevel, additive
over the built-in threshold, same shape as reasoningEffortTokens above.
The conversion table itself is overridable per adapter instance, not just per call. Pass
reasoningEffortTokens as part of the second argument to fromAnthropic, fromGemini,
fromOpenAICompatible, or fromBedrock:
const client = fromAnthropic(anthropic, {
reasoningEffortTokens: { high: 64000 }, // only `high` changes, other tiers keep the default
});Only the tiers you list are changed, any tier left out keeps its built-in value. This affects every
call through that adapter instance, in whichever conversion direction that adapter actually needs
(Anthropic and Gemini convert reasoningEffort into a budget; OpenAI compatible clients convert
budgetTokens into a tier; Bedrock converts reasoningEffort into a budget for Claude models).
See Per-call Overrides for model and generation overrides.
JSON & validation
jsonMode
boolean, default true (false when tools is set). Parses the response as JSON when
enabled. jsonSchema forces it back to true. jsonMode: true returns JsonValue; jsonMode: false returns string.
jsonSchema
JsonSchemaSpec, optional. Enables provider-native JSON Schema structured output and implies
jsonMode: true. See Structured Output.
schema
Zod or Zod-compatible schema, optional. Validates parsed JSON client-side and infers T. See
Structured Output.
schema only runs after JSON parsing. Setting jsonMode: false with schema fails validation
before the provider request instead of returning an unvalidated string.
Provider-specific jsonSchema and tools compatibility is documented in Combining with Tools.
Request lifecycle
requestId
string, optional. Defaults to an auto-generated UUID and is included in usage and relevant
observability events.
signal
AbortSignal, optional. Cancels the current call, including an in-flight attempt or pending
retry delay. See Cancellation.
meta
{ current?: CallMeta }, optional. With fallback, reports which target answered after
call() resolves. Ignored for streaming calls. See
Knowing which target answered.
For cachedCall, each caller has its own cancellation signal. Aborting one coalesced caller does
not cancel the shared operation for other callers.
Usage metering
reserveUsage
Optional. Runs before the logical request. Throwing stops the call with
LLMError('quota_exceeded'). Retries do not invoke it again.
refundUsage
Optional. Runs when a successful reservation must be returned because the call ultimately fails.
These hooks are application supplied. VernLLM manages their lifecycle but does not define quota or billing policy.
For cachedCall, reserveUsage and refundUsage belong at the top level rather than inside the
nested call object. call's type doesn't include them there at all, so a normally-typed caller
gets a compile error rather than discovering the mistake later. A caller that bypasses the type
system and sets them inside call anyway hits LLMError('validation') at runtime instead of
having them silently ignored.
Type parameter
call<T>() is generic over the parsed result:
- With
schema,Tis inferred from the schema. - With
jsonMode: trueand noschema,Tdefaults toJsonValue. - With
jsonMode: false,Tdefaults tostring. - Without any of these,
Tdefaults tounknown.
// result: { name: string; skills: string[] }
const result = await llm.call({
userContent: resumeText,
schema: CandidateSchema,
});
// result: JsonValue
const parsed = await llm.call({
userContent: 'Hello',
jsonMode: true,
});
// result: string
const raw = await llm.call({
userContent: 'Hello',
jsonMode: false,
});