From 3dff6680bd4c3976bcfc13e03a442bfcfadcc68f Mon Sep 17 00:00:00 2001 From: TPTBusiness Date: Sun, 26 Apr 2026 21:33:24 +0200 Subject: [PATCH] fix(loop): prevent step_idx advance on unhandled exceptions + fix consecutive assistant messages Two bugs that together caused an infinite SKIP loop after LoopResumeError: 1. loop.py _run_step: set step_forward=False in the `else: raise` branch so that when LoopResumeError propagates from _propose (LLMUnavailableError), step_idx stays at 0. Previously it advanced to 1, leaving loops permanently stuck with missing direct_exp_gen result on next resume. 2. base.py _create_chat_completion_auto_continue: when finish_reason=="length" triggers a continuation retry, merge into the previous assistant message instead of appending a second consecutive one. llama-server returns 400 on two consecutive assistant messages, which caused LLMUnavailableError -> LoopResumeError cascade. Co-Authored-By: Claude Sonnet 4.6 --- rdagent/oai/backend/base.py | 8 +++++++- rdagent/utils/workflow/loop.py | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rdagent/oai/backend/base.py b/rdagent/oai/backend/base.py index f7703ae2..20853cad 100644 --- a/rdagent/oai/backend/base.py +++ b/rdagent/oai/backend/base.py @@ -720,7 +720,13 @@ class APIBackend(ABC): if finish_reason is None or finish_reason != "length": break # we get a full response now. - new_messages.append({"role": "assistant", "content": response}) + # Merge into the previous assistant message if there already is one at the end. + # Appending a second consecutive assistant message causes llama-server to return 400 + # ("Cannot have 2 or more assistant messages at the end of the list"). + if new_messages and new_messages[-1]["role"] == "assistant": + new_messages[-1]["content"] += response + else: + new_messages.append({"role": "assistant", "content": response}) else: raise RuntimeError(f"Failed to continue the conversation after {try_n} retries.") diff --git a/rdagent/utils/workflow/loop.py b/rdagent/utils/workflow/loop.py index fe54d986..d4bbc25c 100644 --- a/rdagent/utils/workflow/loop.py +++ b/rdagent/utils/workflow/loop.py @@ -270,6 +270,11 @@ class LoopBase: msg = "We have reset the loop instance, stop all the routines and resume." raise self.LoopResumeError(msg) from e else: + # Do NOT advance step_idx for unhandled exceptions (e.g. LoopResumeError + # propagating from _propose). Keeping step_idx at the current step lets + # kickoff_loop retry step 0 on the next resume instead of permanently + # corrupting the loop with a missing direct_exp_gen result. + step_forward = False raise # re-raise unhandled exceptions finally: # No matter the execution succeed or not, we have to finish the following steps