Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions openhands-sdk/openhands/sdk/conversation/impl/local_conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,17 +592,18 @@ def run(self) -> None:
self._state.execution_status = ConversationExecutionStatus.RUNNING

iteration = 0
last_event_count = len(self._state.events)
try:
while True:
logger.debug(f"Conversation run iteration {iteration}")
with self._state:
# Pause attempts to acquire the state lock
# Before value can be modified step can be taken
# Ensure step conditions are checked when lock is already acquired
if self._state.execution_status in [
ConversationExecutionStatus.PAUSED,
ConversationExecutionStatus.STUCK,
]:
if (
self._state.execution_status
== ConversationExecutionStatus.PAUSED
):
break

# Handle stop hooks on FINISHED
Expand Down Expand Up @@ -634,15 +635,25 @@ def run(self) -> None:
break

# Check for stuck patterns if enabled
# Only check if new events have been added since last check
# to avoid repeatedly triggering on the same pattern
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know by any chance what was the pattern? Or which of the stuck scenarios got triggered?

if self._stuck_detector:
is_stuck = self._stuck_detector.is_stuck()
current_event_count = len(self._state.events)
if current_event_count > last_event_count:
is_stuck = self._stuck_detector.is_stuck()

if is_stuck:
logger.warning("Stuck pattern detected.")
self._state.execution_status = (
ConversationExecutionStatus.STUCK
)
continue
if is_stuck:
logger.warning("Stuck pattern detected.")
self._state.execution_status = (
ConversationExecutionStatus.STUCK
)
# Exit the loop when stuck is detected, rather than
# continuing. Continuing would cause an infinite loop
# because is_stuck() would return true again.
# The caller can then decide how to handle it.
break
# Update event count after checking
last_event_count = current_event_count

# clear the flag before calling agent.step() (user approved)
if (
Expand All @@ -657,6 +668,8 @@ def run(self) -> None:
self, on_event=self._on_event, on_token=self._on_token
)
iteration += 1
# Update event count after agent.step() adds new events
last_event_count = len(self._state.events)

# Check for non-finished terminal conditions
# Note: We intentionally do NOT check for FINISHED status here.
Expand Down
Loading