Skip to content
Open
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
1 change: 1 addition & 0 deletions libs/giskard-llm/src/giskard/llm/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

_PROVIDER_REGISTRY: dict[str, tuple[str, str]] = {
"openai": ("giskard.llm.providers.openai", "OpenAIProvider"),
"minimax": ("giskard.llm.providers.openai", "OpenAIProvider"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using OpenAIProvider directly for minimax without explicit configuration will cause it to default to OpenAI's base URL (https://api.openai.com/v1) and look for OPENAI_API_KEY in the environment. This means unconfigured routing for minimax/* models will fail or incorrectly target OpenAI endpoints.

To fix this, we should define a MiniMaxProvider subclass in libs/giskard-llm/src/giskard/llm/providers/openai.py that defaults to the MiniMax base URL (https://api.minimax.chat/v1) and looks up MINIMAX_API_KEY from the environment if not explicitly provided.

For example, in libs/giskard-llm/src/giskard/llm/providers/openai.py:

class MiniMaxProvider(OpenAIProvider):
    _PROVIDER = "minimax"

    def __init__(
        self, 
        api_key: str | None = None, 
        base_url: str | None = None, 
        **kwargs: Any
    ) -> None:
        import os
        api_key = api_key or os.environ.get("MINIMAX_API_KEY")
        base_url = base_url or "https://api.minimax.chat/v1"
        super().__init__(api_key=api_key, base_url=base_url, **kwargs)
Suggested change
"minimax": ("giskard.llm.providers.openai", "OpenAIProvider"),
"minimax": ("giskard.llm.providers.openai", "MiniMaxProvider"),

"google": ("giskard.llm.providers.google", "GoogleProvider"),
"gemini": ("giskard.llm.providers.google", "GoogleProvider"),
"anthropic": ("giskard.llm.providers.anthropic", "AnthropicProvider"),
Expand Down
15 changes: 15 additions & 0 deletions libs/giskard-llm/tests/test_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from giskard.llm.providers.base import CompletionProvider
from giskard.llm.routing import (
LLMClient,
_create_provider,
Expand Down Expand Up @@ -206,6 +207,20 @@ def test_client_unconfigured_registry_provider():
mock_create.assert_called_once_with("openai")


@pytest.mark.parametrize("model", ["MiniMax-M3", "MiniMax-M2.7"])
def test_client_routes_minimax_models(model):
client = LLMClient()
with patch("giskard.llm.routing._create_provider") as mock_create:
mock_create.return_value = MagicMock()
provider, routed_model = client._resolve(
f"minimax/{model}", CompletionProvider, "completions"
)

assert provider is mock_create.return_value
assert routed_model == model
mock_create.assert_called_once_with("minimax")


def test_client_unknown_provider_raises():
client = LLMClient()
with pytest.raises(ValueError, match="not configured"):
Expand Down
Loading