Skip to main content

Custom Provider Registry

The Custom Provider Registry allows you to register custom LLM providers that extend PraisonAI’s capabilities beyond the built-in providers (OpenAI, Anthropic, Google via LiteLLM).
Updated in PR #1624: Built-in providers (openai, anthropic, google) plus aliases (oai, claude, gemini, google_genai) are now auto-registered and backed by LiteLLM. You add custom providers when you need a non-LiteLLM backend or a custom routing/caching/mocking layer.Verified end-to-end in PR #2171 and PR #3011:
  • PR #2171 wired built-in aliases (oai, claude, gemini, google_genai) through the loader map so alias-based create_llm_provider(...) calls resolve.
  • PR #3011 wired the wrapper’s two hot LLM paths (framework-adapter resolver + structured-completion generator) to consult the registry first, so a registered non-built-in provider is now the one that actually serves Agent(llm="…/…") calls — not just standalone create_llm_provider(...).

Built-in providers

Built-in providers are automatically registered when a registry is created:

What Problem Does It Solve?

  • Integrate proprietary or internal LLM APIs
  • Add support for new providers before LiteLLM supports them
  • Create mock providers for testing
  • Build custom routing or caching layers

Quick Start

1

Define provider

2

Register and use

Where a Registered Provider Takes Effect

Registering a provider isn’t just for direct create_llm_provider(...) calls — the registry is now consulted on the hot LLM paths, so your provider is used end-to-end:
  • PraisonAIModel.get_model() — every framework adapter’s model resolver. Any non-built-in prefix (e.g. bedrock/) resolves through your registered provider.
  • AutoGenerator._completion_impl — the YAML generator’s structured-completion path, before the LiteLLM → OpenAI ladder.
Resolution precedence:
  1. Built-in prefixes (openai/, groq/, anthropic/, google/, cohere/, ollama/, openrouter/) keep the fast, direct-SDK path — never routed through the registry.
  2. Non-built-in prefixes are looked up in the registry and, if registered, use your provider.
  3. Anything else falls through to the LiteLLM → OpenAI ladder.
  • Fail-closed on unknown providers is preserved.
  • Registry lookup never raises on the hot path — any registry error degrades to the built-in ladder.
  • For PraisonAIModel, the OpenAI-key requirement is deferred to your registered provider (no spurious auth error when you supply your own credentials).

Structured Outputs from the YAML Generator

To be used by AutoGenerator for structured completion, a registered provider opts in by exposing an async generate_structured(...):
Providers that don’t define generate_structured(...) are skipped and the built-in ladder runs unchanged.

Thread Safety

Enhanced in PR #1597: LLMProviderRegistry is now thread-safe with singleton access and RLock protection for all operations.
All registry methods (register, unregister, resolve, alias lookup, and listing) are safe to call concurrently from threads. Built-in providers are registered automatically on first instantiation. Singleton access pattern (preferred for app code):
The existing helpers register_llm_provider / create_llm_provider continue to work unchanged (backwards compatible).

How Provider Resolution Works

The registry resolves providers in this order:

1. Explicit Provider Format: provider/model

2. Model Prefix Inference

When no provider is specified, the model name prefix determines the provider:

3. Custom Provider with Explicit Name

Where registered providers take effect

Registering a provider makes it reachable from every entry point that resolves models through the wrapper — not just direct create_llm_provider(...) calls. Two wrapper hot paths now consult the registry before falling back to the built-in ladder.
Registering a provider under a built-in prefix (openai/, groq/, cohere/, ollama/, anthropic/, google/, openrouter/) does not hijack the built-in path. Both hot paths gate against a shared _BUILTIN_MODEL_PREFIXES set so the built-in ladder always wins for those prefixes. Use a unique namespace (e.g. mycompany-openai/) if you need custom routing under an OpenAI-like protocol.
The wrapper drops empty api_key/base_url entries from the config it forwards to your provider so the provider’s own environment/credential chain still applies. If you rely on AWS_REGION / AWS_PROFILE (Bedrock), CLOUDFLARE_ACCOUNT_ID (Workers AI), or similar env-driven auth, you do not need to thread anything through the registry — resolve credentials inside your provider’s __init__.
A registered provider that raises during construction now surfaces its real error — it is not silently replaced by the OpenAI-key ValueError from the built-in ladder. Before PR #3011 a broken Bedrock provider looked like a missing OPENAI_API_KEY; the error message now points at the actual provider that failed to construct.

End-to-end Bedrock example

Skip generate_structured if you only need chat completion — PraisonAIModel.get_client() is enough for framework adapters. Add generate_structured when you also need YAML auto-generation (praisonai --auto ...) or another generator that produces pydantic models.

Provider Aliases

Built-in providers support aliases for shorter, more convenient model specifications:

Using Aliases

Registering Custom Providers with Aliases

When registering your own custom providers, you can specify aliases:

Registering Custom Providers Safely

Unique Name Rules

Provider names must be unique. Attempting to register a duplicate name raises an error:
Error message:

Alias Rules

Aliases provide alternative names for a provider:
Alias collision detection:
Error message:

Override Flag

Use override=True only when you intentionally want to replace an existing registration:
Avoid using override=True carelessly - it can break other code that depends on the original provider.

Avoiding Collisions

Use a namespace prefix to avoid collisions:

Reserved Names

These provider names are now registered providers (not just inference defaults):
  • openai - Auto-registered LiteLLM provider
  • anthropic - Auto-registered LiteLLM provider
  • google - Auto-registered LiteLLM provider
  • Their aliases: oai, claude, gemini, google_genai
Re-registering them without override=True will raise ValueError: Provider 'X' is already registered. Use override=True only if you’re intentionally replacing the built-in provider.

Multi-Agent Guidance

Global Registry (Default)

The default global registry is shared across all code:

Isolated Registry (Per Agent/Run)

For multi-agent scenarios where you need isolation:
Benefits of isolated registries:
  • No global state mutation
  • Safe for concurrent/parallel agent runs
  • Each agent can have its own provider configuration
  • Testing isolation

API Reference

register_llm_provider

create_llm_provider

LLMProviderRegistry

Utility Functions

Breaking Changes

Advanced Users Only: The following breaking changes affect low-level API usage. Most users should use register_provider() and resolve_provider() for new code.

Removed APIs

  • LLMProviderRegistry.get_instance() → Use get_default_llm_registry()
  • LLMProviderRegistry._instance and _instance_lock class attributes removed
  • praisonai.profiler.default_profiler module attribute removed

Changed Semantics

The LLMProviderRegistry.register() and LLMProviderRegistry.resolve() methods now have PluginRegistry semantics:

Preserved Aliases

These methods continue to work for backward compatibility:
  • has(), list(), list_all()
  • Module-level register_llm_provider(...), create_llm_provider(...)

Minimal Example

Troubleshooting

Common Errors

“Provider ‘X’ is already registered”
“Unknown provider: ‘X’”
“Alias ‘X’ conflicts with existing provider”

Performance Notes

  • Lazy imports: The registry module only imports typing - no heavy dependencies
  • Import time: ~800μs for praisonai.llm.registry
  • O(1) operations: has(), resolve(), and register() are all O(1)
  • No LiteLLM coupling: The registry is completely independent of LiteLLM

Migration note

Before PR #3011, register_llm_provider("bedrock", ...) succeeded but Agent(llm="bedrock/…") raised ValueError: OPENAI_API_KEY environment variable is required for the default OpenAI service. — because the framework-adapter resolver never consulted the registry. If you worked around this by shipping OPENAI_API_KEY=not-needed or a shim adapter, you can now delete the workaround: the registered provider is used directly.

See Also