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()?;| Provider | How it is reached | Key |
|---|---|---|
| OpenAI | Responses 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 Gemini | Its OpenAI-compatible endpoint | GEMINI_API_KEY |
| OpenRouter (hundreds of models) | OpenAI-compatible | OPENROUTER_API_KEY |
| DeepSeek | deepseek: | DEEPSEEK_API_KEY |
| Mistral AI | mistral: | MISTRAL_API_KEY |
| xAI (Grok) | xai: | XAI_API_KEY |
| Groq | groq: | GROQ_API_KEY |
| Cerebras | cerebras: | CEREBRAS_API_KEY |
| Together AI | together: | TOGETHER_API_KEY |
| Fireworks AI | fireworks: | 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 Foundry | azure:<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 engine | AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY, or AZURE_TENANT_ID + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET |
| Amazon Bedrock | bedrock:<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 planned | AWS_BEARER_TOKEN_BEDROCK + AWS_REGION |
| Google Vertex AI | vertex:<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 planned | GOOGLE_CLOUD_PROJECT + GOOGLE_CLOUD_LOCATION |
| Kaggle Model Proxy (prototypes) | OpenAI-compatible; CriogenAI mints and renews the hourly proxy token | KAGGLE_API_TOKEN or ~/.kaggle/access_token |
| Ollama, LM Studio | ollama:, lmstudio:; local, OpenAI-compatible | none |
| vLLM and any OpenAI-compatible server | Your URL (a key is never sent over plain http:// to another machine unless you pass allow_insecure_http / allowInsecureHttp) | optional |
| Any Anthropic-compatible server | Your URL: AnthropicCompatible / anthropicCompatible | optional |
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
autherror 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::varto 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_URLandMODEL_PROXY_API_KEY(set in Kaggle notebooks);KAGGLE_API_TOKEN; theaccess_tokenfile inKAGGLE_CONFIG_DIRor~/.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 honourRetry-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_overflowto a model with a longer context). - Retries:
model_retry/modelRetry(attempts and backoff), andtool_retry/toolRetryfor tools marked read-only or idempotent. - Keys stay secret: removed from every error message and from
Debugoutput; 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());