Skip to main content
LlmClient is the provider-agnostic model client at the heart of Anvil’s agent system. It owns driver dispatch, transient retries, fallback chains, cost accumulation, and structured-output enforcement — so your agent handlers call generate, generateObject, or stream without worrying about provider-specific details. Import it from anvil/llm:

Constructor

ModelDriver[]
required
One or more driver instances that handle model calls. Each driver advertises which models it supports via driver.supports(model). At least one driver is required. Add multiple drivers to cover different model families.
string
The model used when a generate, generateObject, or stream call omits the model field. If omitted here too, the call throws unless the request specifies a model explicitly.
string[]
An ordered list of model IDs to try after the primary model fails with a transient error (RetryableModelError). The client walks the list left-to-right, retrying maxRetries times per model before advancing. Each fallback model must be supported by one of the registered drivers.
number
Attempts per model before moving to the next in the fallback chain. Defaults to 2.
number
Base backoff delay in milliseconds between retry attempts. The actual wait before each attempt is retryBaseMs * attemptNumber. Defaults to 50. Set to 0 in tests to eliminate wait time.
(event: TraceEvent) => void
Observability hook called after every model call — successful or failed. The TraceEvent carries the model name, provider, attempt number, token usage, cost, and whether the call hit the fallback chain. Use this to feed your own metrics or logging pipeline.

Drivers

Provider SDKs are optional peer dependencies loaded lazily at runtime — the Anvil kernel never pulls them in unless you instantiate the matching driver.
Requires @anthropic-ai/sdk as a peer dependency. Supports all claude-* models (e.g. claude-opus-4-8, claude-sonnet-4-5, claude-haiku-3-5). Uses the top-level system parameter and adaptive thinking when thinking: true is set on the request.

Methods

client.generate(req)

Make a single-turn model call and return the complete result.
string
The model’s text response.
string
The model ID that produced the response (may differ from the request if the fallback chain was used).
string
The provider name, e.g. "anthropic", "openai", "gemini".
{ inputTokens: number, outputTokens: number }
Token counts for this call.
number | undefined
Estimated USD cost from the built-in pricing table. undefined if pricing data for the model isn’t registered.
ToolCall[] | undefined
Tool invocations the model requested, when tools were provided and stopReason is "tool_use".

client.generateObject(req, schema, opts?)

Request structured output validated against a Zod schema. On validation failure the client automatically re-prompts the model with the validation error, up to maxRepairs times.
GenerateRequest
required
The same request shape as generate. Do not set responseFormat manually — generateObject sets it automatically from the Zod schema.
z.ZodType<T>
required
The Zod schema to validate the response against.
number
Maximum number of repair attempts after a validation failure. Defaults to 2. Each attempt re-prompts the model with the Zod error message.
string
Optional name for the JSON schema advertised to the model. Helps some providers choose a better response format.

client.stream(req)

Stream tokens from the model as they arrive. Yields StreamEvent objects.
StreamEvent
A text fragment from the model. Concatenate these to build the full response.
StreamEvent
The final event, carrying the complete GenerateResult with usage, cost, and stop reason.
Streaming does not retry mid-stream — bytes may already be on the wire. The client only falls back to the next model in the chain if the stream fails before yielding any events.

Fallback chain example

Register both Anthropic and OpenAI drivers, set Claude as the primary, and fall back to GPT-4o on transient errors:
The client tries claude-opus-4-8 up to two times. If both attempts throw a RetryableModelError (rate limit, 5xx, connection error) it moves to gpt-4o and tries that up to two times. Non-retryable errors (bad request, auth failure) stop the chain immediately.
Install only the provider SDKs you need. Adding AnthropicDriver to your drivers list does not pull in @anthropic-ai/sdk until the first request that routes through it.