Skip to content

Commit 0344926

Browse files
aabchooyuzisun
authored andcommitted
translator: add marshal/unmarshal for tool choice (envoyproxy#1297)
**Description** Previously, `openAIReq.ToolChoice` would be understood as type `map[string]interface{}` in this code block [1] when given body field `"tool_choice":{"function":{"name":"qa_theme_extractor"},"type":"function"}}`. Adding specific marshaling/unmarshaling logic to fix this issue. Wanted to use openai-go but there is an issue with the tool choice unmarshal [2]. Issue was not caught because tests sent were written in the proper type. Adding a test that replicates the issue by having the code marshal the tool choice. 1. https://github.com/envoyproxy/ai-gateway/compare/aaron/tool-choice-union-type?expand=1#diff-6da52452dbe8387dcea4abc098618db9120d7d8b3071bf502d60530912158737L144-L178 2. openai/openai-go#520 --------- Signed-off-by: Aaron Choo <[email protected]> Co-authored-by: Dan Sun <[email protected]> Signed-off-by: Hrushikesh Patil <[email protected]>
1 parent 309ef40 commit 0344926

File tree

10 files changed

+171
-61
lines changed

10 files changed

+171
-61
lines changed

internal/apischema/openai/openai.go

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ type ChatCompletionRequest struct {
943943
// Specifying a particular tool via `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool.
944944
// `none` is the default when no tools are present. `auto` is the default if tools are present.
945945
// Docs: https://platform.openai.com/docs/api-reference/chat/create#chat-create-tool_choice
946-
ToolChoice ChatCompletionToolChoice `json:"tool_choice,omitempty"` //nolint:tagliatelle //follow openai api
946+
ToolChoice *ChatCompletionToolChoiceUnion `json:"tool_choice,omitempty"` //nolint:tagliatelle //follow openai api
947947

948948
// ParallelToolCalls enables multiple tools to be returned by the model.
949949
// Docs: https://platform.openai.com/docs/guides/function-calling/parallel-function-calling
@@ -994,17 +994,6 @@ type Tool struct {
994994
Function *FunctionDefinition `json:"function,omitempty"`
995995
}
996996

997-
// ToolChoice represents the choice of tool.
998-
type ToolChoice struct {
999-
Type ToolType `json:"type"`
1000-
Function ToolFunction `json:"function,omitempty"`
1001-
}
1002-
1003-
// ToolFunction represents the function to call.
1004-
type ToolFunction struct {
1005-
Name string `json:"name"`
1006-
}
1007-
1008997
// ToolChoiceType represents the type of tool choice.
1009998
type ToolChoiceType string
1010999

@@ -1019,14 +1008,38 @@ const (
10191008
ToolChoiceTypeFunction ToolChoiceType = "function"
10201009
)
10211010

1022-
// ChatCompletionToolChoice represents the tool choice for chat completions.
1011+
// ChatCompletionToolChoiceUnion represents the tool choice for chat completions.
10231012
// It can be either a string (none, auto, required) or a ChatCompletionNamedToolChoice object.
1024-
type ChatCompletionToolChoice any
1013+
type ChatCompletionToolChoiceUnion struct {
1014+
Value any
1015+
}
1016+
1017+
func (c ChatCompletionToolChoiceUnion) MarshalJSON() ([]byte, error) {
1018+
return json.Marshal(c.Value)
1019+
}
1020+
1021+
func (c *ChatCompletionToolChoiceUnion) UnmarshalJSON(data []byte) error {
1022+
// Try to unmarshal as string.
1023+
var str string
1024+
if err := json.Unmarshal(data, &str); err == nil {
1025+
c.Value = str
1026+
return nil
1027+
}
1028+
1029+
// Try to unmarshal as ChatCompletionNamedToolChoice.
1030+
var namedChoice ChatCompletionNamedToolChoice
1031+
if err := json.Unmarshal(data, &namedChoice); err == nil {
1032+
c.Value = namedChoice
1033+
return nil
1034+
}
1035+
1036+
return errors.New("tool choice must be either string or ChatCompletionNamedToolChoice")
1037+
}
10251038

10261039
// ChatCompletionNamedToolChoice specifies a tool the model should use. Use to force the model to call a specific function.
10271040
type ChatCompletionNamedToolChoice struct {
10281041
// Type is the type of the tool. Currently, only `function` is supported.
1029-
Type ToolChoiceType `json:"type"`
1042+
Type ToolType `json:"type"`
10301043
// Function specifies the function to call.
10311044
Function ChatCompletionNamedToolChoiceFunction `json:"function"`
10321045
}

internal/apischema/openai/openai_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,3 +2198,51 @@ func TestUsage(t *testing.T) {
21982198
})
21992199
}
22002200
}
2201+
2202+
func TestChatCompletionNamedToolChoice_MarshalUnmarshal(t *testing.T) {
2203+
original := ChatCompletionNamedToolChoice{
2204+
Type: ToolTypeFunction,
2205+
Function: ChatCompletionNamedToolChoiceFunction{
2206+
Name: "my_func",
2207+
},
2208+
}
2209+
data, err := json.Marshal(original)
2210+
require.NoError(t, err)
2211+
2212+
var unmarshaled ChatCompletionNamedToolChoice
2213+
err = json.Unmarshal(data, &unmarshaled)
2214+
require.NoError(t, err)
2215+
2216+
require.Equal(t, original, unmarshaled)
2217+
require.Equal(t, "my_func", unmarshaled.Function.Name)
2218+
}
2219+
2220+
func TestChatCompletionToolChoiceUnion_MarshalUnmarshal(t *testing.T) {
2221+
// Test with string value
2222+
unionStr := ChatCompletionToolChoiceUnion{Value: "auto"}
2223+
dataStr, err := json.Marshal(unionStr)
2224+
require.NoError(t, err)
2225+
2226+
var unmarshaledStr ChatCompletionToolChoiceUnion
2227+
err = json.Unmarshal(dataStr, &unmarshaledStr)
2228+
require.NoError(t, err)
2229+
require.Equal(t, "auto", unmarshaledStr.Value)
2230+
2231+
// Test with ChatCompletionNamedToolChoice value
2232+
unionObj := ChatCompletionToolChoiceUnion{Value: ChatCompletionNamedToolChoice{
2233+
Type: ToolTypeFunction,
2234+
Function: ChatCompletionNamedToolChoiceFunction{Name: "my_func"},
2235+
}}
2236+
dataObj, err := json.Marshal(unionObj)
2237+
require.NoError(t, err)
2238+
2239+
var unmarshaledObj ChatCompletionToolChoiceUnion
2240+
err = json.Unmarshal(dataObj, &unmarshaledObj)
2241+
require.NoError(t, err)
2242+
2243+
// Type assertion for struct value
2244+
namedChoice, ok := unmarshaledObj.Value.(ChatCompletionNamedToolChoice)
2245+
require.True(t, ok)
2246+
require.Equal(t, unionObj.Value, namedChoice)
2247+
require.Equal(t, "my_func", namedChoice.Function.Name)
2248+
}

