Repository: emcie-co/parlant
File: src/parlant/bin/server.py (Python)

Code before:
def load_openai() -> NLPService:
    from parlant.adapters.nlp.openai import OpenAIService

    return OpenAIService(LOGGER)


def load_together() -> NLPService:
    from parlant.adapters.nlp.together import TogetherService

    return TogetherService(LOGGER)


async def create_agent_if_absent(agent_store: AgentStore) -> None:
    agents = await agent_store.list_agents()
    if not agents:
        await agent_store.create_agent(name=DEFAULT_AGENT_NAME)


@asynccontextmanager
async def load_module(
    container: Container,
    module_path: str,
) -> AsyncIterator[None]:
    mod = importlib.import_module(module_path)

    if module_path.endswith("parlant_config"):
        if not hasattr(mod, "load_modules"):
            raise StartupError("parlant_config must define a function load_modules()")

        submodule_paths = mod.load_modules()
        submodules = []
        for submodule_path in submodule_paths:
            submodule = importlib.import_module(submodule_path)
            if not hasattr(submodule, "initialize_module") or not hasattr(
                submodule, "shutdown_module"
            ):
                raise StartupError(
                    f"Module {submodule.__name__} must define initialize_module and shutdown_module"
                )
            submodules.append(submodule)
    else:
        submodules = [mod]

    for m in submodules:
        await m.initialize_module(container)

    try:
        yield
    finally:
        for m in submodules:
            await m.shutdown_module()

Review comment (suggestion):
config shouldn't be a module but a `.toml` file. I.e.
```toml
[parlant]
modules = [ "module_1", "module_2" ]
```

Code after:
def load_openai() -> NLPService:
    from parlant.adapters.nlp.openai import OpenAIService

    return OpenAIService(LOGGER)


def load_together() -> NLPService:
    from parlant.adapters.nlp.together import TogetherService

    return TogetherService(LOGGER)


async def create_agent_if_absent(agent_store: AgentStore) -> None:
    agents = await agent_store.list_agents()
    if not agents:
        await agent_store.create_agent(name=DEFAULT_AGENT_NAME)


async def get_module_list_from_config() -> list[str]:
    config_file = Path("parlant.toml")

    if config_file.exists():
        config = toml.load(config_file)
        # Expecting structure of:
        # [parlant]
        # modules = ["module_1", "module_2"]
        return list(config.get("parlant", {}).get("modules", []))

    return []


@asynccontextmanager
async def load_modules(
    container: Container,
    modules: Iterable[str],
) -> AsyncIterator[None]:
    imported_modules = []

    for module_path in modules:
        module = importlib.import_module(module_path)
        if not hasattr(module, "initialize_module") or not hasattr(module, "shutdown_module"):
            raise StartupError(
                f"Module '{module.__name__}' must define initialize_module(container: lagom.Container) and shutdown_module()"
            )
        imported_modules.append(module)

    for m in imported_modules:
        LOGGER.info(f"Initializing module '{m.__name__}'")
        await m.initialize_module(container)

    try: