@@ -1384,6 +1384,63 @@ def chat(self, messages, **k):
13841384 self .assertIsNone (loop1 .run ())
13851385 self .assertEqual (deltas , [])
13861386
1387+ def test_compact_no_user_request_returns_false (self ):
1388+ """Compaction needs a real (non-nudge) user request to resume
1389+ with; without one it must fail cleanly."""
1390+ session = RecordingSession ()
1391+ loop = AgentLoop (session , messages = [Message (role = "assistant" , content = "hi" )])
1392+ self .assertFalse (loop .compact ())
1393+
1394+ def test_compact_empty_summary_returns_false (self ):
1395+ """A compaction response with no text must not replace the
1396+ conversation (fail cleanly, reset the compacting flag)."""
1397+ session = RecordingSession ()
1398+
1399+ def empty_chat_sync (messages , system = None , temperature = None ,
1400+ max_tokens = None , reasoning_effort = None ):
1401+ return Message (role = "assistant" , content = "" ), Usage ()
1402+
1403+ session .client .chat_sync = empty_chat_sync
1404+ loop = AgentLoop (session , messages = [Message (role = "user" , content = "do it" )])
1405+ self .assertFalse (loop .compact ())
1406+ self .assertFalse (session .compacting )
1407+
1408+ def test_compact_client_error_returns_false (self ):
1409+ """A failing compaction request is non-fatal: it is logged and
1410+ the loop continues without replacing the history."""
1411+ session = RecordingSession ()
1412+
1413+ def boom_chat_sync (messages , system = None , temperature = None ,
1414+ max_tokens = None , reasoning_effort = None ):
1415+ raise RuntimeError ("compaction API down" )
1416+
1417+ session .client .chat_sync = boom_chat_sync
1418+ loop = AgentLoop (session , messages = [Message (role = "user" , content = "do it" )])
1419+ self .assertFalse (loop .compact ())
1420+ self .assertFalse (session .compacting )
1421+
1422+ def test_error_state_beats_terminal_response (self ):
1423+ """If the loop carries an error state, the error text wins over
1424+ a terminal response (defensive path for the post-supervision
1425+ error check)."""
1426+ session = RecordingSession ()
1427+ session .tools_enabled = False
1428+ session .client .script = ["hello" ]
1429+ loop = AgentLoop (session , messages = [Message (role = "user" , content = "hi" )])
1430+ loop .error = "boom"
1431+ self .assertEqual (loop .run (), "Error: boom" )
1432+
1433+ def test_zero_budget_subagent_returns_none (self ):
1434+ """A sub-agent loop with max_rounds=0 and no assistant text has
1435+ nothing to surface: run() returns None."""
1436+ session = RecordingSession ()
1437+ loop = AgentLoop (
1438+ session ,
1439+ messages = [Message (role = "user" , content = "hi" )],
1440+ top_level = False , max_rounds = 0 ,
1441+ )
1442+ self .assertIsNone (loop .run ())
1443+
13871444
13881445class TestParallelToolRounds (unittest .TestCase ):
13891446 def test_cancel_before_round_skips_all_tools (self ):
0 commit comments