Files
crewAI/lib/crewai/tests/rag/embeddings/test_factory_openrouter.py
Gamal Osama c860613c7a feat(embeddings): add openrouter as a supported embedding provider (#7127)
* feat(embeddings): add openrouter provider type definitions

* feat(embeddings): implement OpenRouterProvider

* feat(embeddings): export openrouter provider package symbols

* feat(embeddings): register openrouter in allowed embedding providers

* feat(embeddings): register openrouter provider and overloads in factory

* feat(tools): add openrouter embedding service support

* test(embeddings): add comprehensive openrouter provider and factory tests

* test(embeddings): add openrouter build test in embedding factory

* test(embeddings): add openrouter model key alias and env tests

* test(tools): add openrouter tests for embedding service

* docs: add openrouter embedder configuration example

* docs(ar): sync openrouter embedder translation

* docs(ko): sync openrouter embedder translation

* docs(pt-BR): sync openrouter embedder translation

* feat(embeddings): allow model alias and None fields in OpenRouterProviderConfig

* fix(tools): resolve EMBEDDINGS_OPENROUTER_API_KEY before OPENROUTER_API_KEY

* test(tools): add regression tests for openrouter env var precedence and fallback

* feat(embeddings): drop organization_id and resolve api_key via OPENROUTER_API_KEY only

* fix(tools): use OPENROUTER_API_KEY in embedding service and update tests

* docs: switch openrouter knowledge example to model_name and document OPENROUTER_API_KEY

* fix(tools): default openrouter model to namespaced openai/text-embedding-3-small

---------

Co-authored-by: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com>
2026-09-10 12:24:15 +05:30

158 lines
6.1 KiB
Python

"""Test OpenRouter embedder configuration with factory."""
from unittest.mock import MagicMock, patch
import pytest
from pydantic import ValidationError
from crewai.rag.embeddings.factory import build_embedder
from crewai.rag.embeddings.providers.openrouter.openrouter_provider import (
OpenRouterProvider,
)
class TestOpenRouterEmbedderFactory:
"""Test OpenRouter embedder configuration with factory function."""
@patch("crewai.rag.embeddings.factory.import_and_validate_definition")
def test_openrouter_with_nested_config(self, mock_import):
"""Test OpenRouter configuration with nested config key."""
mock_provider_class = MagicMock()
mock_provider_instance = MagicMock()
mock_embedding_function = MagicMock()
mock_import.return_value = mock_provider_class
mock_provider_class.return_value = mock_provider_instance
mock_provider_instance.embedding_callable.return_value = mock_embedding_function
embedder_config = {
"provider": "openrouter",
"config": {
"api_key": "test-openrouter-key",
"model_name": "openai/text-embedding-3-large",
"api_base": "https://openrouter.ai/api/v1",
"dimensions": 1536,
},
}
result = build_embedder(embedder_config)
mock_import.assert_called_once_with(
"crewai.rag.embeddings.providers.openrouter.openrouter_provider.OpenRouterProvider"
)
call_kwargs = mock_provider_class.call_args.kwargs
assert call_kwargs["api_key"] == "test-openrouter-key"
assert call_kwargs["model_name"] == "openai/text-embedding-3-large"
assert call_kwargs["api_base"] == "https://openrouter.ai/api/v1"
assert call_kwargs["dimensions"] == 1536
assert result == mock_embedding_function
@patch("crewai.rag.embeddings.factory.import_and_validate_definition")
def test_openrouter_with_model_alias(self, mock_import):
"""Test OpenRouter configuration with 'model' alias instead of 'model_name'."""
mock_provider_class = MagicMock()
mock_provider_instance = MagicMock()
mock_embedding_function = MagicMock()
mock_import.return_value = mock_provider_class
mock_provider_class.return_value = mock_provider_instance
mock_provider_instance.embedding_callable.return_value = mock_embedding_function
embedder_config = {
"provider": "openrouter",
"config": {
"api_key": "test-openrouter-key",
"model": "cohere/embed-multilingual-v3.0",
},
}
result = build_embedder(embedder_config)
mock_import.assert_called_once_with(
"crewai.rag.embeddings.providers.openrouter.openrouter_provider.OpenRouterProvider"
)
call_kwargs = mock_provider_class.call_args.kwargs
assert call_kwargs["api_key"] == "test-openrouter-key"
assert call_kwargs["model"] == "cohere/embed-multilingual-v3.0"
assert result == mock_embedding_function
@patch("crewai.rag.embeddings.factory.import_and_validate_definition")
def test_openrouter_import_error(self, mock_import):
"""Test handling of import errors for OpenRouter provider."""
mock_import.side_effect = ImportError("Failed to import OpenRouter provider")
embedder_config = {
"provider": "openrouter",
"config": {"api_key": "test-key"},
}
with pytest.raises(ImportError) as exc_info:
build_embedder(embedder_config)
assert "Failed to import provider openrouter" in str(exc_info.value)
class TestOpenRouterProviderDirect:
"""Test OpenRouterProvider Pydantic settings model directly."""
def test_default_values(self):
"""Test default values for OpenRouterProvider."""
provider = OpenRouterProvider(api_key="test-key")
assert provider.api_key == "test-key"
assert provider.model_name == "openai/text-embedding-3-small"
assert provider.api_base == "https://openrouter.ai/api/v1"
assert provider.dimensions is None
assert provider.default_headers is None
def test_custom_values(self):
"""Test custom configuration values."""
provider = OpenRouterProvider(
api_key="test-custom-key",
model="openai/text-embedding-3-large",
api_base="https://custom.openrouter.ai/api/v1",
dimensions=3072,
default_headers={"HTTP-Referer": "https://crewai.com"},
)
assert provider.api_key == "test-custom-key"
assert provider.model_name == "openai/text-embedding-3-large"
assert provider.api_base == "https://custom.openrouter.ai/api/v1"
assert provider.dimensions == 3072
assert provider.default_headers == {"HTTP-Referer": "https://crewai.com"}
def test_missing_api_key_raises_validation_error(self, monkeypatch):
"""Test that missing API key raises ValidationError when no env vars set."""
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
with pytest.raises(ValidationError):
OpenRouterProvider()
def test_env_var_openrouter_api_key(self, monkeypatch):
"""Test resolving API key from OPENROUTER_API_KEY env var."""
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-env-key")
provider = OpenRouterProvider()
assert provider.api_key == "sk-or-env-key"
def test_model_alias_normalization(self):
"""Test 'model' parameter maps to 'model_name'."""
provider = OpenRouterProvider(
api_key="test-key",
model="cohere/embed-multilingual-v3.0",
)
assert provider.model_name == "cohere/embed-multilingual-v3.0"
def test_model_name_takes_precedence(self):
"""Test that model_name takes precedence over model if both are given."""
provider = OpenRouterProvider(
api_key="test-key",
model="openai/text-embedding-3-small",
model_name="openai/text-embedding-3-large",
)
assert provider.model_name == "openai/text-embedding-3-large"