1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//! Same-character run detection for a streamed reasoning window (#1351).
//!
//! GLM-5.3-Flash has a known server-side degeneration where `reasoning_content`
//! turns into `!!!!!` and keeps going. The substring guard beside this one
//! (`detect_text_repetition`) needs two matching 300-byte halves, so it sees a
//! pure run only once it is 600 bytes long and, when it fires, names it a
//! repetition rather than what it is. This check fires at 64 and says
//! "same-character run", so the log reads correctly in a postmortem.
//!
//! Only the run ending at the window's tail is inspected: deltas append, so a
//! run that reaches the threshold is the trailing run on the delta that pushed
//! it there. That keeps the check O(run) per delta instead of O(window).
/// Runs of one character the model must not be blamed for: whitespace (code
/// indentation, blank lines) is never a run, and the characters used for
/// rules and dividers (`-----`, `=====`, `*****`) need four times the
/// threshold before they count, since an 80-column divider in reasoning is
/// legitimate.
const DIVIDER_CHARS: = ;
/// Below this length nothing is a run. 64 is longer than any punctuation a
/// model writes on purpose and far shorter than the 600 bytes the substring
/// guard needs.
pub const MIN_RUN: usize = 64;
/// The character and length of the run ending at the tail of `window`, when
/// that run is long enough to be degeneration rather than punctuation.
pub