fix(relaykit): preserve parameterless tools in Claude conversion (#6862)
This commit is contained in:
@@ -32,25 +32,14 @@ func OpenAIChatRequestToClaudeMessages(c context.Context, info convmeta.Meta, te
|
||||
claudeTools := make([]any, 0, len(textRequest.Tools))
|
||||
|
||||
for _, tool := range textRequest.Tools {
|
||||
if params, ok := tool.Function.Parameters.(map[string]any); ok {
|
||||
claudeTool := dto.Tool{
|
||||
Name: tool.Function.Name,
|
||||
Description: tool.Function.Description,
|
||||
}
|
||||
claudeTool.InputSchema = make(map[string]interface{})
|
||||
if params["type"] != nil {
|
||||
claudeTool.InputSchema["type"] = params["type"].(string)
|
||||
}
|
||||
claudeTool.InputSchema["properties"] = params["properties"]
|
||||
claudeTool.InputSchema["required"] = params["required"]
|
||||
for key, value := range params {
|
||||
if key == "type" || key == "properties" || key == "required" {
|
||||
continue
|
||||
}
|
||||
claudeTool.InputSchema[key] = value
|
||||
}
|
||||
claudeTools = append(claudeTools, &claudeTool)
|
||||
if _, ok := tool.Function.Parameters.(map[string]any); !ok && tool.Type != "function" {
|
||||
continue
|
||||
}
|
||||
claudeTools = append(claudeTools, &dto.Tool{
|
||||
Name: tool.Function.Name,
|
||||
Description: tool.Function.Description,
|
||||
InputSchema: sharedclaude.FunctionParametersToInputSchema(tool.Function.Parameters),
|
||||
})
|
||||
}
|
||||
|
||||
if textRequest.WebSearchOptions != nil {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package oaichat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/QuantumNous/new-api/relaykit/dto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOpenAIChatRequestToClaudeMessagesNormalizesToolInputSchema(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
parameters any
|
||||
wantSchema map[string]any
|
||||
}{
|
||||
{
|
||||
name: "omitted parameters",
|
||||
parameters: nil,
|
||||
wantSchema: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing type and properties",
|
||||
parameters: map[string]any{
|
||||
"additionalProperties": false,
|
||||
},
|
||||
wantSchema: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{},
|
||||
"additionalProperties": false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non-string type",
|
||||
parameters: map[string]any{
|
||||
"type": 123,
|
||||
"properties": map[string]any{},
|
||||
},
|
||||
wantSchema: map[string]any{
|
||||
"type": 123,
|
||||
"properties": map[string]any{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
maxTokens := uint(1024)
|
||||
got, err := OpenAIChatRequestToClaudeMessages(context.Background(), nil, dto.GeneralOpenAIRequest{
|
||||
Model: "claude-test",
|
||||
MaxTokens: &maxTokens,
|
||||
Messages: []dto.Message{
|
||||
{Role: "user", Content: "Call the tool."},
|
||||
},
|
||||
Tools: []dto.ToolCallRequest{
|
||||
{
|
||||
Type: "function",
|
||||
Function: dto.FunctionRequest{
|
||||
Name: "get_current_time",
|
||||
Description: "Get the current time",
|
||||
Parameters: tt.parameters,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
tools, ok := got.Tools.([]any)
|
||||
require.True(t, ok)
|
||||
require.Len(t, tools, 1)
|
||||
tool, ok := tools[0].(*dto.Tool)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "get_current_time", tool.Name)
|
||||
assert.Equal(t, tt.wantSchema, tool.InputSchema)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -134,32 +134,12 @@ func responsesFunctionDeclarationsToClaudeTools(functions []dto.FunctionRequest)
|
||||
tools = append(tools, &dto.Tool{
|
||||
Name: function.Name,
|
||||
Description: function.Description,
|
||||
InputSchema: responsesFunctionParametersToClaudeInputSchema(function.Parameters),
|
||||
InputSchema: sharedclaude.FunctionParametersToInputSchema(function.Parameters),
|
||||
})
|
||||
}
|
||||
return tools
|
||||
}
|
||||
|
||||
func responsesFunctionParametersToClaudeInputSchema(parameters any) map[string]interface{} {
|
||||
if params, ok := parameters.(map[string]any); ok {
|
||||
schema := make(map[string]interface{}, len(params))
|
||||
for key, value := range params {
|
||||
schema[key] = value
|
||||
}
|
||||
if schema["type"] == nil {
|
||||
schema["type"] = "object"
|
||||
}
|
||||
if schema["properties"] == nil {
|
||||
schema["properties"] = map[string]interface{}{}
|
||||
}
|
||||
return schema
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
func applyResponsesReasoningToClaude(req *dto.OpenAIResponsesRequest, claudeRequest *dto.ClaudeRequest) {
|
||||
effort := ReasoningEffort(req)
|
||||
switch effort {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package claude
|
||||
|
||||
func FunctionParametersToInputSchema(parameters any) map[string]any {
|
||||
params, _ := parameters.(map[string]any)
|
||||
schema := make(map[string]any, len(params)+2)
|
||||
for key, value := range params {
|
||||
schema[key] = value
|
||||
}
|
||||
if schema["type"] == nil {
|
||||
schema["type"] = "object"
|
||||
}
|
||||
if schema["properties"] == nil {
|
||||
schema["properties"] = map[string]any{}
|
||||
}
|
||||
return schema
|
||||
}
|
||||
Reference in New Issue
Block a user