Repository navigation
fix(gateway): suppress the duplicated provider-error status copy - #98165
Open
liuhao1024 wants to merge 1 commit into
Open
liuhao1024 wants to merge 1 commit into
liuhao1024 wants to merge 1 commit into
Conversation
A provider failure reached chat surfaces twice: the mid-run status
callback was rewritten to the user-safe reply by
_prepare_gateway_status_message, and the failed turn's final response
was rewritten to the byte-identical text by
_sanitize_gateway_final_response. Adapters without
send_or_update_status fall back to a plain send, so both copies stay;
and failed runs are exempted from progress-bubble cleanup
(not response.get("failed")), so even Telegram keeps the status copy.
Suppress the transient status copy instead — the final response still
reports the failure with the same sanitized text, and nothing raw is
delivered on either path.
Fixes NousResearch#72131
Author
|
The Windows-only failure in this run is a known flaky timing test, unrelated to this diff. Failing test: Why it's unrelated to this change:
No rerun attempted since external contributors can't trigger one; happy to rebase if a fresh SHA is preferred. |
4 of 6 tasks
This branch has not been deployed
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.
What does this PR do?
Fixes the double delivery of provider errors to chat surfaces (#72131). A provider failure was surfaced through two gateway channels that produce byte-identical text:
_prepare_gateway_status_messagerewrote the raw provider error via_gateway_provider_error_replyand sent it;_sanitize_gateway_final_responserewrote it to the same user-safe text and sent it again.For adapters without
send_or_update_status,_send_or_update_status_corofalls back to a plainsend(), so the transient status becomes a second persistent message. And per ValeryP's analysis on the issue, even Telegram is affected on failed turns: progress-bubble cleanup is opt-in per platform (display.platforms.<platform>.cleanup_progress) and its registration is guarded byand not response.get("failed")("Failed runs skip cleanup so the bubbles remain as breadcrumbs") — a provider failure is a failed turn, so the surviving bubble is a verbatim copy of the final answer.The fix suppresses the transient status copy instead of delivering the rewrite: a provider-error-shaped status returns
Nonefrom_prepare_gateway_status_message. This closes both surfaces with a single stateless change — no turn-scoped dedup state (the scoping problem that sank #72144). The final response still reports the failure with the same sanitized text, so the user still sees exactly one user-safe message per failed turn, and no raw provider body is delivered on either path.Related Issue
Fixes #72131
Type of Change
Changes Made
gateway/run.py—_prepare_gateway_status_message: provider-error-shaped text now returnsNone(suppressed) instead of being rewritten and delivered; the rewrite previously duplicated the final response's text as a persistent message.tests/gateway/test_telegram_noise_filter.py— replacedtest_telegram_status_sanitizes_raw_provider_security_errors(asserted the rewrite was delivered on the status path) withtest_chat_gateways_suppress_provider_error_statusparametrized over chat platforms, asserting suppression; addedtest_local_status_keeps_raw_provider_errorspinning that local/CLI raw-text surfaces keep the raw diagnostic stream.How to Test
python3 -m pytest tests/gateway/test_telegram_noise_filter.py tests/gateway/test_local_model_connection_reply.py tests/gateway/test_compression_progress_notices.py -q— Observed result: 183 passed.python3 -m pytest tests/gateway/ tests/agent/test_turn_context_overflow_warning.py -q— Observed result: only the pre-existingtests/gateway/relay/test_relay_going_idle.pytiming flakes fail; they fail identically on a cleanupstream/maincheckout (4 failed there), unrelated to this diff.python3 -c "from gateway.run import _prepare_gateway_status_message, _sanitize_gateway_final_response; from gateway.config import Platform; raw='API call failed after 3 retries: HTTP 429'; print(_prepare_gateway_status_message(Platform.TELEGRAM, 'lifecycle', raw)); print(_sanitize_gateway_final_response(Platform.TELEGRAM, raw))"— Observed result:None(no status copy) followed by the single sanitized final reply, i.e. exactly one message per failed turn instead of two.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass (gateway + related suites; only pre-existing main flakes fail, see How to Test)Documentation & Housekeeping
docs/, docstrings) — or N/A (inline comment documents the suppression contract)cli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AFor New Skills
N/A — not a skill.