nanobot/tests/test_truncate_text_shadowing.py
chengyongru 4c751bb8e3 refactor(agent): extract checkpoint.py and turn_writer.py from loop.py
Extract checkpoint and turn-persistence logic from AgentLoop into two
dedicated modules to reduce loop.py's size and improve reviewability.

- checkpoint.py: CheckpointManager handles runtime checkpoints, pending
  user-turn markers, and session recovery after cancellation/crash.
- turn_writer.py: TurnWriter handles message sanitization, turn saving,
  early user-message persistence, and subagent-followup persistence.

AgentLoop retains thin delegate methods for full backward compatibility.
Test helpers updated to initialize the new sub-managers.
2026-05-16 18:35:09 +08:00

34 lines
1.3 KiB
Python

import inspect
from types import SimpleNamespace
def test_sanitize_persisted_blocks_truncate_text_shadowing_regression() -> None:
"""Regression: avoid bool param shadowing imported truncate_text.
Buggy behavior (historical):
- loop.py imports `truncate_text` from helpers
- `_sanitize_persisted_blocks(..., truncate_text: bool=...)` uses same name
- when called with `truncate_text=True`, function body executes `truncate_text(text, ...)`
which resolves to bool and raises `TypeError: 'bool' object is not callable`.
This test asserts the fixed API exists and truncation works without raising.
"""
from nanobot.agent.loop import AgentLoop
sig = inspect.signature(AgentLoop._sanitize_persisted_blocks)
assert "should_truncate_text" in sig.parameters
assert "truncate_text" not in sig.parameters
from nanobot.agent.turn_writer import TurnWriter
writer = TurnWriter(sessions=None, checkpoint=None, max_tool_result_chars=5) # type: ignore[arg-type]
content = [{"type": "text", "text": "0123456789"}]
out = writer.sanitize_persisted_blocks(content, should_truncate_text=True)
assert isinstance(out, list)
assert out and out[0]["type"] == "text"
assert isinstance(out[0]["text"], str)
assert out[0]["text"] != content[0]["text"]