From 4f3b5110e27d388668869565e3f079682925afe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E5=8F=8A?= <522caiji@gmail.com> Date: Mon, 13 Jul 2026 22:40:40 +0800 Subject: [PATCH] fix: parallel tool_use ghost content_block_delta (index error) resToAnthHandleFuncArgsDone used state.ContentBlockIndex directly instead of looking up from OutputIndexToBlockIdx like resToAnthHandleFuncArgsDelta does. When multiple tool_calls arrive in parallel and arguments come as a packed .done (no prior delta), the second+ tool would emit content_block_delta on an index that was never content_block_start'ed, causing Claude Code to report "Content block not found". Fix: resolve block index from OutputIndexToBlockIdx, and skip the delta if the block is already closed or the index doesn't match the current open block. Closes #4193 --- .../pkg/apicompat/responses_to_anthropic.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/backend/internal/pkg/apicompat/responses_to_anthropic.go b/backend/internal/pkg/apicompat/responses_to_anthropic.go index 376f0d97da..2863fe7302 100644 --- a/backend/internal/pkg/apicompat/responses_to_anthropic.go +++ b/backend/internal/pkg/apicompat/responses_to_anthropic.go @@ -452,10 +452,20 @@ func resToAnthHandleFuncArgsDone(evt *ResponsesStreamEvent, state *ResponsesEven raw = string(sanitized) } - idx := state.ContentBlockIndex + // 从事件的 OutputIndex 解析正确的 block index,与 resToAnthHandleFuncArgsDelta 对齐 + blockIdx, ok := state.OutputIndexToBlockIdx[evt.OutputIndex] + if !ok { + blockIdx = state.ContentBlockIndex + } + + // 如果 block 已关闭(ContentBlockIndex 已越过它),说明 arguments 已通过 delta 流式发完,不再补发 + if !state.ContentBlockOpen || blockIdx != state.ContentBlockIndex { + return nil + } + events := []AnthropicStreamEvent{{ Type: "content_block_delta", - Index: &idx, + Index: &blockIdx, Delta: &AnthropicDelta{ Type: "input_json_delta", PartialJSON: raw,