On an MTP GGUF model, speculative decoding on a quantized target surfaces
byte-fallback garbage as U+FFFD plus an orphaned tool-call close tag whose opener
was drained or mangled, which leaked into chat (issue #7084).
Centralize the scrub at the tool-call chokepoints instead of scattering it
per delta:
- strip_tool_markup now sanitizes control chars / U+FFFD and removes a trailing
orphan-close run, gated by a </tool_call> style sentinel so code/XML literals
survive. Kimi and DeepSeek end-of-turn closers join the sentinel set.
- The two streaming-strip entries (safetensors strip_tool_markup_streaming and
the GGUF _strip_tool_markup_streaming) sanitize at the top and drop trailing
orphan closes on the final segment, so live display matches the finalized
answer.
- ToolLoopController.record_result scrubs a tool result before it reaches the
model or the tool card.
Drops the scattered per-delta content, tool-args, and reasoning-channel scrubs
and the secondary live-stream scrub, which are now covered by the chokepoints
above.