Providers
String dispatch by prefix
| String prefix | Resolves to | Required env var |
|---|---|---|
claude-* (incl. claude-opus-*, claude-sonnet-*, claude-haiku-*) | AnthropicModel | ANTHROPIC_API_KEY |
gpt-*, o1-*, o3-*, o4-* | OpenAIModel | OPENAI_API_KEY |
deepseek-* | OpenAIModel at https://api.deepseek.com | DEEPSEEK_API_KEY |
mistral-* | LiteLLMModel | provider-specific |
command-* (Cohere) | LiteLLMModel | COHERE_API_KEY |
bedrock/* | LiteLLMModel | AWS creds |
vertex_ai/* | LiteLLMModel | GCP creds |
gemini/* | LiteLLMModel | GEMINI_API_KEY |
together_ai/* | LiteLLMModel | TOGETHER_API_KEY |
replicate/* | LiteLLMModel | REPLICATE_API_KEY |
azure/* | LiteLLMModel | Azure creds |
ollama/* | LiteLLMModel | local Ollama running |
groq/* | LiteLLMModel | GROQ_API_KEY |
litellm/* | LiteLLMModel (explicit opt-in; strips the prefix) | provider-specific |
echo | EchoModel | none |
Anything that doesn’t match one of these prefixes raises ConfigError
rather than guessing — so mixtral-* or a bare provider name
won’t resolve. For those, prefix with litellm/ (e.g.
litellm/mistral/mixtral-8x7b) to route explicitly through LiteLLM.
from loomflow import Agent
Agent("...", model="claude-opus-4-7")
Agent("...", model="claude-haiku-4-5")
Agent("...", model="gpt-4o")
Agent("...", model="o3-mini")
Agent("...", model="deepseek-chat")
Agent("...", model="mistral-large")
Agent("...", model="command-r-plus")
Agent("...", model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0")
Agent("...", model="vertex_ai/gemini-pro")
Agent("...", model="ollama/llama3")
Agent("...", model="groq/llama-3.1-70b")
Agent("...", model="litellm/claude-3-haiku") # explicit opt-inAnthropic
By string
from loomflow import Agent
agent = Agent("...", model="claude-opus-4-7")
# ANTHROPIC_API_KEY must be set.Install: pip install 'loomflow[anthropic]'.
The adapter wraps the official anthropic SDK’s
AsyncAnthropic.messages.create(stream=True, ...). Tool calls
serialize to Anthropic’s content-block format under the hood.
OpenAI
By string
from loomflow import Agent
agent = Agent("...", model="gpt-4o")
# OPENAI_API_KEY must be set.Install: pip install 'loomflow[openai]'.
OpenAI-compatible endpoints (Together, Fireworks, Anyscale, vLLM)
work via base_url= on the underlying client.
DeepSeek
DeepSeek speaks the OpenAI wire format, so deepseek-* specs resolve
to OpenAIModel pointed at https://api.deepseek.com — keyed by
DEEPSEEK_API_KEY (Secrets backend or env var). A missing key raises
ConfigError loudly rather than falling back to OPENAI_API_KEY.
Agent("...", model="deepseek-chat") # DEEPSEEK_API_KEY must be setUsing DeepSeek through a reseller / gateway? Construct the adapter
directly with the gateway’s endpoint, and pass its actual rates so
cost_usd and budget caps stay honest — the third element is the
cached-input rate:
from loomflow.model.openai import OpenAIModel
model = OpenAIModel(
"deepseek-v4-flash",
api_key=GATEWAY_KEY,
base_url="https://gateway.example.com/v1",
cost_per_mtoken=(0.75, 3.00, 0.008), # (input, output, cached input) USD/MTok
)On failover gateways, also set prompt_caching={"enabled": True, "cache_key": ...} — see Prompt caching
for why the key is load-bearing there.
LiteLLM (~100 providers behind one adapter)
from loomflow import Agent
agent = Agent("...", model="mistral-large")
agent = Agent("...", model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0")
agent = Agent("...", model="ollama/llama3")Install: pip install 'loomflow[litellm]'.
Provider auth is whatever litellm expects. Typically env vars
matching the provider’s official client (AWS_PROFILE,
GOOGLE_APPLICATION_CREDENTIALS, MISTRAL_API_KEY, COHERE_API_KEY,
etc.). See LiteLLM’s docs for the full matrix.
Echo
agent = Agent("...", model="echo")
result = await agent.run("hi")
print(result.output) # "Echo: hi"EchoModel echoes the prompt as the assistant’s reply. No tool calls,
no streaming meaningful tokens. For smoke-testing the agent loop
without burning real tokens.
Scripted
from loomflow import Agent, ScriptedModel, ScriptedTurn
model = ScriptedModel(turns=[
ScriptedTurn(text="The answer is 42."),
ScriptedTurn(tool_calls=[...]),
ScriptedTurn(text="Done."),
])
agent = Agent("...", model=model)For tests with deterministic multi-turn scenarios. Each ScriptedTurn
becomes one model response; the framework consumes them in order.
Secrets handling
API keys resolve in this order inside every adapter:
- Explicit
api_key=argument on the adapter. secrets.lookup_sync(<ENV_VAR_NAME>)if aSecretsbackend is wired onAgent(tuning=Tuning(secrets=...)).os.environ[<ENV_VAR_NAME>]as the bare fallback.
For Vault / AWS Secrets Manager / 1Password, write a custom Secrets
adapter. See Secrets resolution.
Per-tenant model selection. Different tenants can use different
models. Pass an instance per call by constructing a different
Agent per tenant, or set up a router architecture where the
classifier picks a specialist with the right model.