Skip to content

Commit c470dc5

Browse files
committed
fix(state): persist json checkpoints as utf-8
1 parent 92eb5f9 commit c470dc5

2 files changed

Lines changed: 23 additions & 4 deletions

File tree

lib/crewai/src/crewai/state/provider/json_provider.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def checkpoint(
6363
file_path = _build_path(location, branch, parent_id)
6464
file_path.parent.mkdir(parents=True, exist_ok=True)
6565

66-
with open(file_path, "w") as f:
66+
with open(file_path, "w", encoding="utf-8") as f:
6767
f.write(data)
6868
return str(file_path)
6969

@@ -91,7 +91,7 @@ async def acheckpoint(
9191
file_path = _build_path(location, branch, parent_id)
9292
await aiofiles.os.makedirs(str(file_path.parent), exist_ok=True)
9393

94-
async with aiofiles.open(file_path, "w") as f:
94+
async with aiofiles.open(file_path, "w", encoding="utf-8") as f:
9595
await f.write(data)
9696
return str(file_path)
9797

@@ -129,7 +129,7 @@ def from_checkpoint(self, location: str) -> str:
129129
Returns:
130130
The raw JSON string.
131131
"""
132-
return Path(location).read_text()
132+
return Path(location).read_text(encoding="utf-8")
133133

134134
async def afrom_checkpoint(self, location: str) -> str:
135135
"""Read a JSON checkpoint file asynchronously.
@@ -140,7 +140,7 @@ async def afrom_checkpoint(self, location: str) -> str:
140140
Returns:
141141
The raw JSON string.
142142
"""
143-
async with aiofiles.open(location) as f:
143+
async with aiofiles.open(location, encoding="utf-8") as f:
144144
return await f.read()
145145

146146

lib/crewai/tests/test_checkpoint.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,25 @@ def test_checkpoint_writes_to_branch_subdir(self) -> None:
378378
assert path.endswith(".json")
379379
assert os.path.isfile(path)
380380

381+
def test_checkpoint_uses_utf8_for_non_ascii_json(self) -> None:
382+
provider = JsonProvider()
383+
data = '{"message": "olá niño"}'
384+
with tempfile.TemporaryDirectory() as d:
385+
path = provider.checkpoint(data, d, branch="main")
386+
387+
assert Path(path).read_bytes() == data.encode("utf-8")
388+
assert provider.from_checkpoint(path) == data
389+
390+
@pytest.mark.asyncio
391+
async def test_acheckpoint_uses_utf8_for_non_ascii_json(self) -> None:
392+
provider = JsonProvider()
393+
data = '{"message": "olá niño"}'
394+
with tempfile.TemporaryDirectory() as d:
395+
path = await provider.acheckpoint(data, d, branch="main")
396+
397+
assert Path(path).read_bytes() == data.encode("utf-8")
398+
assert await provider.afrom_checkpoint(path) == data
399+
381400
def test_checkpoint_fork_branch_subdir(self) -> None:
382401
provider = JsonProvider()
383402
with tempfile.TemporaryDirectory() as d:

0 commit comments

Comments
 (0)