Four providers, one call shape
Anthropic, any OpenAI-compatible server, the Claude CLI, and in-process llama.cpp. Swapping is a one-line change.
One narrow thing, deliberately:
(system, user, schema, temperature) -> JSONNo streaming. No multi-turn. No tool loops. If you need a conversation, this is the wrong package — that is worth knowing in the next thirty seconds rather than after an afternoon. Widening the provider contract requires an ADR, because every consumer pays for surface area added here.
Four providers, one call shape
Anthropic, any OpenAI-compatible server, the Claude CLI, and in-process llama.cpp. Swapping is a one-line change.
Validation with a retry
Ajv-checked against your schema. One retry, then an honest failure — never a throw, never a coerced value.
A cache you control
Content-addressed, human-inspectable on disk. You compose the key, because only you know what should invalidate an entry.
Cost that never guesses
An unknown model prices as undefined, not as a number someone made up. Budget gates depend on
that distinction.
engines — an older version gets an EBADENGINE warning from
npm, not a refusal, and a second warning from the library on
first use.require() fails with ERR_PACKAGE_PATH_NOT_EXPORTED; from CommonJS,
use a dynamic import.npm install @hawkeyexl/inferenceEverything exports from the package root.