> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Managed Backend Plugins

> Add HostedAgent provider backends via Python entry points

Managed backend plugins let third-party packages register new `HostedAgent(provider=...)` runtimes — like `e2b`, `modal`, or `flyio` — without editing PraisonAI core.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonai import HostedAgent, HostedAgentConfig

hosted = HostedAgent(
    provider="e2b",
    config=HostedAgentConfig(model="claude-haiku-4-5"),
)
agent = Agent(name="Researcher", instructions="Research and summarise.", backend=hosted)
agent.start("Find three sources on agentic RAG.")
```

The user installs a plugin entry point; `HostedAgent` resolves the provider and runs the agent on that backend.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Managed Backend Plugin System"
        A[📦 Third-party Package] --> B[🔌 praisonai.managed_backends]
        B --> C[📝 ManagedBackendRegistry]
        C --> D[🤖 HostedAgent]
    end

    classDef package fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef entrypoint fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef registry fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff

    class A package
    class B entrypoint
    class C registry
    class D agent
```

## Quick Start

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonai import HostedAgent, HostedAgentConfig

# A third-party "e2b" plugin is installed via pip.
# HostedAgent resolves it through the registry — no core change.
hosted = HostedAgent(
    provider="e2b",
    config=HostedAgentConfig(model="claude-haiku-4-5"),
)

agent = Agent(name="Researcher", instructions="Research and summarise.", llm=hosted)
agent.start("Find three sources on agentic RAG.")
```

<Steps>
  <Step title="Simple — Programmatic Registration">
    Register a backend class directly at runtime (ideal for testing or single-project use):

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent
    from praisonai import HostedAgent, HostedAgentConfig
    from praisonai.integrations.backend_registry import get_backend_registry

    class E2BManagedAgent:
        def __init__(self, provider, config=None, **kwargs):
            self.provider = provider
            self.config = config

        def is_available(self):
            try:
                import e2b
                return True
            except ImportError:
                return False

        def run(self, prompt, **kwargs):
            import e2b
            return e2b.run(prompt)

    registry = get_backend_registry()
    registry.register("e2b", E2BManagedAgent)

    hosted = HostedAgent(provider="e2b", config=HostedAgentConfig(model="claude-haiku-4-5"))
    agent = Agent(name="Coder", instructions="Write Python code.", llm=hosted)
    agent.start("Write a function to reverse a string.")
    ```
  </Step>

  <Step title="With Entry Point — pip-installable Plugin">
    Create a Python package with a `praisonai.managed_backends` entry point so your backend is automatically available after `pip install`:

    ```toml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # pyproject.toml
    [project]
    name = "e2b-praisonai"
    version = "1.0.0"
    dependencies = ["e2b", "praisonai"]

    [project.entry-points."praisonai.managed_backends"]
    e2b = "e2b_praisonai.backend:E2BManagedAgent"
    ```

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # e2b_praisonai/backend.py
    import os

    class E2BManagedAgent:
        def __init__(self, provider="e2b", config=None, **kwargs):
            self.provider = provider
            self.config = config

        def is_available(self):
            try:
                import e2b
                return True
            except ImportError:
                return False

        def run(self, prompt, **kwargs):
            import e2b
            sandbox = e2b.Sandbox()
            return sandbox.run_code(prompt)
    ```

    After installation:

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    pip install e2b-praisonai
    ```

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent
    from praisonai import HostedAgent, HostedAgentConfig

    # e2b is now available automatically
    hosted = HostedAgent(provider="e2b", config=HostedAgentConfig(model="claude-haiku-4-5"))
    agent = Agent(name="Researcher", instructions="Research topics.", llm=hosted)
    agent.start("Summarise the key papers on agentic RAG.")
    ```
  </Step>
</Steps>

***

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant HostedAgent
    participant ManagedBackendRegistry
    participant BackendFactory
    participant BackendInstance

    User->>HostedAgent: HostedAgent(provider="e2b", ...)
    HostedAgent->>ManagedBackendRegistry: lookup("e2b")
    ManagedBackendRegistry->>BackendFactory: load entry point / registered class
    BackendFactory-->>ManagedBackendRegistry: E2BManagedAgent class
    ManagedBackendRegistry-->>HostedAgent: E2BManagedAgent class
    HostedAgent->>BackendFactory: E2BManagedAgent(provider="e2b", config=...)
    BackendFactory-->>BackendInstance: e2b_instance
    HostedAgent-->>User: e2b_instance (via __new__ factory)
```

