atomic-agents icon indicating copy to clipboard operation
atomic-agents copied to clipboard

Getting TypeError: Object of type PosixPath is not JSON serializable with multi modal images in AgentMemory

Open shayaantx opened this issue 7 months ago • 0 comments

See below stack trace

It looks like when images created from instructor.Image.from_path(image_path) and used as input they get saved into AgentMemory.

Then once they get reused on subsequent BaseAgent run() calls, the json dumps call fails cause PosixPath is not serializable (dumps gets called when the BaseAgent calls self.memory.copy())

  File "./test/.venv/lib/python3.10/site-packages/atomic_agents/lib/components/agent_memory.py", line 208, in dump
    return json.dumps(memory_data)
  File "./test/.pyenv/versions/3.10.15/lib/python3.10/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "./test/.pyenv/versions/3.10.15/lib/python3.10/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "./test/.pyenv/versions/3.10.15/lib/python3.10/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "./test/.pyenv/versions/3.10.15/lib/python3.10/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type PosixPath is not JSON serializable
    def dump(self) -> str:
....
        serialized_history = []
        for message in self.history:
            content_class = message.content.__class__
            serialized_message = {
                "role": message.role,
                "content": {
                    "class_name": f"{content_class.__module__}.{content_class.__name__}",
                    "data": message.content.model_dump(),
                },
                "turn_id": message.turn_id,
            }
....
return json.dumps(memory_data)

I fixed it in my overridden AgentMemory class with some ugly hacks (I'm sure there is a better way so figured I'd post this issue)


from pathlib import PosixPath
import instructor

....

    def replace_posixpath(self, obj):
        if isinstance(obj, dict):
            return {k: self.replace_posixpath(v) for k, v in obj.items()}
        elif isinstance(obj, list):
            return [self.replace_posixpath(item) for item in obj]
        elif isinstance(obj, PosixPath):
            return {"__class__": "PosixPath", "path": str(obj)}
        else:
            return obj
        
    def reconstruct_image_from_posix_path(self, content_info):
        # Check if the image data contains the PosixPath marker and reconstruct the Image object
        if "image" in content_info["data"] and isinstance(content_info["data"]["image"], dict):
            if "source" in content_info["data"]["image"]:
                if "__class__" in content_info["data"]["image"]["source"]:
                    if content_info["data"]["image"]["source"]["__class__"] == "PosixPath":
                        image_path = content_info["data"]["image"]["source"]["path"]
                        content_info["data"]["image"] = instructor.Image.from_path(image_path)

....
    def dump(self) -> str:
...
        for message in self.history:
            content_class = message.content.__class__
            dumped_data = message.content.model_dump()
            dumped_data = self.replace_posixpath(dumped_data)
            serialized_message = {
                "role": message.role,
                "content": {
                    "class_name": f"{content_class.__module__}.{content_class.__name__}",
                    "data": dumped_data,
                },
                "turn_id": message.turn_id,
            }

....

    def load(self, serialized_data: str) -> None:
...

            for message_data in memory_data["history"]:
                content_info = message_data["content"]
                content_class = self._get_class_from_string(content_info["class_name"])

                self.reconstruct_image_from_posix_path(content_info)
                content_instance = content_class(**content_info["data"])

shayaantx avatar May 26 '25 22:05 shayaantx