Parent
Part of meta-issue #325 (expand LLM provider catalog). Architectural decision to land in core (not separate package) is documented there.
Scope
Add Grok / xAI as a registered LLM backend. xAI's chat-completions endpoint is OpenAI-compatible (POST https://api.x.ai/v1/chat/completions with OpenAI request/response shape), so implementation is a thin factory over atomic_agents/llm/openai_compat.py mirroring moonshot.py.
Implementation
atomic_agents/llm/grok.py (new file, ~50 LOC)
"""GrokLLMBackend factory over OpenAICompatibleLLMBackend.
xAI's chat-completions API is OpenAI-shape with base URL https://api.x.ai/v1
and model strings grok-2, grok-2-mini, etc. (catalog at impl time pulled
from xAI docs). Mirrors moonshot.py's factory pattern.
"""
from .openai_compat import OpenAICompatibleLLMBackend, OpenAICompatibleConfig
GROK_BASE_URL = "https://api.x.ai/v1"
GROK_PROVIDER_NAME = "grok"
# Model catalog as of impl date. Update when xAI catalog changes.
GROK_MODEL_CATALOG = ("grok-2", "grok-2-mini", "grok-3", "grok-3-mini")
def make_grok_backend(api_key: str) -> OpenAICompatibleLLMBackend:
"""Construct a Grok backend with xAI base URL + catalog."""
return OpenAICompatibleLLMBackend(
config=OpenAICompatibleConfig(
base_url=GROK_BASE_URL,
api_key=api_key,
provider_name=GROK_PROVIDER_NAME,
model_catalog=GROK_MODEL_CATALOG,
)
)
Registration in atomic_agents/llm/__init__.py
Add to the _register_default_backends() block (mirroring make_moonshot_backend). Resolve the key via _llm._get_grok_key(); if no key, skip registration silently (matching existing pattern for OpenAI / Moonshot).
atomic_agents/_llm.py — key resolver
def _get_grok_key() -> str:
return _get_key(
env_vars=["ATOMIC_AGENTS_GROK_KEY", "XAI_API_KEY", "GROK_API_KEY"],
keychain_name="atomic-agents-grok",
config_key="grok",
)
(XAI_API_KEY listed first as the canonical xAI env-var name; GROK_API_KEY accepted for operator convenience.)
atomic_agents/_costs.py — pricing table
# Grok / xAI pricing as of impl date. Source: https://x.ai/api (pricing page).
"grok/grok-2": {"input": 2.00, "output": 10.00}, # USD per 1M tokens
"grok/grok-2-mini": {"input": 0.20, "output": 1.00},
"grok/grok-3": {"input": 3.00, "output": 15.00},
"grok/grok-3-mini": {"input": 0.30, "output": 1.50},
Verify exact numbers at impl time; xAI pricing has moved. Spec/31 amendment should note "pricing snapshot date" so future implementers know when to refresh.
Doctor integration
atomic_agents/doctor.py::check_provider_keys extends to iterate registered backends. Each registered backend's backend_id resolves to a doctor row:
- PASS: backend registered + key resolves
- WARN: backend not registered but env var detected (operator may have a stale config)
- FAIL: backend registered but key resolution raises
Mirrors the existing check_provider_keys shape for Anthropic / OpenAI / Moonshot. No new doctor primitive; extend the existing iteration.
Spec/31 amendment
Add GrokLLMBackend (via the make_grok_backend factory) to §"Reference implementations". Add a one-line note in §"Module layout" pointing at grok.py. Add the Grok pricing source + snapshot date in §"Default model" (or a new §"Pricing snapshot dates" subsection if pricing maintenance becomes a recurring concern).
Conformance suite parametrization
tests/test_llm_protocol_conformance.py should already be parametrized across registered backends. Verify the parametrization picks up Grok automatically once registered. Add a Grok-specific smoke test using respx or similar HTTP mock to verify the base URL is right + the request shape matches xAI's expectation.
Acceptance criteria
Out of scope
- Grok-vision / image input (TBD whether xAI exposes; defer to a follow-up if needed).
- Grok streaming (reserved Protocol per spec/31).
- xAI tool-use quirks beyond what
OpenAICompatibleLLMBackend already handles.
References
Parent
Part of meta-issue #325 (expand LLM provider catalog). Architectural decision to land in core (not separate package) is documented there.
Scope
Add Grok / xAI as a registered LLM backend. xAI's chat-completions endpoint is OpenAI-compatible (
POST https://api.x.ai/v1/chat/completionswith OpenAI request/response shape), so implementation is a thin factory overatomic_agents/llm/openai_compat.pymirroringmoonshot.py.Implementation
atomic_agents/llm/grok.py(new file, ~50 LOC)Registration in
atomic_agents/llm/__init__.pyAdd to the
_register_default_backends()block (mirroringmake_moonshot_backend). Resolve the key via_llm._get_grok_key(); if no key, skip registration silently (matching existing pattern for OpenAI / Moonshot).atomic_agents/_llm.py— key resolver(
XAI_API_KEYlisted first as the canonical xAI env-var name;GROK_API_KEYaccepted for operator convenience.)atomic_agents/_costs.py— pricing tableVerify exact numbers at impl time; xAI pricing has moved. Spec/31 amendment should note "pricing snapshot date" so future implementers know when to refresh.
Doctor integration
atomic_agents/doctor.py::check_provider_keysextends to iterate registered backends. Each registered backend'sbackend_idresolves to a doctor row:Mirrors the existing
check_provider_keysshape for Anthropic / OpenAI / Moonshot. No new doctor primitive; extend the existing iteration.Spec/31 amendment
Add
GrokLLMBackend(via themake_grok_backendfactory) to §"Reference implementations". Add a one-line note in §"Module layout" pointing atgrok.py. Add the Grok pricing source + snapshot date in §"Default model" (or a new §"Pricing snapshot dates" subsection if pricing maintenance becomes a recurring concern).Conformance suite parametrization
tests/test_llm_protocol_conformance.pyshould already be parametrized across registered backends. Verify the parametrization picks up Grok automatically once registered. Add a Grok-specific smoke test usingrespxor similar HTTP mock to verify the base URL is right + the request shape matches xAI's expectation.Acceptance criteria
atomic_agents/llm/grok.pyshipped withmake_grok_backendfactory._register_default_backends()skips silently when no Grok key resolves._get_grok_key()resolver in_llm.pywith the 3-env-var ladder._costs.py.check_provider_keysenumerates Grok with PASS/WARN/FAIL.make_grok_backend("test-key").call(messages=[...])constructs a well-formed xAI request (verified via HTTP mock).--providerenum lands; not a blocker for this issue.Out of scope
OpenAICompatibleLLMBackendalready handles.References
atomic_agents/llm/moonshot.py(closest existing analog).