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

# nemoguardrails.llm.clients.base

## Module Contents

### Classes

| Name                                                            | Description |
| --------------------------------------------------------------- | ----------- |
| [`BaseClient`](#nemoguardrails-llm-clients-base-BaseClient)     | -           |
| [`HTTPResponse`](#nemoguardrails-llm-clients-base-HTTPResponse) | -           |

### Functions

| Name                                                                            | Description                                                            |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [`_is_stale_loop_error`](#nemoguardrails-llm-clients-base-_is_stale_loop_error) | Return True if `err` is a RuntimeError caused by a stale loop binding. |

### Data

[`_STALE_LOOP_MARKERS`](#nemoguardrails-llm-clients-base-_STALE_LOOP_MARKERS)

[`log`](#nemoguardrails-llm-clients-base-log)

### API

```python
class nemoguardrails.llm.clients.base.BaseClient(
    base_url: str,
    api_key: typing.Optional[str] = None,
    timeout: typing.Optional[float] = None,
    connect_timeout: typing.Optional[float] = None,
    max_retries: int = DEFAULT_MAX_RETRIES,
    custom_headers: typing.Optional[typing.Dict[str, str]] = None,
    custom_query: typing.Optional[typing.Dict[str, typing.Any]] = None,
    http_client: typing.Optional[httpx.AsyncClient] = None
)
```

```python
nemoguardrails.llm.clients.base.BaseClient.__aenter__()
```

async

```python
nemoguardrails.llm.clients.base.BaseClient.__aexit__(
    args = ()
)
```

async

```python
nemoguardrails.llm.clients.base.BaseClient._apost(
    path: str,
    payload: typing.Dict[str, typing.Any]
) -> nemoguardrails.llm.clients.base.HTTPResponse
```

async

```python
nemoguardrails.llm.clients.base.BaseClient._apost_stream(
    path: str,
    payload: typing.Dict[str, typing.Any]
) -> typing.AsyncGenerator[nemoguardrails.llm.clients.base.HTTPResponse, None]
```

async

```python
nemoguardrails.llm.clients.base.BaseClient._build_headers() -> typing.Dict[str, str]
```

```python
nemoguardrails.llm.clients.base.BaseClient._calculate_retry_delay(
    headers: typing.Any,
    retries_attempted: int
) -> float
```

staticmethod

```python
nemoguardrails.llm.clients.base.BaseClient._check_sse_error(
    parsed: typing.Any,
    headers: typing.Any,
    ctx: typing.Optional[nemoguardrails.llm.clients._errors.ErrorContext] = None
) -> None
```

```python
nemoguardrails.llm.clients.base.BaseClient._error_context() -> nemoguardrails.llm.clients._errors.ErrorContext
```

```python
nemoguardrails.llm.clients.base.BaseClient._should_retry(
    status_code: int,
    headers: typing.Any
) -> bool
```

staticmethod

```python
nemoguardrails.llm.clients.base.BaseClient._sleep_for_retry(
    retries_attempted: int,
    headers: typing.Any = None
) -> None
```

async

```python
nemoguardrails.llm.clients.base.BaseClient.close() -> None
```

async

```python
nemoguardrails.llm.clients.base.BaseClient.is_closed() -> bool
```

```python
class nemoguardrails.llm.clients.base.HTTPResponse(
    body: typing.Dict[str, typing.Any],
    headers: typing.Mapping[str, str] = dict(),
    status_code: int = 200
)
```

Dataclass

```python
nemoguardrails.llm.clients.base._is_stale_loop_error(
    err: BaseException
) -> bool
```

Return True if `err` is a RuntimeError caused by a stale loop binding.

CPython raises one of several messages when an httpx transport (or any
asyncio primitive it owns) is reused on a loop other than the one it
was created on:

* 'Event loop is closed' (BaseEventLoop.\_check\_closed) when the
  original loop has been closed.
* '\<asyncio.X object> is bound to a different event loop' (Lock /
  Event / Semaphore / Queue) when the original loop is still alive.
* 'got Future attached to a different loop' / 'Task got Future ...'
  when a Future created in another loop is awaited.

All three are transient: httpx invalidates the stale primitive on retry
and rebuilds it in the running loop.

```python
nemoguardrails.llm.clients.base._STALE_LOOP_MARKERS = ('event loop is closed', 'different loop', 'different event loop')
```

```python
nemoguardrails.llm.clients.base.log = logging.getLogger(__name__)
```