fix: address review feedback for the Minimax LLM provider
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: MiniMax
|
||||
description: "Configure MiniMax as an LLM provider in Mem0 with API key setup and optional custom endpoint configuration."
|
||||
---
|
||||
|
||||
To use MiniMax LLM models, you have to set the `MINIMAX_API_KEY` environment variable. You can also optionally set `MINIMAX_API_BASE` if you need to use a different API endpoint (defaults to "https://api.minimax.io/v1").
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
import os
|
||||
from mem0 import Memory
|
||||
|
||||
os.environ["MINIMAX_API_KEY"] = "your-api-key"
|
||||
os.environ["OPENAI_API_KEY"] = "your-api-key" # for embedder model
|
||||
|
||||
config = {
|
||||
"llm": {
|
||||
"provider": "minimax",
|
||||
"config": {
|
||||
"model": "MiniMax-M2.7", # default model
|
||||
"temperature": 0.2,
|
||||
"max_tokens": 2000,
|
||||
"top_p": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m = Memory.from_config(config)
|
||||
messages = [
|
||||
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
|
||||
{"role": "assistant", "content": "How about thriller movies? They can be quite engaging."},
|
||||
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
|
||||
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
|
||||
]
|
||||
m.add(messages, user_id="alice", metadata={"category": "movies"})
|
||||
```
|
||||
|
||||
You can also configure the API base URL in the config:
|
||||
|
||||
```python
|
||||
config = {
|
||||
"llm": {
|
||||
"provider": "minimax",
|
||||
"config": {
|
||||
"model": "MiniMax-M2.7",
|
||||
"minimax_base_url": "https://your-custom-endpoint.com",
|
||||
"api_key": "your-api-key" # alternatively to using environment variable
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
All available parameters for the `minimax` config are present in [Master List of All Params in Config](../config).
|
||||
@@ -31,6 +31,7 @@ See the list of supported LLMs below.
|
||||
<Card title="Google AI" href="/components/llms/models/google_AI" />
|
||||
<Card title="AWS bedrock" href="/components/llms/models/aws_bedrock" />
|
||||
<Card title="DeepSeek" href="/components/llms/models/deepseek" />
|
||||
<Card title="MiniMax" href="/components/llms/models/minimax" />
|
||||
<Card title="xAI" href="/components/llms/models/xAI" />
|
||||
<Card title="Sarvam AI" href="/components/llms/models/sarvam" />
|
||||
<Card title="LM Studio" href="/components/llms/models/lmstudio" />
|
||||
|
||||
@@ -34,13 +34,13 @@ class MiniMaxLLM(LLMBase):
|
||||
super().__init__(config)
|
||||
|
||||
if not self.config.model:
|
||||
self.config.model = "MiniMax-M2.1"
|
||||
self.config.model = "MiniMax-M2.7"
|
||||
|
||||
api_key = self.config.api_key or os.getenv("MINIMAX_API_KEY")
|
||||
base_url = (
|
||||
self.config.minimax_base_url
|
||||
or os.getenv("MINIMAX_API_BASE")
|
||||
or "https://api.minimaxi.io/v1"
|
||||
or "https://api.minimax.io/v1"
|
||||
)
|
||||
self.client = OpenAI(api_key=api_key, base_url=base_url)
|
||||
|
||||
@@ -103,6 +103,9 @@ class MiniMaxLLM(LLMBase):
|
||||
}
|
||||
)
|
||||
|
||||
if response_format:
|
||||
params["response_format"] = response_format
|
||||
|
||||
if tools:
|
||||
params["tools"] = tools
|
||||
params["tool_choice"] = tool_choice
|
||||
|
||||
+39
-14
@@ -20,11 +20,11 @@ def mock_minimax_client():
|
||||
def test_minimax_llm_default_base_url():
|
||||
"""Default config uses MiniMax official base URL."""
|
||||
config = BaseLlmConfig(
|
||||
model="MiniMax-M2.1", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
model="MiniMax-M2.7", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
)
|
||||
llm = MiniMaxLLM(config)
|
||||
# OpenAI client may normalize URL with trailing slash
|
||||
assert str(llm.client.base_url).rstrip("/") == "https://api.minimaxi.io/v1"
|
||||
assert str(llm.client.base_url).rstrip("/") == "https://api.minimax.io/v1"
|
||||
|
||||
|
||||
def test_minimax_llm_env_base_url():
|
||||
@@ -33,7 +33,7 @@ def test_minimax_llm_env_base_url():
|
||||
os.environ["MINIMAX_API_BASE"] = provider_base_url
|
||||
try:
|
||||
config = MinimaxConfig(
|
||||
model="MiniMax-M2.1",
|
||||
model="MiniMax-M2.7",
|
||||
temperature=0.7,
|
||||
max_tokens=100,
|
||||
top_p=1.0,
|
||||
@@ -49,7 +49,7 @@ def test_minimax_llm_config_base_url():
|
||||
"""Config uses minimax_base_url when provided."""
|
||||
config_base_url = "https://api.config.com/v1/"
|
||||
config = MinimaxConfig(
|
||||
model="MiniMax-M2.1",
|
||||
model="MiniMax-M2.7",
|
||||
temperature=0.7,
|
||||
max_tokens=100,
|
||||
top_p=1.0,
|
||||
@@ -61,10 +61,10 @@ def test_minimax_llm_config_base_url():
|
||||
|
||||
|
||||
def test_minimax_llm_default_model(mock_minimax_client):
|
||||
"""Default model is MiniMax-M2.1 when not specified."""
|
||||
"""Default model is MiniMax-M2.7 when not specified."""
|
||||
config = MinimaxConfig(temperature=0.7, max_tokens=100, api_key="api_key")
|
||||
llm = MiniMaxLLM(config)
|
||||
assert llm.config.model == "MiniMax-M2.1"
|
||||
assert llm.config.model == "MiniMax-M2.7"
|
||||
|
||||
|
||||
def test_minimax_llm_env_api_key():
|
||||
@@ -74,11 +74,11 @@ def test_minimax_llm_env_api_key():
|
||||
with patch("mem0.llms.minimax.OpenAI") as mock_openai:
|
||||
mock_client = Mock()
|
||||
mock_openai.return_value = mock_client
|
||||
config = MinimaxConfig(model="MiniMax-M2.1", api_key=None)
|
||||
config = MinimaxConfig(model="MiniMax-M2.7", api_key=None)
|
||||
MiniMaxLLM(config)
|
||||
mock_openai.assert_called_once_with(
|
||||
api_key="env-api-key",
|
||||
base_url="https://api.minimaxi.io/v1",
|
||||
base_url="https://api.minimax.io/v1",
|
||||
)
|
||||
finally:
|
||||
os.environ.pop("MINIMAX_API_KEY", None)
|
||||
@@ -87,7 +87,7 @@ def test_minimax_llm_env_api_key():
|
||||
def test_generate_response_without_tools(mock_minimax_client):
|
||||
"""generate_response returns text when no tools provided."""
|
||||
config = BaseLlmConfig(
|
||||
model="MiniMax-M2.1", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
model="MiniMax-M2.7", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
)
|
||||
llm = MiniMaxLLM(config)
|
||||
messages = [
|
||||
@@ -102,7 +102,7 @@ def test_generate_response_without_tools(mock_minimax_client):
|
||||
response = llm.generate_response(messages)
|
||||
|
||||
mock_minimax_client.chat.completions.create.assert_called_once_with(
|
||||
model="MiniMax-M2.1", messages=messages, temperature=0.7, max_tokens=100, top_p=1.0
|
||||
model="MiniMax-M2.7", messages=messages, temperature=0.7, max_tokens=100, top_p=1.0
|
||||
)
|
||||
assert response == "I'm doing well, thank you for asking!"
|
||||
|
||||
@@ -110,7 +110,7 @@ def test_generate_response_without_tools(mock_minimax_client):
|
||||
def test_generate_response_with_tools(mock_minimax_client):
|
||||
"""generate_response returns tool_calls when tools provided."""
|
||||
config = BaseLlmConfig(
|
||||
model="MiniMax-M2.1", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
model="MiniMax-M2.7", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
)
|
||||
llm = MiniMaxLLM(config)
|
||||
messages = [
|
||||
@@ -147,7 +147,7 @@ def test_generate_response_with_tools(mock_minimax_client):
|
||||
response = llm.generate_response(messages, tools=tools)
|
||||
|
||||
mock_minimax_client.chat.completions.create.assert_called_once_with(
|
||||
model="MiniMax-M2.1",
|
||||
model="MiniMax-M2.7",
|
||||
messages=messages,
|
||||
temperature=0.7,
|
||||
max_tokens=100,
|
||||
@@ -162,8 +162,33 @@ def test_generate_response_with_tools(mock_minimax_client):
|
||||
assert response["tool_calls"][0]["arguments"] == {"data": "Today is a sunny day."}
|
||||
|
||||
|
||||
def test_generate_response_with_response_format(mock_minimax_client):
|
||||
"""generate_response passes response_format to the API."""
|
||||
config = BaseLlmConfig(
|
||||
model="MiniMax-M2.7", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
)
|
||||
llm = MiniMaxLLM(config)
|
||||
messages = [{"role": "user", "content": "Return JSON."}]
|
||||
response_format = {"type": "json_object"}
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content='{"key": "value"}'))]
|
||||
mock_minimax_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response(messages, response_format=response_format)
|
||||
|
||||
mock_minimax_client.chat.completions.create.assert_called_once_with(
|
||||
model="MiniMax-M2.7",
|
||||
messages=messages,
|
||||
temperature=0.7,
|
||||
max_tokens=100,
|
||||
top_p=1.0,
|
||||
response_format={"type": "json_object"},
|
||||
)
|
||||
|
||||
|
||||
def test_factory_creates_minimax_llm(mock_minimax_client):
|
||||
"""LlmFactory.create returns MiniMaxLLM for provider 'minimax'."""
|
||||
llm = LlmFactory.create("minimax", {"model": "MiniMax-M2.1", "api_key": "test-key"})
|
||||
llm = LlmFactory.create("minimax", {"model": "MiniMax-M2.7", "api_key": "test-key"})
|
||||
assert isinstance(llm, MiniMaxLLM)
|
||||
assert llm.config.model == "MiniMax-M2.1"
|
||||
assert llm.config.model == "MiniMax-M2.7"
|
||||
|
||||
Reference in New Issue
Block a user