openai-compat, and your own) into PraisonAI via a single Python entry-point group — no fork required.
Publish once under praisonai.endpoint_providers. One plugin is then visible to get_provider(), praisonai endpoints types, and praisonai endpoints invoke --type.
praisonai.endpoint_providers reaches both the provider registry and the CLI dispatch surface.
Quick Start
1
Use a built-in provider
2
Register at runtime
3
Distribute as a pip plugin
How It Works
The registry is thread-safe and loads plugins lazily. Built-ins are discovered on first access, entry points are loaded when needed, and aliases are case-insensitive. The singleton registry is obtained viaget_default_registry().
One Group, Two Readers
There is one canonical entry-point group:praisonai.endpoint_providers. Two readers scan it — the top-level provider registry (instantiates BaseProvider classes for serve / discovery) and the CLI dispatch registry (resolves endpoints invoke --type). One plugin contract serves both surfaces; the CLI adapts your BaseProvider subclass into its internal dispatch shape.
Built-in Dispatch Keys
Which Group Do I Publish Under?
Migration From the Deprecated Group
Rename the entry-point group in yourpyproject.toml. The class and its methods are unchanged.
mcp under the legacy group cannot replace the built-in mcp provider (since PR #4185).
Constants exported by praisonai/endpoints/registry.py:
Streaming
Implementinvoke_stream — not invoke(stream=True) — to support --stream. When --stream is passed the CLI adapter calls provider.invoke_stream(name, input_data, config), which yields {"event": ..., "data": ...} frames. An event == "error" frame prints the error and returns exit code 3 (runtime error); other frames print as [event] data and it returns 0.
Configuration / API
Functions
ProviderRegistry Class
Built-in Provider Types
Common Patterns
Override a Built-in (runtime only)
Override a Built-in (runtime only)
The runtime
register_provider() path is last-write-wins — it can replace a built-in in the current process:A pip-installed plugin cannot override a built-in. The CLI dispatch registry re-asserts its built-in loaders after entry-point discovery, so an entry point may add a new type but never replace a shipped one (
recipe, mcp, openai-compat, …). This inverts the base PluginRegistry precedence, where entry points normally override built-ins. Only the runtime register_provider() call above overrides.Multiple Aliases
Multiple Aliases
Use the underlying PluginRegistry for alias support:
Per-tenant Isolation
Per-tenant Isolation
Instantiate
ProviderRegistry directly for isolation:Best Practices
Always provide a _loader() function
Always provide a _loader() function
Never import your provider class at module top-level — defeats lazy loading and breaks the no-heavy-deps-at-import-time guarantee:
Subclass BaseProvider
Subclass BaseProvider
Required for type compatibility and consistent API:
Distinguish missing vs import failure
Distinguish missing vs import failure
get_provider("unknown") returns None, but import failures propagate:Prefer entry points for distributable packages
Prefer entry points for distributable packages
Use
pyproject.toml entry points instead of register_provider() calls:Related
Integration Registry
The sibling plugin registry for CLI tools / managed agents
Framework Adapter Plugins
Third sibling plugin registry, for framework adapters

