renderers/qwen: tolerate non-leading system messages (#17757)

Coding clients may insert runtime system messages after the initial user turn. The shared Qwen renderer rejected these transcripts before rendering, turning a potentially usable non-standard request into an HTTP 500.

Pass non-leading system turns through the existing raw ChatML path and warn when qwen3.8 encounters one. Extend the Anthropic tool-route integration scenario to cover this message pattern and remove the obsolete rejection test.
This commit is contained in:
Daniel Hiltgen
2026-08-14 14:12:50 -07:00
committed by GitHub
parent f427fa0753
commit 87abaa019e
3 changed files with 4 additions and 18 deletions
+1
View File
@@ -265,6 +265,7 @@ func runAnthropicToolRoute(t *testing.T, ctx context.Context, endpoint, model st
},
"messages": []any{
map[string]any{"role": "user", "content": []any{map[string]any{"type": "text", "text": "Call get_weather for Paris."}}},
map[string]any{"role": "system", "content": []any{map[string]any{"type": "text", "text": "Runtime token budget update."}}},
map[string]any{"role": "assistant", "content": []any{map[string]any{
"type": "tool_use",
"id": toolRoutePreviousID,
+3 -10
View File
@@ -193,16 +193,6 @@ func (r *Qwen35Renderer) validateMessages(messages []api.Message) error {
return fmt.Errorf("no user query found in messages")
}
for i, message := range messages {
switch message.Role {
case "system":
if i != 0 {
return fmt.Errorf("system message must be at the beginning")
}
case "user", "assistant", "tool":
}
}
return nil
}
@@ -297,6 +287,9 @@ func (r *Qwen35Renderer) Render(messages []api.Message, tools []api.Tool, think
prefill := lastMessage && message.Role == "assistant"
if message.Role == "user" || (message.Role == "system" && i != 0) {
if r.variant == qwen35Renderer38 && message.Role == "system" {
slog.Warn("non-leading system message", "renderer", "qwen3.8")
}
sb.WriteString(imStartTag + message.Role + "\n" + content + imEndTag + "\n")
} else if message.Role == "assistant" {
renderAssistantThinkBlock := r.alwaysRenderAssistantThinkBlock || (isThinking && i > lastQueryIndex)
-8
View File
@@ -364,14 +364,6 @@ func TestQwen38RendererRejectsInvalidTranscripts(t *testing.T) {
messages: []api.Message{{Role: "system", Content: "Hello"}},
wantErr: "no user query found in messages",
},
{
name: "late system",
messages: []api.Message{
{Role: "user", Content: "Hello"},
{Role: "system", Content: "Late"},
},
wantErr: "system message must be at the beginning",
},
{
name: "system image",
messages: []api.Message{