`HostedAgent.__new__` acts as a **factory** for non-Anthropic backends. When the resolved backend class is different from `HostedAgent`, Python's `__new__` returns the backend instance directly — `__init__` is skipped. Callers receive the real backend's methods without any `AnthropicManagedAgent`-inherited state:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
hosted = HostedAgent(provider="e2b", config=HostedAgentConfig(model="claude-haiku-4-5"))
type(hosted)  # <class 'e2b_praisonai.backend.E2BManagedAgent'>
```

The builtin `anthropic` backend is pre-registered in `ManagedBackendRegistry` — it resolves to `AnthropicManagedAgent`.

**Async parity.** When an agent with a managed backend calls `achat()` / `astart()` / `arun()`, the backend's async `execute()` is awaited directly through `_adelegate_to_backend` — no worker-thread bridge, and the same rate limiter and cancellation token that gate the sync path apply first. Session history is recorded identically on both paths, so switching an agent between sync and async does not diverge its `chat_history`. Before PR [#3877](https://github.com/MervinPraison/PraisonAI/pull/3877) a configured backend was silently ignored on async entry points and calls fell through to direct-LLM.

***

## Configuration Options

<Card title="ManagedBackendRegistry API Reference" icon="code" href="/docs/sdk/reference/praisonaiagents/modules/main">
  Complete API reference for ManagedBackendRegistry
</Card>

| Entry-point group | `praisonai.managed_backends`             |
| ----------------- | ---------------------------------------- |
| Built-in backends | `anthropic` → `AnthropicManagedAgent`    |
| Discovery         | Auto-discovered on first registry access |

***

## Common Patterns

### Custom Hosted Runtime

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonai import HostedAgent, HostedAgentConfig
from praisonai.integrations.backend_registry import get_backend_registry
import os

class ModalManagedAgent:
    def __init__(self, provider="modal", config=None, **kwargs):
        self.provider = provider
        self.config = config

    def is_available(self):
        try:
            import modal
            return True
        except ImportError:
            return False

    def run(self, prompt, **kwargs):
        import modal
        f = modal.Function.lookup("my-app", "run_agent")
        return f.remote(prompt)

get_backend_registry().register("modal", ModalManagedAgent)

hosted = HostedAgent(
    provider="modal",
    config=HostedAgentConfig(model="claude-haiku-4-5"),
)
agent = Agent(name="Cloud Runner", instructions="Run tasks on Modal.", llm=hosted)
agent.start("Process this dataset in parallel.")
```

### Selecting Between Multiple Registered Backends

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai import HostedAgent, HostedAgentConfig
from praisonai.integrations.backend_registry import get_backend_registry
from praisonaiagents import Agent
import os

registry = get_backend_registry()
available = registry.list_all_names()
print(f"Available backends: {available}")

provider = os.getenv("AGENT_BACKEND", "anthropic")
if provider not in available:
    raise ValueError(f"Backend '{provider}' not installed. Available: {sorted(available)}")

hosted = HostedAgent(provider=provider, config=HostedAgentConfig(model="claude-haiku-4-5"))
agent = Agent(name="Flexible Agent", instructions="Complete tasks.", llm=hosted)
agent.start("What is 2 + 2?")
```

### Graceful Unavailable-Backend Handling

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai import HostedAgent, HostedAgentConfig
from praisonai.integrations.backend_registry import get_backend_registry
from praisonaiagents import Agent

def create_agent(preferred_backend: str) -> Agent:
    registry = get_backend_registry()
    try:
        hosted = HostedAgent(
            provider=preferred_backend,
            config=HostedAgentConfig(model="claude-haiku-4-5"),
        )
    except ValueError:
        available = sorted(registry.list_all_names())
        print(f"Backend '{preferred_backend}' unavailable. Using 'anthropic'. Available: {available}")
        hosted = HostedAgent(
            provider="anthropic",
            config=HostedAgentConfig(model="claude-haiku-4-5"),
        )
    return Agent(name="Resilient Agent", instructions="Complete tasks.", llm=hosted)

agent = create_agent("e2b")
agent.start("Write a hello world script.")
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Entry-point naming conventions">
    Use the provider name as the entry-point key — lowercase, no hyphens. The key becomes the value passed to `provider=`:

    ```toml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    [project.entry-points."praisonai.managed_backends"]
    e2b    = "e2b_praisonai.backend:E2BManagedAgent"     # HostedAgent(provider="e2b")
    modal  = "modal_praisonai.backend:ModalManagedAgent"  # HostedAgent(provider="modal")
    flyio  = "flyio_praisonai.backend:FlyioManagedAgent"  # HostedAgent(provider="flyio")
    ```
  </Accordion>

  <Accordion title="is_available() discipline">
    Always implement `is_available()` with a fast, cached check. The registry calls it during startup probing:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonai._framework_availability import is_available as check_availability

    class E2BManagedAgent:
        def is_available(self) -> bool:
            return check_availability("e2b")  # cached importlib.util.find_spec
    ```

    Never do heavy imports inside `is_available()` — it is called on every registry probe.
  </Accordion>

  <Accordion title="Error-message hints">
    Include helpful hints in your error messages so users know what to install:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    def run(self, prompt, **kwargs):
        if not self.is_available():
            raise RuntimeError(
                "e2b backend requires 'e2b' package. Install with: pip install e2b"
            )
        import e2b
        ...
    ```
  </Accordion>

  <Accordion title="Cleanup hooks">
    Implement resource cleanup if your backend opens connections or sandbox environments:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    class E2BManagedAgent:
        def __init__(self, provider="e2b", config=None, **kwargs):
            self._sandbox = None

        def run(self, prompt, **kwargs):
            import e2b
            self._sandbox = e2b.Sandbox()
            return self._sandbox.run_code(prompt)

        def cleanup(self):
            if self._sandbox:
                self._sandbox.close()
                self._sandbox = None
    ```
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Framework Adapter Plugins" icon="puzzle-piece" href="/docs/features/framework-adapter-plugins">
    Add new execution frameworks via entry points
  </Card>

  <Card title="Hosted Agent" icon="cloud" href="/docs/features/hosted-agent">
    Run agent loops on managed cloud runtimes
  </Card>
</CardGroup>
