@@ -809,6 +809,88 @@ func TestModelURLFallbackToProfileDefault(t *testing.T) {
809809 }
810810}
811811
812+ // TestOpenAICompatibleModelURLBehavior verifies special handling for OpenAI-compatible
813+ // profiles where /v1/models override is ignored to preserve existing configurations.
814+ func TestOpenAICompatibleModelURLBehavior (t * testing.T ) {
815+ tests := []struct {
816+ name string
817+ modelURLConfig string // What user configures
818+ expectProfileDefault bool // Whether we expect the profile default to be used
819+ expectedPath string // Expected discovery path
820+ }{
821+ {
822+ name : "OpenAI-compatible with /v1/models uses profile default" ,
823+ modelURLConfig : "/v1/models" ,
824+ expectProfileDefault : true ,
825+ expectedPath : "/v1/models" ,
826+ },
827+ {
828+ name : "OpenAI-compatible with custom path uses override" ,
829+ modelURLConfig : "/api/v2/models" , // Path, will be combined with server URL
830+ expectProfileDefault : false ,
831+ expectedPath : "/api/v2/models" ,
832+ },
833+ {
834+ name : "OpenAI-compatible with /models ignored (Docker/OpenWebUI case)" ,
835+ modelURLConfig : "/models" , // Often returns HTML, not JSON
836+ expectProfileDefault : true ,
837+ expectedPath : "/v1/models" ,
838+ },
839+ {
840+ name : "OpenAI-compatible with empty model_url uses profile default" ,
841+ modelURLConfig : "" ,
842+ expectProfileDefault : true ,
843+ expectedPath : "/v1/models" ,
844+ },
845+ }
846+
847+ for _ , tt := range tests {
848+ t .Run (tt .name , func (t * testing.T ) {
849+ var requestedPath string
850+
851+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
852+ requestedPath = r .URL .Path
853+ t .Logf ("Server received request at path: %s" , r .URL .Path )
854+
855+ // Only respond to the expected path
856+ if r .URL .Path == tt .expectedPath {
857+ w .WriteHeader (http .StatusOK )
858+ w .Write ([]byte (`{"object": "list", "data": [{"id": "test-model", "object": "model"}]}` ))
859+ return
860+ }
861+
862+ w .WriteHeader (http .StatusNotFound )
863+ }))
864+ defer server .Close ()
865+
866+ // For the override test, we need to build the full URL first
867+ modelURLString := tt .modelURLConfig
868+ if tt .modelURLConfig == "/api/v2/models" {
869+ modelURLString = server .URL + tt .modelURLConfig
870+ }
871+
872+ // Create endpoint with configured model URL
873+ endpoint := createTestEndpointWithModelURL (server .URL , domain .ProfileOpenAICompatible , modelURLString )
874+
875+ client := NewHTTPModelDiscoveryClientWithDefaults (createTestProfileFactory (t ), createTestLogger ())
876+
877+ models , err := client .DiscoverModels (context .Background (), endpoint )
878+
879+ if err != nil {
880+ t .Fatalf ("Unexpected error: %v" , err )
881+ }
882+
883+ if requestedPath != tt .expectedPath {
884+ t .Errorf ("Expected path %q to be used, but server received request at %q" , tt .expectedPath , requestedPath )
885+ }
886+
887+ if len (models ) == 0 {
888+ t .Errorf ("Expected models to be discovered, got 0" )
889+ }
890+ })
891+ }
892+ }
893+
812894type serverResponse struct {
813895 status int
814896 body string
0 commit comments