diff --git a/swarms/structs/agent.py b/swarms/structs/agent.py index 8ae2ff13..1bac7c6f 100644 --- a/swarms/structs/agent.py +++ b/swarms/structs/agent.py @@ -1542,11 +1542,14 @@ class Agent: Called automatically after load() to ensure all components are properly set up. """ try: + # Always create a new executor + self.executor = ThreadPoolExecutor(max_workers=os.cpu_count()) + + # Reinitialize tokenizer + self.tokenizer = TikTokenizer() + # Reinitialize conversation if needed - if ( - not hasattr(self, "short_memory") - or self.short_memory is None - ): + if not hasattr(self, "short_memory") or self.short_memory is None: self.short_memory = Conversation( system_prompt=self.system_prompt, time_enabled=False, @@ -1554,19 +1557,17 @@ class Agent: rules=self.rules, ) - # Reinitialize executor if needed - if not hasattr(self, "executor") or self.executor is None: - self.executor = ThreadPoolExecutor( - max_workers=os.cpu_count() + # Reinitialize tool structure if needed + if hasattr(self, 'tools') and (self.tools or getattr(self, 'list_base_models', None)): + self.tool_struct = BaseTool( + tools=self.tools, + base_models=getattr(self, 'list_base_models', None), + tool_system_prompt=self.tool_system_prompt ) - # # Reinitialize tool structure if needed - # if hasattr(self, 'tools') and (self.tools or getattr(self, 'list_base_models', None)): - # self.tool_struct = BaseTool( - # tools=self.tools, - # base_models=getattr(self, 'list_base_models', None), - # tool_system_prompt=self.tool_system_prompt - # ) + # Restart autosave if it was enabled + if getattr(self, 'autosave', False): + self.enable_autosave() except Exception as e: logger.error(f"Error reinitializing components: {e}") @@ -2148,40 +2149,66 @@ class Agent: def _serialize_attr(self, attr_name: str, attr_value: Any) -> Any: """ Serializes an individual attribute, handling non-serializable objects. + Excludes certain attributes that should be recreated on load rather than serialized. Args: attr_name (str): The name of the attribute. attr_value (Any): The value of the attribute. Returns: - Any: The serialized value of the attribute. - """ + Any: The serialized value of the attribute, or None if it should be excluded. + """ + # List of attributes that should not be serialized + non_serializable_attrs = { + 'executor', # ThreadPoolExecutor + 'autosave_thread', # Thread object + 'llm', # LLM instance that should be passed in constructor + 'tokenizer', # Should be recreated + 'tool_struct', # Should be recreated from tools and base_models + 'long_term_memory', # Should be handled separately + 'memory_manager', # Should be handled separately + 'sentiment_analyzer', # Function/callable + 'stopping_condition', # Function/callable + 'stopping_func', # Function/callable + 'custom_loop_condition', # Function/callable + 'limit_tokens_from_string', # Function/callable + 'output_cleaner', # Function/callable + 'parser', # Function/callable + 'callback', # Function/callable + 'callbacks', # List of functions/callables + 'search_algorithm', # Function/callable + 'evaluator', # Function/callable + } + + # Skip serialization for non-serializable attributes + if attr_name in non_serializable_attrs: + return None + try: if callable(attr_value): return self._serialize_callable(attr_value) elif hasattr(attr_value, "to_dict"): - return ( - attr_value.to_dict() - ) # Recursive serialization for nested objects + return attr_value.to_dict() else: - json.dumps( - attr_value - ) # Attempt to serialize to catch non-serializable objects + # Test if it can be serialized + json.dumps(attr_value) return attr_value - except (TypeError, ValueError): - return f"" + except (TypeError, ValueError, AttributeError): + logger.warning(f"Attribute {attr_name} could not be serialized, excluding from save state") + return None def to_dict(self) -> Dict[str, Any]: """ - Converts all attributes of the class, including callables, into a dictionary. - Handles non-serializable attributes by converting them or skipping them. + Converts serializable attributes of the class into a dictionary. + Excludes non-serializable attributes that should be recreated on load. Returns: - Dict[str, Any]: A dictionary representation of the class attributes. + Dict[str, Any]: A dictionary representation of the serializable class attributes. """ return { attr_name: self._serialize_attr(attr_name, attr_value) for attr_name, attr_value in self.__dict__.items() + if self._serialize_attr(attr_name, attr_value) is not None } def to_json(self, indent: int = 4, *args, **kwargs):