revert: drop cumulative-resend tool-arg heuristic from shared streaming path (#35718) (#35860)

PR #35718 added a per-slot "cumulative-resend" latch to the universal
streaming tool-call accumulator to fix DeepSeek / Baidu Qianfan (#35592).
The latch fires when a delta is a strict superset of the accumulated
buffer (len(_new) > len(_prev) and _new.startswith(_prev)) and then
REPLACES the buffer instead of appending.

That superset test is not an unambiguous cumulative signature. A normal
incremental stream can emit a single fragment that restates an already-
accumulated prefix — trivially common in large code-patch arguments with
repeated lines / indentation — which trips the latch and clobbers the
accumulated buffer, corrupting the tool call. Observed in the wild on
Anthropic Opus (the primary model) building a large patch: corrupted /
short arguments → finish_reason='length' dead-end → session killed.

A guessing heuristic that can silently clobber a tool-call buffer has no
place on the path every provider and model shares. Reverting restores the
known-good plain `+=` accumulator. The #35592 narrow provider bug should
be re-addressed provider-gated so it is structurally impossible to touch
Anthropic / OpenAI incremental streams, rather than via a heuristic on the
shared path.

Reverts ca03486b6.
This commit is contained in:
Teknium
2026-05-31 06:14:32 -07:00
committed by GitHub
parent f2d4cf4f76
commit 2b5268f716
4 changed files with 1 additions and 295 deletions
-67
View File
@@ -182,58 +182,6 @@ def _escape_invalid_chars_in_json_strings(raw: str) -> str:
return "".join(out)
def _collapse_repeated_json_arguments(raw_stripped: str) -> str | None:
"""Collapse concatenated-duplicate tool-call argument JSON.
Some OpenAI-compatible streaming providers (DeepSeek / Baidu Qianfan
among them) resend the *full* cumulative ``arguments`` string in every
stream chunk instead of incremental fragments. Our stream accumulator
concatenates argument deltas with ``+=`` (correct for spec-compliant
incremental providers), so a cumulative-resend provider yields the
object repeated once per chunk:
'{"path":"x"}{"path":"x"}{"path":"x"}...'
A spec-compliant provider always produces exactly one valid JSON object
after concatenation, so this function is only ever reached for strings
that already fail ``json.loads`` (issue #35592).
Detection is unambiguous and operates on the fully-accumulated string,
not on partial per-chunk data: the input must be K>=2 *exact* repeats of
a unit substring that itself parses as valid JSON. Returns the single
collapsed unit (re-serialised compactly) when that holds, else ``None``
so the caller falls through to the generic repair passes.
Safety: a single object like ``{"command":{"command":"x"}}`` parses on
the first ``json.loads`` attempt in the caller and never reaches here;
even if it did, it is not an exact-repeat string, so this returns
``None`` and leaves it untouched.
"""
n = len(raw_stripped)
if n < 2:
return None
# The unit must divide the total length evenly for an exact K-repeat.
# Try the smallest plausible unit first (divisors of n, ascending),
# capping the repeat count so a pathological input can't blow up.
for unit_len in range(1, n // 2 + 1):
if n % unit_len != 0:
continue
k = n // unit_len
if k < 2:
continue
unit = raw_stripped[:unit_len]
if unit * k != raw_stripped:
continue
# The repeated unit must itself be valid JSON for this to be a
# cumulative-resend collapse and not a coincidental string repeat.
try:
parsed = json.loads(unit, strict=False)
except (json.JSONDecodeError, ValueError):
continue
return json.dumps(parsed, separators=(",", ":"))
return None
def _repair_tool_call_arguments(raw_args: str, tool_name: str = "?") -> str:
"""Attempt to repair malformed tool_call argument JSON.
@@ -272,20 +220,6 @@ def _repair_tool_call_arguments(raw_args: str, tool_name: str = "?") -> str:
except (json.JSONDecodeError, TypeError, ValueError):
pass
# Repair pass 1: collapse concatenated-duplicate JSON. Cumulative-resend
# streaming providers (DeepSeek / Baidu Qianfan, #35592) yield the full
# arguments object repeated once per stream chunk; our += accumulator
# turns that into '{...}{...}{...}'. Only reached when pass 0 above
# already failed, so spec-compliant single objects are never touched.
collapsed = _collapse_repeated_json_arguments(raw_stripped)
if collapsed is not None:
logger.warning(
"Collapsed cumulative-resend duplicate tool_call arguments for "
"%s (%d chars -> %d)",
tool_name, len(raw_stripped), len(collapsed),
)
return collapsed
# Attempt common JSON repairs
fixed = raw_stripped
# 1. Strip trailing commas before } or ]
@@ -502,7 +436,6 @@ __all__ = [
"_sanitize_messages_surrogates",
"_escape_invalid_chars_in_json_strings",
"_repair_tool_call_arguments",
"_collapse_repeated_json_arguments",
"_strip_non_ascii",
"_sanitize_messages_non_ascii",
"_sanitize_tools_non_ascii",