[fix] plugin: accept version pinned model names
The pattern that validates the model name rejected "@", so names like gemini-1.5-pro@001 were refused with "no valid model configured". Those names are ordinary on the gateways this plugin can be pointed at, which made the api_key support less useful than it looks. Verified against a LiteLLM gateway serving an alias named gemma4-e4b@001: the model list, the request and the streamed answer all carry the pinned name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,11 @@ if t.TYPE_CHECKING:
|
|||||||
from . import PluginCfg
|
from . import PluginCfg
|
||||||
|
|
||||||
VALID_ROLES = ("user", "assistant")
|
VALID_ROLES = ("user", "assistant")
|
||||||
MODEL_NAME_REGEXP = re.compile(r"[A-Za-z0-9._:/-]{1,128}")
|
# Model names differ per provider: "gemma3:4b" (Ollama), "bedrock/anthropic.
|
||||||
|
# claude-3-5-sonnet" (a gateway's routing prefix), "gemini-1.5-pro@001" (a
|
||||||
|
# pinned version). The pattern accepts those and rejects anything that could
|
||||||
|
# change the meaning of the request body it is placed into.
|
||||||
|
MODEL_NAME_REGEXP = re.compile(r"[A-Za-z0-9._:/@-]{1,128}")
|
||||||
|
|
||||||
log = logging.getLogger("searx.plugins.ai_summary")
|
log = logging.getLogger("searx.plugins.ai_summary")
|
||||||
|
|
||||||
|
|||||||
@@ -324,9 +324,29 @@ class PluginAISummary(SearxTestCase):
|
|||||||
self.assertEqual(res.status_code, 400)
|
self.assertEqual(res.status_code, 400)
|
||||||
|
|
||||||
def test_endpoint_invalid_model_pref(self):
|
def test_endpoint_invalid_model_pref(self):
|
||||||
self.client.set_cookie("ai_summary_model", "bad model name!")
|
# an empty preference is not invalid -- it falls back to the
|
||||||
|
# administrator's default, which is covered by the tests above
|
||||||
|
for model in ["bad model name!", "model;rm -rf", 'model"quoted', "model\nname", "x" * 129]:
|
||||||
|
self.client.set_cookie("ai_summary_model", model)
|
||||||
res = self.client.post("/ai_summary", json={"messages": [{"role": "user", "content": "hi"}]})
|
res = self.client.post("/ai_summary", json={"messages": [{"role": "user", "content": "hi"}]})
|
||||||
self.assertEqual(res.status_code, 400)
|
self.assertEqual(res.status_code, 400, model)
|
||||||
|
|
||||||
|
def test_endpoint_accepts_provider_model_names(self):
|
||||||
|
# model names differ per provider: a version pin (@), a gateway's
|
||||||
|
# routing prefix (/) and an Ollama tag (:) are all valid names
|
||||||
|
for model in [
|
||||||
|
"gemma3:4b",
|
||||||
|
"llama3.2:3b",
|
||||||
|
"gemini-1.5-pro@001",
|
||||||
|
"bedrock/anthropic.claude-3-5-sonnet",
|
||||||
|
"azure/my-deployment",
|
||||||
|
]:
|
||||||
|
self.mock_upstream(sse_stream_mock([]))
|
||||||
|
self.client.set_cookie("ai_summary_model", model)
|
||||||
|
res = self.client.post("/ai_summary", json={"messages": [{"role": "user", "content": "hi"}]})
|
||||||
|
self.assertEqual(res.status_code, 200, model)
|
||||||
|
lines = [json.loads(line) for line in res.data.decode().splitlines() if line]
|
||||||
|
self.assertEqual(lines[-1], {"done": True, "model": model})
|
||||||
|
|
||||||
def test_endpoint_no_server_configured(self):
|
def test_endpoint_no_server_configured(self):
|
||||||
self.setattr4test(searx.get_setting("ai_summary"), "base_url", "")
|
self.setattr4test(searx.get_setting("ai_summary"), "base_url", "")
|
||||||
|
|||||||
Reference in New Issue
Block a user