@@ -916,6 +916,188 @@ func getChatCompletionBody(r *http.Request) (openai.ChatCompletionRequest, error
916
916
return completion , nil
917
917
}
918
918
919
+ func TestChatCompletionRequestExtraBody (t * testing.T ) {
920
+ t .Run ("ExtraBodySerialization" , func (t * testing.T ) {
921
+ req := openai.ChatCompletionRequest {
922
+ Model : "gpt-4" ,
923
+ Messages : []openai.ChatCompletionMessage {
924
+ {
925
+ Role : openai .ChatMessageRoleUser ,
926
+ Content : "Hello!" ,
927
+ },
928
+ },
929
+ ExtraBody : map [string ]any {
930
+ "custom_param" : "custom_value" ,
931
+ "numeric_param" : 42 ,
932
+ "boolean_param" : true ,
933
+ "array_param" : []string {"item1" , "item2" },
934
+ "object_param" : map [string ]any {
935
+ "nested_key" : "nested_value" ,
936
+ },
937
+ },
938
+ }
939
+
940
+ data , err := json .Marshal (req )
941
+ checks .NoError (t , err , "Failed to marshal request with ExtraBody" )
942
+
943
+ // Verify that ExtraBody fields are included in JSON
944
+ jsonStr := string (data )
945
+ if ! strings .Contains (jsonStr , `"extra_body"` ) {
946
+ t .Error ("ExtraBody should be serialized in JSON" )
947
+ }
948
+ if ! strings .Contains (jsonStr , `"custom_param":"custom_value"` ) {
949
+ t .Error ("Custom string parameter should be serialized" )
950
+ }
951
+ if ! strings .Contains (jsonStr , `"numeric_param":42` ) {
952
+ t .Error ("Numeric parameter should be serialized" )
953
+ }
954
+ if ! strings .Contains (jsonStr , `"boolean_param":true` ) {
955
+ t .Error ("Boolean parameter should be serialized" )
956
+ }
957
+
958
+ // Verify that we can unmarshal it back
959
+ var unmarshaled openai.ChatCompletionRequest
960
+ err = json .Unmarshal (data , & unmarshaled )
961
+ checks .NoError (t , err , "Failed to unmarshal request with ExtraBody" )
962
+
963
+ if unmarshaled .ExtraBody ["custom_param" ] != "custom_value" {
964
+ t .Error ("Custom parameter not correctly unmarshaled" )
965
+ }
966
+ if int (unmarshaled .ExtraBody ["numeric_param" ].(float64 )) != 42 {
967
+ t .Error ("Numeric parameter not correctly unmarshaled" )
968
+ }
969
+ if unmarshaled .ExtraBody ["boolean_param" ] != true {
970
+ t .Error ("Boolean parameter not correctly unmarshaled" )
971
+ }
972
+ })
973
+
974
+ t .Run ("EmptyExtraBody" , func (t * testing.T ) {
975
+ req := openai.ChatCompletionRequest {
976
+ Model : "gpt-4" ,
977
+ Messages : []openai.ChatCompletionMessage {
978
+ {
979
+ Role : openai .ChatMessageRoleUser ,
980
+ Content : "Hello!" ,
981
+ },
982
+ },
983
+ ExtraBody : map [string ]any {},
984
+ }
985
+
986
+ data , err := json .Marshal (req )
987
+ checks .NoError (t , err , "Failed to marshal request with empty ExtraBody" )
988
+
989
+ // Empty ExtraBody should be omitted due to omitempty tag
990
+ jsonStr := string (data )
991
+ if strings .Contains (jsonStr , `"extra_body"` ) {
992
+ t .Error ("Empty ExtraBody should be omitted from JSON" )
993
+ }
994
+ })
995
+
996
+ t .Run ("NilExtraBody" , func (t * testing.T ) {
997
+ req := openai.ChatCompletionRequest {
998
+ Model : "gpt-4" ,
999
+ Messages : []openai.ChatCompletionMessage {
1000
+ {
1001
+ Role : openai .ChatMessageRoleUser ,
1002
+ Content : "Hello!" ,
1003
+ },
1004
+ },
1005
+ ExtraBody : nil ,
1006
+ }
1007
+
1008
+ data , err := json .Marshal (req )
1009
+ checks .NoError (t , err , "Failed to marshal request with nil ExtraBody" )
1010
+
1011
+ // Nil ExtraBody should be omitted due to omitempty tag
1012
+ jsonStr := string (data )
1013
+ if strings .Contains (jsonStr , `"extra_body"` ) {
1014
+ t .Error ("Nil ExtraBody should be omitted from JSON" )
1015
+ }
1016
+ })
1017
+ }
1018
+
1019
+ func TestChatCompletionWithExtraBody (t * testing.T ) {
1020
+ client , server , teardown := setupOpenAITestServer ()
1021
+ defer teardown ()
1022
+
1023
+ // Set up a handler that verifies ExtraBody fields are merged into the request body
1024
+ server .RegisterHandler ("/v1/chat/completions" , func (w http.ResponseWriter , r * http.Request ) {
1025
+ var reqBody map [string ]any
1026
+ body , err := io .ReadAll (r .Body )
1027
+ if err != nil {
1028
+ http .Error (w , "Failed to read request body" , http .StatusInternalServerError )
1029
+ return
1030
+ }
1031
+
1032
+ err = json .Unmarshal (body , & reqBody )
1033
+ if err != nil {
1034
+ http .Error (w , "Failed to parse request body" , http .StatusInternalServerError )
1035
+ return
1036
+ }
1037
+
1038
+ // Verify that ExtraBody fields are merged at the top level
1039
+ if reqBody ["custom_parameter" ] != "test_value" {
1040
+ http .Error (w , "ExtraBody custom_parameter not found in request" , http .StatusBadRequest )
1041
+ return
1042
+ }
1043
+ if reqBody ["additional_config" ] != true {
1044
+ http .Error (w , "ExtraBody additional_config not found in request" , http .StatusBadRequest )
1045
+ return
1046
+ }
1047
+
1048
+ // Verify standard fields are still present
1049
+ if reqBody ["model" ] != "gpt-4" {
1050
+ http .Error (w , "Standard model field not found" , http .StatusBadRequest )
1051
+ return
1052
+ }
1053
+
1054
+ // Return a mock response
1055
+ res := openai.ChatCompletionResponse {
1056
+ ID : "test-id" ,
1057
+ Object : "chat.completion" ,
1058
+ Created : time .Now ().Unix (),
1059
+ Model : "gpt-4" ,
1060
+ Choices : []openai.ChatCompletionChoice {
1061
+ {
1062
+ Index : 0 ,
1063
+ Message : openai.ChatCompletionMessage {
1064
+ Role : openai .ChatMessageRoleAssistant ,
1065
+ Content : "Hello! I received your message with extra parameters." ,
1066
+ },
1067
+ FinishReason : openai .FinishReasonStop ,
1068
+ },
1069
+ },
1070
+ Usage : openai.Usage {
1071
+ PromptTokens : 10 ,
1072
+ CompletionTokens : 20 ,
1073
+ TotalTokens : 30 ,
1074
+ },
1075
+ }
1076
+
1077
+ w .Header ().Set ("Content-Type" , "application/json" )
1078
+ json .NewEncoder (w ).Encode (res )
1079
+ })
1080
+
1081
+ // Test ChatCompletion with ExtraBody
1082
+ _ , err := client .CreateChatCompletion (context .Background (), openai.ChatCompletionRequest {
1083
+ Model : "gpt-4" ,
1084
+ Messages : []openai.ChatCompletionMessage {
1085
+ {
1086
+ Role : openai .ChatMessageRoleUser ,
1087
+ Content : "Hello!" ,
1088
+ },
1089
+ },
1090
+ ExtraBody : map [string ]any {
1091
+ "custom_parameter" : "test_value" ,
1092
+ "additional_config" : true ,
1093
+ "numeric_setting" : 123 ,
1094
+ "array_setting" : []string {"option1" , "option2" },
1095
+ },
1096
+ })
1097
+
1098
+ checks .NoError (t , err , "CreateChatCompletion with ExtraBody should not fail" )
1099
+ }
1100
+
919
1101
func TestFinishReason (t * testing.T ) {
920
1102
c := & openai.ChatCompletionChoice {
921
1103
FinishReason : openai .FinishReasonNull ,
0 commit comments