From c3a425837cb5f0d8131c8cd779b0eefebfd8a4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= <2829624376@qq.com> Date: Wed, 15 Jul 2026 14:05:26 +0800 Subject: [PATCH] fix(apicompat): scope additional tools parsing --- .../chatcompletions_responses_bridge.go | 14 ++++++++--- ...ions_responses_bridge_custom_tools_test.go | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/backend/internal/pkg/apicompat/chatcompletions_responses_bridge.go b/backend/internal/pkg/apicompat/chatcompletions_responses_bridge.go index 8aa9eab60ab..0d2de969ddf 100644 --- a/backend/internal/pkg/apicompat/chatcompletions_responses_bridge.go +++ b/backend/internal/pkg/apicompat/chatcompletions_responses_bridge.go @@ -91,16 +91,22 @@ func EffectiveResponsesTools(req *ResponsesRequest) ([]ResponsesTool, error) { if len(raw) == 0 || raw[0] != '{' { continue } + var discriminator struct { + Type string `json:"type"` + } + if err := json.Unmarshal(raw, &discriminator); err != nil { + return nil, fmt.Errorf("parse responses additional tools item: %w", err) + } + if discriminator.Type != "additional_tools" { + continue + } var item struct { - Type string `json:"type"` Tools []ResponsesTool `json:"tools"` } if err := json.Unmarshal(raw, &item); err != nil { return nil, fmt.Errorf("parse responses additional tools item: %w", err) } - if item.Type == "additional_tools" { - tools = append(tools, item.Tools...) - } + tools = append(tools, item.Tools...) } return tools, nil } diff --git a/backend/internal/pkg/apicompat/chatcompletions_responses_bridge_custom_tools_test.go b/backend/internal/pkg/apicompat/chatcompletions_responses_bridge_custom_tools_test.go index 5b1d994eb31..6265a64d0a5 100644 --- a/backend/internal/pkg/apicompat/chatcompletions_responses_bridge_custom_tools_test.go +++ b/backend/internal/pkg/apicompat/chatcompletions_responses_bridge_custom_tools_test.go @@ -79,6 +79,31 @@ func TestEffectiveResponsesTools_SkipsStringInputItems(t *testing.T) { assert.Equal(t, "exec", tools[0].Name) } +func TestEffectiveResponsesTools_IgnoresMalformedToolsOnNonAdditionalItem(t *testing.T) { + req := &ResponsesRequest{ + Input: json.RawMessage(`[ + {"type":"message","role":"user","tools":"not-an-array","content":[{"type":"input_text","text":"hello"}]}, + {"type":"additional_tools","tools":[{"type":"custom","name":"exec"}]} + ]`), + } + + tools, err := EffectiveResponsesTools(req) + require.NoError(t, err) + require.Len(t, tools, 1) + assert.Equal(t, "exec", tools[0].Name) +} + +func TestEffectiveResponsesTools_RejectsMalformedAdditionalTools(t *testing.T) { + req := &ResponsesRequest{ + Input: json.RawMessage(`[{"type":"additional_tools","tools":"not-an-array"}]`), + } + + tools, err := EffectiveResponsesTools(req) + require.Error(t, err) + assert.Contains(t, err.Error(), "parse responses additional tools item") + assert.Empty(t, tools) +} + func TestResponsesToChatCompletionsRequest_DropsToolChoiceWhenNoConvertibleTools(t *testing.T) { req := &ResponsesRequest{ Model: "glm-5.2",