Any model
Point an agent at any provider with a single model reference. Every call routes through one governed seam, so swapping models never bypasses governance.
Any model
An agent's model is a single string. Change the string, change the provider, and the rest of your code is unchanged.
from jamjet import Agent
Agent("bot", model="anthropic/claude-sonnet-4-6", tools=[...])
Agent("bot", model="openai/gpt-4o", tools=[...])
Agent("bot", model="gemini/gemini-2.0-flash", tools=[...])
Agent("bot", model="ollama/llama3.2", tools=[...])Every one of those calls goes through the same governed seam, so the model is swappable without touching governance, tools, or the agent loop.
The model reference format
A model reference is "provider/model". The provider prefix selects the route;
the rest is passed through to the provider.
"anthropic/claude-sonnet-4-6" # provider: anthropic
"openai/gpt-4o" # provider: openai
"gemini/gemini-2.0-flash" # provider: gemini
"ollama/llama3.2" # provider: ollamaJamJet routes the prefixes anthropic, openai, gemini, and ollama through
the seam. Use gemini/ for Google Gemini models. Any other prefix is treated as
an OpenAI-compatible endpoint.
A bare string with no provider/ prefix defaults to the openai provider. So
model="claude-sonnet-4-6" routes to OpenAI, not Anthropic. Always prefix the
provider: model="anthropic/claude-sonnet-4-6".
Provider keys
The model seam is backed by LiteLLM, which reads each provider's key from the environment. Install the model extra and set the key for whichever providers you use:
pip install 'jamjet[model]'
export ANTHROPIC_API_KEY=sk-ant-... # anthropic/*
export OPENAI_API_KEY=sk-... # openai/*
export GEMINI_API_KEY=... # gemini/*Local models through Ollama need no API key. The ollama/ prefix targets a local
Ollama server at http://localhost:11434.
The governed seam
Application code never calls a provider directly. Every model call enters the
Model seam, which runs a middleware chain around the provider call: the model
allowlist denies disallowed models, PII redaction rewrites outbound prompts,
the budget check fails closed when spend is exhausted, and metering records token
and cost usage. The provider is only reached after the before chain passes.
Because this seam is the single path for every call, swapping providers never
bypasses governance. An agent capped at budget=0.50 keeps that ceiling whether
it runs on Claude, GPT, or a local model. See
Governance for the knobs that configure the chain.
Durable model calls go through the sidecar
On the in-process path (agent.run()), the seam runs in your own process. On the
durable path (agent.run_durable() and deployed agents), the model calls are
made by the Rust engine, so to keep the same governed seam the engine routes
them to a model sidecar: a local Python process that wraps jamjet.model.Model.
pip install 'jamjet[sidecar]'
uvicorn jamjet.model.sidecar_server:app --host 127.0.0.1 --port 4280Then point the engine at it:
export JAMJET_MODEL_SEAM_URL=http://127.0.0.1:4280The engine probes the sidecar's /health at startup and refuses to start if it
is unreachable, so durable model calls never silently bypass the governed seam.
If JAMJET_MODEL_SEAM_URL is unset, the engine falls back to native Rust
adapters, which is the default for development.
jamjet dev starts the sidecar, the engine, and the worker together and wires
JAMJET_MODEL_SEAM_URL for you, so the governed seam is on by default in local
development. See the Quickstart.
Next steps
Governance (on by default)
Every Agent is governed out of the box. PII redaction, signed audit, and receipts are on by default. Add policy, approval, and budget caps with one keyword each.
Reliability
What the durable engine guarantees. Event log, deterministic replay, idempotency, park-on-429, continue-as-new, immutable artifacts, and the exact consistency contract.