> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/gym/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/gym/_mcp/server.

# nemo_gym.base_environment_server

Shared lifecycle for environment servers.

## Module Contents

### Classes

| Name                                                                                           | Description                                                     |
| ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| [`BaseEnvironmentServer`](#nemo_gym-base_environment_server-BaseEnvironmentServer)             | Expose a typed episode protocol with shared limits and cleanup. |
| [`BaseEnvironmentServerConfig`](#nemo_gym-base_environment_server-BaseEnvironmentServerConfig) | Configure protocol-neutral episode limits.                      |
| [`CleanupContext`](#nemo_gym-base_environment_server-CleanupContext)                           | Hold bounded process-local cleanup callbacks for one episode.   |
| [`CleanupHandle`](#nemo_gym-base_environment_server-CleanupHandle)                             | Close one registered participant at a protocol boundary.        |
| [`HandledEpisodeError`](#nemo_gym-base_environment_server-HandledEpisodeError)                 | Carry a failure that belongs in the native episode response.    |
| [`_CleanupEntry`](#nemo_gym-base_environment_server-_CleanupEntry)                             | -                                                               |

### Data

[`CleanupCallback`](#nemo_gym-base_environment_server-CleanupCallback)

[`EpisodeRequestT`](#nemo_gym-base_environment_server-EpisodeRequestT)

[`EpisodeResponseT`](#nemo_gym-base_environment_server-EpisodeResponseT)

[`LOGGER`](#nemo_gym-base_environment_server-LOGGER)

### API

```python
class nemo_gym.base_environment_server.BaseEnvironmentServer()
```

**Bases:** [SimpleServer](/nemo-gym/nemo_gym/server_utils#nemo_gym-server_utils-SimpleServer), `Generic[EpisodeRequestT, EpisodeResponseT]`

Expose a typed episode protocol with shared limits and cleanup.

**`_admission`** `Semaphore | None = None`

---

**`config`** `BaseEnvironmentServerConfig`

---

**`request_model`** `type[EpisodeRequestT]`

---

**`response_model`** `type[EpisodeResponseT]`

---

```python
nemo_gym.base_environment_server.BaseEnvironmentServer._unhandled_failure_response(
    request: nemo_gym.base_environment_server.EpisodeRequestT,
    error: Exception
) -> nemo_gym.base_environment_server.EpisodeResponseT
```

```python
nemo_gym.base_environment_server.BaseEnvironmentServer.failure_response(
    request: nemo_gym.base_environment_server.EpisodeRequestT,
    failure: nemo_gym.episode_types.EpisodeFailure
) -> nemo_gym.base_environment_server.EpisodeResponseT
```

```python
nemo_gym.base_environment_server.BaseEnvironmentServer.model_post_init(
    context: typing.Any
) -> None
```

```python
nemo_gym.base_environment_server.BaseEnvironmentServer.run(
    request: nemo_gym.base_environment_server.EpisodeRequestT,
    cleanup: nemo_gym.base_environment_server.CleanupContext
) -> nemo_gym.base_environment_server.EpisodeResponseT
```

async

abstract

Run one concrete environment protocol.

```python
nemo_gym.base_environment_server.BaseEnvironmentServer.run_request(
    request: nemo_gym.base_environment_server.EpisodeRequestT
) -> nemo_gym.base_environment_server.EpisodeResponseT
```

async

```python
nemo_gym.base_environment_server.BaseEnvironmentServer.setup_webserver() -> fastapi.FastAPI
```

```python
nemo_gym.base_environment_server.BaseEnvironmentServer.validate_response_identity(
    request: nemo_gym.base_environment_server.EpisodeRequestT,
    response: nemo_gym.base_environment_server.EpisodeResponseT
) -> None
```

staticmethod

```python
class nemo_gym.base_environment_server.BaseEnvironmentServerConfig()
```

**Bases:** [BaseRunServerInstanceConfig](/nemo-gym/nemo_gym/config_types#nemo_gym-config_types-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`

---

```python
nemo_gym.base_environment_server.BaseEnvironmentServerConfig.validate_queue_timeout() -> typing_extensions.Self
```

```python
class nemo_gym.base_environment_server.CleanupContext(
    episode_id: nemo_gym.episode_types.EpisodeId,
    cleanup_timeout_seconds: float,
    _cleanups: list[nemo_gym.base_environment_server._CleanupEntry] = list()
)
```

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 within one total 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 are logged and do not stop later callbacks. Cleanup has no
durable retry after this context is discarded.

**`_cleanups`** `list[_CleanupEntry] = field(default_factory=list)`

---

**`cleanup_timeout_seconds`** `float`

---

**`episode_id`** `EpisodeId`

---

```python
nemo_gym.base_environment_server.CleanupContext.aclose() -> None
```

async

```python
nemo_gym.base_environment_server.CleanupContext.register_cleanup(
    name: str,
    callback: nemo_gym.base_environment_server.CleanupCallback
) -> nemo_gym.base_environment_server.CleanupHandle
```

```python
class nemo_gym.base_environment_server.CleanupHandle(
    entry: nemo_gym.base_environment_server._CleanupEntry,
    timeout_seconds: float
)
```

Dataclass

Close one registered participant at a protocol boundary.

**`entry`** `_CleanupEntry`

---

**`timeout_seconds`** `float`

---

```python
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.

```python
class nemo_gym.base_environment_server.HandledEpisodeError(
    failure: nemo_gym.episode_types.EpisodeFailure
)
```

Exception

**Bases:** `Exception`

Carry a failure that belongs in the native episode response.

```python
class nemo_gym.base_environment_server._CleanupEntry(
    name: str,
    callback: nemo_gym.base_environment_server.CleanupCallback,
    active: bool = True,
    lock: asyncio.Lock = asyncio.Lock()
)
```

Dataclass

**`active`** `bool = True`

---

**`callback`** `CleanupCallback`

---

**`lock`** `Lock = field(default_factory=(asyncio.Lock))`

---

**`name`** `str`

---

```python
nemo_gym.base_environment_server._CleanupEntry.close() -> None
```

async

```python
nemo_gym.base_environment_server.CleanupCallback = Callable[[], Awaitable[None]]
```

```python
nemo_gym.base_environment_server.EpisodeRequestT = TypeVar('EpisodeRequestT', bound=(BaseEpisodeRequest[Any]))
```

```python
nemo_gym.base_environment_server.EpisodeResponseT = TypeVar('EpisodeResponseT', bound=(BaseEpisodeResponse[Any]))
```

```python
nemo_gym.base_environment_server.LOGGER = logging.getLogger(__name__)
```