Skip to content

Python: Retry the Magentic progress ledger when it names an unknown agent - #9181

Open
Lanre Shittu (Shizoqua) wants to merge 2 commits into
microsoft:mainfrom
Shizoqua:magentic-next-speaker
Open

Lanre Shittu (Shizoqua) wants to merge 2 commits into
microsoft:mainfrom
Shizoqua:magentic-next-speaker

Conversation

@Shizoqua

Copy link
Copy Markdown
Contributor

Motivation & Context

StandardMagenticManager.create_progress_ledger says it avoids selecting a non-existent agent, but the next_speaker in the ledger was never checked. When the model named a participant slightly wrong, such as "Coder" for "coder", the orchestrator treated it as invalid and went straight to the final answer, ending the run with the task unfinished.

Description & Review Guide

  • What are the major changes? Inside the existing retry loop, a ledger whose next_speaker is not a participant now raises, so it is retried like a parse failure. The check is skipped when the request is already satisfied.
  • What is the impact of these changes? A small naming slip from the model gets another attempt instead of ending the run early. Ledgers with valid names are unaffected.
  • What do you want reviewers to focus on? If every retry still names an unknown agent, the existing failure path applies and the orchestrator resets and replans.

Related Issue

Fixes #9178

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix), and a workflow keeps the label and title prefix in sync automatically.

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.

@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Oct 7, 2026
@eavanvalkenburg

Copy link
Copy Markdown
Member

/review

@github-actions github-actions Bot 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.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 45c45d921517
Model: gpt-5.6-sol

Overview

The change validates unsatisfied progress ledgers against configured participant names and reuses the existing bounded per-call parse retry mechanism. It preserves satisfied-ledger handling, empty-team validation, and configured round/reset limits, with a focused test for recovery on the second response. However, persistent invalid output now enters the orchestrator's reset/replan path, whose limits are unlimited by default, creating an unbounded paid-call loop.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 high) across 1 file. Details are attached to the affected lines below.

Affected areas: python/packages/orchestrations/agent_framework_orchestrations/_magentic.py

and isinstance(next_speaker, str)
and next_speaker not in agent_names
):
raise ValueError(f"Unknown next speaker '{next_speaker}'. Valid names: {names_csv}.")

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.

With the default max_reset_count and max_round_count both unlimited, a model that keeps returning an unknown speaker exhausts these retries and the resulting error is caught by the orchestrator as a reason to reset and replan. That repeats without advancing stall state, and the retries resend identical input, so one untrusted task can keep issuing paid model calls until cancellation or recursion failure. Please preserve the guard against premature final answers but make exhaustion terminate under a finite budget or use another bounded fallback instead of entering the reset loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Fixed in b1b5142. Unknown names are still retried, but once the retries run out the last ledger is returned, so the run ends through the existing invalid speaker path instead of resetting. Added a test for it.

# brief backoff before next try
await asyncio.sleep(0.25 * attempts)

if unknown_speaker_ledger is not None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Lanre Shittu (@Shizoqua) unknown_speaker_ledger survives later parse failures, so unknown -> malformed -> malformed returns the stale unknown-speaker ledger instead of raising the final parse failure. That masks the actual failure and routes exhaustion through the invalid-speaker final-answer path. The saved ledger should only win when the final attempt was an unknown-speaker result.

This branch was successfully deployed

1 active deployment
github-app-auth — b1b51425 Deployed Oct 8, 2026 by Shizoqua via add_label #24822
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Magentic run ends early when the progress ledger names an unknown agent

3 participants