From a3d9c5183b4f38ca288183595e4b8fd4768809d2 Mon Sep 17 00:00:00 2001 From: enwaiax Date: Sat, 15 Aug 2026 20:21:19 +0800 Subject: [PATCH 1/2] fix(relaykit): preserve assistant text with tool calls --- .../claude_messages/to_oai_chat_req.go | 2 +- .../relayconvert/request_registry_test.go | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/relaykit/relayconvert/internal/claude_messages/to_oai_chat_req.go b/relaykit/relayconvert/internal/claude_messages/to_oai_chat_req.go index 56e6663e1a0..bf6ea337f1b 100644 --- a/relaykit/relayconvert/internal/claude_messages/to_oai_chat_req.go +++ b/relaykit/relayconvert/internal/claude_messages/to_oai_chat_req.go @@ -197,7 +197,7 @@ func ClaudeMessagesRequestToOpenAIChat(claudeRequest dto.ClaudeRequest, info con if len(toolCalls) > 0 { openAIMessage.SetToolCalls(toolCalls) } - if len(mediaMessages) > 0 && len(toolCalls) == 0 { + if len(mediaMessages) > 0 { openAIMessage.SetMediaContent(mediaMessages) } } diff --git a/relaykit/relayconvert/request_registry_test.go b/relaykit/relayconvert/request_registry_test.go index 5649ed09cd0..757aa409339 100644 --- a/relaykit/relayconvert/request_registry_test.go +++ b/relaykit/relayconvert/request_registry_test.go @@ -1,6 +1,7 @@ package relayconvert import ( + "context" "testing" "github.com/QuantumNous/new-api/relaykit/dto" @@ -12,6 +13,48 @@ import ( "github.com/stretchr/testify/require" ) +func TestClaudeMessagesToOpenAIChatPreservesAssistantTextWithToolCalls(t *testing.T) { + text := "I will look that up." + request := dto.ClaudeRequest{ + Model: "claude-test", + Messages: []dto.ClaudeMessage{ + { + Role: "assistant", + Content: []dto.ClaudeMediaMessage{ + {Type: "text", Text: &text}, + { + Type: "tool_use", + Id: "call_1", + Name: "lookup", + Input: map[string]any{"query": "weather"}, + }, + }, + }, + }, + } + + result, err := ConvertRequest( + context.Background(), + &convmeta.Values{}, + types.RelayFormatOpenAI, + &request, + ) + require.NoError(t, err) + + converted, ok := result.Value.(*dto.GeneralOpenAIRequest) + require.True(t, ok) + require.Len(t, converted.Messages, 1) + + assistant := converted.Messages[0] + assert.Equal(t, "assistant", assistant.Role) + toolCalls := assistant.ParseToolCalls() + require.Len(t, toolCalls, 1) + assert.Equal(t, "call_1", toolCalls[0].ID) + require.Len(t, assistant.ParseContent(), 1) + assert.Equal(t, "text", assistant.ParseContent()[0].Type) + assert.Equal(t, text, assistant.ParseContent()[0].Text) +} + func TestRequestConverterRegistryListsSupportedTextConverters(t *testing.T) { tests := []struct { converter string From 013818c57a0531568763c37fd140319d327a97fc Mon Sep 17 00:00:00 2001 From: enwaiax Date: Sat, 15 Aug 2026 20:27:17 +0800 Subject: [PATCH 2/2] test(relaykit): cover tool-only assistant messages --- .../relayconvert/request_registry_test.go | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/relaykit/relayconvert/request_registry_test.go b/relaykit/relayconvert/request_registry_test.go index 757aa409339..187618e9e0e 100644 --- a/relaykit/relayconvert/request_registry_test.go +++ b/relaykit/relayconvert/request_registry_test.go @@ -55,6 +55,43 @@ func TestClaudeMessagesToOpenAIChatPreservesAssistantTextWithToolCalls(t *testin assert.Equal(t, text, assistant.ParseContent()[0].Text) } +func TestClaudeMessagesToOpenAIChatKeepsToolOnlyContentEmpty(t *testing.T) { + request := dto.ClaudeRequest{ + Model: "claude-test", + Messages: []dto.ClaudeMessage{ + { + Role: "assistant", + Content: []dto.ClaudeMediaMessage{ + { + Type: "tool_use", + Id: "call_1", + Name: "lookup", + Input: map[string]any{"query": "weather"}, + }, + }, + }, + }, + } + + result, err := ConvertRequest( + context.Background(), + &convmeta.Values{}, + types.RelayFormatOpenAI, + &request, + ) + require.NoError(t, err) + + converted, ok := result.Value.(*dto.GeneralOpenAIRequest) + require.True(t, ok) + require.Len(t, converted.Messages, 1) + + assistant := converted.Messages[0] + assert.Empty(t, assistant.ParseContent()) + toolCalls := assistant.ParseToolCalls() + require.Len(t, toolCalls, 1) + assert.Equal(t, "call_1", toolCalls[0].ID) +} + func TestRequestConverterRegistryListsSupportedTextConverters(t *testing.T) { tests := []struct { converter string