Skip to content

Commit a3f7d32

Browse files
authored
Merge branch 'main' into python_3_13
2 parents 308e492 + 136d2fd commit a3f7d32

36 files changed

+1277
-277
lines changed

.github/workflows/run-forecast-explainer-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ jobs:
5454
$CONDA/bin/conda init
5555
source /home/runner/.bashrc
5656
pip install -r test-requirements-operators.txt
57-
pip install "oracle-automlx[forecasting]>=25.1.1"
57+
pip install "oracle-automlx[forecasting]>=25.3.0"
5858
pip install pandas>=2.2.0
5959
python -m pytest -v -p no:warnings --durations=5 tests/operators/forecast/test_explainers.py

.github/workflows/run-forecast-unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ jobs:
5656
$CONDA/bin/conda init
5757
source /home/runner/.bashrc
5858
pip install -r test-requirements-operators.txt
59-
pip install "oracle-automlx[forecasting]>=25.1.1"
59+
pip install "oracle-automlx[forecasting]>=25.3.0"
6060
pip install pandas>=2.2.0
6161
python -m pytest -v -p no:warnings --durations=5 tests/operators/forecast --ignore=tests/operators/forecast/test_explainers.py

ads/aqua/client/client.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,19 @@ def embeddings(
582582
payload = {**(payload or {}), "input": input}
583583
return self._request(payload=payload, headers=headers)
584584

585+
def fetch_data(self) -> Union[Dict[str, Any], Iterator[Mapping[str, Any]]]:
586+
"""Fetch Data in json format by sending a request to the endpoint.
587+
588+
Args:
589+
590+
Returns:
591+
Union[Dict[str, Any], Iterator[Mapping[str, Any]]]: The server's response, typically including the data in JSON format.
592+
"""
593+
# headers = {"Content-Type", "application/json"}
594+
response = self._client.get(self.endpoint)
595+
json_response = response.json()
596+
return json_response
597+
585598

586599
class AsyncClient(BaseClient):
587600
"""

ads/aqua/common/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class InferenceContainerTypeFamily(ExtendedEnum):
5858
AQUA_VLLM_LLAMA4_CONTAINER_FAMILY = "odsc-vllm-serving-llama4"
5959
AQUA_TGI_CONTAINER_FAMILY = "odsc-tgi-serving"
6060
AQUA_LLAMA_CPP_CONTAINER_FAMILY = "odsc-llama-cpp-serving"
61+
AQUA_VLLM_OPENAI_CONTAINER_FAMILY = "odsc-vllm-serving-openai"
6162

6263

6364
class CustomInferenceContainerTypeFamily(ExtendedEnum):

ads/aqua/common/utils.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,44 @@ def get_container_params_type(container_type_name: str) -> str:
997997
return UNKNOWN
998998

999999

1000+
def get_container_env_type(container_type_name: Optional[str]) -> str:
1001+
"""
1002+
Determine the container environment type based on the container type name.
1003+
1004+
This function matches the provided container type name against the known
1005+
values of `InferenceContainerType`. The check is case-insensitive and
1006+
allows for partial matches so that changes in container naming conventions
1007+
(e.g., prefixes or suffixes) will still be matched correctly.
1008+
1009+
Examples:
1010+
>>> get_container_env_type("odsc-vllm-serving")
1011+
'vllm'
1012+
>>> get_container_env_type("ODSC-TGI-Serving")
1013+
'tgi'
1014+
>>> get_container_env_type("custom-unknown-container")
1015+
'UNKNOWN'
1016+
1017+
Args:
1018+
container_type_name (Optional[str]):
1019+
The deployment container type name (e.g., "odsc-vllm-serving").
1020+
1021+
Returns:
1022+
str:
1023+
- A matching `InferenceContainerType` value string (e.g., "VLLM", "TGI", "LLAMA-CPP").
1024+
- `"UNKNOWN"` if no match is found or the input is empty/None.
1025+
"""
1026+
if not container_type_name:
1027+
return UNKNOWN
1028+
1029+
needle = container_type_name.strip().casefold()
1030+
1031+
for container_type in InferenceContainerType.values():
1032+
if container_type and container_type.casefold() in needle:
1033+
return container_type.upper()
1034+
1035+
return UNKNOWN
1036+
1037+
10001038
def get_restricted_params_by_container(container_type_name: str) -> set:
10011039
"""The utility function accepts the deployment container type name and returns a set of restricted params
10021040
for that container.

ads/aqua/config/container_config.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -191,21 +191,28 @@ def from_service_config(
191191
additional_configurations.get("modelFormats")
192192
)
193193

194-
# Parse environment variables from `additional_configurations`.
195-
# Only keys present in the configuration will be added to the result.
196-
config_keys = {
197-
"MODEL_DEPLOY_PREDICT_ENDPOINT": UNKNOWN,
198-
"MODEL_DEPLOY_HEALTH_ENDPOINT": UNKNOWN,
199-
"PORT": UNKNOWN,
200-
"HEALTH_CHECK_PORT": UNKNOWN,
201-
"VLLM_USE_V1": UNKNOWN,
202-
}
203-
204-
env_vars = [
205-
{key: additional_configurations.get(key, default)}
206-
for key, default in config_keys.items()
207-
if key in additional_configurations
208-
]
194+
# TODO: Remove the else condition once SMC env variable config is updated everywhere
195+
if additional_configurations.get("env_vars", None):
196+
env_vars_dict = json.loads(
197+
additional_configurations.get("env_vars") or "{}"
198+
)
199+
env_vars = [
200+
{key: str(value)} for key, value in env_vars_dict.items()
201+
]
202+
else:
203+
config_keys = {
204+
"MODEL_DEPLOY_PREDICT_ENDPOINT": UNKNOWN,
205+
"MODEL_DEPLOY_HEALTH_ENDPOINT": UNKNOWN,
206+
"PORT": UNKNOWN,
207+
"HEALTH_CHECK_PORT": UNKNOWN,
208+
"VLLM_USE_V1": UNKNOWN,
209+
}
210+
211+
env_vars = [
212+
{key: additional_configurations.get(key, default)}
213+
for key, default in config_keys.items()
214+
if key in additional_configurations
215+
]
209216

210217
# Build container spec
211218
container_item.spec = AquaContainerConfigSpec(

ads/aqua/extension/deployment_handler.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,37 @@ def post(self, *args, **kwargs): # noqa: ARG002
373373
)
374374

375375

376+
class AquaModelListHandler(AquaAPIhandler):
377+
"""Handler for Aqua model list params REST APIs.
378+
379+
Methods
380+
-------
381+
get(self, *args, **kwargs)
382+
Validates parameters for the given model id.
383+
"""
384+
385+
@handle_exceptions
386+
def get(self, model_deployment_id):
387+
"""
388+
Handles get model list for the Active Model Deployment
389+
Raises
390+
------
391+
HTTPError
392+
Raises HTTPError if inputs are missing or are invalid
393+
"""
394+
395+
self.set_header("Content-Type", "application/json")
396+
endpoint: str = ""
397+
model_deployment = AquaDeploymentApp().get(model_deployment_id)
398+
endpoint = model_deployment.endpoint.rstrip("/") + "/predict/v1/models"
399+
aqua_client = Client(endpoint=endpoint)
400+
try:
401+
list_model_result = aqua_client.fetch_data()
402+
return self.finish(list_model_result)
403+
except Exception as ex:
404+
raise HTTPError(500, str(ex))
405+
406+
376407
__handlers__ = [
377408
("deployments/?([^/]*)/params", AquaDeploymentParamsHandler),
378409
("deployments/config/?([^/]*)", AquaDeploymentHandler),
@@ -381,4 +412,5 @@ def post(self, *args, **kwargs): # noqa: ARG002
381412
("deployments/?([^/]*)/activate", AquaDeploymentHandler),
382413
("deployments/?([^/]*)/deactivate", AquaDeploymentHandler),
383414
("inference/stream/?([^/]*)", AquaDeploymentStreamingInferenceHandler),
415+
("deployments/models/list/?([^/]*)", AquaModelListHandler),
384416
]

ads/aqua/modeldeployment/config_loader.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class MultiModelConfig(Serializable):
8888
gpu_count (int, optional): Number of GPUs count to this model of this shape.
8989
parameters (Dict[str, str], optional): A dictionary of parameters (e.g., VLLM_PARAMS) to
9090
configure the behavior of a particular GPU shape.
91+
env (Dict[str, Dict[str, str]]): Environment variables grouped by namespace (e.g., "VLLM": {"VAR": "VAL"}).
9192
"""
9293

9394
gpu_count: Optional[int] = Field(
@@ -97,6 +98,10 @@ class MultiModelConfig(Serializable):
9798
default_factory=dict,
9899
description="Key-value pairs for GPU shape parameters (e.g., VLLM_PARAMS).",
99100
)
101+
env: Optional[Dict[str, Dict[str, str]]] = Field(
102+
default_factory=dict,
103+
description="Environment variables grouped by namespace",
104+
)
100105

101106
class Config:
102107
extra = "allow"
@@ -130,6 +135,7 @@ class ConfigurationItem(Serializable):
130135
configure the behavior of a particular GPU shape.
131136
multi_model_deployment (List[MultiModelConfig], optional): A list of multi model configuration details.
132137
shape_info (DeploymentShapeInfo, optional): The shape information to this model for specific CPU shape.
138+
env (Dict[str, Dict[str, str]]): Environment variables grouped by namespace (e.g., "VLLM": {"VAR": "VAL"}).
133139
"""
134140

135141
parameters: Optional[Dict[str, str]] = Field(
@@ -143,6 +149,10 @@ class ConfigurationItem(Serializable):
143149
default_factory=DeploymentShapeInfo,
144150
description="The shape information to this model for specific shape",
145151
)
152+
env: Optional[Dict[str, Dict[str, str]]] = Field(
153+
default_factory=dict,
154+
description="Environment variables grouped by namespace",
155+
)
146156

147157
class Config:
148158
extra = "allow"

ads/aqua/modeldeployment/deployment.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
build_pydantic_error_message,
2828
find_restricted_params,
2929
get_combined_params,
30+
get_container_env_type,
3031
get_container_params_type,
3132
get_ocid_substring,
3233
get_params_list,
@@ -199,7 +200,7 @@ def create(
199200
if create_deployment_details.instance_shape.lower() not in available_shapes:
200201
raise AquaValueError(
201202
f"Invalid Instance Shape. The selected shape '{create_deployment_details.instance_shape}' "
202-
f"is not available in the {self.region} region. Please choose another shape to deploy the model."
203+
f"is not supported in the {self.region} region. Please choose another shape to deploy the model."
203204
)
204205

205206
# Get container config
@@ -381,6 +382,7 @@ def _create(
381382
Tags.AQUA_SERVICE_MODEL_TAG,
382383
Tags.AQUA_FINE_TUNED_MODEL_TAG,
383384
Tags.AQUA_TAG,
385+
Tags.BASE_MODEL_CUSTOM,
384386
]:
385387
if tag in aqua_model.freeform_tags:
386388
tags[tag] = aqua_model.freeform_tags[tag]
@@ -1042,6 +1044,7 @@ def get_deployment_config(self, model_id: str) -> AquaDeploymentConfig:
10421044
config = self.get_config_from_metadata(
10431045
model_id, AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION
10441046
).config
1047+
10451048
if config:
10461049
logger.info(
10471050
f"Fetched {AquaModelMetadataKeys.DEPLOYMENT_CONFIGURATION} from defined metadata for model: {model_id}."
@@ -1126,7 +1129,7 @@ def get_deployment_default_params(
11261129
model_id: str,
11271130
instance_shape: str,
11281131
gpu_count: int = None,
1129-
) -> List[str]:
1132+
) -> Dict:
11301133
"""Gets the default params set in the deployment configs for the given model and instance shape.
11311134
11321135
Parameters
@@ -1148,6 +1151,7 @@ def get_deployment_default_params(
11481151
11491152
"""
11501153
default_params = []
1154+
default_envs = {}
11511155
config_params = {}
11521156
model = DataScienceModel.from_id(model_id)
11531157
try:
@@ -1157,19 +1161,15 @@ def get_deployment_default_params(
11571161
except ValueError:
11581162
container_type_key = UNKNOWN
11591163
logger.debug(
1160-
f"{AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME} key is not available in the custom metadata field for model {model_id}."
1164+
f"{AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME} key is not available in the "
1165+
f"custom metadata field for model {model_id}."
11611166
)
11621167

1163-
if (
1164-
container_type_key
1165-
and container_type_key in InferenceContainerTypeFamily.values()
1166-
):
1168+
if container_type_key:
11671169
deployment_config = self.get_deployment_config(model_id)
1168-
11691170
instance_shape_config = deployment_config.configuration.get(
11701171
instance_shape, ConfigurationItem()
11711172
)
1172-
11731173
if instance_shape_config.multi_model_deployment and gpu_count:
11741174
gpu_params = instance_shape_config.multi_model_deployment
11751175

@@ -1178,12 +1178,18 @@ def get_deployment_default_params(
11781178
config_params = gpu_config.parameters.get(
11791179
get_container_params_type(container_type_key), UNKNOWN
11801180
)
1181+
default_envs = instance_shape_config.env.get(
1182+
get_container_env_type(container_type_key), {}
1183+
)
11811184
break
11821185

11831186
else:
11841187
config_params = instance_shape_config.parameters.get(
11851188
get_container_params_type(container_type_key), UNKNOWN
11861189
)
1190+
default_envs = instance_shape_config.env.get(
1191+
get_container_env_type(container_type_key), {}
1192+
)
11871193

11881194
if config_params:
11891195
params_list = get_params_list(config_params)
@@ -1196,7 +1202,7 @@ def get_deployment_default_params(
11961202
if params.split()[0] not in restricted_params_set:
11971203
default_params.append(params)
11981204

1199-
return default_params
1205+
return {"data": default_params, "env": default_envs}
12001206

12011207
def validate_deployment_params(
12021208
self,

ads/aqua/modeldeployment/entities.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class CreateModelDeploymentDetails(BaseModel):
233233
None, description="The description of the deployment."
234234
)
235235
model_id: Optional[str] = Field(None, description="The model OCID to deploy.")
236+
236237
models: Optional[List[AquaMultiModelRef]] = Field(
237238
None, description="List of models for multimodel deployment."
238239
)

0 commit comments

Comments
 (0)