| """ |
| External algorithm backends for SkyDiscover. |
| |
| Thin wrappers that delegate to external evolution packages (OpenEvolve, |
| ShinkaEvolve, GEPA, etc.) while returning SkyDiscover's unified DiscoveryResult. |
| |
| To add a new backend: |
| 1. Create skydiscover/extras/external/<name>_backend.py with an async ``run`` function |
| 2. Add an entry to ``_BACKENDS`` below |
| """ |
|
|
| from typing import Awaitable, Callable, Dict |
|
|
| |
| _REGISTRY: Dict[str, Callable[..., Awaitable]] = {} |
|
|
| |
| |
| KNOWN_EXTERNAL = {"openevolve", "shinkaevolve", "gepa"} |
|
|
| |
| _PACKAGE_NAMES = { |
| "shinkaevolve": "shinka", |
| "gepa": "gepa[full]", |
| } |
|
|
|
|
| def get_package_name(search_type: str) -> str: |
| """Return the pip-installable package name for a search type.""" |
| return _PACKAGE_NAMES.get(search_type, search_type) |
|
|
|
|
| _BACKENDS = [ |
| ("openevolve", "skydiscover.extras.external.openevolve_backend", "run"), |
| ("shinkaevolve", "skydiscover.extras.external.shinkaevolve_backend", "run"), |
| ("gepa", "skydiscover.extras.external.gepa_backend", "run"), |
| ] |
|
|
|
|
| def is_external(search_type: str) -> bool: |
| return search_type in _REGISTRY |
|
|
|
|
| def get_runner(search_type: str): |
| return _REGISTRY[search_type] |
|
|
|
|
| def _register_backends(): |
| """Attempt to register each backend. Missing packages are silently skipped.""" |
| import importlib |
| import logging |
|
|
| _logger = logging.getLogger(__name__) |
| for name, module_path, func_name in _BACKENDS: |
| try: |
| mod = importlib.import_module(module_path) |
| _REGISTRY[name] = getattr(mod, func_name) |
| except ImportError: |
| pass |
| except Exception as e: |
| _logger.warning("Backend '%s' package is installed but failed to register: %s", name, e) |
|
|
|
|
| _register_backends() |
|
|