Skip to content

fix(agentchat): retry MagenticOne ledger parsing when next_speaker is missing#7913

Open
nolanchic wants to merge 1 commit into
microsoft:mainfrom
nolanchic:fix/magentic-one-missing-next-speaker
Open

fix(agentchat): retry MagenticOne ledger parsing when next_speaker is missing#7913
nolanchic wants to merge 1 commit into
microsoft:mainfrom
nolanchic:fix/magentic-one-missing-next-speaker

Conversation

@nolanchic

Copy link
Copy Markdown

Why are these changes needed?

In MagenticOneOrchestrator._orchestrate_step, when the model returns a valid progress-ledger JSON object that is missing the next_speaker field (or the field is malformed), the for key in required_keys loop correctly sets key_error = True and breaks — intending to trigger a retry.

However, the next_speaker validation that runs after that loop unconditionally accesses progress_ledger["next_speaker"]["answer"]:

# Validate the next speaker if the task is not yet complete
if (
    not progress_ledger["is_request_satisfied"]["answer"]
    and progress_ledger["next_speaker"]["answer"] not in self._participant_names  # <- KeyError
):
    key_error = True
    break

When next_speaker is the missing key, this raises KeyError, which is not caught by the surrounding except (json.JSONDecodeError, TypeError). The exception propagates and crashes the orchestrator instead of retrying up to _max_json_retries (10) as designed.

This is a real-world failure mode: some models occasionally omit a field from the progress-ledger JSON. The existing retries exist precisely to tolerate this, but the unhandled KeyError bypasses them.

Fix

Add a not key_error guard so the next_speaker validation is skipped when a required key is already missing/malformed, letting the retry path run as designed:

if (
    not key_error
    and not progress_ledger["is_request_satisfied"]["answer"]
    and progress_ledger["next_speaker"]["answer"] not in self._participant_names
):
    key_error = True
    break

Related issue number

N/A — no existing issue covers this code path. (Related issues #6599 / #6547 describe a different root cause — markdown-wrapped JSON — which was already fixed via extract_json_from_str.) Happy to open a tracking issue if the maintainers prefer.

Checks

  • I've included any doc changes needed for https://microsoft.github.io/autogen/. (No doc changes needed — internal fix.)
  • I've added tests (if relevant) corresponding to the changes introduced in this PR. (Added test_magentic_one_group_chat_ledger_missing_next_speaker_retries, which feeds a ledger missing next_speaker and asserts the team run completes via retry instead of raising KeyError. This test fails on main with KeyError: 'next_speaker' and passes with the fix.)
  • I've made sure all auto checks have passed. (Local verification below.)

Local verification

cd python
uv run pytest packages/autogen-agentchat/tests/test_magentic_one_group_chat.py -q   # 8 passed
uv run ruff format --check packages/autogen-agentchat/src packages/autogen-agentchat/tests   # already formatted
uv run ruff check packages/autogen-agentchat/src packages/autogen-agentchat/tests   # all checks passed
uv run pyright packages/autogen-agentchat/src packages/autogen-agentchat/tests      # 0 errors
uv run mypy --config-file pyproject.toml packages/autogen-agentchat/src packages/autogen-agentchat/tests   # no issues

… missing

In MagenticOneOrchestrator._orchestrate_step, when the model returns a
valid progress-ledger JSON object that is missing the next_speaker field
(or the field is malformed), the required_keys loop correctly sets
key_error = True and breaks, intending to trigger a retry.

However, the next_speaker validation that runs after the loop
unconditionally accesses progress_ledger["next_speaker"]["answer"].
When next_speaker is the missing key this raises KeyError, which is not
caught by the surrounding 'except (json.JSONDecodeError, TypeError)' and
crashes the orchestrator instead of retrying up to _max_json_retries.

Add a 'not key_error' guard so the next_speaker validation is skipped
when a required key is already missing, letting the retry path run as
designed. Adds a regression test that feeds a ledger missing
next_speaker and asserts the team run completes via retry.
@nolanchic

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@microsoft-github-policy-service

Copy link
Copy Markdown
Contributor

@nolanchic the command you issued was incorrect. Please try again.

Examples are:

@microsoft-github-policy-service agree

and

@microsoft-github-policy-service agree company="your company"

@nolanchic

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@nolanchic

Copy link
Copy Markdown
Author

While working on this, I want to flag a related behavior boundary I intentionally did not change, in case reviewers want to weigh in.

There are two distinct "next_speaker problem" cases in _orchestrate_step, and after this fix they are handled inconsistently:

Case Cause Behavior after this PR
next_speaker key missing or malformed for key in required_keys loop → key_error = True; break ✅ Retries (this is what the fix corrects)
next_speaker present but answer not in participant_names post-loop check → key_error = True; break (line 373-374) ❌ Does not retry — the break exits the whole for _ in range(self._max_json_retries) loop, so it raises ValueError("Failed to parse ledger information after multiple retries.") immediately

The second case is pre-existing behavior (the break on line 374 was already there before this PR). I left it as-is because it seemed plausibly intentional — if the model keeps returning an out-of-vocab speaker name, retrying up to 10× may just waste tokens vs. failing fast.

But if maintainers prefer symmetry — i.e. the "speaker not in participants" case should also count as a parse failure and trigger a retry — that's a one-line change: replace the break on line 374 with continue (and drop the now-redundant guard). Happy to do that here or in a follow-up, depending on the desired semantics.

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.

1 participant