Skip to content

fix(agent): prevent GLM stop-to-length heuristic false positives (#14572)#15463

Closed
aj-nt wants to merge 2 commits into
NousResearch:mainfrom
aj-nt:fix/glm-stop-heuristic-14572
Closed

fix(agent): prevent GLM stop-to-length heuristic false positives (#14572)#15463
aj-nt wants to merge 2 commits into
NousResearch:mainfrom
aj-nt:fix/glm-stop-heuristic-14572

Conversation

@aj-nt

@aj-nt aj-nt commented Apr 25, 2026

Copy link
Copy Markdown

Summary

Fixes #14572 — the Ollama/GLM stop-to-length heuristic was triggering 100% false positives on responses ending with emoji sign-offs (💛, ✨, 🙌), Markdown links, or conversational text lacking terminal punctuation. Each false positive wasted up to 3 continuation API calls per turn.

Root cause: _has_natural_response_ending() only recognized ASCII and CJK punctuation as natural endings. Any response ending with an emoji, symbol, or bare word was classified as truncated.

Three-pronged fix

1. Expand _has_natural_response_ending() — emoji and symbol recognition

  • Strip trailing Unicode combining marks (variation selectors U+FE0F, ZWJ U+200D) before checking last character
  • Detect unicodedata.category() So (Other_Symbol), Sk (Modifier_Symbol), and Sm (Math_Symbol) as natural endings
  • Check Extended Pictographic heuristic range U+1F000–U+1FAFF
  • Removed dead hardcoded string "✓✔✗✘♠♣♥♦♪♫☀☁☂★☆" — every character was already caught by the So category check (the comment incorrectly claimed they were "outside those ranges")
  • Added Sm category to cover arrows (→ ←) and math symbols (∞ ≈) that commonly end structured responses

2. 500-char minimum-length gate in _should_treat_stop_as_truncated()

  • Responses under 500 visible chars are almost certainly complete — they couldn't have hit a meaningful token limit
  • Retains original 20-char/no-whitespace short-junk detection
  • Eliminates the vast majority of false positives from conversational replies

3. Config opt-out — agent.glm_truncation_heuristic

  • New flag in cli-config.yaml.example, defaults to true (heuristic enabled)
  • Set to false to disable the heuristic entirely
  • Read with getattr(self, "_glm_truncation_heuristic_enabled", True) for backwards compatibility

Refactoring pass (commit 2)

  • Moved import unicodedata from inline in method body to module top-level
  • Added Sm (Math_Symbol) to category check for arrows and math symbols
  • Removed dead hardcoded string (all chars were So, already covered)
  • Renamed misleading test test_emoji_sign_off_with_100_charstest_short_response_with_emoji_does_not_trigger (it tests the 500-char gate, not emoji recognition)
  • Added 8 parametrized tests for Sm/So characters including arrows and codepoints from the removed list

Test plan

  • 65 tests total (57 original + 8 new Sm/So parametrized tests)
  • 2 existing integration tests pass with updated mock content
  • All categories covered: So, Sk, Sm, Extended Pictographic range, variation selectors
  • 500-char gate verified for both short (pass) and long (block) responses
  • Config opt-out verified

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder provider/ollama Ollama / local models area/config Config system, migrations, profiles labels Apr 25, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #14574 — both fix #14572 (emoji sign-off false positives in GLM stop-to-length heuristic). This PR is more comprehensive (adds 500-char min gate + config opt-out) but targets the same root cause in _has_natural_response_ending(). Also overlaps with #15363. Maintainer should pick one.

AJ added 2 commits April 24, 2026 23:56
…sResearch#14572)

Three-pronged fix for the Ollama/GLM stop-to-length heuristic that was
triggering continuation loops on any response not ending with ASCII/CJK
punctuation — including emoji sign-offs (💛, ✨, 🙌), Markdown links, and
conversational text lacking terminal punctuation.

1. Expand _has_natural_response_ending() with emoji recognition:
   - Strip trailing Unicode combining marks (variation selectors, ZWJ)
     before checking the base character.
   - Detect Unicode categories So (Other_Symbol) and Sk (Modifier_Symbol).
   - Check Extended_Pictographic heuristic range U+1F000–U+1FAFF.
   - Hardcode common sign-off codepoints outside those ranges.

2. Add 500-char minimum-length gate in _should_treat_stop_as_truncated():
   - Responses under 500 visible chars are almost certainly complete —
     they couldn't have hit a meaningful token limit.
   - Retains the original 20-char/no-whitespace short-junk detection.
   - Eliminates the vast majority of false positives from conversational
     replies and emoji sign-offs.

3. Config opt-out via agent.glm_truncation_heuristic (default true):
   - Set to false to disable the heuristic entirely.
   - Read with getattr(self, _glm_truncation_heuristic_enabled, True)
     for backwards compatibility.

57 new tests in test_glm_stop_heuristic.py. Updated existing integration
test mock content to >=500 chars so it still triggers the heuristic.
…search#14572)\n\n- Move import unicodedata to module top-level (was inline in method body)\n- Add Sm (Math_Symbol) category to natural-ending recognition for arrows\n  and math symbols that commonly end structured responses\n- Remove dead hardcoded string - every character in it is category So,\n  already caught by the category check. The comment claimed they were\n  outside those ranges but they weren't.\n- Rename test_emoji_sign_off_with_100_chars to\n  test_short_response_with_emoji_does_not_trigger to accurately describe\n  what it tests (the 500-char gate, not emoji recognition).\n- Add 8 parametrized tests for Sm/So characters including arrows, math\n  symbols, and codepoints from the removed hardcoded list.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists provider/ollama Ollama / local models type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Ollama/GLM stop-to-length heuristic false-triggers on responses ending with emoji sign-offs

2 participants