fix: improve truncation-aware parse failure logging#754
Conversation
Greptile SummaryThis PR adds a planning document for issue #411 that describes how to surface actionable guidance when a parse failure follows a model response that was truncated due to hitting the output-token budget or context-window limit. No production code is changed; the plan must be approved before implementation begins (per
|
| Filename | Overview |
|---|---|
| plans/411/truncation-aware-parse-failure-guidance.md | New plan document for truncation-aware parse failure guidance; well-aligned with the codebase but contains an inconsistency between its "Explicitly excluded" files list and the PR description's claimed test coverage. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[ModelFacade generate / agenerate] --> B[Call completion]
B --> C{Parser succeeds?}
C -- Yes --> D[Return result - discard accumulated truncation_reason]
C -- No --> E[Classify finish_reason from choices]
E --> F{Canonical reason found?}
F -- Yes --> G[Merge into accumulated GenerationTruncationReason]
F -- No --> H[Try raw-response fallback via get_value_from]
H --> G
G --> I{Retries or restarts left?}
I -- Correction --> J[Append error as user message]
J --> B
I -- Restart --> K[Reset messages, keep accumulation]
K --> B
I -- Exhausted --> L[Raise GenerationValidationFailureError with truncation_reason]
L --> M[catch_llm_exceptions calls handle_llm_exceptions]
M --> N{truncation_reason?}
N -- MAX_TOKENS --> O[Advise increase max_tokens in inference_parameters]
N -- MODEL_CONTEXT_WINDOW_EXCEEDED --> P[Advise reduce prompt or use larger-context model]
N -- None --> Q[Existing generic validation message]
O --> R[Raise ModelGenerationValidationFailureError]
P --> R
Q --> R
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[ModelFacade generate / agenerate] --> B[Call completion]
B --> C{Parser succeeds?}
C -- Yes --> D[Return result - discard accumulated truncation_reason]
C -- No --> E[Classify finish_reason from choices]
E --> F{Canonical reason found?}
F -- Yes --> G[Merge into accumulated GenerationTruncationReason]
F -- No --> H[Try raw-response fallback via get_value_from]
H --> G
G --> I{Retries or restarts left?}
I -- Correction --> J[Append error as user message]
J --> B
I -- Restart --> K[Reset messages, keep accumulation]
K --> B
I -- Exhausted --> L[Raise GenerationValidationFailureError with truncation_reason]
L --> M[catch_llm_exceptions calls handle_llm_exceptions]
M --> N{truncation_reason?}
N -- MAX_TOKENS --> O[Advise increase max_tokens in inference_parameters]
N -- MODEL_CONTEXT_WINDOW_EXCEEDED --> P[Advise reduce prompt or use larger-context model]
N -- None --> Q[Existing generic validation message]
O --> R[Raise ModelGenerationValidationFailureError]
P --> R
Q --> R
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
plans/411/truncation-aware-parse-failure-guidance.md:119-123
**Contradiction between "Explicitly excluded" list and PR description**
The plan marks `test_dataset_builder.py` as explicitly excluded from the implementation, but the PR description's Changes section reads: *"Adds regression coverage for sync generation, async generation, Anthropic stop reasons, **sync DatasetBuilder logging**, and async scheduler row-drop logging."* A reviewer reading only the PR description would expect DatasetBuilder test coverage to land in this PR; the plan would deliver something different. Either the PR description should be updated to remove "sync DatasetBuilder logging", or the exclusion list here should be revised to allow it.
Reviews (2): Last reviewed commit: "docs: plan #411 truncation guidance" | Re-trigger Greptile
|
Thanks for the automated review. Greptile, DCO, semantic title, and the agentic CI gate are now passing. The only failing check is the linked-issue gate because #411 does not yet have the maintainer-added |
Stale PR reminderThis PR has had failing checks for 7 days without activity. Failing checks: check Please push an update or leave a comment if you're still working on this. To prevent auto-close, add the |
|
Issue #411 has been triaged. The linked issue check is being re-evaluated. |
|
Thanks for the contribution, this is a nice quality-of-life fix. I reviewed the truncation metadata flow, Anthropic
Focused tests and smoke checks passed locally. Once those small items are addressed, this looks good to merge from my side. |
|
One broader simplification suggestion, especially now that the legacy sync builder has been removed from The current flow is roughly:
The async scheduler already logs the formatted public exception, so I think the same behavior can be implemented with fewer layers:
For the narrow scope of #411, an internal There is also one Anthropic nuance worth accounting for in the design: Anthropic can terminate with either
If we want this PR to support both, a small canonical truncation-reason enum on the internal error would be cleaner than a boolean. If we intentionally keep this PR limited to #411's output-token case, the dedicated subtype plus a follow-up for context-window truncation would keep this change small and explicit. Overall, I think the behavior is worth keeping; this is mainly an opportunity to reduce coupling and make the Anthropic boundary clearer before merge. |
nabinchha
left a comment
There was a problem hiding this comment.
One broader simplification suggestion, especially now that the legacy sync builder has been removed from main: could we avoid threading truncated_by_max_tokens through both exception classes and then reading it with getattr() in the builder?
The current flow is roughly:
finish_reason → boolean → GenerationValidationFailureError → boolean → ModelGenerationValidationFailureError → builder formatting
The async scheduler already logs the formatted public exception, so I think the same behavior can be implemented with fewer layers:
- Normalize the provider termination reason in the client adapter.
- Accumulate the truncation state locally across correction attempts/restarts.
- Raise a dedicated internal validation-error subtype (or carry a typed reason only on the internal validation error).
- Format the actionable message in
handle_llm_exceptions(). - Let the scheduler log the existing
ModelGenerationValidationFailureErrornormally.
For the narrow scope of #411, an internal MaxTokensGenerationFailureError(GenerationValidationFailureError) subtype would be enough. That would avoid adding truncated_by_max_tokens to the public model error, avoid the builder getattr(), and allow the obsolete sync-builder hunk and test to be dropped during the rebase.
There is also one Anthropic nuance worth accounting for in the design: Anthropic can terminate with either max_tokens or model_context_window_exceeded, and both can leave structured output truncated. They need different guidance:
max_tokens: increaseinference_parameters.max_tokens.model_context_window_exceeded: reduce the prompt/context/schema or use a model with a larger context window; increasingmax_tokenswill not help.
If we want this PR to support both, a small canonical truncation-reason enum on the internal error would be cleaner than a boolean. If we intentionally keep this PR limited to #411's output-token case, the dedicated subtype plus a follow-up for context-window truncation would keep this change small and explicit.
Overall, I think the behavior is worth keeping; this is mainly an opportunity to reduce coupling and make the Anthropic boundary clearer before merge.
|
@stepwise-ai-dev, are you planning to continue working on this PR? We think the behavior is worth keeping, but If you are not planning to continue, we will likely close this PR and implement a smaller version in a separate maintainer PR. Please let us know. Thanks again for the contribution. |
|
Yes, I'm planning to continue. Thanks for checking in, and for the clear feedback on the current error flow. I've reviewed the changes on I've prepared a smaller plan around the current async path: normalize provider termination reasons, accumulate truncation across correction and restart attempts, keep the reason internal, and let the scheduler log the existing public error. It also distinguishes I'll add the plan to the PR for review before resuming implementation. |
Signed-off-by: stepwise-ai-dev <stepwise-ai-dev@users.noreply.github.com>
8411985 to
7e4a8a4
Compare
|
|
||
| All new behavior is implemented test-first. | ||
|
|
||
| 1. Adapter normalization: | ||
| - Anthropic `end_turn`, `tool_use`, `max_tokens`, and `model_context_window_exceeded` become canonical finish reasons. |
There was a problem hiding this comment.
Contradiction between "Explicitly excluded" list and PR description
The plan marks test_dataset_builder.py as explicitly excluded from the implementation, but the PR description's Changes section reads: "Adds regression coverage for sync generation, async generation, Anthropic stop reasons, sync DatasetBuilder logging, and async scheduler row-drop logging." A reviewer reading only the PR description would expect DatasetBuilder test coverage to land in this PR; the plan would deliver something different. Either the PR description should be updated to remove "sync DatasetBuilder logging", or the exclusion list here should be revised to allow it.
Prompt To Fix With AI
This is a comment left during a code review.
Path: plans/411/truncation-aware-parse-failure-guidance.md
Line: 119-123
Comment:
**Contradiction between "Explicitly excluded" list and PR description**
The plan marks `test_dataset_builder.py` as explicitly excluded from the implementation, but the PR description's Changes section reads: *"Adds regression coverage for sync generation, async generation, Anthropic stop reasons, **sync DatasetBuilder logging**, and async scheduler row-drop logging."* A reviewer reading only the PR description would expect DatasetBuilder test coverage to land in this PR; the plan would deliver something different. Either the PR description should be updated to remove "sync DatasetBuilder logging", or the exclusion list here should be revised to allow it.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
andreatgretel
left a comment
There was a problem hiding this comment.
Thanks for revising this against current main. The plan addresses the earlier feedback from @nabinchha and me, and the direction looks good. Approved to proceed with implementation.
Two non-blocking follow-ups:
- Put direct
parse_anthropic_response()coverage intest_anthropic_translation.py. - Update the PR description to reflect the new plan and remove the obsolete sync DatasetBuilder claims.
Summary
Fixes #411 by surfacing an actionable message when a parse or recipe failure follows a model response that ended because of max_tokens.
Changes
Validation
Attention Areas
Fixes #411