fix(compressor): widen empty-content abort to sibling no-response shapes + snapshot state field
Follow-up to PR #94531 salvage: - classify the auxiliary boundary's terminal 'None response' / 'invalid response' errors (#7264) into the same empty-content abort carve-out so those shapes also preserve the session (#94459's wider classification, sibling shapes from #94448) - register _last_summary_empty_content_failure in _COMPRESSOR_ATTEMPT_STATE_FIELDS so pre-commit hard-cancel rollback restores the flag (conversation_compression snapshot allow-list) - tests: cooldown re-entry keeps aborting; both sibling shapes abort - attribution: map zhangyswx@163.com -> YusenZhang0601
This commit is contained in:
@@ -5150,8 +5150,14 @@ This compaction should PRIORITISE preserving all information related to the focu
|
||||
_is_streaming_closed = _is_connection_error(e)
|
||||
# Provider returned HTTP 200 with empty or whitespace body (e.g.
|
||||
# degraded proxy channel / upstream provider fault; #94448).
|
||||
_is_empty_content = (
|
||||
isinstance(e, RuntimeError) and "empty content" in _err_str
|
||||
_is_empty_content = isinstance(e, RuntimeError) and (
|
||||
"empty content" in _err_str
|
||||
# Sibling terminal "no usable response" shapes from the
|
||||
# auxiliary boundary's _validate_llm_response (#7264): a None
|
||||
# response or a malformed/missing choices[0].message — same
|
||||
# degraded-provider class (#94448).
|
||||
or "llm returned none response" in _err_str
|
||||
or "llm returned invalid response" in _err_str
|
||||
)
|
||||
# Authentication, permission, and exhausted-quota failures are NOT
|
||||
# transient or fixable by retrying the same request. Flag them so
|
||||
|
||||
@@ -289,6 +289,7 @@ _COMPRESSOR_ATTEMPT_STATE_FIELDS = (
|
||||
"_last_compress_aborted",
|
||||
"_last_summary_auth_failure",
|
||||
"_last_summary_network_failure",
|
||||
"_last_summary_empty_content_failure",
|
||||
"_last_aux_model_failure_error",
|
||||
"_last_aux_model_failure_model",
|
||||
"_summary_model_fallen_back",
|
||||
|
||||
2
contributors/emails/zhangyswx@163.com
Normal file
2
contributors/emails/zhangyswx@163.com
Normal file
@@ -0,0 +1,2 @@
|
||||
YusenZhang0601
|
||||
# PR #94531 salvage (#94448)
|
||||
@@ -966,6 +966,61 @@ class TestAuthFailureAborts:
|
||||
assert c._last_summary_fallback_used is False
|
||||
assert c._last_summary_dropped_count == 0
|
||||
|
||||
# Cooldown re-entry must keep aborting, same as network/auth —
|
||||
# _generate_summary() returns None from the cooldown early-return
|
||||
# without re-asserting the flag, so compress() must still see it.
|
||||
second = c.compress(msgs, current_tokens=999999)
|
||||
assert second == msgs
|
||||
assert c._last_compress_aborted is True
|
||||
assert c._last_summary_fallback_used is False
|
||||
|
||||
def test_auxiliary_none_response_aborts_compression(self):
|
||||
"""Sibling shape (#94459, from #7264): the auxiliary boundary's own
|
||||
terminal "None response" error is the same degraded-provider class
|
||||
and must ABORT, not fall through to the destructive fallback."""
|
||||
with patch("agent.context_compressor.get_model_context_length", return_value=100000):
|
||||
c = ContextCompressor(
|
||||
model="test",
|
||||
quiet_mode=True,
|
||||
protect_first_n=2,
|
||||
protect_last_n=2,
|
||||
abort_on_summary_failure=False,
|
||||
)
|
||||
msgs = self._msgs(12)
|
||||
with patch(
|
||||
"agent.context_compressor.call_llm",
|
||||
side_effect=RuntimeError("Auxiliary compression: LLM returned None response"),
|
||||
):
|
||||
result = c.compress(msgs, current_tokens=999999, force=True)
|
||||
assert result == msgs
|
||||
assert c._last_compress_aborted is True
|
||||
assert c._last_summary_empty_content_failure is True
|
||||
|
||||
def test_auxiliary_invalid_response_aborts_compression(self):
|
||||
"""Sibling shape (#94459, from #7264): malformed/missing
|
||||
choices[0].message terminal error must ABORT the same way."""
|
||||
with patch("agent.context_compressor.get_model_context_length", return_value=100000):
|
||||
c = ContextCompressor(
|
||||
model="test",
|
||||
quiet_mode=True,
|
||||
protect_first_n=2,
|
||||
protect_last_n=2,
|
||||
abort_on_summary_failure=False,
|
||||
)
|
||||
msgs = self._msgs(12)
|
||||
with patch(
|
||||
"agent.context_compressor.call_llm",
|
||||
side_effect=RuntimeError(
|
||||
"Auxiliary compression: LLM returned invalid response "
|
||||
"(type=str): 'oops'. Expected object with .choices[0].message "
|
||||
"— check provider adapter or custom endpoint compatibility."
|
||||
),
|
||||
):
|
||||
result = c.compress(msgs, current_tokens=999999, force=True)
|
||||
assert result == msgs
|
||||
assert c._last_compress_aborted is True
|
||||
assert c._last_summary_empty_content_failure is True
|
||||
|
||||
|
||||
class TestSummaryFallbackToMainModel:
|
||||
"""When ``summary_model`` differs from the main model and the summary LLM
|
||||
|
||||
Reference in New Issue
Block a user