Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions nemo_rl/models/generation/sglang/sglang_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ def __init__(
if init_handles:
ray.get(init_handles)

@property
def cfg(self) -> SGLangConfig:
"""Full generation config, matching the ``GenerationInterface`` contract.

``sglang_cfg`` already is that config, so alias it rather than keep a
second reference. Backend-agnostic callers such as
``nemo_rl.weight_sync.factory.create_weight_synchronizer`` read
``generation.cfg`` regardless of backend.
"""
return self.sglang_cfg

# ------------------------------------------------------------------
# Engine topology properties (formerly ``ServerGroup``)
# ------------------------------------------------------------------
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/weight_sync/test_weight_synchronizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,36 @@ def test_colocated_sglang_returns_http(self):
)
assert isinstance(sync, HTTPWeightSynchronizer)

def test_colocated_sglang_accepts_real_generation_object(self):
"""A real SGLangGeneration must expose ``cfg`` like the other backends.

``create_weight_synchronizer`` reads ``generation.cfg`` before any
backend dispatch. The MagicMock double used above answers ``cfg``
automatically, so only the real class can catch a missing attribute.
"""
from nemo_rl.models.generation.sglang.sglang_generation import (
SGLangGeneration,
)

# ``__new__`` skips ``__init__``, which would need Ray, a router and
# live engines; ``cfg`` only depends on ``sglang_cfg``.
gen = SGLangGeneration.__new__(SGLangGeneration)
gen.sglang_cfg = {"backend": "sglang", "model_name": "dummy"}
# ``__del__`` calls ``shutdown()``, which reads these four attributes.
gen.all_engines = []
gen._router_actor = None
gen._http_client = None
gen._async_loop = None
assert gen.cfg is gen.sglang_cfg

sync = create_weight_synchronizer(
policy=_mock_policy(),
generation=gen,
generation_backend=SGLANG_BACKEND,
colocated=True,
)
assert isinstance(sync, HTTPWeightSynchronizer)

def test_colocated_megatron_returns_ipc(self):
policy = _mock_policy()
gen = _mock_generation()
Expand Down
Loading