Skip to content

fix(agentchat): SelectorGroupChat fallback must not return excluded previous speaker when allow_repeated_speaker=False#7936

Open
Diwak4r wants to merge 1 commit into
microsoft:mainfrom
Diwak4r:fix/selector-group-chat-livelock-fallback
Open

fix(agentchat): SelectorGroupChat fallback must not return excluded previous speaker when allow_repeated_speaker=False#7936
Diwak4r wants to merge 1 commit into
microsoft:mainfrom
Diwak4r:fix/selector-group-chat-livelock-fallback

Conversation

@Diwak4r

@Diwak4r Diwak4r commented Jul 9, 2026

Copy link
Copy Markdown

Problem

In SelectorGroupChat, when allow_repeated_speaker=False, _select_speaker excludes the previous speaker from the participants list passed to the model. If the model fails to make a valid selection after max_selector_attempts retries, the fallback logic returned self._previous_speaker anyway:

if self._previous_speaker is not None:
    return self._previous_speaker

Since the previous speaker was deliberately excluded from participants, returning it violates the allow_repeated_speaker=False contract — and, worse, in a two-agent team it causes a livelock: the same agent is picked again and again, never making progress (see #7471).

Fix

Gate the "use previous speaker" fallback behind allow_repeated_speaker. When repeated speakers are disallowed, the fallback now picks the first participant that is not the previous speaker:

if self._previous_speaker is not None:
    if self._allow_repeated_speaker:
        return self._previous_speaker
    fallback = next((p for p in participants if p != self._previous_speaker), None)
    if fallback is not None:
        return fallback
return participants[0]

participants[0] remains the final safe fallback (it already excludes the previous speaker when disallowed).

Verification

Added test_selector_group_chat_fallback_respects_allow_repeated_speaker, which makes the selector model always "select" the previous speaker and asserts the fallback moves to the other participant (no agent speaks twice in a row). Run on both runtime variants:

python -m pytest test_group_chat.py::test_selector_group_chat_fallback_respects_allow_repeated_speaker -q
# 2 passed
python -m pytest test_group_chat.py::test_selector_group_chat -q
# 2 passed (no regression)

Fixes #7471

Copilot AI review requested due to automatic review settings July 9, 2026 07:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ErenAta16 ErenAta16 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Checked out the branch and ran the existing group-chat suite before anything else, and it surfaces something worth flagging before this merges: test_selector_group_chat_fall_back_to_previous_after_3_attempts now fails.

Looking at that test, it does not pass allow_repeated_speaker explicitly, so it runs against the default (False). The model client always returns "agent2" (the already-excluded previous speaker) for all 4 attempts, and the test asserts the fallback still returns "agent2" a second time — which is exactly the pre-existing bug this PR is fixing, just encoded as the expected outcome in an older test. So the fix logic itself is correct and matches the allow_repeated_speaker=False contract described in the docstring, but this specific pre-existing test needs its assertions (and probably its name) updated to match the corrected behavior, otherwise this fails CI as soon as the full suite runs. Not showing up yet since only license/cla and the security check have completed on this SHA.

Once that test is updated to reflect "fallback must not repeat when allow_repeated_speaker=False" rather than asserting the old repeat, happy to re-review.

…revious speaker when allow_repeated_speaker=False

When allow_repeated_speaker=False, _select_speaker excludes the previous
speaker from the participants list. If the model fails after max_attempts,
the fallback returned self._previous_speaker anyway — which is excluded
from the list and causes a livelock where one agent speaks forever.

Fix: check allow_repeated_speaker in the fallback. If disallowed, pick
the first participant that isn't the previous speaker instead.

Fixes microsoft#7471

Signed-off-by: Diwak4r <diwakar.pandey2004@gmail.com>
Signed-off-by: Diwak4r <diwak4r.comp@gmail.com>
@Diwak4r Diwak4r force-pushed the fix/selector-group-chat-livelock-fallback branch from f944e46 to 2568b4d Compare July 14, 2026 08:48
@Diwak4r

Diwak4r commented Jul 14, 2026

Copy link
Copy Markdown
Author

Thanks for the detailed review, @ErenAta16. You were right: the existing test was asserting the old buggy behavior. I updated est_selector_group_chat_fall_back_to_previous_after_3_attempts to est_selector_group_chat_fall_back_to_non_previous_after_3_attempts and changed the final assertion to expect �gent1 (the first non-previous candidate) instead of �gent2. All 32 selector group chat tests now pass locally. Please re-review when you have a moment.

@ErenAta16

Copy link
Copy Markdown

Re-reviewed. The renamed test now asserts agent1 at index 2 after the model exhausts 4 attempts on the excluded agent2, that's the correct fallback target given participants=[agent1, agent2] and _previous_speaker=agent2.

The new test_selector_group_chat_fallback_respects_allow_repeated_speaker is a good addition beyond just fixing the old test, it exercises the alternating-fallback case across multiple exhaustion cycles and explicitly asserts no two consecutive messages share a source, which is the actual invariant allow_repeated_speaker=False is supposed to guarantee, not just the single-fallback case the old test covered.

Fix logic and both tests look correct to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] SelectorGroupChat livelock: fallback returns excluded previous speaker when allow_repeated_speaker=False

3 participants