autogen - ✅(Solved) Fix [Bug] SelectorGroupChat livelock: fallback returns excluded previous speaker when allow_repeated_speaker=False [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
microsoft/autogen#7471Fetched 2026-04-08 01:42:18
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1referenced ×1

Root Cause

In _selector_group_chat.py, the fallback after exhausting max_selector_attempts:

if self._previous_speaker is not None:
    return self._previous_speaker  # BUG: returns the excluded speaker

Fix Action

Fixed

PR fix notes

PR #7472: fix(agentchat): prevent livelock in SelectorGroupChat fallback when allow_repeated_speaker=False

Description (problem / solution / changelog)

Summary

  • Fix a livelock bug in SelectorGroupChat where the fallback after exhausting max_selector_attempts returns self._previous_speaker even when allow_repeated_speaker=False, causing an infinite loop (A speaks -> selector fails to pick non-A -> falls back to A -> repeat)
  • When allow_repeated_speaker=False and selector attempts are exhausted, the fallback now picks a random participant that is NOT the previous speaker
  • Updated existing test to explicitly set allow_repeated_speaker=True for the case that tests fallback-to-previous behavior
  • Added new test test_selector_group_chat_no_livelock_on_fallback_when_repeated_speaker_disallowed to verify the fix

Fixes #7471

Test plan

  • Existing test test_selector_group_chat_fall_back_to_previous_after_3_attempts continues to pass (now explicitly uses allow_repeated_speaker=True)
  • New test verifies that when allow_repeated_speaker=False and the LLM exhausts all attempts by picking the previous speaker, the fallback selects a different participant
  • Edge case: if only one participant exists, fallback still returns the previous speaker (no alternative available)

🤖 Generated with Claude Code

Changed files

  • python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_selector_group_chat.py (modified, +12/-0)
  • python/packages/autogen-agentchat/tests/test_group_chat.py (modified, +34/-0)

Code Example

from autogen_agentchat.teams import SelectorGroupChat

team = SelectorGroupChat(
    participants=[agent_a, agent_b, agent_c],
    model_client=client,
    allow_repeated_speaker=False,
    max_selector_attempts=3,
)
# If the LLM consistently selects the previous speaker in all 3 attempts,
# the fallback returns the previous speaker, violating allow_repeated_speaker=False

---

if self._previous_speaker is not None:
    return self._previous_speaker  # BUG: returns the excluded speaker

---

if not self._allow_repeated_speaker and self._previous_speaker is not None:
    candidates = [p for p in participants if p != self._previous_speaker]
    if candidates:
        return random.choice(candidates)
return self._previous_speaker  # only if repeated speaker IS allowed or no alternatives
RAW_BUFFERClick to expand / collapse

Bug Description

When allow_repeated_speaker=False in SelectorGroupChat, if the LLM-based selector fails to pick a valid (non-previous) speaker within max_selector_attempts, the fallback logic in _selector_group_chat.py returns self._previous_speaker — the exact speaker that was supposed to be excluded.

This creates a livelock: Agent A speaks → selector tries to pick someone else → exhausts attempts → falls back to A → A speaks again → repeat forever.

Reproduction

from autogen_agentchat.teams import SelectorGroupChat

team = SelectorGroupChat(
    participants=[agent_a, agent_b, agent_c],
    model_client=client,
    allow_repeated_speaker=False,
    max_selector_attempts=3,
)
# If the LLM consistently selects the previous speaker in all 3 attempts,
# the fallback returns the previous speaker, violating allow_repeated_speaker=False

Root Cause

In _selector_group_chat.py, the fallback after exhausting max_selector_attempts:

if self._previous_speaker is not None:
    return self._previous_speaker  # BUG: returns the excluded speaker

Suggested Fix

When allow_repeated_speaker=False, the fallback should select a random participant that is NOT the previous speaker:

if not self._allow_repeated_speaker and self._previous_speaker is not None:
    candidates = [p for p in participants if p != self._previous_speaker]
    if candidates:
        return random.choice(candidates)
return self._previous_speaker  # only if repeated speaker IS allowed or no alternatives

extent analysis

Fix Plan

To resolve the livelock issue, we need to modify the fallback logic in _selector_group_chat.py. Here are the steps:

  • Update the _selector_group_chat.py file to include the new fallback logic.
  • Modify the __init__ method to ensure self._allow_repeated_speaker is set correctly.
  • Implement the new fallback logic using a list comprehension to filter out the previous speaker.

Code Changes

import random

class SelectorGroupChat:
    def __init__(self, participants, model_client, allow_repeated_speaker=False, max_selector_attempts=3):
        # ...
        self._allow_repeated_speaker = allow_repeated_speaker
        # ...

    def _fallback_selector(self, participants):
        if not self._allow_repeated_speaker and self._previous_speaker is not None:
            candidates = [p for p in participants if p != self._previous_speaker]
            if candidates:
                return random.choice(candidates)
        return self._previous_speaker  # only if repeated speaker IS allowed or no alternatives

Verification

To verify the fix, you can use the following test case:

team = SelectorGroupChat(
    participants=[agent_a, agent_b, agent_c],
    model_client=client,
    allow_repeated_speaker=False,
    max_selector_attempts=3,
)

# Simulate the LLM consistently selecting the previous speaker
team._previous_speaker = agent_a
selected_speaker = team._fallback_selector([agent_a, agent_b, agent_c])
assert selected_speaker != agent_a

This test case ensures that the fallback logic selects a speaker other than the previous speaker when allow_repeated_speaker=False.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING