Models and providers

from criogenai import Agent, Anthropic, AnthropicCompatible, Gemini, Groq, Ollama, OpenAI, OpenAICompatible, Qwen, Retry

Agent("openai:gpt-5-mini")  # key from OPENAI_API_KEY
Agent(Anthropic("claude-sonnet-5-5"))  # ANTHROPIC_API_KEY
Agent(Gemini("gemini-2.5-flash"))  # GEMINI_API_KEY
Agent(OpenAI("gpt-5-mini", api_key="sk-…"))  # or pass the key yourself

# Open models on fast hosts, by name: deepseek, mistral, xai, groq, cerebras,
# together, fireworks, qwen, moonshot, zai.
Agent("deepseek:deepseek-chat")  # DEEPSEEK_API_KEY
Agent(Groq("llama-3.3-70b-versatile"))  # GROQ_API_KEY
Agent(Qwen("qwen-plus", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"))  # China endpoint
Agent(AnthropicCompatible("glm-5.2", base_url="https://api.z.ai/api/anthropic", api_key="…"))

# Self-hosted: nothing leaves your network.
Agent(Ollama("llama3.2"))
Agent(OpenAICompatible("qwen3", base_url="http://gpu-box:8000/v1"))  # vLLM, LM Studio, a gateway

# Rate limits, overload and outages go to the next model.
Agent("openai:gpt-5-mini", fallbacks=[Ollama("llama3.2")], model_retry=Retry(max_attempts=4))
import { Agent, anthropic, anthropicCompatible, gemini, groq, ollama, openai, openaiCompatible, qwen } from "criogenai";

new Agent({ model: "openai:gpt-5-mini" }); // key from OPENAI_API_KEY
new Agent({ model: anthropic("claude-sonnet-5-5") }); // ANTHROPIC_API_KEY
new Agent({ model: gemini("gemini-2.5-flash") }); // GEMINI_API_KEY
new Agent({ model: openai("gpt-5-mini", { apiKey: "sk-…" }) }); // or pass the key yourself

// Open models on fast hosts, by name: deepseek, mistral, xai, groq, cerebras,
// together, fireworks, qwen, moonshot, zai.
new Agent({ model: "deepseek:deepseek-chat" }); // DEEPSEEK_API_KEY
new Agent({ model: groq("llama-3.3-70b-versatile") }); // GROQ_API_KEY
new Agent({ model: qwen("qwen-plus", { baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1" }) }); // China endpoint
new Agent({ model: anthropicCompatible("glm-5.2", { baseUrl: "https://api.z.ai/api/anthropic", apiKey: "…" }) });

// Self-hosted: nothing leaves your network.
new Agent({ model: ollama("llama3.2") });
new Agent({ model: openaiCompatible("qwen3", { baseUrl: "http://gpu-box:8000/v1" }) }); // vLLM, LM Studio, a gateway

// Rate limits, overload and outages go to the next model.
new Agent({ model: "openai:gpt-5-mini", fallbacks: [ollama("llama3.2")], modelRetry: { maxAttempts: 4 } });
use criogenai_agent::Agent;
use criogenai_providers::{Endpoint, ProviderModel};

let openai = ProviderModel::new(Endpoint::openai(key), "gpt-5-mini")?;
let claude = ProviderModel::new(
    Endpoint::anthropic(std::env::var("ANTHROPIC_API_KEY")?),
    "claude-sonnet-5-5",
)?;
let gemini = ProviderModel::new(
    Endpoint::gemini(std::env::var("GEMINI_API_KEY")?),
    "gemini-2.5-flash",
)?;
// Self-hosted: nothing leaves your network.
let local = ProviderModel::new(Endpoint::ollama(), "llama3.2")?;
let vllm = ProviderModel::new(Endpoint::vllm("http://gpu-box:8000/v1", None), "qwen3")?;

// Rate limits, overload and outages go to the next model.
let agent = Agent::builder(openai).fallback(local).build()?;
ProviderHow it is reachedKey
OpenAIResponses API (reasoning works with tools; store: false, so OpenAI keeps nothing)OPENAI_API_KEY
Anthropic (Claude)Messages API, natively (reasoning, caching)ANTHROPIC_API_KEY
Google GeminiIts OpenAI-compatible endpointGEMINI_API_KEY
OpenRouter (hundreds of models)OpenAI-compatibleOPENROUTER_API_KEY
DeepSeekdeepseek:DEEPSEEK_API_KEY
Mistral AImistral:MISTRAL_API_KEY
xAI (Grok)xai:XAI_API_KEY
Groqgroq:GROQ_API_KEY
Cerebrascerebras:CEREBRAS_API_KEY
Together AItogether:TOGETHER_API_KEY
Fireworks AIfireworks:FIREWORKS_API_KEY
Qwen (Alibaba Cloud Model Studio)qwen: (international endpoint; pass base_url for China)DASHSCOPE_API_KEY
Moonshot AI (Kimi)moonshot: (pass base_url for China keys)MOONSHOT_API_KEY
Z.ai (GLM)zai: (pass base_url for China keys)ZAI_API_KEY
Azure OpenAI and Microsoft Foundryazure:<deployment> / Azure(...) / azure(...): the resource's v1 API, Responses (or api="chat" for Foundry's other models); an API key, or Entra ID (service principal, managed identity) with tokens renewed by the engineAZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY, or AZURE_TENANT_ID + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET
Amazon Bedrockbedrock:<model id> / Bedrock(...) / bedrock(...): Claude over the Messages API, other makers' models over Chat Completions, on bedrock-runtime in your region (there is no default region). API keys only for now; IAM roles (SigV4) are plannedAWS_BEARER_TOKEN_BEDROCK + AWS_REGION
Google Vertex AIvertex:<model> / Vertex(...) / vertex(...): Gemini and Google's hosted models over the OpenAI-compatible endpoint, Claude over rawPredict, in your project and location (no defaults). Tokens from gcloud auth application-default login, the metadata server on Google Cloud, or a token you pass; service-account key files are plannedGOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION
Kaggle Model Proxy (prototypes)OpenAI-compatible; CriogenAI mints and renews the hourly proxy tokenKAGGLE_API_TOKEN or ~/.kaggle/access_token
Ollama, LM Studioollama:, lmstudio:; local, OpenAI-compatiblenone
vLLM and any OpenAI-compatible serverYour URL (a key is never sent over plain http:// to another machine unless you pass allow_insecure_http / allowInsecureHttp)optional
Any Anthropic-compatible serverYour URL: AnthropicCompatible / anthropicCompatibleoptional

Each name works as a string ("groq:llama-3.3-70b-versatile") or as a class (Groq(...) in Python, groq(...) in TypeScript). Model names go to the provider unchanged, so a new model works the day it ships. Not yet built: Bedrock with IAM roles (SigV4) and Vertex with service-account key files.

Azure OpenAI and Foundry#

The model name is your deployment name, and endpoint is the resource name (my-resource) or its URL; /openai/v1 is added for you.

from criogenai import Agent, Azure

# An API key (or AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY and "azure:gpt-5-mini")
agent = Agent(Azure("gpt-5-mini", endpoint="my-resource", api_key=key))

# No keys at all: the identity of the Azure VM or App Service this runs on
agent = Agent(Azure("gpt-5-mini", endpoint="my-resource", managed_identity=True))

# A service principal (Entra ID); tokens are obtained and renewed for you
agent = Agent(Azure("gpt-5-mini", endpoint="my-resource",
                    tenant_id=tenant, client_id=app_id, client_secret=secret))
import { Agent, azure } from "criogenai";

const agent = new Agent({ model: azure("gpt-5-mini", { endpoint: "my-resource", managedIdentity: true }) });

Foundry's models from other makers (DeepSeek, Llama, Mistral, Grok) answer only on Chat Completions: pass api="chat" / api: "chat". Checked against local test servers; not yet against a live Azure resource.

Keep your keys in the environment#

Every provider reads its key from its usual environment variable, so you can keep several side by side and pick a model by changing one string. Put them in a .env file next to your code (and add .env to .gitignore):

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=...
OPENROUTER_API_KEY=sk-or-...
from criogenai import Agent, load_env, env

load_env()                      # reads ./.env; never replaces a variable already set
print(env.status())             # {"openai": True, "anthropic": True, ...}: yes or no, never a key

fast = Agent("openai:gpt-5-mini")
careful = Agent("anthropic:claude-sonnet-5-5")
import { Agent, loadEnv, envStatus } from "criogenai";

loadEnv();                      // reads ./.env; never replaces a variable already set
console.log(envStatus());       // { openai: true, anthropic: true, ... }: yes or no, never a key

const fast = new Agent({ model: "openai:gpt-5-mini" });
const careful = new Agent({ model: "anthropic:claude-sonnet-5-5" });
  • Call load_env() / loadEnv() before you build a model; the key is read then.
  • It returns the names it set, never the values. A variable that is already set wins; pass override=True / { override: true } to replace it.
  • A missing file is fine (a deployment sets real environment variables instead); pass required=True / { required: true } to insist on it.
  • A model with no key fails at once and says which variable to set, instead of failing later with an auth error from the provider.
  • Quotes, export NAME=value, and # comments work. There is no variable expansion.
  • In Rust, pass the key you read with std::env::var to the provider.

Kaggle's model allowance (prototypes and tests)#

A Kaggle account comes with an AI-model allowance (at the time of writing $10 a day, $100 a month) for hosted models such as anthropic/claude-sonnet-5@default, google/gemini-3.6-flash, google/gemini-3.5-flash-lite, openai/gpt-oss-120b and openai/gpt-5.4-nano-2026-03-17. Which models an account may use is decided by Kaggle; a model you may not use fails with not_found and costs nothing.

from criogenai import Agent, Kaggle

agent = Agent("kaggle:google/gemini-3.6-flash")      # or Kaggle("...", api_token=...)
import { Agent, kaggle } from "criogenai";

const agent = new Agent({ model: "kaggle:google/gemini-3.6-flash" }); // or kaggle("...", { apiToken })
use criogenai_providers::KaggleModel;

let model = KaggleModel::from_env("google/gemini-3.6-flash")?;
  • Credentials, in order: a token you pass; MODEL_PROXY_URL and MODEL_PROXY_API_KEY (set in Kaggle notebooks); KAGGLE_API_TOKEN; the access_token file in KAGGLE_CONFIG_DIR or ~/.kaggle (what the Kaggle CLI writes). Create the token at kaggle.com/settings, under API.
  • CriogenAI mints the short-lived proxy token itself, renews it before it expires, and renews and retries once if the proxy refuses it. Tools and streaming work.
  • In the gateway: { provider = "kaggle", model = "google/gemini-3.6-flash" }.
  • Use it for prototypes, tests and MVPs, not production traffic: the allowance is small and meant for evaluation, there is no service guarantee, and prompts pass through Kaggle. Never send patient or customer data through it.

What every model gets#

  • Streaming, assembled into one message the same way for every provider.
  • Classified errors: rate_limited, overloaded, context_overflow, auth, … (all codes). Retries honour Retry-After; requests that never left are retried at once.
  • Fallback: rate limits, overload and outages move to the next model (fallbacks); other error kinds can too (fallback_on / fallbackOn, e.g. context_overflow to a model with a longer context).
  • Retries: model_retry / modelRetry (attempts and backoff), and tool_retry / toolRetry for tools marked read-only or idempotent.
  • Keys stay secret: removed from every error message and from Debug output; never sent to another host (redirects are not followed).
  • Bounded: a response larger than 64 MiB fails instead of filling memory.

For self-hosted models nothing leaves your network, which is often the simplest answer for patient data.

Call a model directly#

For one call without an agent (summarize, classify, draft, embed), use Gateway: chat returns the answer, stream yields it as it is written, embed turns texts into vectors. Retries and fallback models work as for an agent, and reply.model names the model that answered. With output (a JSON Schema) the answer is JSON, parsed and checked against the schema. A stream that a retry starts over yields a restart chunk, so a UI can drop the text it showed. Gateway runs in your process; the gateway server is a separate program.

from criogenai import Embedder, Gateway, Ollama

gw = Gateway(fallbacks=[Ollama("llama3.2")])  # retries and fallbacks as for an agent
reply = await gw.chat("openai:gpt-5-mini", "Summarize: …", instructions="Two sentences.")
print(reply.text, reply.model)  # reply.model: the model that answered

async for chunk in gw.stream("openai:gpt-5-mini", "Write a haiku"):
    print(chunk.text, end="")

triage = {"type": "object", "properties": {"urgent": {"type": "boolean"}}, "required": ["urgent"]}
reply = await gw.chat("openai:gpt-5-mini", "Patient reports chest pain.", output=triage)
reply.output  # {"urgent": True}, checked against the schema

vectors = await gw.embed(Embedder.openai(), ["first note", "second note"])
import { Embedder, Gateway } from "criogenai";

const gw = new Gateway({ fallbacks: [ollama("llama3.2")] }); // retries and fallbacks as for an agent
const reply = await gw.chat("openai:gpt-5-mini", "Summarize: …", { instructions: "Two sentences." });
console.log(reply.text, reply.model); // reply.model: the model that answered

for await (const chunk of gw.stream("openai:gpt-5-mini", "Write a haiku")) process.stdout.write(chunk.text);

const triage = { type: "object", properties: { urgent: { type: "boolean" } }, required: ["urgent"] };
const answer = await gw.chat<{ urgent: boolean }>("openai:gpt-5-mini", "Patient reports chest pain.", { output: triage });
answer.output?.urgent; // checked against the schema

const vectors = await gw.embed(Embedder.openai(), ["first note", "second note"]);
use std::sync::Arc;

use criogenai_agent::ResilientModel;
use criogenai_core::RetryPolicy;
use criogenai_providers::{Endpoint, Message, Model, ModelRequest, ProviderModel};

let openai = ProviderModel::new(Endpoint::openai(key), "gpt-5-mini")?;
let local = ProviderModel::new(Endpoint::ollama(), "llama3.2")?;
// Retries and fallbacks as for an agent.
let model = ResilientModel::new(Arc::new(openai))
    .fallback(Arc::new(local))
    .retry(RetryPolicy::new().max_attempts(4));
let request = ModelRequest::new(vec![
    Message::system("Two sentences."),
    Message::user("Summarize: …"),
]);
let response = model.invoke(&request).await?;
println!("{}", response.message.text());