internal/extproc/translator/gemini_helper.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,11 @@ func openAIToolsToGeminiTools(openaiTools []openai.Tool) ([]genai.Tool, error) {
352352
// ]
353353
// }
354354
// }
355-
func openAIToolChoiceToGeminiToolConfig(toolChoice any) (*genai.ToolConfig, error) {
355+
func openAIToolChoiceToGeminiToolConfig(toolChoice *openai.ChatCompletionToolChoiceUnion) (*genai.ToolConfig, error) {
356356
if toolChoice == nil {
357357
return nil, nil
358358
}
359-
switch tc := toolChoice.(type) {
359+
switch tc := toolChoice.Value.(type) {
360360
case string:
361361
switch tc {
362362
case "auto":
@@ -368,7 +368,7 @@ func openAIToolChoiceToGeminiToolConfig(toolChoice any) (*genai.ToolConfig, erro
368368
default:
369369
return nil, fmt.Errorf("unsupported tool choice: '%s'", tc)
370370
}
371-
case openai.ToolChoice:
371+
case openai.ChatCompletionNamedToolChoice:
372372
return &genai.ToolConfig{
373373
FunctionCallingConfig: &genai.FunctionCallingConfig{
374374
Mode: genai.FunctionCallingConfigModeAny,

internal/extproc/translator/gemini_helper_test.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -994,30 +994,32 @@ func TestOpenAIToolsToGeminiTools(t *testing.T) {
994994
func TestOpenAIToolChoiceToGeminiToolConfig(t *testing.T) {
995995
tests := []struct {
996996
name string
997-
input any
997+
input *openai.ChatCompletionToolChoiceUnion
998998
expected *genai.ToolConfig
999999
expectErr string
10001000
}{
10011001
{
10021002
name: "string auto",
1003-
input: "auto",
1003+
input: &openai.ChatCompletionToolChoiceUnion{Value: "auto"},
10041004
expected: &genai.ToolConfig{FunctionCallingConfig: &genai.FunctionCallingConfig{Mode: genai.FunctionCallingConfigModeAuto}},
10051005
},
10061006
{
10071007
name: "string none",
1008-
input: "none",
1008+
input: &openai.ChatCompletionToolChoiceUnion{Value: "none"},
10091009
expected: &genai.ToolConfig{FunctionCallingConfig: &genai.FunctionCallingConfig{Mode: genai.FunctionCallingConfigModeNone}},
10101010
},
10111011
{
10121012
name: "string required",
1013-
input: "required",
1013+
input: &openai.ChatCompletionToolChoiceUnion{Value: "required"},
10141014
expected: &genai.ToolConfig{FunctionCallingConfig: &genai.FunctionCallingConfig{Mode: genai.FunctionCallingConfigModeAny}},
10151015
},
10161016
{
10171017
name: "ToolChoice struct",
1018-
input: openai.ToolChoice{
1019-
Type: openai.ToolTypeFunction,
1020-
Function: openai.ToolFunction{Name: "myfunc"},
1018+
input: &openai.ChatCompletionToolChoiceUnion{
1019+
Value: openai.ChatCompletionNamedToolChoice{
1020+
Type: openai.ToolTypeFunction,
1021+
Function: openai.ChatCompletionNamedToolChoiceFunction{Name: "myfunc"},
1022+
},
10211023
},
10221024
expected: &genai.ToolConfig{
10231025
FunctionCallingConfig: &genai.FunctionCallingConfig{
@@ -1029,12 +1031,12 @@ func TestOpenAIToolChoiceToGeminiToolConfig(t *testing.T) {
10291031
},
10301032
{
10311033
name: "unsupported type",
1032-
input: 123,
1034+
input: &openai.ChatCompletionToolChoiceUnion{Value: 123},
10331035
expectErr: "unsupported tool choice type",
10341036
},
10351037
{
10361038
name: "unsupported string value",
1037-
input: "invalid",
1039+
input: &openai.ChatCompletionToolChoiceUnion{Value: "invalid"},
10381040
expectErr: "unsupported tool choice: 'invalid'",
10391041
},
10401042
}

internal/extproc/translator/openai_awsbedrock.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func (o *openAIToAWSBedrockTranslatorV1ChatCompletion) openAIToolsToBedrockToolC
142142
bedrockReq.ToolConfig.Tools = tools
143143

144144
if openAIReq.ToolChoice != nil {
145-
if toolChoice, ok := openAIReq.ToolChoice.(string); ok {
145+
if toolChoice, ok := openAIReq.ToolChoice.Value.(string); ok {
146146
switch toolChoice {
147147
case "auto":
148148
bedrockReq.ToolConfig.ToolChoice = &awsbedrock.ToolChoice{
@@ -166,15 +166,14 @@ func (o *openAIToAWSBedrockTranslatorV1ChatCompletion) openAIToolsToBedrockToolC
166166
}
167167
}
168168
}
169-
} else if toolChoice, ok := openAIReq.ToolChoice.(openai.ToolChoice); ok {
170-
tool := string(toolChoice.Type)
169+
} else if toolChoice, ok := openAIReq.ToolChoice.Value.(openai.ChatCompletionNamedToolChoice); ok {
171170
bedrockReq.ToolConfig.ToolChoice = &awsbedrock.ToolChoice{
172171
Tool: &awsbedrock.SpecificToolChoice{
173-
Name: &tool,
172+
Name: &toolChoice.Function.Name,
174173
},
175174
}
176175
} else {
177-
return fmt.Errorf("unexpected type: %T", openAIReq.ToolChoice)
176+
return fmt.Errorf("unexpected type: %T", openAIReq.ToolChoice.Value)
178177
}
179178
}
180179
return nil

internal/extproc/translator/openai_awsbedrock_test.go

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_RequestBody(t *testing.T)
505505
},
506506
},
507507
},
508-
ToolChoice: "auto",
508+
ToolChoice: &openai.ChatCompletionToolChoiceUnion{Value: "auto"},
509509
},
510510
output: awsbedrock.ConverseInput{
511511
InferenceConfig: &awsbedrock.InferenceConfiguration{},
@@ -556,7 +556,7 @@ func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_RequestBody(t *testing.T)
556556
},
557557
},
558558
},
559-
ToolChoice: "required",
559+
ToolChoice: &openai.ChatCompletionToolChoiceUnion{Value: "required"},
560560
},
561561
output: awsbedrock.ConverseInput{
562562
InferenceConfig: &awsbedrock.InferenceConfiguration{},
@@ -607,7 +607,7 @@ func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_RequestBody(t *testing.T)
607607
},
608608
},
609609
},
610-
ToolChoice: "some-tools",
610+
ToolChoice: &openai.ChatCompletionToolChoiceUnion{Value: "some-tools"},
611611
},
612612
output: awsbedrock.ConverseInput{
613613
InferenceConfig: &awsbedrock.InferenceConfiguration{},
@@ -662,10 +662,12 @@ func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_RequestBody(t *testing.T)
662662
},
663663
},
664664
},
665-
ToolChoice: openai.ToolChoice{
666-
Type: openai.ToolType("function"),
667-
Function: openai.ToolFunction{
668-
Name: "my_function",
665+
ToolChoice: &openai.ChatCompletionToolChoiceUnion{
666+
Value: openai.ChatCompletionNamedToolChoice{
667+
Type: openai.ToolType("function"),
668+
Function: openai.ChatCompletionNamedToolChoiceFunction{
669+
Name: "my_function",
670+
},
669671
},
670672
},
671673
},
@@ -693,7 +695,7 @@ func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_RequestBody(t *testing.T)
693695
},
694696
ToolChoice: &awsbedrock.ToolChoice{
695697
Tool: &awsbedrock.SpecificToolChoice{
696-
Name: ptr.To("function"),
698+
Name: ptr.To("my_function"),
697699
},
698700
},
699701
},
@@ -1688,6 +1690,50 @@ func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_ResponseBody(t *testing.T)
16881690
}
16891691
}
16901692

