Add MiniMax as a first-class LLM provider#1738
Add MiniMax as a first-class LLM provider#1738octo-patch wants to merge 3216 commits intoNVIDIA-NeMo:developfrom
Conversation
add api key to server ci tests
…_and_yarn/npm_and_yarn-3655252575 Bump webpack-dev-server from 4.15.2 to 5.2.2 in the npm_and_yarn group across 1 directory
Update cohere model
fix link to server documentation
…/pip-829a645e36 Bump the pip group across 1 directory with 3 updates
move docs stuff to /docs
realias docs navbar to guardrailsai.com
…llm-pin URGENT - pin litellm below vulnerable version
Pouyanpi
left a comment
There was a problem hiding this comment.
Thank you @octo-patch for the PR.
Is there any reason that you are avoiding following config:
models:
- type: main
engine: openai
model: MiniMax-M2.7
parameters:
api_key: ${MINIMAX_API_KEY}
base_url: https://api.minimax.io/v1
temperature: 0.5|
Great point @Pouyanpi! You're right — since MiniMax's API is OpenAI-compatible, using the The main reason for the dedicated engine was to handle MiniMax-specific behavior like temperature clamping (MiniMax requires temperature > 0) and think-tag stripping from reasoning model responses. But these could also be handled as pre/post-processing within the openai engine config. If you'd prefer the simpler |
[GR-1405]: Use guardrails_ai.types and Standard Http Client instead of guardrails_api_client
- Add MiniMaxCallable and AsyncMiniMaxCallable to llm_providers.py - MiniMax uses OpenAI-compatible API (api.minimax.io/v1) with MINIMAX_API_KEY - Supports MiniMax-M2.7 and MiniMax-M2.7-highspeed models - Auto-routes model names starting with 'MiniMax' to MiniMaxCallable - Handles MiniMax temperature constraint (must be in (0.0, 1.0]) - Add unit tests for MiniMaxCallable and routing logic
1366861 to
8ff6806
Compare
Greptile SummaryThis PR adds
|
| Filename | Overview |
|---|---|
| guardrails/llm_providers.py | Adds MiniMaxCallable and AsyncMiniMaxCallable; routing logic in get_llm_ask / get_async_llm_ask looks correct, but API key validation uses is None instead of not resolved_api_key, silently passing empty-string keys to OpenAI client. |
| tests/unit_tests/test_llm_providers.py | Adds tests for MiniMaxCallable sync path; the no-API-key test passes for the wrong reason (empty-string vs. None check mismatch), and AsyncMiniMaxCallable routing via get_async_llm_ask is not covered. |
Comments Outside Diff (4)
-
guardrails/llm_providers.py, line 302-307 (link)API key validation misses empty-string keys
is Noneonly catches a missing key; an empty string (MINIMAX_API_KEY="") evaluatesNone or ""→"", which is notNone, so the guard never fires. The code then callsopenai.Client(api_key=""), which eventually fails with an opaque OpenAI auth error instead of the intended clear message. The same bug is inAsyncMiniMaxCallableat line 886–890. -
guardrails/llm_providers.py, line 313-315 (link)Silent temperature override may surprise callers
The condition
kwargs.get("temperature", 0) == 0is intentionally true when no temperature is provided (default 0), but it is also true when a caller explicitly passestemperature=0. Since MiniMax forbidstemperature=0, overriding it to1.0is necessary, but doing so silently discards the user's explicit choice. Adding awarnings.warnwhen the passed value is exactly0would surface this constraint rather than silently change it. The same pattern is repeated inAsyncMiniMaxCallableat line 898–899. -
tests/unit_tests/test_llm_providers.py, line 415-426 (link)Test passes for the wrong reason
mocker.patch.dict("os.environ", {"MINIMAX_API_KEY": ""})sets the key to an empty string, not removes it. With the currentis Nonecheck in_invoke_llm,resolved_api_keyevaluates to""(notNone), so the guard never fires. The test passes only becausePromptCallableBase.__call__wraps all downstream exceptions asPromptCallableException. If the validation check is fixed toif not resolved_api_key:, the test would immediately test the right code path. In the meantime this is masking the empty-string bug described above. -
guardrails/llm_providers.py, line 309 (link)New OpenAI client created on every invocation
openai.Client(...)is instantiated inside_invoke_llm, so every call to the callable creates a new HTTP client with its own connection pool. The same applies toAsyncMiniMaxCallableat line 893. Caching the client as an instance attribute set during__init__would reuse the underlying connection pool across calls, consistent with how most SDK clients are intended to be used.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: guardrails/llm_providers.py
Line: 302-307
Comment:
**API key validation misses empty-string keys**
`is None` only catches a missing key; an empty string (`MINIMAX_API_KEY=""`) evaluates `None or ""` → `""`, which is not `None`, so the guard never fires. The code then calls `openai.Client(api_key="")`, which eventually fails with an opaque OpenAI auth error instead of the intended clear message. The same bug is in `AsyncMiniMaxCallable` at line 886–890.
```suggestion
resolved_api_key = api_key or os.environ.get("MINIMAX_API_KEY")
if not resolved_api_key:
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: guardrails/llm_providers.py
Line: 313-315
Comment:
**Silent temperature override may surprise callers**
The condition `kwargs.get("temperature", 0) == 0` is intentionally true when no temperature is provided (default 0), but it is also true when a caller explicitly passes `temperature=0`. Since MiniMax forbids `temperature=0`, overriding it to `1.0` is necessary, but doing so silently discards the user's explicit choice. Adding a `warnings.warn` when the passed value is exactly `0` would surface this constraint rather than silently change it. The same pattern is repeated in `AsyncMiniMaxCallable` at line 898–899.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: tests/unit_tests/test_llm_providers.py
Line: 415-426
Comment:
**Test passes for the wrong reason**
`mocker.patch.dict("os.environ", {"MINIMAX_API_KEY": ""})` sets the key to an empty string, not removes it. With the current `is None` check in `_invoke_llm`, `resolved_api_key` evaluates to `""` (not `None`), so the guard never fires. The test passes only because `PromptCallableBase.__call__` wraps all downstream exceptions as `PromptCallableException`. If the validation check is fixed to `if not resolved_api_key:`, the test would immediately test the right code path. In the meantime this is masking the empty-string bug described above.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: guardrails/llm_providers.py
Line: 309
Comment:
**New OpenAI client created on every invocation**
`openai.Client(...)` is instantiated inside `_invoke_llm`, so every call to the callable creates a new HTTP client with its own connection pool. The same applies to `AsyncMiniMaxCallable` at line 893. Caching the client as an instance attribute set during `__init__` would reuse the underlying connection pool across calls, consistent with how most SDK clients are intended to be used.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat: add MiniMax provider support via O..." | Re-trigger Greptile
Summary
Add MiniMax as a first-class LLM provider in NeMo Guardrails, enabling users to configure MiniMax models (M2.7, M2.5, M2.5-highspeed) via the standard
config.ymlwithengine: minimax.MiniMax provides an OpenAI-compatible API, so the integration uses
ChatOpenAIfromlangchain-openaiunder the hood with MiniMax's API endpoint (https://api.minimax.io/v1). This follows the same pattern used by the existing NIM provider initializer.Changes
nemoguardrails/llm/models/langchain_initializer.py: Add_init_minimax_model()function and register"minimax"in_PROVIDER_INITIALIZERSChatOpenAIwith MiniMax's base URLMINIMAX_API_KEYenv var andapi_keyparameterbase_urloverride supportexamples/configs/llm/minimax/config.yml: Configuration exampleexamples/configs/llm/minimax/README.md: Documentation with available models and usagetests/llm/models/test_minimax_provider.py: 16 tests (unit + integration)_handle_model_special_casesUsage
Set the API key via environment variable:
Test Plan
pytest tests/llm/models/test_minimax_provider.py)pytest tests/llm/models/test_langchain_special_cases.py— 6 passed, 4 skipped)MINIMAX_API_KEYis set)