Skip to main content
from praisonaiagents import Agent

agent = Agent(name="di-agent", instructions="Use dependency injection via the agent registry.")
agent.start("Resolve and inject the database service for this task.")
The user runs generation with a custom adapter registry so tenants or tests stay isolated. Inject a custom adapter registry when you need tenant isolation, parallel test safety, or per-run plugin overrides.
from praisonai.framework_adapters.registry import FrameworkAdapterRegistry
from praisonai.agents_generator import AgentsGenerator

registry = FrameworkAdapterRegistry()
registry.register("crewai", CustomCrewAIAdapter)

generator = AgentsGenerator(
    agent_file="agents.yaml",
    framework="crewai",
    config_list=[...],
    adapter_registry=registry,
)

Quick Start

1

Simple Usage

Use the process-default registry for normal applications:
from praisonai.agents_generator import AgentsGenerator

# adapter_registry=None → uses get_default_registry()
generator = AgentsGenerator("agents.yaml", "crewai", config_list=[...])
2

With Configuration

Inject a custom registry for tenant isolation or testing:
from praisonai.framework_adapters.registry import FrameworkAdapterRegistry
from praisonai.agents_generator import AgentsGenerator

tenant_registry = FrameworkAdapterRegistry()
tenant_registry.register("crewai", CustomCrewAIAdapter)

generator = AgentsGenerator(
    agent_file="agents.yaml",
    framework="crewai",
    config_list=[...],
    adapter_registry=tenant_registry,
)

How It Works

RegistryModuleDocs
Framework adapterspraisonai.framework_adapters.registryFramework Adapter Plugins
Bot platformspraisonai.bots._registryBot Platform Plugins
Sandbox backendspraisonai.sandbox._registrySandbox Backends
Search providerspraisonai.cli.features._search_registrySearch Providers
All plugin registries expose Registry.default() or get_default_registry() unless noted. When a SandboxConfig’s sandbox_type is unknown to the built-in list, SandboxManager now resolves it through praisonai.sandbox._registry automatically — no manual registry.resolve() call is needed for typical use.

Common Patterns

Multi-tenant isolation

def create_tenant_generator(tenant_id: str):
    registry = FrameworkAdapterRegistry()
    adapter = EnterpriseCrewAIAdapter if tenant_id == "enterprise" else StandardCrewAIAdapter
    registry.register("crewai", adapter)

    return AgentsGenerator(
        agent_file=f"tenants/{tenant_id}/agents.yaml",
        framework="crewai",
        config_list=[...],
        adapter_registry=registry,
    )

Test isolation

def test_custom_adapter():
    test_registry = FrameworkAdapterRegistry()
    test_registry.register("crewai", MockCrewAIAdapter)

    generator = AgentsGenerator(
        agent_file="test_agents.yaml",
        framework="crewai",
        config_list=[...],
        adapter_registry=test_registry,
    )
    # Parallel tests do not share registrations

AutoGenerator with custom registry

from praisonai.auto import AutoGenerator

reg = FrameworkAdapterRegistry()
auto = AutoGenerator(
    topic="...",
    agent_file="test.yaml",
    framework="crewai",
    config_list=[...],
    adapter_registry=reg,
)

# The resolved adapter is retained after construction
print(auto._adapter.name)   # canonical dispatch object
print(auto.framework)       # authoritative name from adapter.name
After construction, AutoGenerator retains the resolved adapter as self._adapter (mirroring AgentsGenerator.framework_adapter), and self.framework is derived from adapter.name — the authoritative name, not the raw constructor argument. This is a stable observable side effect; the underscore prefix marks it private-by-convention, so treat the attribute name itself as an implementation detail.

Injecting a tool-timeout executor

Like adapter_registry=, the tool_timeout_executor= constructor parameter lets you supply a shared thread-pool instead of letting each AgentsGenerator lazily create its own.
import concurrent.futures
from praisonai.agents_generator import AgentsGenerator

# One pool, many sessions
shared_pool = concurrent.futures.ThreadPoolExecutor(max_workers=16)

for cfg in tenant_configs:
    with AgentsGenerator(
        agent_file=cfg.path,
        framework=cfg.framework,
        config_list=cfg.llms,
        tool_timeout_executor=shared_pool,  # borrowed
    ) as gen:
        gen.generate_crew_and_kickoff()
The injected executor is treated as borrowedgen.close() and exiting the with block will not shut it down. You stay responsible for shared_pool.shutdown().

Best Practices

Accept registries as parameters rather than calling defaults inside helpers:
# Good — accepts registry parameter
def process_with_framework(framework: str, registry: FrameworkAdapterRegistry):
    return registry.create(framework).run(...)

# Risky — hardcoded to default
def process_with_framework(framework: str):
    from praisonai.framework_adapters.registry import get_default_registry
    return get_default_registry().create(framework).run(...)
Registry operations are thread-safe, but adapter instances may not be. Prefer one registry per worker or test case.
Custom registries add complexity. Reach for DI only when you need tenant overrides, test isolation, or sandboxed experimental adapters.

Framework Adapter Plugins

Extend PraisonAI with custom execution frameworks

Bot Platform Plugins

Add custom messaging platforms via entry points