fix: improve error handling in policy generation and rollout - #24
Merged
Conversation
The policy stage calls generate_structured() which can return valid HTTP responses with malformed JSON that doesn't parse into a policy dict. Previously this immediately raised ValueError and failed the pipeline. - Retry structured generation up to 2 attempts on parse failure - Log a warning on each retry attempt - Include actionable hint in error message (rerun command, check endpoint quota) when retries are exhausted - Include last response text (truncated) for debugging The rate limiter (_with_retries) already handles HTTP-level errors (429, 5xx) inside generate_structured(). This retry is a separate layer for content-quality failures where the HTTP call succeeded but the output is unusable.
The auditor retry loop (L659) and target turn loop (L741) both used broad 'except Exception' which caught LLMRateLimitError, LLMAuthError, and other classified LLM errors. This caused: - Rate-limit errors treated as 'bad auditor output' and retried with a guidance prompt instead of propagating for clean error display - Auth errors wasting 2 more attempts before recording as [AUDITOR ERROR] - LLM errors in target turns buried as [TARGET ERROR] in the transcript then surfaced as 'RuntimeError: scenario ended with target_error' with a noisy traceback instead of a clean one-line message Fix: add an explicit catch for (LLMAuthError, LLMInputError, LLMRateLimitError, LLMProviderError) before the broad 'except Exception' that re-raises immediately. The runner's top-level handler at L393 already knows how to present these cleanly. Non-LLM errors (e.g. target runtime crashes, JSON parse failures) still follow the existing path — recorded in transcript and surfaced as target_error.
Collaborator
Author
|
@microsoft-github-policy-service agree company="Microsoft" |
AaronAspinwall123
approved these changes
May 8, 2026
AaronAspinwall123
added a commit
that referenced
this pull request
May 8, 2026
Resolves conflicts in p2m/runner.py and p2m/stages/rollout.py introduced by main's centralized-logging refactor (PR #22) and policy/rollout error-handling improvements (PR #24). p2m/runner.py: kept the artifact-cache stage path (prepare_artifact_plan / activate_artifact_plan / override_cacheable_output_paths) and combined it with main's logging style. The two stage-skip messages now use log.info with the new '[stage] Skipped' prefix instead of the deleted _progress() helper, and _progress() itself was removed since main's logging configuration writes to sys.__stderr__ via RichHandler, neutralizing the original Phoenix sys.stderr-wrapping concern. p2m/stages/rollout.py: dropped the sys.__stderr__ rollout progress writer in favor of main's log.info / log.warning calls (same rationale). Kept the 're' import that the cache code uses for _VERSIONED_ARTIFACT_RE; dropped the now-unused 'sys' import. Verified: pytest passes for tests/test_artifact_cache.py, tests/test_runner_artifact_cache.py, tests/test_runner_progress.py, and tests/test_viewer_server_artifacts.py (56 passed, 2 skipped). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix two error handling issues that caused noisy failures and poor user experience during pipeline runs.
Changes
Commit 1: Retry structured policy generation on transient parse failures
Problem: The policy stage calls
generate_structured()which can return a valid HTTP response with malformed JSON that doesn't parse into a policy dict. This immediately raisedValueErrorand failed the pipeline, even though a simple retry usually succeeds.Fix:
Note: The rate limiter (
_with_retriesinsidegenerate_structured()) handles HTTP-level errors (429/5xx). This retry is a separate layer for content-quality failures where the HTTP call succeeded but the output is unusable.Commit 2: Propagate LLM errors from rollout instead of burying in transcript
Problem: Two broad
except Exceptionblocks inrollout.pycaught classified LLM errors (LLMRateLimitError,LLMAuthError, etc.) and either:[TARGET ERROR]in the transcript, then surfaced them asRuntimeError: scenario ended with target_errorwith a noisy traceback (target turn loop, L741)Fix: Add explicit catch for
(LLMAuthError, LLMInputError, LLMRateLimitError, LLMProviderError)before the broadexcept Exceptionthat re-raises immediately. The runner's top-level handler at L393 already presents these with clean, actionable messages. Non-LLM errors (runtime crashes, JSON parse failures) still follow the existing transcript recording path.Testing