fix: guard against tools=None crash and string arguments in chat_template.jinja

#22

Problem

Two crashes can occur in chat_template.jinja when used with sglang or any OpenAI-compatible server:

1. TypeError: 'NoneType' object is not iterable

When a role="tool" message has non-string content (structured list), the template enters the else branch and executes for tool in tools — but tools is None when no tools were passed in the request. The top-level {%- if tools -%} guard at the top of the file does not cover this inner loop.

Reproduces when replaying a tool-calling conversation history without re-passing the tools array, or when any client omits tools from the request.

Related upstream issue: sgl-project/sglang#6702

2. AttributeError: 'str' object has no attribute 'items'

In the tool_calls rendering block, tc.arguments is iterated with .items() assuming it is a dict. Several OpenAI-compatible clients and model outputs serialize arguments as a JSON string, causing a crash on this line.

Fix

  • Wrap the inner for tool in tools loop inside the role="tool" branch with {%- if tools -%} ... {%- endif -%}
  • Deserialize tc.arguments if it is a string before calling .items():
    {%- set _args = tc.arguments if tc.arguments is mapping else tc.arguments | from_json -%}
    

Testing

  • Plain chat request with no tools key: no regression
  • Tool-calling request with tools array: no regression
  • Replayed tool-use history without tools in request: no longer crashes
  • tc.arguments as JSON string: no longer crashes
Ready to merge
This branch is ready to get merged automatically.

Sign up or log in to comment