(sap) update tests

This commit is contained in:
Vasilisa Parshikova 2026-03-05 12:55:10 +04:00 • committed by Sameer Kankute
parent 00adbca6c7
commit fe390e0b3c
No known key found for this signature in database
3 changed files with 385 additions and 257 deletions

View file

@ -281,7 +281,7 @@ class GenAIHubOrchestrationConfig(OpenAIGPTConfig):
placeholder_values = optional_params.pop("placeholder_values", {})
placeholder_values = {"placeholder_values": placeholder_values} if placeholder_values else {}
fallback_modules = optional_params.pop("fallback_modules", [])
fallback_modules = optional_params.pop("fallback_sap_modules", [])
modules = [
_build_prompt_module(

View file

@ -1,244 +1,5 @@
from litellm.llms.sap.chat.transformation import GenAIHubOrchestrationConfig
import pytest
def test_sap_placeholder_defaults():
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hello. Answer {{ ?user_query }}"}
],
optional_params={'deployment_url': "shouldn't be in results",
"placeholder_defaults": {"user_query": "default value"}},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["prompt_templating"]["prompt"]["defaults"] == {"user_query": "default value"}
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_placeholder_values():
placeholder_values = {"user_query": "Some text"}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hello. Answer {{ ?user_query }}"}
],
optional_params={'deployment_url': "shouldn't be in results",
"placeholder_values": placeholder_values},
litellm_params={},
headers={}
)
assert config["placeholder_values"] == placeholder_values
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_grounding():
grounding_config = {
'type': 'document_grounding_service',
'config': {
'filters': [
{'id': 's3-docs',
'data_repository_type': 'vector',
'search_config': {'max_chunk_count': 2},
'data_repositories': ['123456890-test']
}
],
'placeholders': {'input': ['user_query'], 'output': 'grounding_response'},
'metadata_params': ['source', 'webUrl', 'title', 'mimeType', 'fileSuffix']
}
}
placeholder_values = {"user_query": "Some text"}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hello. Answer {{ ?user_query }} using context: {{ ?grounding_response }}"}
],
optional_params={'deployment_url': "shouldn't be in results",
"grounding": grounding_config,
"placeholder_values": placeholder_values},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["grounding"] == grounding_config
assert config["placeholder_values"] == placeholder_values
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_filtering():
filtering_config_azure = {
'input':
{
'filters':
[
{'type': 'azure_content_safety',
'config':
{'hate': 0,
'sexual': 0,
'violence': 0,
'self_harm': 0
}
}
]
},
'output':
{
'filters':
[
{'type': 'azure_content_safety',
'config': {'hate': 0,
'sexual': 0,
'violence': 0,
'self_harm': 0
}
}
]
}
}
filtering_config_llama = {
'input':
{
'filters':
[
{
'type': 'llama_guard_3_8b',
'config': {'hate': True,
"elections": True}
}
]
},
'output':
{
'filters':
[
{
'type': 'llama_guard_3_8b',
'config': {'hate': True, "elections": True}
}
]
}
}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"filtering": filtering_config_azure},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["filtering"] == filtering_config_azure
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"filtering": filtering_config_llama},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["filtering"] == filtering_config_llama
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_masking():
masking_config = {
'providers':
[
{
'type': 'sap_data_privacy_integration',
'method': 'anonymization',
'entities': [
{'type': 'profile-address'},
{'type': 'profile-email'},
{'type': 'profile-phone'},
{'type': 'profile-person'},
{'type': 'profile-location'}
]
}
]
}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"masking": masking_config},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["masking"] == masking_config
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_translation():
translation_config = {
'input':
{'type': 'sap_document_translation',
'config':
{'source_language': 'en-US',
'target_language': 'de-DE'}
},
'output':
{'type': 'sap_document_translation',
'config':
{'source_language': 'de-DE',
'target_language': 'fr-FR'}
}
}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"translation": translation_config},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["translation"] == translation_config
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_multiple_modules():
translation_config = {
'input':
{'type': 'sap_document_translation',
'config':
{'source_language': 'en-US',
'target_language': 'de-DE'}
},
'output':
{'type': 'sap_document_translation',
'config':
{'source_language': 'de-DE',
'target_language': 'fr-FR'}
}
}
config = GenAIHubOrchestrationConfig().transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"fallback_modules": [{"model": "sap/gpt-5",
"messages": [{"role": "user", "content": "Hello world!"}],
"translation": translation_config
}]
,
},
litellm_params={},
headers={}
)
assert "translation" not in config["config"]["modules"][0]
assert config["config"]["modules"][1]["translation"] == translation_config
assert config["config"]["modules"][1]["prompt_templating"]["model"]["name"] == "gpt-5"
assert config["config"]["modules"][0]["prompt_templating"]["model"]["name"] == "gpt-4o"
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
assert config["config"]["modules"][1]["prompt_templating"]["prompt"]["template"][0]["content"] == "Hello world!"
assert config["config"]["modules"][0]["prompt_templating"]["prompt"]["template"][0]["content"] == "Hello."
class TestSAPTransformationIntegration:
"""Integration tests for SAP transformation with parameter classification."""
@ -335,21 +96,340 @@ class TestSAPTransformationIntegration:
for excluded_param in test_case["expected_excluded"]:
assert excluded_param not in filtered_params, f"Case {i + 1}: {excluded_param} should be excluded from model params"
try:
result = mock_config.transform_request(
model, messages, test_case["params"], {}, {}
)
if result and "config" in result:
model_params = result["config"]["modules"][0]["prompt_templating"]["model"]["params"]
result = mock_config.transform_request(
model, messages, test_case["params"], {}, {}
)
if result and "config" in result:
model_params = result["config"]["modules"][0]["prompt_templating"]["model"]["params"]
for excluded_param in test_case["expected_excluded"]:
assert excluded_param not in model_params, (
f"Case {i + 1}: {excluded_param} should not be in actual model params"
)
except AttributeError as e:
if "deployment_url" in str(e):
pass
else:
pytest.fail(f"Unexpected AttributeError: {e}")
except Exception as e:
pytest.fail(f"Unexpected exception in transform_request: {e}")
for excluded_param in test_case["expected_excluded"]:
assert excluded_param not in model_params, (
f"Case {i + 1}: {excluded_param} should not be in actual model params"
)
def test_config_transform_with_response_format_json_object(self, mock_config):
expected_dict = {'config':
{'modules':[
{'prompt_templating':
{'prompt':
{'template':
[{'role': 'user', 'content': 'First man on the moon, answer in json'}],
'response_format': {'type': 'json_object'}},
'model': {'name': 'gpt-4o', 'params': {}, 'version': 'latest'}
}
}],
'stream': {}
}
}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{'role': 'user', 'content': 'First man on the moon, answer in json'}],
optional_params={'response_format': {'type': 'json_object'},
'deployment_url': "shouldn't be in results"},
litellm_params={},
headers={}
)
assert config == expected_dict
def test_config_transform_with_response_format_json_schema(self, mock_config):
expected_response_format = {
'type': 'json_schema',
'json_schema': {
'description': 'Schema for person information',
'name': 'person_info',
'schema': {
'type': 'object',
'properties': {
'name': {
'type': 'string',
'description': "The person's full name"
},
'age': {
'type': 'integer',
'description': "The person's age in years"
},
'occupation': {
'type': 'string',
'description': "The person's job title"
}
},
'required': ['name', 'age', 'occupation'],
'additionalProperties': False
},
'strict': True
}
}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{'role': 'user', 'content': 'First man on the moon, answer in json'}],
optional_params={'response_format': expected_response_format,
'deployment_url': "shouldn't be in results"},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["prompt_templating"]["prompt"]["response_format"] == expected_response_format
assert len(config["config"]["modules"][0]["prompt_templating"]["model"]["params"]) == 0
def test_config_transform_with_stream(self, mock_config):
expected_dict = {
'config': {
'modules': [{
'prompt_templating': {
'prompt': {
'template': [{'role': 'user', 'content': 'Hello, how are you?'}]
},
'model': {
'name': 'anthropic--claude-4-sonnet',
'params': {},
'version': 'latest'
}
}
}],
'stream': {'chunk_size': 10}
}
}
config = mock_config.transform_request(
model="anthropic--claude-4-sonnet",
messages=[{'content': 'Hello, how are you?', 'role': 'user'}],
optional_params={'stream': True,
'stream_options': {'chunk_size': 10},
'model_version': 'latest',
'deployment_url': "shouldn't be in results"},
litellm_params={},
headers={}
)
assert config == expected_dict
def test_sap_placeholder_defaults(self, mock_config):
config = mock_config.transform_request(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hello. Answer {{ ?user_query }}"}
],
optional_params={'deployment_url': "shouldn't be in results",
"placeholder_defaults": {"user_query": "default value"}},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["prompt_templating"]["prompt"]["defaults"] == {
"user_query": "default value"}
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_placeholder_values(self, mock_config):
placeholder_values = {"user_query": "Some text"}
config = mock_config.transform_request(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hello. Answer {{ ?user_query }}"}
],
optional_params={'deployment_url': "shouldn't be in results",
"placeholder_values": placeholder_values},
litellm_params={},
headers={}
)
assert config["placeholder_values"] == placeholder_values
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_grounding(self, mock_config):
grounding_config = {
'type': 'document_grounding_service',
'config': {
'filters': [
{'id': 's3-docs',
'data_repository_type': 'vector',
'search_config': {'max_chunk_count': 2},
'data_repositories': ['123456890-test']
}
],
'placeholders': {'input': ['user_query'], 'output': 'grounding_response'},
'metadata_params': ['source', 'webUrl', 'title', 'mimeType', 'fileSuffix']
}
}
placeholder_values = {"user_query": "Some text"}
config = mock_config.transform_request(
model="gpt-4o",
messages=[
{"role": "user", "content": "Hello. Answer {{ ?user_query }} using context: {{ ?grounding_response }}"}
],
optional_params={'deployment_url': "shouldn't be in results",
"grounding": grounding_config,
"placeholder_values": placeholder_values},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["grounding"] == grounding_config
assert config["placeholder_values"] == placeholder_values
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_filtering(self, mock_config):
filtering_config_azure = {
'input':
{
'filters':
[
{'type': 'azure_content_safety',
'config':
{'hate': 0,
'sexual': 0,
'violence': 0,
'self_harm': 0
}
}
]
},
'output':
{
'filters':
[
{'type': 'azure_content_safety',
'config': {'hate': 0,
'sexual': 0,
'violence': 0,
'self_harm': 0
}
}
]
}
}
filtering_config_llama = {
'input':
{
'filters':
[
{
'type': 'llama_guard_3_8b',
'config': {'hate': True,
"elections": True}
}
]
},
'output':
{
'filters':
[
{
'type': 'llama_guard_3_8b',
'config': {'hate': True, "elections": True}
}
]
}
}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"filtering": filtering_config_azure},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["filtering"] == filtering_config_azure
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"filtering": filtering_config_llama},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["filtering"] == filtering_config_llama
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_masking(self, mock_config):
masking_config = {
'providers':
[
{
'type': 'sap_data_privacy_integration',
'method': 'anonymization',
'entities': [
{'type': 'profile-address'},
{'type': 'profile-email'},
{'type': 'profile-phone'},
{'type': 'profile-person'},
{'type': 'profile-location'}
]
}
]
}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"masking": masking_config},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["masking"] == masking_config
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_translation(self, mock_config):
translation_config = {
'input':
{'type': 'sap_document_translation',
'config':
{'source_language': 'en-US',
'target_language': 'de-DE'}
},
'output':
{'type': 'sap_document_translation',
'config':
{'source_language': 'de-DE',
'target_language': 'fr-FR'}
}
}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"translation": translation_config},
litellm_params={},
headers={}
)
assert config["config"]["modules"][0]["translation"] == translation_config
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
def test_sap_multiple_modules(self, mock_config):
translation_config = {
'input':
{'type': 'sap_document_translation',
'config':
{'source_language': 'en-US',
'target_language': 'de-DE'}
},
'output':
{'type': 'sap_document_translation',
'config':
{'source_language': 'de-DE',
'target_language': 'fr-FR'}
}
}
config = mock_config.transform_request(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello."}],
optional_params={'deployment_url': "shouldn't be in results",
"fallback_sap_modules": [{"model": "sap/gpt-5",
"messages": [{"role": "user", "content": "Hello world!"}],
"translation": translation_config
}]
,
},
litellm_params={},
headers={}
)
assert "translation" not in config["config"]["modules"][0]
assert config["config"]["modules"][1]["translation"] == translation_config
assert config["config"]["modules"][1]["prompt_templating"]["model"]["name"] == "gpt-5"
assert config["config"]["modules"][0]["prompt_templating"]["model"]["name"] == "gpt-4o"
assert config["config"]["modules"][0]["prompt_templating"]["model"]["params"] == {}
assert config["config"]["modules"][1]["prompt_templating"]["prompt"]["template"][0]["content"] == "Hello world!"
assert config["config"]["modules"][0]["prompt_templating"]["prompt"]["template"][0]["content"] == "Hello."

View file

@ -0,0 +1,48 @@
from unittest.mock import patch, PropertyMock
import pytest
from litellm.llms.sap.embed.transformation import GenAIHubEmbeddingConfig
@pytest.fixture
def fake_token_creator():
return lambda: "Bearer FAKE_TOKEN", "https://api.ai.moke-sap.com", "fake-group"
@pytest.fixture
def fake_deployment_url():
return "https://api.ai.moke-sap.com/v2/inference/deployments/mokeid"
def test_basic_config_transform(fake_token_creator, fake_deployment_url):
expected_dict = {
'config': {
'modules': {
'embeddings': {
'model': {
'name': 'text-embedding-3-small',
'version': 'latest',
'params': {}
}
}
}
},
'input': {
'text': 'Hi',
'type': 'text'
}
}
with patch(
"litellm.llms.sap.embed.transformation.GenAIHubEmbeddingConfig.deployment_url",
new_callable=PropertyMock,
return_value=fake_deployment_url,
), patch(
"litellm.llms.sap.embed.transformation.get_token_creator",
return_value=fake_token_creator,
):
body = GenAIHubEmbeddingConfig().transform_embedding_request(
model="text-embedding-3-small",
input="Hi",
optional_params={},
headers={}
)
assert body == expected_dict