You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

validation_service.py 6.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # validation/validation_service.py
  2. import importlib
  3. from calendar import c
  4. from typing import Any, Dict, List, Optional
  5. from autogen_core import ComponentModel, is_component_class
  6. from pydantic import BaseModel
  7. class ValidationRequest(BaseModel):
  8. component: ComponentModel
  9. class ValidationError(BaseModel):
  10. field: str
  11. error: str
  12. suggestion: Optional[str] = None
  13. class ValidationResponse(BaseModel):
  14. is_valid: bool
  15. errors: List[ValidationError] = []
  16. warnings: List[ValidationError] = []
  17. class ValidationService:
  18. @staticmethod
  19. def validate_provider(provider: str) -> Optional[ValidationError]:
  20. """Validate that the provider exists and can be imported"""
  21. try:
  22. if provider in ["azure_openai_chat_completion_client", "AzureOpenAIChatCompletionClient"]:
  23. provider = "autogen_ext.models.openai.AzureOpenAIChatCompletionClient"
  24. elif provider in ["openai_chat_completion_client", "OpenAIChatCompletionClient"]:
  25. provider = "autogen_ext.models.openai.OpenAIChatCompletionClient"
  26. module_path, class_name = provider.rsplit(".", maxsplit=1)
  27. module = importlib.import_module(module_path)
  28. component_class = getattr(module, class_name)
  29. if not is_component_class(component_class):
  30. return ValidationError(
  31. field="provider",
  32. error=f"Class {provider} is not a valid component class",
  33. suggestion="Ensure the class inherits from Component and implements required methods",
  34. )
  35. return None
  36. except ImportError:
  37. return ValidationError(
  38. field="provider",
  39. error=f"Could not import provider {provider}",
  40. suggestion="Check that the provider module is installed and the path is correct",
  41. )
  42. except Exception as e:
  43. return ValidationError(
  44. field="provider",
  45. error=f"Error validating provider: {str(e)}",
  46. suggestion="Check the provider string format and class implementation",
  47. )
  48. @staticmethod
  49. def validate_component_type(component: ComponentModel) -> Optional[ValidationError]:
  50. """Validate the component type"""
  51. if not component.component_type:
  52. return ValidationError(
  53. field="component_type",
  54. error="Component type is missing",
  55. suggestion="Add a component_type field to the component configuration",
  56. )
  57. @staticmethod
  58. def validate_config_schema(component: ComponentModel) -> List[ValidationError]:
  59. """Validate the component configuration against its schema"""
  60. errors = []
  61. try:
  62. # Convert to ComponentModel for initial validation
  63. model = component.model_copy(deep=True)
  64. # Get the component class
  65. provider = model.provider
  66. module_path, class_name = provider.rsplit(".", maxsplit=1)
  67. module = importlib.import_module(module_path)
  68. component_class = getattr(module, class_name)
  69. # Validate against component's schema
  70. if hasattr(component_class, "component_config_schema"):
  71. try:
  72. component_class.component_config_schema.model_validate(model.config)
  73. except Exception as e:
  74. errors.append(
  75. ValidationError(
  76. field="config",
  77. error=f"Config validation failed: {str(e)}",
  78. suggestion="Check that the config matches the component's schema",
  79. )
  80. )
  81. else:
  82. errors.append(
  83. ValidationError(
  84. field="config",
  85. error="Component class missing config schema",
  86. suggestion="Implement component_config_schema in the component class",
  87. )
  88. )
  89. except Exception as e:
  90. errors.append(
  91. ValidationError(
  92. field="config",
  93. error=f"Schema validation error: {str(e)}",
  94. suggestion="Check the component configuration format",
  95. )
  96. )
  97. return errors
  98. @staticmethod
  99. def validate_instantiation(component: ComponentModel) -> Optional[ValidationError]:
  100. """Validate that the component can be instantiated"""
  101. try:
  102. model = component.model_copy(deep=True)
  103. # Attempt to load the component
  104. module_path, class_name = model.provider.rsplit(".", maxsplit=1)
  105. module = importlib.import_module(module_path)
  106. component_class = getattr(module, class_name)
  107. component_class.load_component(model)
  108. return None
  109. except Exception as e:
  110. return ValidationError(
  111. field="instantiation",
  112. error=f"Failed to instantiate component: {str(e)}",
  113. suggestion="Check that the component can be properly instantiated with the given config",
  114. )
  115. @classmethod
  116. def validate(cls, component: ComponentModel) -> ValidationResponse:
  117. """Validate a component configuration"""
  118. errors = []
  119. warnings = []
  120. # Check provider
  121. if provider_error := cls.validate_provider(component.provider):
  122. errors.append(provider_error)
  123. # Check component type
  124. if type_error := cls.validate_component_type(component):
  125. errors.append(type_error)
  126. # Validate schema
  127. schema_errors = cls.validate_config_schema(component)
  128. errors.extend(schema_errors)
  129. # Only attempt instantiation if no errors so far
  130. if not errors:
  131. if inst_error := cls.validate_instantiation(component):
  132. errors.append(inst_error)
  133. # Check for version warnings
  134. if not component.version:
  135. warnings.append(
  136. ValidationError(
  137. field="version",
  138. error="Component version not specified",
  139. suggestion="Consider adding a version to ensure compatibility",
  140. )
  141. )
  142. return ValidationResponse(is_valid=len(errors) == 0, errors=errors, warnings=warnings)