fix: retry on "thinking block must contain thinking" upstream error

Some clients reuse assistant history from other models when switching to
claude with extended thinking enabled. If a prior thinking block lacks the
thinking text field, upstream returns:
  messages.X.content.Y.thinking: each thinking block must contain thinking

Add this pattern to isThinkingBlockSignatureError so the existing
FilterThinkingBlocksForRetry retry path triggers and rewrites/drops the
offending blocks.
This commit is contained in:
name 2026-05-20 18:46:50 +08:00
parent 771e0ca973
commit 8211aa7066
2 changed files with 40 additions and 0 deletions

View File

@ -379,6 +379,37 @@ func TestFilterThinkingBlocksForRetry_RemovesRedactedThinkingAndKeepsValidConten
require.Equal(t, "Visible", content0["text"])
}
func TestFilterThinkingBlocksForRetry_DropsThinkingBlockWithEmptyContent(t *testing.T) {
// 跨模型场景:其他模型回过的 assistant 历史里携带了 type=thinking 但 thinking 字段为空,
// 喂给开启 extended thinking 的 claude 时上游会报:
// "messages.1.content.0.thinking: each thinking block must contain thinking"
// 重试应当把空 thinking 块丢弃,并保留其它有效内容。
input := []byte(`{
"thinking":{"type":"enabled","budget_tokens":1024},
"messages":[
{"role":"user","content":[{"type":"text","text":"Hi"}]},
{"role":"assistant","content":[
{"type":"thinking","thinking":"","signature":"sig"},
{"type":"text","text":"Answer"}
]}
]
}`)
out := FilterThinkingBlocksForRetry(input)
var req map[string]any
require.NoError(t, json.Unmarshal(out, &req))
_, hasThinking := req["thinking"]
require.False(t, hasThinking, "top-level thinking should be removed")
msgs := req["messages"].([]any)
assistant := msgs[1].(map[string]any)
content := assistant["content"].([]any)
require.Len(t, content, 1, "empty thinking block should be dropped, only text remains")
require.Equal(t, "text", content[0].(map[string]any)["type"])
require.Equal(t, "Answer", content[0].(map[string]any)["text"])
}
func TestFilterThinkingBlocksForRetry_EmptyContentGetsPlaceholder(t *testing.T) {
input := []byte(`{
"thinking":{"type":"enabled"},

View File

@ -6765,6 +6765,15 @@ func (s *GatewayService) isThinkingBlockSignatureError(respBody []byte) bool {
return true
}
// 检测 thinking block 缺少 thinking 字段的错误(跨模型切换时常见:
// 其他模型回过的 assistant 历史里有 type=thinking 但没有 thinking 文本,
// 喂给开启 extended thinking 的 claude 时会被拒)
// 例如: "messages.1.content.0.thinking: each thinking block must contain thinking"
if strings.Contains(msg, "thinking block must contain") {
logger.LegacyPrintf("service.gateway", "[SignatureCheck] Detected thinking block missing content error")
return true
}
return false
}