fix: chat template — null handling, reasoning preservation, turn-tag balance, input validation

#47

Summary

Improves Gemma4 chat template:

Bug fixes

  • None values now render as null instead of Python's None
  • String-typed tool_calls[].function.arguments now raises a clear error instead of silently producing malformed DSL
  • Prior-turn reasoning/thinking is preserved across multi-turn tool-call chains (preserve_thinking flag, default=true)
  • Consecutive assistant messages now produce balanced <|turn>model/<turn|> tags via forward-scan continuation detection

Improvements

  • enable_thinking normalized once with | default(false), eliminating repetitive is defined and checks
  • image_url and input_audio content types now map to <|image|> and <|audio|> (OpenAI compatibility)
  • Empty messages=[] handled gracefully instead of crashing
  • Unmatched tool_call_id in tool responses falls back to 'unknown' instead of crashing
  • Consistent .get() access prevents StrictUndefined errors for optional message keys
  • O(1) backward scan for model-turn continuation (was O(n) per message)

I'm not particularly sure if it helps with Gemma 4 26B looping that happens when it's trying to list things (I'm no engineer), but if it does is implementing https://huggingface.co/google/gemma-4-26B-A4B-it/discussions/48 into this set of improvements possible as well? I tried that template out for a bit and it did seem to get better, even when it did get stuck for a moment it was no longer a complete breakdown. For reference there's some more information about looping on DeepMind GitHub too - https://github.com/google-deepmind/gemma/issues/610

Ready to merge
This branch is ready to get merged automatically.

Sign up or log in to comment