[Bug]: MiniCPM5 chat template may lose text after <tool_sep> due to loop-local assignments
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 62/100
Research direction
Start by rendering the referenced chat_template.jinja with the provided Jinja2 reproduction and inspect lines 84, 86, 112, 116, and 127. Verify how loop-local assignments affect processed_content and has_tool_sep. Done means both BEFORE and AFTER survive around one emitted tool XML block, with the intended behavior confirmed.
Written by the indexing model from the issue text.
Description
Is there an existing issue?
- I searched existing issues for
tool_sep,processed_content,chat_template, andjinjaand did not find this problem reported.
Describe the bug
MiniCPM5-2B's chat template appears to use loop-local set assignments to accumulate processed_content for use after the loops. Jinja2 does not propagate these assignments to the enclosing scope.
With assistant content BEFORE<tool_sep>AFTER and one tool call, the rendered prompt loses AFTER. The tool XML is emitted once by the later direct-output branch.
Template: openbmb/MiniCPM5-2B/chat_template.jinja, revision a063f08de1bd09dfc9ae4cf3da35e6064949e533.
To reproduce
Download the unchanged template as chat_template.jinja, then run this script in the same directory. It only requires Jinja2; no model weights or inference are involved.
from pathlib import Path
from jinja2 import Environment
template = Environment(trim_blocks=True, lstrip_blocks=True).from_string(
Path("chat_template.jinja").read_text(encoding="utf-8")
)
for content in ["BEFORE", "BEFORE<tool_sep>AFTER"]:
output = template.render(
bos_token="",
tools=[],
messages=[
{"role": "user", "content": "Question"},
{
"role": "assistant",
"content": content,
"tool_calls": [
{
"function": {
"name": "lookup",
"arguments": {"q": "weather"},
}
}
],
},
],
add_generation_prompt=False,
)
print("Input:", content)
print("Contains AFTER:", "AFTER" in output)
print("Tool XML count:", output.count('<function name="'))
print(repr(output))
Observed output:
Input: BEFORE
Contains AFTER: False
Tool XML count: 1
'<|im_start|>user\nQuestion<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\nBEFORE\n<function name="lookup"><param name="q">weather</param></function><|im_end|>\n'
Input: BEFORE<tool_sep>AFTER
Contains AFTER: False
Tool XML count: 1
'<|im_start|>user\nQuestion<|im_end|>\n<|im_start|>assistant\n<think>\n\n</think>\n\nBEFORE\n<function name="lookup"><param name="q">weather</param></function><|im_end|>\n'
Expected behavior
Assuming <tool_sep> marks an in-place tool-call position, I would expect both surrounding text segments to survive, with the tool XML inserted between BEFORE and AFTER. Could you confirm whether this is the intended behavior?
Environment
- Python 3.12.2
- Jinja2 3.1.3
- Direct rendering of the unchanged template with
Environment(trim_blocks=True, lstrip_blocks=True)
Additional context
The assignments at template lines 84, 86, and 112 are inside nested loops. When line 116 reads processed_content, its enclosing value remains content_parts[0]. Jinja documents this assignment-scoping behavior and the use of namespace objects for cross-scope state.
The final tool-output condition at line 127 also reads has_tool_sep, which is not defined anywhere in this template or supplied by this reproducer. The condition is therefore true for the tool-calling messages above. If accumulation is changed to persist across loops, that final output condition should be reviewed together with it so that each tool call is emitted once.
- Dominant language
- Jupyter Notebook
- Stars
- 11.3k
- Forks
- 778
- Avg merge
- 5h 3m
- Merged PRs (30d)
- 6
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from OpenBMB/MiniCPM
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
-
Difficulty 5/5 Over a week Newbie friendliness 15/100
-
Difficulty 3/5 1-2 days Newbie friendliness 55/100
-
feature
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
cloudflare/agents#2498 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
e2b-dev/e2b-cookbook#145 ·
Maintainers usually reply within 1 day
-
external-plugin ready-for-review
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
github/awesome-copilot#4529 · 1 comment ·
Maintainers usually reply within 1 day
-
Vision tools don't tell the model their options, and an unknown focus is silently treated as 'all'Openbug p3
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
selective-claw: freshTailTurns=0 keeps ALL turns verbatim and summarizes none (slice(-0) === slice(0))Possibly taken @zjncs claimed this today. Opencomponent:tokenless
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
agentic-os-org/ANOLISA#6112 · 1 comment ·
Maintainers usually reply within 1 day