11"""Adapter registry: ``load_model("dummy")`` -> a WorldModelAdapter.
22
3- This is the ``transformers``-style entry point for the project. New backends
4- register a factory here (or, later, via package entry points) and become
5- reachable by name from the CLI, the runtime node and the benchmark.
3+ This is the ``transformers``-style entry point for the project. Backends become
4+ reachable by name from the CLI, the runtime node and the benchmark in three ways:
5+
6+ 1. built-in adapters (dummy / remote / ijepa / vjepa2),
7+ 2. in-process ``register("name", factory)``,
8+ 3. **package entry points** — an external pip package exposes adapters under the
9+ ``world_model_ros2.adapters`` group, so installing it makes new World Models
10+ available with no edits here. This is what makes it an adapter *hub*.
11+
12+ In your package's pyproject.toml:
13+
14+ [project.entry-points."world_model_ros2.adapters"]
15+ mymodel = "my_pkg.adapter:make_my_adapter"
616"""
717from __future__ import annotations
818
19+ import warnings
920from typing import Callable , Dict
1021
1122from .adapters import DummyAdapter , RemoteAdapter , WorldModelAdapter
1223
24+ ENTRY_POINT_GROUP = "world_model_ros2.adapters"
25+
1326
1427def _make_ijepa (** kwargs ) -> WorldModelAdapter :
1528 # Lazy: importing jepa pulls torch/transformers only when actually used.
@@ -25,32 +38,64 @@ def _make_vjepa2(**kwargs) -> WorldModelAdapter:
2538 return make_vjepa2_adapter (** kwargs )
2639
2740
28- # name -> factory(**kwargs) -> adapter
29- _REGISTRY : Dict [str , Callable [..., WorldModelAdapter ]] = {
41+ # built-in name -> factory(**kwargs) -> adapter
42+ _BUILTIN : Dict [str , Callable [..., WorldModelAdapter ]] = {
3043 "dummy" : DummyAdapter ,
3144 "remote" : RemoteAdapter ,
3245 "ijepa" : _make_ijepa ,
3346 "vjepa2" : _make_vjepa2 ,
3447}
3548
49+ # adapters added at runtime via register()
50+ _EXTRA : Dict [str , Callable [..., WorldModelAdapter ]] = {}
51+
52+ # cache of entry-point-discovered factories (None until first discovery)
53+ _DISCOVERED : Dict [str , Callable [..., WorldModelAdapter ]] | None = None
54+
55+
56+ def _discover_entry_points () -> Dict [str , Callable [..., WorldModelAdapter ]]:
57+ """Load adapter factories advertised by installed packages. Cached; a single
58+ bad entry point warns rather than breaking the whole registry."""
59+ from importlib .metadata import entry_points
60+
61+ found : Dict [str , Callable [..., WorldModelAdapter ]] = {}
62+ try :
63+ eps = entry_points (group = ENTRY_POINT_GROUP )
64+ except TypeError : # very old importlib.metadata
65+ eps = entry_points ().get (ENTRY_POINT_GROUP , []) # type: ignore[attr-defined]
66+ for ep in eps :
67+ try :
68+ found [ep .name ] = ep .load ()
69+ except Exception as exc : # noqa: BLE001
70+ warnings .warn (f"failed to load adapter entry point '{ ep .name } ': { exc } " )
71+ return found
72+
73+
74+ def _registry () -> Dict [str , Callable [..., WorldModelAdapter ]]:
75+ global _DISCOVERED
76+ if _DISCOVERED is None :
77+ _DISCOVERED = _discover_entry_points ()
78+ # precedence: discovered < built-in < explicit register()
79+ return {** _DISCOVERED , ** _BUILTIN , ** _EXTRA }
80+
3681
3782def register (name : str , factory : Callable [..., WorldModelAdapter ]) -> None :
3883 """Register a new adapter factory under ``name`` (overwrites if present)."""
39- _REGISTRY [name ] = factory
84+ _EXTRA [name ] = factory
4085
4186
4287def available_models () -> list [str ]:
43- return sorted (_REGISTRY )
88+ return sorted (_registry () )
4489
4590
4691def load_model (name : str , ** kwargs ) -> WorldModelAdapter :
4792 """Instantiate the adapter registered under ``name``.
4893
49- Extra keyword arguments are passed to the adapter constructor , e.g.
94+ Extra keyword arguments are passed to the adapter factory , e.g.
5095 ``load_model("remote", url="http://gpu-box:8080/predict_future")``.
5196 """
5297 try :
53- factory = _REGISTRY [name ]
98+ factory = _registry () [name ]
5499 except KeyError :
55100 raise KeyError (
56101 f"unknown world model '{ name } '. available: { available_models ()} "
0 commit comments