Skip to content

Commit 50e6210

Browse files
chore: fix 'Object of is not JSON serializable' when use ChatAgent.save_memory() (#3179)
Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com> Co-authored-by: Wendong-Fan <w3ndong.fan@gmail.com>
1 parent fd4b431 commit 50e6210

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

camel/memories/records.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,31 @@ def from_dict(cls, record_dict: Dict[str, Any]) -> "MemoryRecord":
7070
Args:
7171
record_dict(Dict[str, Any]): A dict generated by :meth:`to_dict`.
7272
"""
73+
from camel.types import (
74+
OpenAIBackendRole,
75+
RoleType,
76+
)
77+
7378
message_cls = cls._MESSAGE_TYPES[record_dict["message"]["__class__"]]
7479
kwargs: Dict = record_dict["message"].copy()
7580
kwargs.pop("__class__")
81+
82+
# Convert role_type string back to RoleType enum if it's a string
83+
if "role_type" in kwargs and isinstance(kwargs["role_type"], str):
84+
kwargs["role_type"] = RoleType(kwargs["role_type"])
85+
7686
reconstructed_message = message_cls(**kwargs)
87+
88+
# Convert role_at_backend string back to OpenAIBackendRole enum if
89+
# it's a string
90+
role_at_backend = record_dict["role_at_backend"]
91+
if isinstance(role_at_backend, str):
92+
role_at_backend = OpenAIBackendRole(role_at_backend)
93+
7794
return cls(
7895
uuid=UUID(record_dict["uuid"]),
7996
message=reconstructed_message,
80-
role_at_backend=record_dict["role_at_backend"],
97+
role_at_backend=role_at_backend,
8198
extra_info=record_dict["extra_info"],
8299
timestamp=record_dict["timestamp"],
83100
agent_id=record_dict["agent_id"],
@@ -93,7 +110,9 @@ def to_dict(self) -> Dict[str, Any]:
93110
"__class__": self.message.__class__.__name__,
94111
**asdict(self.message),
95112
},
96-
"role_at_backend": self.role_at_backend,
113+
"role_at_backend": self.role_at_backend.value
114+
if hasattr(self.role_at_backend, "value")
115+
else self.role_at_backend,
97116
"extra_info": self.extra_info,
98117
"timestamp": self.timestamp,
99118
"agent_id": self.agent_id,

camel/storages/key_value_storages/json.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from pathlib import Path
1818
from typing import Any, ClassVar, Dict, List, Optional
1919

20+
from pydantic import BaseModel
21+
2022
from camel.storages.key_value_storages import BaseKeyValueStorage
2123
from camel.types import (
2224
ModelType,
@@ -27,8 +29,13 @@
2729

2830

2931
class CamelJSONEncoder(json.JSONEncoder):
30-
r"""A custom JSON encoder for serializing specifically enumerated types.
31-
Ensures enumerated types can be stored in and retrieved from JSON format.
32+
r"""A custom JSON encoder for serializing CAMEL-specific types.
33+
34+
Handles serialization of:
35+
- Enumerated types (RoleType, TaskType, ModelType, OpenAIBackendRole)
36+
- Pydantic BaseModel objects (from structured outputs)
37+
38+
Ensures these types can be stored in and retrieved from JSON format.
3239
"""
3340

3441
CAMEL_ENUMS: ClassVar[Dict[str, EnumMeta]] = {
@@ -39,8 +46,14 @@ class CamelJSONEncoder(json.JSONEncoder):
3946
}
4047

4148
def default(self, obj) -> Any:
49+
# Handle CAMEL enum types
4250
if type(obj) in self.CAMEL_ENUMS.values():
4351
return {"__enum__": str(obj)}
52+
53+
# Handle Pydantic BaseModel objects (e.g., from structured outputs)
54+
if isinstance(obj, BaseModel):
55+
return obj.model_dump()
56+
4457
# Let the base class default method raise the TypeError
4558
return json.JSONEncoder.default(self, obj)
4659

0 commit comments

Comments
 (0)