@@ -30,7 +30,7 @@ class SkillVersion:
3030 """
3131
3232 major : int = 0
33- minor : int = 1
33+ minor : int = 0
3434 patch : int = 0
3535
3636 def __post_init__ (self ) -> None :
@@ -94,11 +94,14 @@ def to_dict(self) -> Dict[str, int]:
9494
9595 @classmethod
9696 def from_dict (cls , data : Dict [str , Any ]) -> "SkillVersion" :
97- return cls (
98- major = data .get ("major" , 0 ),
99- minor = data .get ("minor" , 1 ),
100- patch = data .get ("patch" , 0 ),
101- )
97+ try :
98+ return cls (
99+ major = int (data .get ("major" , 0 )),
100+ minor = int (data .get ("minor" , 0 )),
101+ patch = int (data .get ("patch" , 0 )),
102+ )
103+ except (TypeError , ValueError ) as exc :
104+ raise ValidationError (f"Invalid SkillVersion data: { exc } " ) from exc
102105
103106
104107class SkillCategory (str , Enum ):
@@ -428,9 +431,13 @@ def suggestions_by_type(self, evo_type: EvolutionType) -> List[EvolutionSuggesti
428431 return [s for s in self .evolution_suggestions if s .evolution_type == evo_type ]
429432
430433 def validate (self ) -> None :
431- """Validate analysis fields."""
434+ """Validate analysis fields and nested objects ."""
432435 if not self .task_id :
433436 raise ValidationError ("task_id must be non-empty" )
437+ for j in self .skill_judgments :
438+ j .validate ()
439+ for s in self .evolution_suggestions :
440+ s .validate ()
434441
435442 def to_dict (self ) -> Dict [str , Any ]:
436443 return {
@@ -447,17 +454,20 @@ def to_dict(self) -> Dict[str, Any]:
447454
448455 @classmethod
449456 def from_dict (cls , data : Dict [str , Any ]) -> "ExecutionAnalysis" :
450- return cls (
451- task_id = data ["task_id" ],
452- timestamp = datetime .fromisoformat (data ["timestamp" ]),
453- task_completed = data .get ("task_completed" , False ),
454- execution_note = data .get ("execution_note" , "" ),
455- tool_issues = data .get ("tool_issues" , []),
456- skill_judgments = [SkillJudgment .from_dict (j ) for j in data .get ("skill_judgments" , [])],
457- evolution_suggestions = [EvolutionSuggestion .from_dict (s ) for s in data .get ("evolution_suggestions" , [])],
458- analyzed_by = data .get ("analyzed_by" , "" ),
459- analyzed_at = (datetime .fromisoformat (data ["analyzed_at" ]) if data .get ("analyzed_at" ) else datetime .now ()),
460- )
457+ try :
458+ return cls (
459+ task_id = str (data ["task_id" ]),
460+ timestamp = datetime .fromisoformat (data ["timestamp" ]),
461+ task_completed = data .get ("task_completed" , False ),
462+ execution_note = data .get ("execution_note" , "" ),
463+ tool_issues = data .get ("tool_issues" , []),
464+ skill_judgments = [SkillJudgment .from_dict (j ) for j in data .get ("skill_judgments" , [])],
465+ evolution_suggestions = [EvolutionSuggestion .from_dict (s ) for s in data .get ("evolution_suggestions" , [])],
466+ analyzed_by = data .get ("analyzed_by" , "" ),
467+ analyzed_at = (datetime .fromisoformat (data ["analyzed_at" ]) if data .get ("analyzed_at" ) else datetime .now ()),
468+ )
469+ except (TypeError , ValueError ) as exc :
470+ raise ValidationError (f"Invalid ExecutionAnalysis data: { exc } " ) from exc
461471
462472
463473# Full skill profile (identity + lineage + deps + quality)
@@ -555,7 +565,8 @@ def validate(self) -> None:
555565 f"total_completions ({ self .total_completions } ) must not exceed "
556566 f"total_applied ({ self .total_applied } )"
557567 )
558- self .lineage .validate ()
568+ if self .lineage is not None :
569+ self .lineage .validate ()
559570
560571 def to_dict (self ) -> Dict [str , Any ]:
561572 return {
@@ -582,30 +593,33 @@ def to_dict(self) -> Dict[str, Any]:
582593
583594 @classmethod
584595 def from_dict (cls , data : Dict [str , Any ]) -> "SkillRecord" :
585- record = cls (
586- skill_id = data ["skill_id" ],
587- name = data ["name" ],
588- description = data .get ("description" , "" ),
589- path = data .get ("path" , "" ),
590- is_active = data .get ("is_active" , True ),
591- category = SkillCategory (data ["category" ]) if data .get ("category" ) else SkillCategory .WORKFLOW ,
592- tags = data .get ("tags" , []),
593- visibility = (SkillVisibility (data ["visibility" ]) if data .get ("visibility" ) else SkillVisibility .PRIVATE ),
594- creator_id = data .get ("creator_id" , "" ),
595- lineage = (
596- SkillLineage .from_dict (data ["lineage" ])
597- if data .get ("lineage" )
598- else SkillLineage (origin = SkillOrigin .IMPORTED )
599- ),
600- tool_dependencies = data .get ("tool_dependencies" , []),
601- critical_tools = data .get ("critical_tools" , []),
602- total_selections = data .get ("total_selections" , 0 ),
603- total_applied = data .get ("total_applied" , 0 ),
604- total_completions = data .get ("total_completions" , 0 ),
605- total_fallbacks = data .get ("total_fallbacks" , 0 ),
606- first_seen = (datetime .fromisoformat (data ["first_seen" ]) if data .get ("first_seen" ) else datetime .now ()),
607- last_updated = (datetime .fromisoformat (data ["last_updated" ]) if data .get ("last_updated" ) else datetime .now ()),
608- )
596+ try :
597+ record = cls (
598+ skill_id = str (data ["skill_id" ]),
599+ name = str (data ["name" ]),
600+ description = data .get ("description" , "" ),
601+ path = data .get ("path" , "" ),
602+ is_active = data .get ("is_active" , True ),
603+ category = SkillCategory (data ["category" ]) if data .get ("category" ) else SkillCategory .WORKFLOW ,
604+ tags = data .get ("tags" , []),
605+ visibility = (SkillVisibility (data ["visibility" ]) if data .get ("visibility" ) else SkillVisibility .PRIVATE ),
606+ creator_id = data .get ("creator_id" , "" ),
607+ lineage = (
608+ SkillLineage .from_dict (data ["lineage" ])
609+ if data .get ("lineage" )
610+ else SkillLineage (origin = SkillOrigin .IMPORTED )
611+ ),
612+ tool_dependencies = data .get ("tool_dependencies" , []),
613+ critical_tools = data .get ("critical_tools" , []),
614+ total_selections = int (data .get ("total_selections" , 0 )),
615+ total_applied = int (data .get ("total_applied" , 0 )),
616+ total_completions = int (data .get ("total_completions" , 0 )),
617+ total_fallbacks = int (data .get ("total_fallbacks" , 0 )),
618+ first_seen = (datetime .fromisoformat (data ["first_seen" ]) if data .get ("first_seen" ) else datetime .now ()),
619+ last_updated = (datetime .fromisoformat (data ["last_updated" ]) if data .get ("last_updated" ) else datetime .now ()),
620+ )
621+ except (TypeError , ValueError ) as exc :
622+ raise ValidationError (f"Invalid SkillRecord data: { exc } " ) from exc
609623 for a in data .get ("recent_analyses" , []):
610624 record .recent_analyses .append (ExecutionAnalysis .from_dict (a ))
611625 return record
0 commit comments