Repository navigation
Description
Summary
The placeholder string [System: Empty message content sanitised to satisfy protocol] is still appearing in conversations. This was previously reported in #17564 and closed as completed, but the issue persists (or has regressed) when using GLM-5.2 via an OpenAI-compatible provider (@ai-sdk/openai-compatible).
Environment
- OpenCode: latest (as of 2026-06-22)
- Provider:
xiaofengche(custom OpenAI-compatible provider,@ai-sdk/openai-compatible)- baseURL:
https://api.svips.org
- baseURL:
- Model:
glm-5.2(GLM-5.2 by Zhipu AI) - Agent mode:
build(primary) - OS: Windows
Root Cause (same as #17564)
As identified in #17564, when the Vercel AI SDK converts ModelMessage[] to the OpenAI wire format, assistant messages that contain only tool calls get content: "" (empty string):
// @ai-sdk/openai-compatible
messages.push({
role: 'assistant',
content: text, // "" when assistant only used tools
tool_calls: toolCalls,
})OpenCode has a guard in packages/opencode/src/provider/transform.ts (normalizeMessages), but per #17564 it was reportedly extended to all providers. However, the placeholder still appears with GLM-5.2.
What happens
GLM-5.2 (via the OpenAI-compatible proxy at api.svips.org) behaves similarly to the LiteLLM case: it replaces empty content fields with the placeholder string [System: Empty message content sanitised to satisfy protocol] before forwarding. This modified message is then stored in conversation history and displayed to the user on every tool-call turn.
This happens because GLM-5.2 tends to emit tool calls without any accompanying text, unlike Claude/GPT which typically output a short explanation before calling tools.
Evidence from logs
OpenCode log file shows the model streaming and the placeholder appearing on every tool-call turn:
INFO service=llm providerID=xiaofengche modelID=glm-5.2 session.id=ses_113992737ffebYGPPQBkNvI4cK small=false agent=build mode=primary stream
And the user-visible output contains [System: Empty message content sanitised to satisfy protocol] repeatedly between tool calls.
Impact
- Visual noise: Users see system placeholder text instead of clean tool-call transitions
- Context pollution: The placeholder text is stored in conversation history and sent back to the model on subsequent turns, wasting context tokens
- User confusion: Users may think the model or framework is malfunctioning
Expected Behavior
Assistant messages with only tool calls should not have empty content sent to the API. The normalizeMessages empty-content filter should apply to all providers unconditionally, as originally proposed in #17564.
Suggested Fix
Per #17564, the fix in packages/opencode/src/provider/transform.ts should ensure the empty content filter runs unconditionally (not gated by provider npm package name):
// Should run for ALL providers, not just @ai-sdk/anthropic / @ai-sdk/amazon-bedrock
msgs = msgs.map(/* filter empty content */).filter(...)And in packages/opencode/src/session/llm.ts, empty system prompt strings should be filtered:
...system.filter((x) => x !== "").map((x): ModelMessage => ({ role: "system", content: x })),Related Issues
- [System: Empty message content sanitised to satisfy protocol] appears in conversation when using LiteLLM/Open WebUI proxy #17564 — Original report, closed as completed (same root cause)
- bug: text content blocks must be non-empty in custom provider #16332 — Empty text content blocks via OpenAI-compatible provider
- text content blocks must be non-empty when using Claude models and tools #24087 — text content blocks must be non-empty when using Claude models and tools
- Empty text parts in assistant message history cause 422 on strict providers #31046 — Empty text parts in assistant message history cause 422 on strict providers
- github-copilot (Claude): 400 "text content blocks must contain non-whitespace text" from whitespace-only assistant message #31259 — github-copilot (Claude): 400 "text content blocks must contain non-whitespace text"
Reproduction
- Configure OpenCode with an OpenAI-compatible provider pointing to a proxy that routes to GLM-5.2 (e.g.
https://api.svips.org) - Ask OpenCode any question that requires tool use (e.g. "list files in the current directory")
- Observe
[System: Empty message content sanitised to satisfy protocol]appearing in the response on every tool-call turn
This affects every tool-call turn because GLM-5.2 emits tool calls without accompanying text.
Activity
github-actions commentedon Aug 21, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.