We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Expected XGBoost model file "model.bst" extension is undocumented? 
On https://github.com/SeldonIO/MLServer/blob/master/runtimes/xgboost/mlserver_xgboost/xgboost.py#L21 you can see that MLServer is looking for an XGBoost model file called "model.bst". However, I cannot find any reference to that file extension in the XGBoost documentation. As far as I can see, XGBoost's documented file extensions are:

- ".json" added in 1.0.0, an "open format that can be easily reused"
- ".ubj" for Universal Binary JSON format, available in 1.6.0
- ".model" for the "old binary internal format" prior to 1.0.0, as shown in examples

Where does MLServer get the ".bst" extension from, and what model format does it use? Shouldn't it use one of the extensions mentioned in the XGBoost documentation instead, to avoid ambiguity?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `runtimes/xgboost/mlserver_xgboost/xgboost.py`
Content:
```
1 import xgboost as xgb
2 
3 from typing import List
4 from xgboost.sklearn import XGBModel
5 
6 from mlserver.errors import InferenceError
7 from mlserver.model import MLModel
8 from mlserver.utils import get_model_uri
9 from mlserver.codecs import NumpyRequestCodec, NumpyCodec
10 from mlserver.types import (
11     InferenceRequest,
12     InferenceResponse,
13     RequestOutput,
14     ResponseOutput,
15 )
16 
17 PREDICT_OUTPUT = "predict"
18 PREDICT_PROBA_OUTPUT = "predict_proba"
19 VALID_OUTPUTS = [PREDICT_OUTPUT, PREDICT_PROBA_OUTPUT]
20 
21 WELLKNOWN_MODEL_FILENAMES = ["model.bst", "model.json"]
22 
23 
24 def _load_sklearn_interface(model_uri: str) -> XGBModel:
25     try:
26         regressor = xgb.XGBRegressor()
27         regressor.load_model(model_uri)
28         return regressor
29     except TypeError:
30         # If there was an error, it's likely due to the model being a
31         # classifier
32         classifier = xgb.XGBClassifier()
33         classifier.load_model(model_uri)
34         return classifier
35 
36 
37 class XGBoostModel(MLModel):
38     """
39     Implementationof the MLModel interface to load and serve `xgboost` models.
40     """
41 
42     async def load(self) -> bool:
43         model_uri = await get_model_uri(
44             self._settings, wellknown_filenames=WELLKNOWN_MODEL_FILENAMES
45         )
46 
47         self._model = _load_sklearn_interface(model_uri)
48 
49         return True
50 
51     def _check_request(self, payload: InferenceRequest) -> InferenceRequest:
52         if not payload.outputs:
53             # By default, only return the result of `predict()`
54             payload.outputs = [RequestOutput(name=PREDICT_OUTPUT)]
55         else:
56             for request_output in payload.outputs:
57                 if request_output.name not in VALID_OUTPUTS:
58                     raise InferenceError(
59                         f"XGBoostModel only supports '{PREDICT_OUTPUT}' and "
60                         f"'{PREDICT_PROBA_OUTPUT}' as outputs "
61                         f"({request_output.name} was received)"
62                     )
63 
64         # Regression models do not support `predict_proba`
65         if PREDICT_PROBA_OUTPUT in [o.name for o in payload.outputs]:
66             if isinstance(self._model, xgb.XGBRegressor):
67                 raise InferenceError(
68                     f"XGBRegressor models do not support '{PREDICT_PROBA_OUTPUT}"
69                 )
70 
71         return payload
72 
73     def _get_model_outputs(self, payload: InferenceRequest) -> List[ResponseOutput]:
74         decoded_request = self.decode_request(payload, default_codec=NumpyRequestCodec)
75 
76         outputs = []
77         for request_output in payload.outputs:  # type: ignore
78             predict_fn = getattr(self._model, request_output.name)
79             y = predict_fn(decoded_request)
80 
81             output = self.encode(y, request_output, default_codec=NumpyCodec)
82             outputs.append(output)
83 
84         return outputs
85 
86     async def predict(self, payload: InferenceRequest) -> InferenceResponse:
87         payload = self._check_request(payload)
88         outputs = self._get_model_outputs(payload)
89 
90         return InferenceResponse(
91             model_name=self.name,
92             model_version=self.version,
93             outputs=outputs,
94         )
95
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/runtimes/xgboost/mlserver_xgboost/xgboost.py b/runtimes/xgboost/mlserver_xgboost/xgboost.py
--- a/runtimes/xgboost/mlserver_xgboost/xgboost.py
+++ b/runtimes/xgboost/mlserver_xgboost/xgboost.py
@@ -18,7 +18,7 @@
 PREDICT_PROBA_OUTPUT = "predict_proba"
 VALID_OUTPUTS = [PREDICT_OUTPUT, PREDICT_PROBA_OUTPUT]
 
-WELLKNOWN_MODEL_FILENAMES = ["model.bst", "model.json"]
+WELLKNOWN_MODEL_FILENAMES = ["model.bst", "model.json", "model.ubj"]
 
 
 def _load_sklearn_interface(model_uri: str) -> XGBModel:

{"golden_diff": "diff --git a/runtimes/xgboost/mlserver_xgboost/xgboost.py b/runtimes/xgboost/mlserver_xgboost/xgboost.py\n--- a/runtimes/xgboost/mlserver_xgboost/xgboost.py\n+++ b/runtimes/xgboost/mlserver_xgboost/xgboost.py\n@@ -18,7 +18,7 @@\n PREDICT_PROBA_OUTPUT = \"predict_proba\"\n VALID_OUTPUTS = [PREDICT_OUTPUT, PREDICT_PROBA_OUTPUT]\n \n-WELLKNOWN_MODEL_FILENAMES = [\"model.bst\", \"model.json\"]\n+WELLKNOWN_MODEL_FILENAMES = [\"model.bst\", \"model.json\", \"model.ubj\"]\n \n \n def _load_sklearn_interface(model_uri: str) -> XGBModel:\n", "issue": "Expected XGBoost model file \"model.bst\" extension is undocumented? \nOn https://github.com/SeldonIO/MLServer/blob/master/runtimes/xgboost/mlserver_xgboost/xgboost.py#L21 you can see that MLServer is looking for an XGBoost model file called \"model.bst\". However, I cannot find any reference to that file extension in the XGBoost documentation. As far as I can see, XGBoost's documented file extensions are:\r\n\r\n- \".json\" added in 1.0.0, an \"open format that can be easily reused\"\r\n- \".ubj\" for Universal Binary JSON format, available in 1.6.0\r\n- \".model\" for the \"old binary internal format\" prior to 1.0.0, as shown in examples\r\n\r\nWhere does MLServer get the \".bst\" extension from, and what model format does it use? Shouldn't it use one of the extensions mentioned in the XGBoost documentation instead, to avoid ambiguity?\n", "before_files": [{"content": "import xgboost as xgb\n\nfrom typing import List\nfrom xgboost.sklearn import XGBModel\n\nfrom mlserver.errors import InferenceError\nfrom mlserver.model import MLModel\nfrom mlserver.utils import get_model_uri\nfrom mlserver.codecs import NumpyRequestCodec, NumpyCodec\nfrom mlserver.types import (\n    InferenceRequest,\n    InferenceResponse,\n    RequestOutput,\n    ResponseOutput,\n)\n\nPREDICT_OUTPUT = \"predict\"\nPREDICT_PROBA_OUTPUT = \"predict_proba\"\nVALID_OUTPUTS = [PREDICT_OUTPUT, PREDICT_PROBA_OUTPUT]\n\nWELLKNOWN_MODEL_FILENAMES = [\"model.bst\", \"model.json\"]\n\n\ndef _load_sklearn_interface(model_uri: str) -> XGBModel:\n    try:\n        regressor = xgb.XGBRegressor()\n        regressor.load_model(model_uri)\n        return regressor\n    except TypeError:\n        # If there was an error, it's likely due to the model being a\n        # classifier\n        classifier = xgb.XGBClassifier()\n        classifier.load_model(model_uri)\n        return classifier\n\n\nclass XGBoostModel(MLModel):\n    \"\"\"\n    Implementationof the MLModel interface to load and serve `xgboost` models.\n    \"\"\"\n\n    async def load(self) -> bool:\n        model_uri = await get_model_uri(\n            self._settings, wellknown_filenames=WELLKNOWN_MODEL_FILENAMES\n        )\n\n        self._model = _load_sklearn_interface(model_uri)\n\n        return True\n\n    def _check_request(self, payload: InferenceRequest) -> InferenceRequest:\n        if not payload.outputs:\n            # By default, only return the result of `predict()`\n            payload.outputs = [RequestOutput(name=PREDICT_OUTPUT)]\n        else:\n            for request_output in payload.outputs:\n                if request_output.name not in VALID_OUTPUTS:\n                    raise InferenceError(\n                        f\"XGBoostModel only supports '{PREDICT_OUTPUT}' and \"\n                        f\"'{PREDICT_PROBA_OUTPUT}' as outputs \"\n                        f\"({request_output.name} was received)\"\n                    )\n\n        # Regression models do not support `predict_proba`\n        if PREDICT_PROBA_OUTPUT in [o.name for o in payload.outputs]:\n            if isinstance(self._model, xgb.XGBRegressor):\n                raise InferenceError(\n                    f\"XGBRegressor models do not support '{PREDICT_PROBA_OUTPUT}\"\n                )\n\n        return payload\n\n    def _get_model_outputs(self, payload: InferenceRequest) -> List[ResponseOutput]:\n        decoded_request = self.decode_request(payload, default_codec=NumpyRequestCodec)\n\n        outputs = []\n        for request_output in payload.outputs:  # type: ignore\n            predict_fn = getattr(self._model, request_output.name)\n            y = predict_fn(decoded_request)\n\n            output = self.encode(y, request_output, default_codec=NumpyCodec)\n            outputs.append(output)\n\n        return outputs\n\n    async def predict(self, payload: InferenceRequest) -> InferenceResponse:\n        payload = self._check_request(payload)\n        outputs = self._get_model_outputs(payload)\n\n        return InferenceResponse(\n            model_name=self.name,\n            model_version=self.version,\n            outputs=outputs,\n        )\n", "path": "runtimes/xgboost/mlserver_xgboost/xgboost.py"}], "after_files": [{"content": "import xgboost as xgb\n\nfrom typing import List\nfrom xgboost.sklearn import XGBModel\n\nfrom mlserver.errors import InferenceError\nfrom mlserver.model import MLModel\nfrom mlserver.utils import get_model_uri\nfrom mlserver.codecs import NumpyRequestCodec, NumpyCodec\nfrom mlserver.types import (\n    InferenceRequest,\n    InferenceResponse,\n    RequestOutput,\n    ResponseOutput,\n)\n\nPREDICT_OUTPUT = \"predict\"\nPREDICT_PROBA_OUTPUT = \"predict_proba\"\nVALID_OUTPUTS = [PREDICT_OUTPUT, PREDICT_PROBA_OUTPUT]\n\nWELLKNOWN_MODEL_FILENAMES = [\"model.bst\", \"model.json\", \"model.ubj\"]\n\n\ndef _load_sklearn_interface(model_uri: str) -> XGBModel:\n    try:\n        regressor = xgb.XGBRegressor()\n        regressor.load_model(model_uri)\n        return regressor\n    except TypeError:\n        # If there was an error, it's likely due to the model being a\n        # classifier\n        classifier = xgb.XGBClassifier()\n        classifier.load_model(model_uri)\n        return classifier\n\n\nclass XGBoostModel(MLModel):\n    \"\"\"\n    Implementationof the MLModel interface to load and serve `xgboost` models.\n    \"\"\"\n\n    async def load(self) -> bool:\n        model_uri = await get_model_uri(\n            self._settings, wellknown_filenames=WELLKNOWN_MODEL_FILENAMES\n        )\n\n        self._model = _load_sklearn_interface(model_uri)\n\n        return True\n\n    def _check_request(self, payload: InferenceRequest) -> InferenceRequest:\n        if not payload.outputs:\n            # By default, only return the result of `predict()`\n            payload.outputs = [RequestOutput(name=PREDICT_OUTPUT)]\n        else:\n            for request_output in payload.outputs:\n                if request_output.name not in VALID_OUTPUTS:\n                    raise InferenceError(\n                        f\"XGBoostModel only supports '{PREDICT_OUTPUT}' and \"\n                        f\"'{PREDICT_PROBA_OUTPUT}' as outputs \"\n                        f\"({request_output.name} was received)\"\n                    )\n\n        # Regression models do not support `predict_proba`\n        if PREDICT_PROBA_OUTPUT in [o.name for o in payload.outputs]:\n            if isinstance(self._model, xgb.XGBRegressor):\n                raise InferenceError(\n                    f\"XGBRegressor models do not support '{PREDICT_PROBA_OUTPUT}\"\n                )\n\n        return payload\n\n    def _get_model_outputs(self, payload: InferenceRequest) -> List[ResponseOutput]:\n        decoded_request = self.decode_request(payload, default_codec=NumpyRequestCodec)\n\n        outputs = []\n        for request_output in payload.outputs:  # type: ignore\n            predict_fn = getattr(self._model, request_output.name)\n            y = predict_fn(decoded_request)\n\n            output = self.encode(y, request_output, default_codec=NumpyCodec)\n            outputs.append(output)\n\n        return outputs\n\n    async def predict(self, payload: InferenceRequest) -> InferenceResponse:\n        payload = self._check_request(payload)\n        outputs = self._get_model_outputs(payload)\n\n        return InferenceResponse(\n            model_name=self.name,\n            model_version=self.version,\n            outputs=outputs,\n        )\n", "path": "runtimes/xgboost/mlserver_xgboost/xgboost.py"}]}