#9674·pi

mistral-conversations: empty content deltas open text blocks (GLM 5.x trailing whitespace)

Author: kedfCreated Sep 16, 2026Updated Sep 17, 2026
Labelsbug

What happened?

Follow-up to #8069, closed as not_planned. The workarounds there route GLM 5.2 through openai-completions, which loses the native Mistral prompt cache. This is the fix on the mistral-conversations side.

Zero-length content: "" deltas open empty text blocks. Every zai-glm variant currently served by the API (zai-glm-5, zai-glm-5-2, zai-glm-5-3, zai-glm-latest) sends them with every tool_calls chunk and the final finish_reason. Each one becomes a text block, which shows up as trailing whitespace after the thinking block. With a long tool call (~80 argument chunks) a single assistant message accumulated ~80 empty text blocks.

GLM 5.3 can also send a non-empty content string in the same delta as the first tool_calls fragment:

data: {"choices":[{"index":0,"delta":{"tool_calls":[...],"index":0,"content":" that time."},"finish_reason":null}]}

I have a tested patch for this on 0.85.1.

Steps to reproduce

Reproduced on a plain pi -ne config, no extensions loaded.

Stream a tool call from zai-glm-5-2, or any other served zai-glm variant (needs a Mistral API key; the SSE excerpt below is enough to see the issue without one):

curl -sS https://api.mistral.ai/v1/chat/completions \
  -H "Authorization: Bearer $MISTRAL_API_KEY" -H "Content-Type: application/json" -d '{
    "model":"zai-glm-5-2","stream":true,"reasoning_effort":"high",
    "messages":[{"role":"system","content":"Use the get_weather tool when asked about weather."},
                {"role":"user","content":"What is the weather in Paris? Use the get_weather tool."}],
    "tools":[{"type":"function","function":{"name":"get_weather",
      "description":"Get current weather for a city.",
      "parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]
  }'

Every tool_calls chunk carries "content":"". pi-ai opens an empty text block for each. SSE excerpt (thinking block, then the first tool_calls chunk with its empty content):

data: {"choices":[{"index":0,"delta":{"index":0,"content":[{"type":"thinking","thinking":[{"type":"text","text":" the get_weather tool."}],"closed":true}]}}]}
data: {"choices":[{"index":0,"delta":{"tool_calls":[{"id":"chatcmpl-tool-...","type":"function","function":{"name":"get_weather","arguments":""},"index":0}],"index":0,"content":""}}]}
data: {"choices":[{"index":0,"delta":{"index":0,"content":""},"finish_reason":"tool_calls"}]}

Expected behavior

Zero-length content deltas do not produce text blocks, so there is no trailing whitespace after the thinking block.

Version

0.85.1