1693+
func TestOpenAIToAWSBedrockTranslatorV1ChatCompletion_RequestBodyErr(t *testing.T) {
1694+
tests := []struct {
1695+
name string
1696+
input openai.ChatCompletionRequest
1697+
err error
1698+
}{
1699+
{
1700+
name: "test unexpected tool choice type",
1701+
input: openai.ChatCompletionRequest{
1702+
Model: "gpt-4o",
1703+
Messages: []openai.ChatCompletionMessageParamUnion{
1704+
{
1705+
OfUser: &openai.ChatCompletionUserMessageParam{
1706+
Content: openai.StringOrUserRoleContentUnion{
1707+
Value: "from-user",
1708+
},
1709+
Role: openai.ChatMessageRoleUser,
1710+
},
1711+
},
1712+
},
1713+
Tools: []openai.Tool{
1714+
{
1715+
Type: "function",
1716+
Function: &openai.FunctionDefinition{
1717+
Name: "get_current_weather",
1718+
Description: "Get the current weather in a given location",
1719+
},
1720+
},
1721+
},
1722+
ToolChoice: &openai.ChatCompletionToolChoiceUnion{Value: 123},
1723+
},
1724+
err: fmt.Errorf("unexpected type: int"),
1725+
},
1726+
}
1727+
for _, tt := range tests {
1728+
t.Run(tt.name, func(t *testing.T) {
1729+
o := &openAIToAWSBedrockTranslatorV1ChatCompletion{}
1730+
originalReq := tt.input
1731+
_, _, err := o.RequestBody(nil, &originalReq, false)
1732+
require.Equal(t, err.Error(), tt.err.Error())
1733+
})
1734+
}
1735+
}
1736+
16911737
// base64RealStreamingEvents is the base64 encoded raw binary response from bedrock anthropic.claude model.
16921738
// The request is to find the cosine of number 7 with a tool configuration.
16931739
const base64RealStreamingEvents = "AAAAmwAAAFJGkfmwCzpldmVudC10eXBlBwAMbWVzc2FnZVN0YXJ0DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDRCIsInJvbGUiOiJhc3Npc3RhbnQifbCidJ0AAACpAAAAV+0a5tkLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJ0ZXh0IjoiVG8ifSwicCI6ImFiY2RlZmdoaWprbG1uIn0rY75JAAAAsQAAAFe9ijqaCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6IiBjYWxjdWxhdGUgdGhlIGNvc2luZSJ9LCJwIjoiYWJjIn3hywqfAAAA2gAAAFdTaHzGCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6IiBvZiA3LCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTYifUsRwHsAAADXAAAAV6v4uHcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJ0ZXh0IjoiIHdlIGNhbiB1c2UgdGhlIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVSJ9jBuxjAAAALwAAABXRRr+Kws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIgXCIifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGIn3SOp66AAAA2wAAAFduCFV2CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6ImNvc2luZVwiIGZ1bmN0aW9uIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXIn2f+1UQAAAA2QAAAFcUyAYWCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6IiB0aGF0In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1NiJ9uD7t8wAAAM8AAABX+2hkNAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIgaXMifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWSJ9p52nrQAAAMQAAABXjLhVJQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIgYXZhaWxhYmxlIHRvIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0QifYC08b0AAADTAAAAV154HrcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJ0ZXh0IjoiIHVzLiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxIn0mTm4jAAAAtAAAAFd1arXqCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6IiBMZXQifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3In34BFwTAAAA0AAAAFcZ2GRnCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6IidzIHVzZSJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWVyJ9vfdBjQAAALwAAABXRRr+Kws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIgdGhpcyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNEIn1Xtb4jAAAAuAAAAFewmljrCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsidGV4dCI6IiBmdW5jdGlvbiB0byJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFycyJ9GYv84AAAALQAAABXdWq16gs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIgZ2V0In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2dyJ99bdUOgAAAN4AAABXpujaBgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIgdGhlIHJlc3VsdCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NSJ9niPS/gAAAM0AAABXgag3VAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InRleHQiOiIuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFkifRc68JQAAACuAAAAVig9Cl8LOmV2ZW50LXR5cGUHABBjb250ZW50QmxvY2tTdG9wDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1AifY2eizoAAAEEAAAAV67xblsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tTdGFydA06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVIiLCJzdGFydCI6eyJ0b29sVXNlIjp7Im5hbWUiOiJjb3NpbmUiLCJ0b29sVXNlSWQiOiJ0b29sdXNlX1FrbHJFSEtqUnU2T2M0QlFVZnk3WlEifX19kpNGawAAAK0AAABXGJpAGQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRvb2xVc2UiOnsiaW5wdXQiOiIifX0sInAiOiJhYmNkZWZnIn3XeK+kAAAAswAAAFfHSmn6CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidG9vbFVzZSI6eyJpbnB1dCI6IntcInhcIjogN30ifX0sInAiOiJhYmMifaN4jhsAAACxAAAAVsqNCgwLOmV2ZW50LXR5cGUHABBjb250ZW50QmxvY2tTdG9wDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlMifUJp3UkAAACFAAAAUQBIgekLOmV2ZW50LXR5cGUHAAttZXNzYWdlU3RvcA06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7InAiOiJhYmNkIiwic3RvcFJlYXNvbiI6InRvb2xfdXNlIn3ejv14AAAAygAAAE5X40OECzpldmVudC10eXBlBwAIbWV0YWRhdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJtZXRyaWNzIjp7ImxhdGVuY3lNcyI6MTk1N30sInAiOiJhYmNkZWZnIiwidXNhZ2UiOnsiaW5wdXRUb2tlbnMiOjM4Niwib3V0cHV0VG9rZW5zIjo3NSwidG90YWxUb2tlbnMiOjQ2MX19Ke/W4Q=="

