Skip to navigation

nemo_gym.base_environment_server

View as Markdown

Shared lifecycle for environment servers.

Module Contents

Classes

NameDescription
BaseEnvironmentServerExpose a typed episode protocol with shared limits and cleanup.
BaseEnvironmentServerConfigConfigure protocol-neutral episode limits.
CleanupContextHold bounded process-local cleanup callbacks for one episode.
CleanupHandleClose one registered participant at a protocol boundary.
HandledEpisodeErrorCarry a failure that belongs in the episode response.
_CleanupEntry-

Data

CleanupCallback

EpisodeRequestT

EpisodeResponseT

LOGGER

API

class nemo_gym.base_environment_server.BaseEnvironmentServer()

Bases: SimpleServer, Generic[EpisodeRequestT, EpisodeResponseT]

Expose a typed episode protocol with shared limits and cleanup.

_admission
Semaphore | None = None
_checkpoint
EnvironmentParticipant | None = None
checkpoint_boundaries
bool = False
config
BaseEnvironmentServerConfig
request_model
type[EpisodeRequestT]
response_model
type[EpisodeResponseT]
nemo_gym.base_environment_server.BaseEnvironmentServer._unhandled_failure_response(
error: Exception
nemo_gym.base_environment_server.BaseEnvironmentServer.aggregate_metrics(
asyncabstract

Aggregate per-rollout scores into task-level metrics.

nemo_gym.base_environment_server.BaseEnvironmentServer.checkpoint_boundary(
state: dict[str, pydantic.JsonValue] | collections.abc.Callable[[], dict[str, pydantic.JsonValue]]
) -> None
async

Record that a protocol step completed; state names the next step and what it needs.

While a checkpoint is open the episode parks here until resume. A replacement attempt that continues a checkpoint receives the latest recorded state from checkpoint_continuation. Pass a function when building state costs something: it is called only with checkpointing on.

nemo_gym.base_environment_server.BaseEnvironmentServer.checkpoint_continuation(
) -> dict[str, pydantic.JsonValue] | None

Return the protocol state this attempt continues from a checkpoint, once, or None.

nemo_gym.base_environment_server.BaseEnvironmentServer.checkpoint_restart(
) -> None
async

Mark this episode as a restart: a server it uses cannot capture its part, such as a restart-only agent.

Call it when a seed reply says so (nemo_gym._checkpoint.steps.seed_restarts). The episode then never holds up a checkpoint and is never exported; after a crash, the controller starts it over from its input.

nemo_gym.base_environment_server.BaseEnvironmentServer.checkpoint_step(
mode: nemo_gym._checkpoint.steps.StepMode
) -> contextlib.AbstractAsyncContextManager[None]

Run one protocol step in wait or replay mode (see nemo_gym._checkpoint.steps).

Use replay only for a step that is safe to run again after a crash and does not change checkpointed state; everything else waits.

nemo_gym.base_environment_server.BaseEnvironmentServer.failure_response(
nemo_gym.base_environment_server.BaseEnvironmentServer.model_post_init(
context: typing.Any
) -> None
asyncabstract

Run one concrete environment protocol.

nemo_gym.base_environment_server.BaseEnvironmentServer.run_request(
async
nemo_gym.base_environment_server.BaseEnvironmentServer.setup_environment_checkpoint(
app: fastapi.FastAPI
) -> None

Take part in partial-rollout checkpoints when they are enabled.

Every episode is tracked. A protocol that records boundaries (checkpoint_boundaries) continues after a restore; the episodes of a protocol that records none are restarts, which never hold up a checkpoint and start over from their input after a crash. Call this from any setup_webserver that builds its own app.

nemo_gym.base_environment_server.BaseEnvironmentServer.setup_webserver() -> fastapi.FastAPI
nemo_gym.base_environment_server.BaseEnvironmentServer.validate_response_identity(
) -> None
staticmethod
class nemo_gym.base_environment_server.BaseEnvironmentServerConfig()

Bases: BaseRunServerInstanceConfig

Configure protocol-neutral episode limits.

cleanup_timeout_seconds
PositiveFloat
default_episode_timeout_seconds
PositiveFloat | None = None
max_concurrent_episodes
PositiveInt | None = None
model_config
= ConfigDict(extra='forbid')
queue_timeout_seconds
PositiveFloat | None = None
nemo_gym.base_environment_server.BaseEnvironmentServerConfig.validate_queue_timeout() -> typing_extensions.Self
class nemo_gym.base_environment_server.CleanupContext(
cleanup_timeout_seconds: float,
)
Dataclass

Hold bounded process-local cleanup callbacks for one episode.

Callbacks:

  • are process-local Python objects, although they may issue remote close requests;
  • run sequentially in LIFO order, each with its own cleanup timeout;
  • must be idempotent because a timed-out remote request may have succeeded;
  • are lost on process or host failure, so remote owners need expiry or reaping.

Callback failures or timeouts do not prevent later owners from tearing down their resources. Total cleanup is bounded by the number of registered callbacks times the per-callback timeout. Cleanup has no durable retry after this context is discarded.

_cleanups
list[_CleanupEntry] = field(default_factory=list)
cleanup_timeout_seconds
float
episode_id
EpisodeId
nemo_gym.base_environment_server.CleanupContext.aclose() -> None
async
nemo_gym.base_environment_server.CleanupContext.register_cleanup(
name: str,
class nemo_gym.base_environment_server.CleanupHandle(
timeout_seconds: float
)
Dataclass

Close one registered participant at a protocol boundary.

entry
_CleanupEntry
timeout_seconds
float
nemo_gym.base_environment_server.CleanupHandle.close() -> None
async

Run this idempotent callback once.

The episode timeout bounds calls made during the protocol. The context’s cleanup timeout bounds callbacks left for final unwinding.

class nemo_gym.base_environment_server.HandledEpisodeError(
)
Exception

Bases: Exception

Carry a failure that belongs in the episode response.

class nemo_gym.base_environment_server._CleanupEntry(
name: str,
active: bool = True,
lock: asyncio.Lock = asyncio.Lock()
)
Dataclass
active
bool = True
callback
CleanupCallback
lock
Lock = field(default_factory=(asyncio.Lock))
name
str
nemo_gym.base_environment_server._CleanupEntry.close() -> None
async
nemo_gym.base_environment_server.CleanupCallback = Callable[[], Awaitable[None]]
nemo_gym.base_environment_server.EpisodeRequestT = TypeVar('EpisodeRequestT', bound=(BaseEpisodeRequest[Any]))
nemo_gym.base_environment_server.EpisodeResponseT = TypeVar('EpisodeResponseT', bound=(BaseEpisodeResponse[Any]))
nemo_gym.base_environment_server.LOGGER = logging.getLogger(__name__)