mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-15 23:31:29 +00:00
(sap) add filtering, masking, translation SAP GEN AI Hub modules
This commit is contained in:
parent
d0bb619365
commit
f6e331a436
2 changed files with 513 additions and 75 deletions
|
|
@ -1,4 +1,5 @@
|
|||
from typing import Union, Literal
|
||||
from typing import Union, Literal, Optional
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator, ValidationError
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ def validate_different_content(v: Union[str, dict, list]) -> str:
|
|||
elif isinstance(v, str):
|
||||
return v
|
||||
raise ValueError("Content must be a string")
|
||||
return v
|
||||
|
||||
|
||||
|
||||
class TextContent(BaseModel):
|
||||
|
|
@ -113,6 +114,7 @@ class SAPToolChatMessage(BaseModel):
|
|||
validate_different_content
|
||||
)
|
||||
|
||||
|
||||
ChatMessage = Union[SAPUserMessage, SAPAssistantMessage, SAPToolChatMessage, SAPMessage]
|
||||
|
||||
|
||||
|
|
@ -155,11 +157,11 @@ class GroundingSearchConfig(BaseModel):
|
|||
class DocumentGroundingFilter(BaseModel):
|
||||
id_: str = Field(default=None, alias="id")
|
||||
data_repository_type: Literal["vector", "help.sap.com"]
|
||||
search_config: GroundingSearchConfig = None
|
||||
data_repositories: list[str] = None
|
||||
data_repository_metadata: list[KeyValueListPair] = None
|
||||
document_metadata: list[DocumentMetadataKeyValueListPairs] = None
|
||||
chunk_metadata: list[KeyValueListPair] = None
|
||||
search_config: Optional[GroundingSearchConfig] = None
|
||||
data_repositories: Optional[list[str]]= None
|
||||
data_repository_metadata: Optional[list[KeyValueListPair]] = None
|
||||
document_metadata: Optional[list[DocumentMetadataKeyValueListPairs]] = None
|
||||
chunk_metadata: Optional[list[KeyValueListPair]] = None
|
||||
|
||||
|
||||
class DocumentGroundingPlaceholders(BaseModel):
|
||||
|
|
@ -168,9 +170,9 @@ class DocumentGroundingPlaceholders(BaseModel):
|
|||
|
||||
|
||||
class DocumentGroundingConfig(BaseModel):
|
||||
filters: list[DocumentGroundingFilter] = None
|
||||
filters: Optional[list[DocumentGroundingFilter]] = None
|
||||
placeholders: DocumentGroundingPlaceholders
|
||||
metadata_params: list[str] = None
|
||||
metadata_params: Optional[list[str]] = None
|
||||
|
||||
|
||||
class GroundingModuleConfig(BaseModel):
|
||||
|
|
@ -180,15 +182,15 @@ class GroundingModuleConfig(BaseModel):
|
|||
|
||||
class Template(BaseModel):
|
||||
template: list[ChatMessage]
|
||||
defaults: dict = None
|
||||
response_format: ResponseFormat | ResponseFormatJSONSchema = None
|
||||
tools: list[ChatCompletionTool] = None
|
||||
defaults: Optional[dict[str, str]] = None
|
||||
response_format: Optional[Union[ResponseFormat, ResponseFormatJSONSchema]] = None
|
||||
tools: Optional[list[ChatCompletionTool]] = None
|
||||
|
||||
|
||||
class LLMModelDetails(BaseModel):
|
||||
name: str
|
||||
version: str = "latest"
|
||||
params: dict = None
|
||||
params: Optional[dict] = None
|
||||
|
||||
|
||||
class PromptTemplatingModuleConfig(BaseModel):
|
||||
|
|
@ -196,44 +198,486 @@ class PromptTemplatingModuleConfig(BaseModel):
|
|||
model: LLMModelDetails
|
||||
|
||||
|
||||
class SAPMaskingProfileEntity(str, Enum):
|
||||
"""
|
||||
Enumerates the entity categories that can be masked by the SAP Data Privacy Integration service.
|
||||
|
||||
This enum lists different types of personal or sensitive information (PII) that can be detected and masked
|
||||
by the data masking module, such as personal details, organizational data, contact information, and identifiers.
|
||||
|
||||
Values:
|
||||
PERSON: Represents personal names.
|
||||
|
||||
ORG: Represents organizational names.
|
||||
|
||||
UNIVERSITY: Represents educational institutions.
|
||||
|
||||
LOCATION: Represents geographical locations.
|
||||
|
||||
EMAIL: Represents email addresses.
|
||||
|
||||
PHONE: Represents phone numbers.
|
||||
|
||||
ADDRESS: Represents physical addresses.
|
||||
|
||||
SAP_IDS_INTERNAL: Represents internal SAP identifiers.
|
||||
|
||||
SAP_IDS_PUBLIC: Represents public SAP identifiers.
|
||||
|
||||
URL: Represents URLs.
|
||||
|
||||
USERNAME_PASSWORD: Represents usernames and passwords.
|
||||
|
||||
NATIONAL_ID: Represents national identification numbers.
|
||||
|
||||
IBAN: Represents International Bank Account Numbers.
|
||||
|
||||
SSN: Represents Social Security Numbers.
|
||||
|
||||
CREDIT_CARD_NUMBER: Represents credit card numbers.
|
||||
|
||||
PASSPORT: Represents passport numbers.
|
||||
|
||||
DRIVING_LICENSE: Represents driving license numbers.
|
||||
|
||||
NATIONALITY: Represents nationality information.
|
||||
|
||||
RELIGIOUS_GROUP: Represents religious group affiliation.
|
||||
|
||||
POLITICAL_GROUP: Represents political group affiliation.
|
||||
|
||||
PRONOUNS_GENDER: Represents pronouns and gender identity.
|
||||
|
||||
GENDER: Represents gender information.
|
||||
|
||||
SEXUAL_ORIENTATION: Represents sexual orientation.
|
||||
|
||||
TRADE_UNION: Represents trade union membership.
|
||||
|
||||
SENSITIVE_DATA: Represents any other sensitive information.
|
||||
"""
|
||||
|
||||
PERSON = "profile-person"
|
||||
ORG = "profile-org"
|
||||
UNIVERSITY = "profile-university"
|
||||
LOCATION = "profile-location"
|
||||
EMAIL = "profile-email"
|
||||
PHONE = "profile-phone"
|
||||
ADDRESS = "profile-address"
|
||||
SAP_IDS_INTERNAL = "profile-sapids-internal"
|
||||
SAP_IDS_PUBLIC = "profile-sapids-public"
|
||||
URL = "profile-url"
|
||||
USERNAME_PASSWORD = "profile-username-password"
|
||||
NATIONAL_ID = "profile-nationalid"
|
||||
IBAN = "profile-iban"
|
||||
SSN = "profile-ssn"
|
||||
CREDIT_CARD_NUMBER = "profile-credit-card-number"
|
||||
PASSPORT = "profile-passport"
|
||||
DRIVING_LICENSE = "profile-driverlicense"
|
||||
NATIONALITY = "profile-nationality"
|
||||
RELIGIOUS_GROUP = "profile-religious-group"
|
||||
POLITICAL_GROUP = "profile-political-group"
|
||||
PRONOUNS_GENDER = "profile-pronouns-gender"
|
||||
GENDER = "profile-gender"
|
||||
SEXUAL_ORIENTATION = "profile-sexual-orientation"
|
||||
TRADE_UNION = "profile-trade-union"
|
||||
SENSITIVE_DATA = "profile-sensitive-data"
|
||||
ETHNICITY = "profile-ethnicity"
|
||||
|
||||
|
||||
class DPIMethodConstant(BaseModel):
|
||||
"""
|
||||
Replaces the entity with the specified value followed by an incrementing number
|
||||
"""
|
||||
method: str = "constant"
|
||||
value: str
|
||||
|
||||
|
||||
class DPIMethodFabricatedData(BaseModel):
|
||||
"""
|
||||
Replaces the entity with a randomly generated value appropriate to its type.
|
||||
"""
|
||||
method: str = "fabricated_data"
|
||||
|
||||
|
||||
class DPICustomEntity(BaseModel):
|
||||
"""
|
||||
regex: Regular expression to match the entity
|
||||
replacement_strategy: Replacement strategy to be used for the entity
|
||||
"""
|
||||
regex: str
|
||||
replacement_strategy: DPIMethodConstant
|
||||
|
||||
|
||||
class DPIStandardEntity(BaseModel):
|
||||
"""
|
||||
type: Standard entity type to be masked
|
||||
replacement_strategy: Replacement strategy to be used for the entity
|
||||
"""
|
||||
type_: SAPMaskingProfileEntity = Field(..., alias="type")
|
||||
replacement_strategy: Optional[Union[DPIMethodConstant, DPIMethodFabricatedData]] = None
|
||||
|
||||
|
||||
class MaskGroundingInput(BaseModel):
|
||||
"""
|
||||
Controls whether the input to the grounding module will be masked with the configuration
|
||||
supplied in the masking module
|
||||
"""
|
||||
enabled: bool = False
|
||||
|
||||
|
||||
class MaskingProviderConfig(BaseModel):
|
||||
"""
|
||||
SAP Data Privacy Integration provider for data masking.
|
||||
|
||||
This class implements the SAP Data Privacy Integration service, which can anonymize or pseudonymize
|
||||
specified entity categories in the input data. It supports masking sensitive information like personal names,
|
||||
contact details, and identifiers.
|
||||
|
||||
Args:
|
||||
method: The method of masking to apply (anonymization or pseudonymization).
|
||||
|
||||
entities: A list of entity categories to be masked, such as names, locations, or emails.
|
||||
|
||||
allowlist: A list of strings that should not be masked.
|
||||
|
||||
mask_grounding_input: A flag indicating whether to mask input to the grounding module.
|
||||
"""
|
||||
type_: str = Field(default="sap_data_privacy_integration", alias="type")
|
||||
method: Literal["anonymization", "pseudonymization"]
|
||||
entities: list[Union[DPIStandardEntity, DPICustomEntity]]
|
||||
allowlist: Optional[list[str]] = None
|
||||
mask_grounding_input: Optional[MaskGroundingInput] = None
|
||||
|
||||
|
||||
class MaskingModuleConfig(BaseModel):
|
||||
"""
|
||||
Configuration for the data masking module.
|
||||
|
||||
Args:
|
||||
providers: list of masking service provider configurations
|
||||
masking_providers: list of masking provider configurations
|
||||
IMPORTANT: use exactly one of the parameters to set the list of masking provider configurations.
|
||||
DEPRECATED: parameter 'masking_providers' will be removed Sept 15, 2026. Use 'providers' instead.
|
||||
"""
|
||||
providers: Optional[list[MaskingProviderConfig]] = Field(min_length=1, default=None)
|
||||
masking_providers: Optional[list[MaskingProviderConfig]] = Field(min_length=1, default=None)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def enforce_exactly_one_provider_list(self):
|
||||
|
||||
has_providers = self.providers is not None
|
||||
has_masking_providers = self.masking_providers is not None
|
||||
|
||||
if has_providers == has_masking_providers:
|
||||
raise ValueError(
|
||||
"For SAP Masking Module Config must set exactly one of: 'providers' or 'masking_providers' "
|
||||
"DEPRECATED: parameter 'masking_providers' will be removed Sept 15, 2026. Use 'providers' instead."
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
|
||||
class AzureThreshold(int, Enum):
|
||||
"""
|
||||
Enumerates the threshold levels for the Azure Content Safety service.
|
||||
|
||||
This enum defines the various threshold levels that can be used to filter
|
||||
content based on its safety score. Each threshold value represents a specific
|
||||
level of content moderation.
|
||||
|
||||
Values:
|
||||
ALLOW_SAFE: Allows only Safe content.
|
||||
|
||||
ALLOW_SAFE_LOW: Allows Safe and Low content.
|
||||
|
||||
ALLOW_SAFE_LOW_MEDIUM: Allows Safe, Low, and Medium content.
|
||||
|
||||
ALLOW_ALL: Allows all content (Safe, Low, Medium, and High).
|
||||
"""
|
||||
|
||||
ALLOW_SAFE = 0
|
||||
ALLOW_SAFE_LOW = 2
|
||||
ALLOW_SAFE_LOW_MEDIUM = 4
|
||||
ALLOW_ALL = 6
|
||||
|
||||
|
||||
class AzureContentFilter(BaseModel):
|
||||
"""
|
||||
Specific filter configuration for Azure Content Safety.
|
||||
|
||||
This class configures content filtering based on Azure's categories and
|
||||
severity levels. It allows setting thresholds for hate speech, sexual content,
|
||||
violence, and self-harm content.
|
||||
|
||||
Values:
|
||||
hate: Threshold for hate speech content.
|
||||
|
||||
sexual: Threshold for sexual content.
|
||||
|
||||
violence: Threshold for violent content.
|
||||
|
||||
self_harm: Threshold for self-harm content.
|
||||
"""
|
||||
|
||||
hate: Optional[Union[AzureThreshold, Literal[0, 2, 4, 6]]] = None
|
||||
sexual: Optional[Union[AzureThreshold, Literal[0, 2, 4, 6]]] = None
|
||||
violence: Optional[Union[AzureThreshold, Literal[0, 2, 4, 6]]] = None
|
||||
self_harm: Optional[Union[AzureThreshold, Literal[0, 2, 4, 6]]] = None
|
||||
|
||||
|
||||
class AzureContentSafetyInput(AzureContentFilter):
|
||||
"""
|
||||
Filter configuration for Azure Content Safety Input
|
||||
|
||||
Values:
|
||||
hate: Threshold for hate speech content.
|
||||
|
||||
sexual: Threshold for sexual content.
|
||||
|
||||
violence: Threshold for violent content.
|
||||
|
||||
self_harm: Threshold for self-harm content.
|
||||
|
||||
prompt_shield: A flag to use prompt shield
|
||||
"""
|
||||
prompt_shield: Optional[bool] = False
|
||||
|
||||
|
||||
class AzureContentSafetyOutput(AzureContentFilter):
|
||||
"""
|
||||
Filter configuration for Azure Content Safety Output
|
||||
|
||||
Values:
|
||||
hate: Threshold for hate speech content.
|
||||
|
||||
sexual: Threshold for sexual content.
|
||||
|
||||
violence: Threshold for violent content.
|
||||
|
||||
self_harm: Threshold for self-harm content.
|
||||
|
||||
protected_material_code: Detect protected code content from known GitHub repositories.
|
||||
The scan includes software libraries, source code, algorithms,
|
||||
and other proprietary programming content.
|
||||
"""
|
||||
|
||||
protected_material_code: Optional[bool] = False
|
||||
|
||||
|
||||
class LlamaGuard38bFilter(BaseModel):
|
||||
"""
|
||||
Specific implementation of ContentFilter for Llama Guard 3. Llama Guard 3 is a
|
||||
Llama-3.1-8B pretrained model, fine-tuned for content safety classification.
|
||||
|
||||
Args:
|
||||
violent_crimes: Responses that enable, encourage, or endorse the commission of violent crimes.
|
||||
|
||||
non_violent_crimes: Responses that enable, encourage, or endorse the commission of non-violent crimes.
|
||||
|
||||
sex_crimes: Responses that enable, encourage, or endorse the commission of sex-related crimes.
|
||||
|
||||
child_exploitation: Responses that contain, describe, enable or endorse the sexual abuse of children.
|
||||
|
||||
defamation: Responses that are both verifiably false and likely to injure a living person's reputation.
|
||||
|
||||
specialized_advice: Responses that contain specialized financial, medical or legal advice.
|
||||
|
||||
privacy: Responses that contain sensitive or nonpublic personal information.
|
||||
|
||||
intellectual_property: Responses that may violate the intellectual property rights of any third party.
|
||||
|
||||
indiscriminate_weapons: Responses that enable, encourage, or endorse the creation of indiscriminate weapons.
|
||||
|
||||
hate: Responses that demean or dehumanize people on the basis of their sensitive, personal characteristics.
|
||||
|
||||
self_harm: Responses that enable, encourage, or endorse acts of intentional self-harm.
|
||||
|
||||
sexual_content: Responses that contain erotica.
|
||||
|
||||
elections: Responses that contain factually incorrect information about electoral systems and processes.
|
||||
|
||||
code_interpreter_abuse: Responses that seek to abuse code interpreters.
|
||||
"""
|
||||
|
||||
violent_crimes: bool = Field(default=False)
|
||||
non_violent_crimes: bool = Field(default=False)
|
||||
sex_crimes: bool = Field(default=False)
|
||||
child_exploitation: bool = Field(default=False)
|
||||
defamation: bool = Field(default=False)
|
||||
specialized_advice: bool = Field(default=False)
|
||||
privacy: bool = Field(default=False)
|
||||
intellectual_property: bool = Field(default=False)
|
||||
indiscriminate_weapons: bool = Field(default=False)
|
||||
hate: bool = Field(default=False)
|
||||
self_harm: bool = Field(default=False)
|
||||
sexual_content: bool = Field(default=False)
|
||||
elections: bool = Field(default=False)
|
||||
code_interpreter_abuse: bool = Field(default=False)
|
||||
|
||||
|
||||
class LlamaGuard38bFilterConfig(BaseModel):
|
||||
type_: str = Field(default="llama_guard_3_8b", alias="type")
|
||||
config: LlamaGuard38bFilter
|
||||
|
||||
|
||||
class AzureContentSafetyInputFilterConfig(BaseModel):
|
||||
type_: str = Field(default="azure_content_safety", alias="type")
|
||||
config: Optional[AzureContentSafetyInput] = None
|
||||
|
||||
|
||||
class AzureContentSafetyOutputFilterConfig(BaseModel):
|
||||
type_: str = Field(default="azure_content_safety", alias="type")
|
||||
config: Optional[AzureContentSafetyOutput] = None
|
||||
|
||||
|
||||
class FilteringStreamOptions(BaseModel):
|
||||
"""
|
||||
overlap: Number of characters that should be additionally sent to content filtering services
|
||||
from previous chunks as additional context.
|
||||
"""
|
||||
overlap: Optional[int] = Field(default=0, ge=0, le=10000)
|
||||
|
||||
|
||||
class InputFiltering(BaseModel):
|
||||
"""Module for managing and applying input content filters.
|
||||
|
||||
Args:
|
||||
filters: List of ContentFilter objects to be applied to input content.
|
||||
"""
|
||||
filters: list[Union[AzureContentSafetyInputFilterConfig, LlamaGuard38bFilterConfig]] = Field(min_length=1)
|
||||
|
||||
|
||||
class OutputFiltering(BaseModel):
|
||||
"""Module for managing and applying output content filters.
|
||||
|
||||
Args:
|
||||
filters: List of ContentFilter objects to be applied to output content.
|
||||
|
||||
stream_options: Module-specific streaming options.
|
||||
"""
|
||||
|
||||
filters: list[
|
||||
Union[AzureContentSafetyOutputFilterConfig, LlamaGuard38bFilterConfig]] = Field(min_length=1)
|
||||
stream_options: Optional[FilteringStreamOptions] = None
|
||||
|
||||
|
||||
class FilteringModuleConfig(BaseModel):
|
||||
"""Module for managing and applying content filters.
|
||||
|
||||
Args:
|
||||
input: Module for filtering and validating input content before processing.
|
||||
|
||||
output: Module for filtering and validating output content after generation.
|
||||
"""
|
||||
input: Optional[InputFiltering] = None
|
||||
output: Optional[OutputFiltering] = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def enforce_min_properties(cls, values): # pylint: disable=no-self-argument
|
||||
"""
|
||||
Ensure at least one of input or output filtering is provided.
|
||||
"""
|
||||
assert values.input is not None or values.output is not None, \
|
||||
"For using SAP Filtering Module you must provide at least one property: input or output filters."
|
||||
return values
|
||||
|
||||
|
||||
class SAPDocumentTranslationApplyToSelector(BaseModel):
|
||||
"""
|
||||
This selector allows you to define the scope of translation, such as specific placeholders or
|
||||
messages with specific roles.
|
||||
For example, {"category": "placeholders",
|
||||
"items": ["user_input"],
|
||||
"source_language": "de-DE"}
|
||||
targets the value of "user_input" in placeholder_values specified in the request payload;
|
||||
and considers the value to be in German.
|
||||
"""
|
||||
category: Literal["placeholders", "template_roles"]
|
||||
items: list[str]
|
||||
source_language: str
|
||||
|
||||
|
||||
class InputTranslationConfig(BaseModel):
|
||||
"""
|
||||
Configuration for input translation.
|
||||
|
||||
Args:
|
||||
source_language: Language of the text to be translated. Example: de-DE
|
||||
target_language: Language to which the text should be translated. Example: en-US
|
||||
apply_to: List of selectors that define the scope of translation.
|
||||
"""
|
||||
source_language: Optional[str] = None
|
||||
target_language: str
|
||||
apply_to: Optional[list[SAPDocumentTranslationApplyToSelector]] = None
|
||||
|
||||
|
||||
class OutputTranslationConfig(BaseModel):
|
||||
source_language: Optional[str] = None
|
||||
target_language: Union[str, SAPDocumentTranslationApplyToSelector]
|
||||
|
||||
|
||||
class SAPDocumentTranslationInput(BaseModel):
|
||||
"""
|
||||
Configuration for input translation
|
||||
|
||||
Args:
|
||||
type: The type of translation module (e.g., 'sap_document_translation').
|
||||
|
||||
translate_messages_history: If true, the messages history will be translated as well.
|
||||
|
||||
config: Configuration object for the translation module.
|
||||
"""
|
||||
type_: str = Field(default="sap_document_translation", alias="type")
|
||||
translate_messages_history: Optional[bool] = None
|
||||
config: InputTranslationConfig
|
||||
|
||||
|
||||
class SAPDocumentTranslationOutput(BaseModel):
|
||||
"""
|
||||
Configuration for output translation
|
||||
|
||||
Args:
|
||||
type: The type of translation module (e.g., 'sap_document_translation').
|
||||
|
||||
config: Configuration object for the translation module.
|
||||
"""
|
||||
type_: str = Field(default="sap_document_translation", alias="type")
|
||||
config: OutputTranslationConfig
|
||||
|
||||
|
||||
class TranslationModuleConfig(BaseModel):
|
||||
"""
|
||||
Configuration for translation module
|
||||
|
||||
Args:
|
||||
input: Configuration for input translation
|
||||
|
||||
output: Configuration for output translation
|
||||
"""
|
||||
input: Optional[SAPDocumentTranslationInput] = None
|
||||
output: Optional[SAPDocumentTranslationOutput] = None
|
||||
|
||||
|
||||
class ModuleConfig(BaseModel):
|
||||
prompt_templating: PromptTemplatingModuleConfig
|
||||
# filtering: Optional[FilteringModuleConfig] = None
|
||||
# masking: Optional[MaskingModuleConfig] = None
|
||||
grounding: GroundingModuleConfig = None
|
||||
# translation: Optional[TranslationModuleConfig] = None
|
||||
filtering: Optional[FilteringModuleConfig] = None
|
||||
masking: Optional[MaskingModuleConfig] = None
|
||||
grounding: Optional[GroundingModuleConfig] = None
|
||||
translation: Optional[TranslationModuleConfig] = None
|
||||
|
||||
|
||||
class GlobalStreamOptions(BaseModel):
|
||||
enabled: bool = False
|
||||
chunk_size: int = 100
|
||||
delimiters: list[str] = None
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_streaming_params(self):
|
||||
"""Validate that chunk_size and delimiters are not set when enabled is False."""
|
||||
if not self.enabled:
|
||||
if self.chunk_size != 100: # Check if chunk_size was explicitly set
|
||||
raise ValueError("chunk_size cannot be set when enabled is False")
|
||||
if self.delimiters is not None:
|
||||
raise ValueError("delimiters cannot be set when enabled is False")
|
||||
return self
|
||||
|
||||
def model_dump(self, **kwargs):
|
||||
"""Override model_dump to exclude chunk_size and delimiters when enabled is False."""
|
||||
data = super().model_dump(**kwargs)
|
||||
if not self.enabled:
|
||||
# Remove chunk_size and delimiters from output when streaming is disabled
|
||||
data.pop('chunk_size', None)
|
||||
data.pop('delimiters', None)
|
||||
return data
|
||||
delimiters: Optional[list[str]] = None
|
||||
|
||||
|
||||
class OrchestrationConfig(BaseModel):
|
||||
modules: ModuleConfig
|
||||
stream: GlobalStreamOptions = None
|
||||
stream: Optional[GlobalStreamOptions] = None
|
||||
|
||||
|
||||
class OrchestrationRequest(BaseModel):
|
||||
config: OrchestrationConfig
|
||||
placeholder_values: dict = None
|
||||
placeholder_values: Optional[dict[str, str]] = None
|
||||
|
|
|
|||
|
|
@ -218,20 +218,7 @@ class GenAIHubOrchestrationConfig(OpenAIGPTConfig):
|
|||
litellm_params: dict,
|
||||
headers: dict,
|
||||
) -> dict:
|
||||
# Filter out parameters that are not valid model params for SAP Orchestration API
|
||||
# - tools, model_version, deployment_url: handled separately
|
||||
excluded_params = {"tools", "model_version", "deployment_url"}
|
||||
|
||||
# Filter strict for GPT models only - SAP AI Core doesn't accept it as a model param
|
||||
# LangChain agents pass strict=true at top level, which fails for GPT models
|
||||
# Anthropic models accept strict, so preserve it for them
|
||||
if model.startswith("gpt"):
|
||||
excluded_params.add("strict")
|
||||
|
||||
model_params = {
|
||||
k: v for k, v in optional_params.items() if k not in {"tools", "model_version", "deployment_url", "grounding", "placeholder_values"}
|
||||
}
|
||||
|
||||
optional_params.pop("deployment_url", None)
|
||||
model_version = optional_params.pop("model_version", "latest")
|
||||
template = messages
|
||||
|
||||
|
|
@ -241,7 +228,7 @@ class GenAIHubOrchestrationConfig(OpenAIGPTConfig):
|
|||
else:
|
||||
tools = {}
|
||||
|
||||
response_format = model_params.pop("response_format", {})
|
||||
response_format = optional_params.pop("response_format", {})
|
||||
resp_type = response_format.get("type", None)
|
||||
if resp_type:
|
||||
if resp_type == "json_schema":
|
||||
|
|
@ -251,44 +238,51 @@ class GenAIHubOrchestrationConfig(OpenAIGPTConfig):
|
|||
else:
|
||||
response_format = validate_dict(response_format, ResponseFormat)
|
||||
response_format = {"response_format": response_format}
|
||||
model_params.pop("stream", False)
|
||||
optional_params.pop("stream", False)
|
||||
stream_config = {}
|
||||
if "stream_options" in model_params:
|
||||
# stream_config["enabled"] = True
|
||||
stream_options = model_params.pop("stream_options", {})
|
||||
if "stream_options" in optional_params:
|
||||
stream_options = optional_params.pop("stream_options", {})
|
||||
stream_config["chunk_size"] = stream_options.get("chunk_size", 100)
|
||||
if "delimiters" in stream_options:
|
||||
stream_config["delimiters"] = stream_options.get("delimiters")
|
||||
# else:
|
||||
# stream_config["enabled"] = False
|
||||
|
||||
placeholder_defaults = optional_params.pop("placeholder_defaults", {})
|
||||
if placeholder_defaults:
|
||||
placeholder_defaults = {"defaults": placeholder_defaults}
|
||||
|
||||
placeholder_values = optional_params.pop("placeholder_values", {})
|
||||
if placeholder_values:
|
||||
placeholder_values = {"placeholder_values": placeholder_values}
|
||||
|
||||
optional_modules = {}
|
||||
optional_modules_lst = ["grounding", "masking", "filtering", "translation"]
|
||||
for module in optional_modules_lst:
|
||||
if optional_params.get(module, None):
|
||||
optional_modules[module] = optional_params.pop(module)
|
||||
|
||||
request_body = {
|
||||
"config": {
|
||||
"modules": {
|
||||
"prompt_templating": {
|
||||
"prompt": {"template": template, **tools, **response_format},
|
||||
"prompt": {
|
||||
"template": template,
|
||||
**placeholder_defaults,
|
||||
**tools,
|
||||
**response_format
|
||||
},
|
||||
"model": {
|
||||
"name": model,
|
||||
"params": model_params,
|
||||
"params": optional_params,
|
||||
"version": model_version,
|
||||
},
|
||||
},
|
||||
**optional_modules
|
||||
},
|
||||
"stream": stream_config,
|
||||
}
|
||||
},
|
||||
**placeholder_values,
|
||||
}
|
||||
|
||||
placeholder_defaults = optional_params.pop("placeholder_defaults", {})
|
||||
if placeholder_defaults:
|
||||
request_body["config"]["modules"]["prompt_templating"]["prompt"]["defaults"] = placeholder_defaults
|
||||
|
||||
placeholder_values = optional_params.pop("placeholder_values", {})
|
||||
if placeholder_values:
|
||||
request_body["placeholder_values"] = placeholder_values
|
||||
|
||||
grounding_config = optional_params.pop("grounding", {})
|
||||
if grounding_config:
|
||||
request_body["config"]["modules"]["grounding"] = grounding_config
|
||||
|
||||
validate_dict(request_body, OrchestrationRequest)
|
||||
|
||||
return request_body
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue