fix: repair flush sentinel test — mock auxiliary client and add guard
The TestFlushSentinelNotLeaked test from PR #227 had two issues: 1. flush_memories() uses get_text_auxiliary_client() which could bypass agent.client entirely — mock it to return (None, None) 2. No assertion that the API was actually called — added guard assert Without these fixes the test passed vacuously (API never called).
This commit is contained in:
@@ -2273,6 +2273,7 @@ class AIAgent:
|
|||||||
api_msg["reasoning_content"] = reasoning
|
api_msg["reasoning_content"] = reasoning
|
||||||
api_msg.pop("reasoning", None)
|
api_msg.pop("reasoning", None)
|
||||||
api_msg.pop("finish_reason", None)
|
api_msg.pop("finish_reason", None)
|
||||||
|
api_msg.pop("_flush_sentinel", None)
|
||||||
api_messages.append(api_msg)
|
api_messages.append(api_msg)
|
||||||
|
|
||||||
if self._cached_system_prompt:
|
if self._cached_system_prompt:
|
||||||
|
|||||||
@@ -821,3 +821,44 @@ class TestRetryExhaustion:
|
|||||||
):
|
):
|
||||||
with pytest.raises(RuntimeError, match="rate limited"):
|
with pytest.raises(RuntimeError, match="rate limited"):
|
||||||
agent.run_conversation("hello")
|
agent.run_conversation("hello")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Flush sentinel leak
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestFlushSentinelNotLeaked:
|
||||||
|
"""_flush_sentinel must be stripped before sending messages to the API."""
|
||||||
|
|
||||||
|
def test_flush_sentinel_stripped_from_api_messages(self, agent_with_memory_tool):
|
||||||
|
"""Verify _flush_sentinel is not sent to the API provider."""
|
||||||
|
agent = agent_with_memory_tool
|
||||||
|
agent._memory_store = MagicMock()
|
||||||
|
agent._memory_flush_min_turns = 1
|
||||||
|
agent._user_turn_count = 10
|
||||||
|
agent._cached_system_prompt = "system"
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{"role": "user", "content": "hello"},
|
||||||
|
{"role": "assistant", "content": "hi"},
|
||||||
|
{"role": "user", "content": "remember this"},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Mock the API to return a simple response (no tool calls)
|
||||||
|
mock_msg = SimpleNamespace(content="OK", tool_calls=None)
|
||||||
|
mock_choice = SimpleNamespace(message=mock_msg)
|
||||||
|
mock_response = SimpleNamespace(choices=[mock_choice])
|
||||||
|
agent.client.chat.completions.create.return_value = mock_response
|
||||||
|
|
||||||
|
# Bypass auxiliary client so flush uses agent.client directly
|
||||||
|
with patch("agent.auxiliary_client.get_text_auxiliary_client", return_value=(None, None)):
|
||||||
|
agent.flush_memories(messages, min_turns=0)
|
||||||
|
|
||||||
|
# Check what was actually sent to the API
|
||||||
|
call_args = agent.client.chat.completions.create.call_args
|
||||||
|
assert call_args is not None, "flush_memories never called the API"
|
||||||
|
api_messages = call_args.kwargs.get("messages") or call_args[1].get("messages")
|
||||||
|
for msg in api_messages:
|
||||||
|
assert "_flush_sentinel" not in msg, (
|
||||||
|
f"_flush_sentinel leaked to API in message: {msg}"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user