internal/extproc/translator/openai_gcpanthropic.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ func isAnthropicSupportedImageMediaType(mediaType string) bool {
9595
}
9696

9797
// translateAnthropicToolChoice converts the OpenAI tool_choice parameter to the Anthropic format.
98-
func translateAnthropicToolChoice(openAIToolChoice any, disableParallelToolUse anthropicParam.Opt[bool]) (anthropic.ToolChoiceUnionParam, error) {
98+
func translateAnthropicToolChoice(openAIToolChoice *openai.ChatCompletionToolChoiceUnion, disableParallelToolUse anthropicParam.Opt[bool]) (anthropic.ToolChoiceUnionParam, error) {
9999
var toolChoice anthropic.ToolChoiceUnionParam
100100

101101
if openAIToolChoice == nil {
102102
return toolChoice, nil
103103
}
104104

105-
switch choice := openAIToolChoice.(type) {
105+
switch choice := openAIToolChoice.Value.(type) {
106106
case string:
107107
switch choice {
108108
case string(openAIconstant.ValueOf[openAIconstant.Auto]()):
@@ -121,7 +121,7 @@ func translateAnthropicToolChoice(openAIToolChoice any, disableParallelToolUse a
121121
default:
122122
return anthropic.ToolChoiceUnionParam{}, fmt.Errorf("unsupported tool_choice value: %s", choice)
123123
}
124-
case openai.ToolChoice:
124+
case openai.ChatCompletionNamedToolChoice:
125125
if choice.Type == openai.ToolTypeFunction && choice.Function.Name != "" {
126126
toolChoice = anthropic.ToolChoiceUnionParam{
127127
OfTool: &anthropic.ToolChoiceToolParam{
@@ -139,7 +139,7 @@ func translateAnthropicToolChoice(openAIToolChoice any, disableParallelToolUse a
139139

140140
// translateOpenAItoAnthropicTools translates OpenAI tool and tool_choice parameters
141141
// into the Anthropic format and returns translated tool & tool choice.
142-
func translateOpenAItoAnthropicTools(openAITools []openai.Tool, openAIToolChoice any, parallelToolCalls *bool) (tools []anthropic.ToolUnionParam, toolChoice anthropic.ToolChoiceUnionParam, err error) {
142+
func translateOpenAItoAnthropicTools(openAITools []openai.Tool, openAIToolChoice *openai.ChatCompletionToolChoiceUnion, parallelToolCalls *bool) (tools []anthropic.ToolUnionParam, toolChoice anthropic.ToolChoiceUnionParam, err error) {
143143
if len(openAITools) > 0 {
144144
anthropicTools := make([]anthropic.ToolUnionParam, 0, len(openAITools))
145145
for _, openAITool := range openAITools {

0 commit comments

Comments
 (0)