Source code for haive.core.utils.haive_discovery.component_info
"""Component information data model with serialization support."""importjsonimportloggingfromdataclassesimportdataclassfromtypingimportAnylogger=logging.getLogger(__name__)
[docs]@dataclassclassComponentInfo:"""Standardized component information with serialization support."""name:strcomponent_type:strmodule_path:strclass_name:strdescription:strsource_code:strenv_vars:list[str]schema:dict[str,Any]metadata:dict[str,Any]timestamp:str# Tool and engine creation resultstool_instance:Any|None=Noneengine_config:Any|None=None
[docs]defto_dict(self)->dict[str,Any]:"""Convert to dictionary, handling non-serializable fields."""data={"name":self.name,"component_type":self.component_type,"module_path":self.module_path,"class_name":self.class_name,"description":self.description,"source_code":self.source_code,"env_vars":self.env_vars,"timestamp":self.timestamp,}# Handle schema serializationtry:data["schema"]=self._make_json_serializable(self.schema)exceptExceptionase:logger.debug(f"Could not serialize schema for {self.name}: {e}")data["schema"]={"error":f"Schema not serializable: {e!s}"}# Handle metadata serializationtry:data["metadata"]=self._make_json_serializable(self.metadata)exceptExceptionase:logger.debug(f"Could not serialize metadata for {self.name}: {e}")data["metadata"]={"error":f"Metadata not serializable: {e!s}"}# Add tool info if availableifself.tool_instance:data["has_tool"]=Truedata["tool_name"]=getattr(self.tool_instance,"name","unknown")data["tool_description"]=getattr(self.tool_instance,"description","")else:data["has_tool"]=False# Add engine config if availableifself.engine_config:try:data["engine_config"]=self._make_json_serializable(self.engine_config)exceptExceptionase:logger.debug(f"Could not serialize engine config for {self.name}: {e}")data["engine_config"]={"error":f"Engine config not serializable: {e!s}"}returndata
def_make_json_serializable(self,obj:Any,max_depth:int=5,current_depth:int=0)->Any:"""Recursively make an object JSON serializable."""ifcurrent_depth>max_depth:returnf"<Max depth {max_depth} reached>"ifobjisNoneorisinstance(obj,str|int|float|bool):returnobjifisinstance(obj,list|tuple):return[self._make_json_serializable(item,max_depth,current_depth+1)foriteminobj]ifisinstance(obj,dict):result={}forkey,valueinobj.items():try:str_key=str(key)result[str_key]=self._make_json_serializable(value,max_depth,current_depth+1)exceptExceptionase:result[str_key]=f"<Error serializing value: {e!s}>"returnresult# Handle objects with __dict__ifhasattr(obj,"__dict__"):try:returnself._make_json_serializable({k:vfork,vinobj.__dict__.items()ifnotk.startswith("_")},max_depth,current_depth+1,)exceptException:pass# Handle Pydantic modelsifhasattr(obj,"model_dump"):try:returnobj.model_dump()exceptException:passifhasattr(obj,"dict"):try:returnobj.dict()exceptException:pass# Last resort - convert to stringtry:returnstr(obj)exceptException:returnf"<{type(obj).__name__} object>"
[docs]defto_document_content(self)->str:"""Convert to RAG-friendly document content."""content=[]content.append(f"# {self.name}")content.append(f"**Type:** {self.component_type}")content.append(f"**Module:** {self.module_path}")content.append(f"**Class:** {self.class_name}")content.append("")ifself.description:content.append("## Description")content.append(self.description)content.append("")ifself.env_vars:content.append("## Environment Variables")forvarinself.env_vars:content.append(f"- `{var}`")content.append("")ifself.schemaandnot(isinstance(self.schema,dict)andself.schema.get("error")):content.append("## Schema")content.append("```json")try:content.append(json.dumps(self.schema,indent=2))exceptBaseException:content.append(str(self.schema))content.append("```")content.append("")ifself.tool_instance:content.append("## Usage as Tool")content.append(f"**Tool Name:** `{getattr(self.tool_instance,'name','unknown')}`")content.append(f"**Description:** {getattr(self.tool_instance,'description','')}")content.append("")ifself.engine_config:content.append("## Engine Configuration")content.append("This component can be used as a Haive engine:")content.append("```python")content.append("# Example engine usage")content.append(f"engine = {self.class_name}Engine(name='{self.name}')")content.append("```")content.append("")ifself.metadataandnot(isinstance(self.metadata,dict)andself.metadata.get("error")):content.append("## Metadata")content.append("```json")try:content.append(json.dumps(self.metadata,indent=2))exceptBaseException:content.append(str(self.metadata))content.append("```")content.append("")content.append("## Source Code")content.append("```python")content.append(self.source_code)content.append("```")return"\n".join(content)