1616
1717import re
1818from typing import List , Any
19- from dataclasses import fields
19+ from dataclasses import fields , is_dataclass
2020
2121from agentkit .toolkit .config .config import CommonConfig
2222
@@ -82,7 +82,59 @@ def validate_common_config(config: CommonConfig) -> List[str]:
8282 return errors
8383
8484 @staticmethod
85- def _validate_conditional_fields (config : CommonConfig ) -> List [str ]:
85+ def validate_dataclass (config : Any ) -> List [str ]:
86+ if not is_dataclass (config ):
87+ return []
88+
89+ errors : List [str ] = []
90+
91+ for field in fields (config ):
92+ if field .name .startswith ("_" ):
93+ continue
94+
95+ validation = field .metadata .get ("validation" , {})
96+
97+ if validation .get ("type" ) == "conditional" :
98+ continue
99+
100+ value = getattr (config , field .name )
101+
102+ if validation .get ("required" ) and (
103+ not value or (isinstance (value , str ) and not value .strip ())
104+ ):
105+ desc = field .metadata .get ("description" , field .name )
106+ errors .append (f"{ desc } is required" )
107+ continue
108+
109+ pattern = validation .get ("pattern" )
110+ if pattern and value and isinstance (value , str ):
111+ if not re .match (pattern , value ):
112+ desc = field .metadata .get ("description" , field .name )
113+ msg = validation .get ("message" , "Invalid format" )
114+ errors .append (f"{ desc } : { msg } " )
115+
116+ choices = field .metadata .get ("choices" )
117+ if choices and value :
118+ valid_values = []
119+ if isinstance (choices , list ):
120+ if choices and isinstance (choices [0 ], dict ):
121+ valid_values = [c ["value" ] for c in choices ]
122+ else :
123+ valid_values = choices
124+
125+ if valid_values and value not in valid_values :
126+ desc = field .metadata .get ("description" , field .name )
127+ errors .append (
128+ f"{ desc } must be one of: { ', ' .join (map (str , valid_values ))} "
129+ )
130+
131+ conditional_errors = ConfigValidator ._validate_conditional_fields (config )
132+ errors .extend (conditional_errors )
133+
134+ return errors
135+
136+ @staticmethod
137+ def _validate_conditional_fields (config : Any ) -> List [str ]:
86138 """Execute conditional validation (cross-field dependencies).
87139
88140 Args:
@@ -93,7 +145,7 @@ def _validate_conditional_fields(config: CommonConfig) -> List[str]:
93145 """
94146 errors = []
95147
96- for field in fields (CommonConfig ):
148+ for field in fields (config ):
97149 if field .name .startswith ("_" ):
98150 continue
99151
@@ -111,11 +163,6 @@ def _validate_conditional_fields(config: CommonConfig) -> List[str]:
111163 depend_value = getattr (config , depends_on , None )
112164 current_value = getattr (config , field .name , None )
113165
114- if not current_value or (
115- isinstance (current_value , str ) and not current_value .strip ()
116- ):
117- continue
118-
119166 if depend_value in rules :
120167 rule = rules [depend_value ]
121168 field_errors = ConfigValidator ._apply_conditional_rule (
@@ -143,6 +190,12 @@ def _apply_conditional_rule(
143190 errors = []
144191 desc = metadata .get ("description" , field_name )
145192
193+ if rule .get ("required" ) and (
194+ value is None or (isinstance (value , str ) and not value .strip ())
195+ ):
196+ errors .append (f"{ desc } is required" )
197+ return errors
198+
146199 if "choices" in rule :
147200 if value not in rule ["choices" ]:
148201 msg = rule .get (
0 commit comments