From 0fd4d0ab29e99311ab0614f0376639beeae62b14 Mon Sep 17 00:00:00 2001 From: chengyongru <2755839590@qq.com> Date: Wed, 15 Jul 2026 01:04:27 +0800 Subject: [PATCH] fix(prompts): handle undecodable overrides --- nanobot/utils/workspace_prompts.py | 4 ++-- tests/agent/test_evaluator.py | 8 ++++++++ tests/command/test_builtin_evaluator_prompt.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/nanobot/utils/workspace_prompts.py b/nanobot/utils/workspace_prompts.py index 5dfa2a76..104503d8 100644 --- a/nanobot/utils/workspace_prompts.py +++ b/nanobot/utils/workspace_prompts.py @@ -25,7 +25,7 @@ def load_workspace_prompt_override( Returns the loaded text and its original length. Missing, unreadable, and empty files return ``(None, 0)`` so callers can fall back to their default. """ - with suppress(OSError): + with suppress(OSError, UnicodeDecodeError): text = path.read_text(encoding="utf-8").rstrip() if text: original_chars = len(text) @@ -50,7 +50,7 @@ def initialize_workspace_prompt(path: Path, default_prompt: str) -> bool: not path.is_file() or bool(path.read_text(encoding="utf-8").strip()) ): return False - except OSError: + except (OSError, UnicodeDecodeError): return False path.parent.mkdir(parents=True, exist_ok=True) diff --git a/tests/agent/test_evaluator.py b/tests/agent/test_evaluator.py index eb19af98..f5f2dff7 100644 --- a/tests/agent/test_evaluator.py +++ b/tests/agent/test_evaluator.py @@ -56,6 +56,14 @@ def test_resolve_evaluator_prompt_uses_default_for_empty_override(tmp_path) -> N assert resolve_evaluator_prompt(tmp_path) == default_evaluator_prompt() +def test_resolve_evaluator_prompt_uses_default_for_undecodable_override(tmp_path) -> None: + path = evaluator_prompt_file(tmp_path) + path.parent.mkdir() + path.write_bytes("Custom evaluator prompt.".encode("utf-16")) + + assert resolve_evaluator_prompt(tmp_path) == default_evaluator_prompt() + + def test_resolve_evaluator_prompt_caps_workspace_override(tmp_path) -> None: path = evaluator_prompt_file(tmp_path) path.parent.mkdir() diff --git a/tests/command/test_builtin_evaluator_prompt.py b/tests/command/test_builtin_evaluator_prompt.py index 76f91da3..01ebd176 100644 --- a/tests/command/test_builtin_evaluator_prompt.py +++ b/tests/command/test_builtin_evaluator_prompt.py @@ -59,6 +59,23 @@ async def test_evaluator_prompt_init_does_not_overwrite_existing_prompt(tmp_path assert prompt_file.read_text(encoding="utf-8") == "custom" +@pytest.mark.asyncio +async def test_evaluator_prompt_handles_undecodable_existing_prompt(tmp_path) -> None: + prompt_file = tmp_path / "prompts" / "evaluator.md" + prompt_file.parent.mkdir() + original = "custom".encode("utf-16") + prompt_file.write_bytes(original) + + status = await cmd_evaluator_prompt(_make_ctx(tmp_path)) + init = await cmd_evaluator_prompt( + _make_ctx(tmp_path, "/evaluator-prompt init", "init") + ) + + assert "Heartbeat evaluator prompt: nanobot default" in status.content + assert "already exists" in init.content + assert prompt_file.read_bytes() == original + + @pytest.mark.asyncio async def test_evaluator_prompt_init_recreates_empty_prompt(tmp_path) -> None: prompt_file = tmp_path / "prompts" / "evaluator.md"