Providers¶
nagents supports multiple LLM providers with a unified interface, making it easy to switch between providers without changing your application logic.
Provider Types¶
| Provider | Type | Description |
|---|---|---|
| OpenAI | ProviderType.OPENAI_COMPATIBLE |
OpenAI API and compatible services |
| Anthropic | ProviderType.ANTHROPIC |
Anthropic Claude API |
ProviderType.GEMINI_NATIVE |
Google Gemini API | |
| OpenRouter | ProviderType.OPENROUTER |
OpenAI-compatible API with OpenRouter identification |
| LiteLLM | ProviderType.LITELLM |
API-key gateway with an explicit API prefix |
Sign in from ngn¶
Use /provider in the TUI or Settings → Global/Workspace → Provider connections
in ngn serve to manage named connections shared across clients. Global ones
are saved to $XDG_CONFIG_HOME/ngn/providers.json; workspace ones are saved to
workspace-specific JSON under the same config root. Both use environment-variable references,
not key values. OpenAI can select ngn ChatGPT login, local Codex discovery, or
an API-key variable. Azure AI Foundry supports API-key variables and Microsoft
Entra ID through the optional azure-identity package. Voice settings for a
named connection use the same endpoint and credential reference. See
named provider configuration.
Chat model selection is independent: use /model in the TUI, --model for a
single CLI invocation, or the global/workspace chat-model selector in web
Settings. Connections display their credential source and effective endpoint;
their JSON entries do not contain a chat model. Voice preferences are stored
separately from provider connections.
ngn login chatgpt stores the device credential used by a named OpenAI
connection with "auth": "chatgpt". Login alone does not activate a provider;
select a named connection in the registry or with --provider-id. API-key
connections use the environment-variable name specified in providers.json.
ngn login --status and ngn logout manage saved login credentials. Library
users pass credentials explicitly as shown below.
Discover Model IDs¶
Local Codex configuration¶
With no explicit credentials, OpenAIProvider discovers Codex configuration under CODEX_HOME
or ~/.codex. It reads config.toml and file-based auth.json to select the
model, API contract and authentication method. Saved ChatGPT login uses the
existing Codex OAuth transport; API-key/custom-provider configuration uses the
selected Responses or legacy Chat Completions API. An unrelated OPENAI_API_KEY
does not replace a saved ChatGPT login.
Optional overrides are OpenAIProvider(home=..., profile=..., model=...).
An explicit API key bypasses local discovery, including saved ChatGPT login:
Use api="chat_completions" to select that protocol. A custom base_url
requires an explicit api_key. provider.uses_chatgpt_auth distinguishes
subscription authentication from API-key authentication.
Selected NAME.config.toml profile files and legacy [profiles.NAME] tables are
supported. Custom providers can specify base_url, wire_api, env_key, and
requires_openai_auth. Project-local configuration is not used for authentication
or endpoint discovery. No credentials are copied or written. OAuth tokens are
reread before requests, picking up refreshes performed by Codex; Nagents does not
rotate the external application's refresh tokens.
This discovery path currently requires file credentials. Keyring-only/ephemeral logins and provider command-auth/custom-header/query settings report an explicit configuration error instead of silently selecting another route. Supplying the existing credential callback continues to work for application-owned OAuth.
Explicit catalog discovery¶
await provider.get_model_list() -> list[str] is included in v0.15.0. See the
Provider API example for a complete
async example using your own OPENAI_API_KEY environment variable.
Discovery is explicit and fresh. It does not select a model, alter configuration,
or generate a response. OpenAI-compatible, OpenRouter, LiteLLM, and Azure v1 connections
query their configured API prefix plus /models, using their own API key. A
custom service must implement the conventional data array with string id
fields. Keep a manual model-ID input: unsupported discovery raises
NotImplementedError, and missing credentials, upstream failures, or malformed
catalogs raise ModelListError. An empty list means a valid empty catalog, not a
fallback after a failure. Native Gemini, Anthropic, and versioned Azure discovery is not
implemented by this method; their existing verification behavior is unchanged.
Catalog IDs are not capability or entitlement guarantees. The generation service
can reject a listed model or accept an unlisted one. API-key catalogs and
ChatGPT/Codex OAuth catalogs are separate connections, not interchangeable ways
to use a subscription. Never pass a Codex OAuth token as Provider.api_key, or
send it to an OpenAI-compatible endpoint. Use OpenAIProvider with ChatGPT authentication and
the existing ngn login flow for subscription access.
Its get_model_list() fetches picker-visible slug IDs from the fixed Codex
catalog using a fresh credential snapshot. supported_in_api: false does not
exclude an OAuth model. See the ChatGPT API example and pinned contract
for authentication, visibility validation, and compatibility limits. This follows
the official Codex client, not a stable public API guarantee; manual entry remains
available without changing login or billing mode.
OpenAI Compatible¶
Works with OpenAI API and any compatible service (Azure, local models, etc.):
from nagents import Provider, ProviderType
provider = Provider(
provider_type=ProviderType.OPENAI_COMPATIBLE,
api_key="sk-...",
model="gpt-4o-mini",
)
Available models:
gpt-4o- Most capablegpt-4o-mini- Fast and affordablegpt-4-turbo- Previous generationgpt-3.5-turbo- Legacy, fastest
provider = Provider(
provider_type=ProviderType.OPENAI_COMPATIBLE,
api_key="your-azure-key",
model="gpt-4",
base_url="https://your-resource.openai.azure.com/openai/deployments/gpt-4",
)
Azure Configuration
Set base_url to your Azure OpenAI deployment endpoint.
# Ollama
provider = Provider(
provider_type=ProviderType.OPENAI_COMPATIBLE,
api_key="not-needed", # (1)!
model="llama2",
base_url="http://localhost:11434/v1",
)
# vLLM
provider = Provider(
provider_type=ProviderType.OPENAI_COMPATIBLE,
api_key="not-needed",
model="meta-llama/Llama-2-7b-chat-hf",
base_url="http://localhost:8000/v1",
)
- Local servers typically don't require an API key, but the parameter is still required.
Anthropic Claude¶
Native Anthropic API support with all Claude models:
from nagents import Provider, ProviderType
provider = Provider(
provider_type=ProviderType.ANTHROPIC,
api_key="sk-ant-...",
model="claude-3-5-sonnet-20241022",
)
Available models:
| Model | Description |
|---|---|
claude-3-5-sonnet-20241022 |
Best balance of intelligence and speed |
claude-3-opus-20240229 |
Most capable, best for complex tasks |
claude-3-sonnet-20240229 |
Balanced performance |
claude-3-haiku-20240307 |
Fastest, best for simple tasks |
Model Selection
Start with claude-3-5-sonnet for most use cases. Use opus for complex reasoning and haiku for high-throughput, simple tasks.
Google Gemini¶
Native Gemini API support:
from nagents import Provider, ProviderType
provider = Provider(
provider_type=ProviderType.GEMINI_NATIVE,
api_key="...",
model="gemini-2.0-flash",
)
Available models:
| Model | Description |
|---|---|
gemini-2.0-flash |
Latest, fastest multimodal model |
gemini-1.5-pro |
Most capable, large context window |
gemini-1.5-flash |
Fast and efficient |
Switching Providers¶
The unified interface makes it easy to switch providers dynamically:
import os
from pathlib import Path
from nagents import Agent, ErrorEvent, Provider, ProviderType, SessionManager, TextChunkEvent
def get_provider(provider_name: str) -> Provider:
"""Create a provider based on name."""
match provider_name:
case "openai":
return Provider(
provider_type=ProviderType.OPENAI_COMPATIBLE,
api_key=os.environ["OPENAI_API_KEY"],
model=os.environ["OPENAI_MODEL"],
)
case "anthropic":
return Provider(
provider_type=ProviderType.ANTHROPIC,
api_key=os.environ["ANTHROPIC_API_KEY"],
model=os.environ["ANTHROPIC_MODEL"],
)
case "gemini":
return Provider(
provider_type=ProviderType.GEMINI_NATIVE,
api_key=os.environ["GOOGLE_API_KEY"],
model=os.environ["GOOGLE_MODEL"],
)
case _:
raise ValueError(f"Unknown provider: {provider_name}")
async def main():
# Select provider from environment or config
provider_name = os.getenv("LLM_PROVIDER", "openai")
provider = get_provider(provider_name)
session_manager = SessionManager(Path("sessions.db"))
# The same text-only agent interface can use any of these providers.
agent = Agent(
provider=provider,
session_manager=session_manager,
streaming=True,
)
try:
async for event in agent.run("Hello!"):
if isinstance(event, TextChunkEvent):
print(event.chunk, end="", flush=True)
elif isinstance(event, ErrorEvent):
print(f"\nError: {event.message}")
finally:
await agent.close()
Set the selected provider's API key and *_MODEL environment variables before
calling main(). Choose a model available to your account.
Provider Agnostic
The text-generation interface is shared, but media, reasoning, batch, and generation-option support depend on the backend and HTTP contract. Your application can use this interface to:
- Switch providers for cost optimization
- Use different providers for different tasks
- Fail over to backup providers
- Test with local models, deploy with cloud providers
Provider Comparison¶
Feature Comparison
| Feature | OpenAI | Anthropic | Gemini |
|---|---|---|---|
| Streaming | |||
| Tool Calling | |||
| Vision | |||
| Max Context | 128K | 200K | 2M |
| Custom Base URL |
Best Practices¶
Recommendations
- Use environment variables for API keys
- Start with smaller models (gpt-4o-mini, claude-3-haiku, gemini-flash) for development
- Implement fallback logic for production systems
- Monitor token usage via the
usagefield in events