Repository navigation
fix(glm45): emit the newline before every tool call after assistant text - #203
Merged
hallerite merged 1 commit intoOct 28, 2026
Conversation
The GLM-4.5 chat template opens every tool call with "\n<tool_call>", but when an assistant turn had text and two or more calls the renderer only emitted that newline before the first call. I emit it before each later call too and add a parity scenario with text plus two tool calls. Assisted-by: Claude Assisted-by: GPT-6 Astra Signed-off-by: mottopanikeiku <176798723+mottopanikeiku@users.noreply.github.com>
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.
GLM45Rendererdrops the newline before the second and later tool calls when an assistant turn has text and more than one tool call. The GLM-4.5 / GLM-4.5-Air chat template opens every call with a newline (chat_template.jinja#L68-L79):The renderer appends one
\nto the text, so the first call keeps its BPE merge. It then emits the per-call\nonly when the text is empty, so the later calls come out as</tool_call><tool_call>. Turns with empty text, or with a single call, were already correct. That is why the existingtool-call-contentandmultiple-tool-callscells pass.This change emits the
\nbefore every call after the first. A newmultiple-tool-calls-contentparity scenario (text plus two calls) runs for every catalog model. Llama 3.2 and DeepSeek V3/R1 exclude it next tomultiple-tool-calls, for the same reasons they exclude that cell.Reproducer:
...</tool_call><tool_call>get_weather...bash/str_replace_editorcalls, then tool results, an edit, a final answer and a new user turn. Rendered withGLM45RendererConfig(thinking_retention="all")as in prime-rl'sexamples/advanced/glm-4.5-air/swe.toml(template: 624 tokens)parse_responseand re-rendered withrender(), compared withbridge_to_next_turnon the same tokensPrimeIntellect/INTELLECT-3-SFT-10K,toolsplit: 39 of 10,000 rows contain such a turnpytest tests/test_parity.py -k multiple-tool-calls-contentprime-rl's SFT tokenization uses full
render(). verifiers' train client also falls back to it whenever a turn is not bridged, for example at each new user turn under the defaulttool_cyclepolicy. On those paths these turns did not match the chat template. For a turn sampled in the template's format, they also did not match the sampled tokens.After the change,
pytest tests -k "GLM-4.5 or glm45 or glm-4.5"gives 189 passed, 3 skipped. ruff 0.15.12 check and format pass, and ty reports the same 65 existing diagnostics as on main.I found this by reading and testing the code.
I made this PR and directed its development, with AI assistance from Claude and GPT-6 Astra.
Note
Fix
GLM45Renderertool-call newline after assistant contentmultiple-tool-calls-contentparity scenario in tests/parity.py and excludes it for the listed DeepSeek and Llama 3.2 Instruct models, which already exclude the related tool-call scenarios.Macroscope summarized f02ccd4.