Skip to content

Groq provider

Standalone — usable in any Node project, no @warlock.js/core required.

@warlock.js/ai-groq is the Groq provider adapter for @warlock.js/ai — open models (Llama, GPT-OSS, DeepSeek-R1 distill) served fast on Groq’s LPU hardware. Groq speaks the OpenAI Chat Completions protocol, so this package is a thin wrapper over @warlock.js/ai-openai: it owns an internal OpenAISDK pointed at Groq’s endpoint (https://api.groq.com/openai/v1) and delegates the wire work, while injecting Groq’s own capability inference and default pricing.

Terminal window
npm install @warlock.js/ai @warlock.js/ai-groq
import { GroqSDK } from "@warlock.js/ai-groq";
const groq = new GroqSDK({
apiKey: process.env.GROQ_API_KEY!,
});

baseURL defaults to https://api.groq.com/openai/v1 (Groq’s OpenAI-compatible endpoint) — override only to route through a proxy or gateway. provider defaults to "groq" and flows through to ModelContract.provider, AgentReport.model.provider, and logs. Every upstream OpenAI ClientOptions field (timeout, maxRetries, defaultHeaders, fetch, …) is forwarded verbatim to the inner client.

const model = groq.model({ name: "llama-3.3-70b-versatile" });
// Pass to any @warlock.js/ai agent / workflow / supervisor.

name is the Groq-hosted open-weight id (the upstream name), NOT an OpenAI id. Any current Groq model id works — the list below is curated, not an allow-list:

groq.model({ name: "llama-3.3-70b-versatile" }); // flagship general-purpose text
groq.model({ name: "llama-3.1-8b-instant" }); // fastest / cheapest small text
groq.model({ name: "openai/gpt-oss-120b" }); // vision + reasoning auto-true
groq.model({ name: "deepseek-r1-distill-llama-70b" }); // reasoning auto-true

The whole reason this wrapper exists: Groq’s ids aren’t OpenAI’s, so the OpenAI adapter’s prefix inference would never fire. GroqSDK carries its own name lists:

  • Vision — auto-inferred true for gpt-oss, llama-4, and llama-3.2-*-vision; false otherwise (e.g. llama-3.3-70b-versatile, llama-3.1-8b-instant).
  • Reasoning — auto-inferred true for gpt-oss, deepseek-r1 / deepseek-r1-distill, qwq, and qwen3; false otherwise. Drives whether reasoning_effort is forwarded.
  • Structured output — true; Groq accepts OpenAI-style response_format.
  • Prompt caching — inherited from the inner OpenAI adapter (true; read-side cachedTokens accounting).

An explicit flag always wins over inference:

groq.model({ name: "some-custom-llama", vision: true }); // force on for an unlisted multimodal id
groq.model({ name: "openai/gpt-oss-120b", reasoning: false }); // pin off

Reasoning models accept a discrete effort knob, forwarded by the inner adapter as OpenAI’s reasoning_effort:

const model = groq.model({ name: "deepseek-r1-distill-llama-70b" }); // reasoning auto-true
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
  • reasoning.effort ("low" | "medium" | "high" | "none") maps verbatim.
  • reasoning.maxTokens has no Chat Completions equivalent and is ignored (same as the OpenAI adapter).
  • When capabilities.reasoning is false (e.g. llama-3.3-70b-versatile), the option is dropped — never sent as an unsupported param.

pricing is a registry keyed by model name, rates in USD per 1,000,000 tokens (input, output, optional cachedInput). The adapter ships built-in default rates (GROQ_DEFAULT_PRICING) as the final fallback, taken from Groq’s model list, fetched 2026-10-17: openai/gpt-oss-120b, openai/gpt-oss-20b, openai/gpt-oss-safeguard-20b and qwen/qwen3.8-27b. Cached input is 50% of the input rate on the gpt-oss models — the only ones Groq caches, automatically and with no write charge. The Llama models have no public price (“Enterprise – Contact Sales”), so they are unpriced unless you pass a rate:

import { GroqSDK } from "@warlock.js/ai-groq";
const groq = new GroqSDK({
apiKey: process.env.GROQ_API_KEY ?? "",
pricing: {
"llama-3.3-70b-versatile": { input: 0.59, output: 0.79 }, // your contract rate
},
});
// Or per model, overriding the SDK entry:
const model = groq.model({
name: "llama-3.1-8b-instant",
pricing: { input: 0.05, output: 0.08 },
});

Resolution at model() time: per-model pricing > SDK pricing[name] > GROQ_DEFAULT_PRICING > undefined (no cost computed).

Every response reports token usage (with cachedTokens inside input, inputIncludesCache: true) — on model.complete() and the streaming done chunk too, with usage.cost when priced. Groq takes no cache hint, so promptCacheKey is never sent. Need an offline estimate before a call? groq.count(text) returns a fast character-heuristic approximation — good for budgeting and quota guards, not for billing.

An overloaded endpoint (HTTP 503) surfaces as ProviderOverloadedError (code: "PROVIDER_OVERLOADED", retryable: true); every provider error carries status, retryable and billed (false for 401 / 402 / 403, otherwise "unknown").

Structured output and streaming are inherited unchanged from @warlock.js/ai-openai: a responseSchema maps to response_format: json_schema (strict) when the schema is a proper root object, else loose json_object; model.stream() drains the streaming Chat Completions response and yields delta / tool-call / done chunks with include_usage on. Raw errors are wrapped into the typed @warlock.js/ai AIError hierarchy by the inner adapter (dispatch keys on status + code).

For the full wire-level surface — it is identical here — see the OpenAI provider page and the warlock-js-ai-groq skill.

  • OpenAI provider — the wrapped adapter; full wire / streaming / structured-output detail.
  • Mistral provider — another OpenAI-compatible wrapper, for the Mistral model families.
  • @warlock.js/ai — passing the model into ai.agent({ ... }).

This adapter delegates Chat Completions to the OpenAI adapter, so providerOptions.openai.body adds native Chat request fields. Other provider keys are ignored. Plain-object fields merge one level deep with neutral options; caller-provided keys win, while arrays, scalars and null replace the field. The OpenAI adapter’s protected conversation, tool and transport fields remain protected here too. Send only fields supported by this provider; do not reuse OpenAI-only bodies across a mixed-provider fallback chain.

Models from this adapter have no native countTokens method. Check model.countTokens before using an optional native counting capability; sdk.count(text) is a separate offline estimate.