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 <noreply@anthropic.com>
This commit is contained in:
TPTBusiness
2026-04-26 21:33:24 +02:00
parent 6e9d4d34ff
commit 3dff6680bd
2 changed files with 12 additions and 1 deletions
+7 -1
View File
@@ -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.")
+5
View File
@@ -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