feat: add metric history bulk fetch endpoint (#1535)

This adds a new endpoint to fetch metric history items for multiple
experiment runs at once:

  GET /experiment_runs/metric_history

Without arguments this fetches metric history for every experiment run.

To fetch metric history for a specific set of experiment runs, the
`filterQuery` param can be used with `experimentRunId IN (1,2,3)`:

  GET /experiment_runs/metric_history?filterQuery=experimentRunId+IN+(1,2,3)

AI-assisted: Claude Code 1.0.63 (claude-sonnet-4@20250514)

Signed-off-by: Jon Burdo <jon@jonburdo.com>
This commit is contained in:
Jon Burdo 2025-09-05 02:11:12 -04:00 committed by GitHub
parent af2e09940a
commit ec49073cff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 874 additions and 28 deletions

View File

@ -253,6 +253,35 @@ paths:
operationId: createExperimentRun
summary: Create an ExperimentRun
description: Creates a new instance of an `ExperimentRun`.
"/api/model_registry/v1alpha3/experiment_runs/metric_history":
summary: Path used to get metric history for multiple experiment runs.
description: >-
The REST endpoint/path used to get metric history for multiple `ExperimentRun` entities. This path contains a `GET` operation to retrieve metrics with optional filtering.
get:
tags:
- ModelRegistryService
parameters:
- $ref: "#/components/parameters/filterQuery"
- $ref: "#/components/parameters/name"
- $ref: "#/components/parameters/stepIds"
- $ref: "#/components/parameters/pageSize"
- $ref: "#/components/parameters/orderBy"
- $ref: "#/components/parameters/sortOrder"
- $ref: "#/components/parameters/nextPageToken"
responses:
"200":
$ref: "#/components/responses/MetricListResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalServerError"
"503":
$ref: "#/components/responses/ServiceUnavailable"
operationId: getExperimentRunsMetricHistory
summary: Get metric history for multiple ExperimentRuns
description: Gets the metric history for multiple `ExperimentRun` entities with optional filtering by metric name, step IDs, and experiment run IDs.
"/api/model_registry/v1alpha3/experiment_runs/{experimentrunId}":
summary: Path used to manage a single ExperimentRun.
description: >-

View File

@ -1520,6 +1520,35 @@ paths:
type: string
in: path
required: true
"/api/model_registry/v1alpha3/experiment_runs/metric_history":
summary: Path used to get metric history for multiple experiment runs.
description: >-
The REST endpoint/path used to get metric history for multiple `ExperimentRun` entities. This path contains a `GET` operation to retrieve metrics with optional filtering.
get:
tags:
- ModelRegistryService
parameters:
- $ref: "#/components/parameters/filterQuery"
- $ref: "#/components/parameters/name"
- $ref: "#/components/parameters/stepIds"
- $ref: "#/components/parameters/pageSize"
- $ref: "#/components/parameters/orderBy"
- $ref: "#/components/parameters/sortOrder"
- $ref: "#/components/parameters/nextPageToken"
responses:
"200":
$ref: "#/components/responses/MetricListResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/InternalServerError"
"503":
$ref: "#/components/responses/ServiceUnavailable"
operationId: getExperimentRunsMetricHistory
summary: Get metric history for multiple ExperimentRuns
description: Gets the metric history for multiple `ExperimentRun` entities with optional filtering by metric name, step IDs, and experiment run IDs.
"/api/model_registry/v1alpha3/experiment_runs/{experimentrunId}/metric_history":
summary: Path used to get metric history for an experiment run.
description: >-

View File

@ -102,6 +102,7 @@ Class | Method | HTTP request | Description
*ModelRegistryServiceApi* | [**get_experiment_run_artifacts**](mr_openapi/docs/ModelRegistryServiceApi.md#get_experiment_run_artifacts) | **GET** /api/model_registry/v1alpha3/experiment_runs/{experimentrunId}/artifacts | List all artifacts associated with the &#x60;ExperimentRun&#x60;
*ModelRegistryServiceApi* | [**get_experiment_run_metric_history**](mr_openapi/docs/ModelRegistryServiceApi.md#get_experiment_run_metric_history) | **GET** /api/model_registry/v1alpha3/experiment_runs/{experimentrunId}/metric_history | Get metric history for an ExperimentRun
*ModelRegistryServiceApi* | [**get_experiment_runs**](mr_openapi/docs/ModelRegistryServiceApi.md#get_experiment_runs) | **GET** /api/model_registry/v1alpha3/experiment_runs | List All ExperimentRuns
*ModelRegistryServiceApi* | [**get_experiment_runs_metric_history**](mr_openapi/docs/ModelRegistryServiceApi.md#get_experiment_runs_metric_history) | **GET** /api/model_registry/v1alpha3/experiment_runs/metric_history | Get metric history for multiple ExperimentRuns
*ModelRegistryServiceApi* | [**get_experiments**](mr_openapi/docs/ModelRegistryServiceApi.md#get_experiments) | **GET** /api/model_registry/v1alpha3/experiments | List All Experiments
*ModelRegistryServiceApi* | [**get_inference_service**](mr_openapi/docs/ModelRegistryServiceApi.md#get_inference_service) | **GET** /api/model_registry/v1alpha3/inference_services/{inferenceserviceId} | Get a InferenceService
*ModelRegistryServiceApi* | [**get_inference_service_model**](mr_openapi/docs/ModelRegistryServiceApi.md#get_inference_service_model) | **GET** /api/model_registry/v1alpha3/inference_services/{inferenceserviceId}/model | Get InferenceService&#39;s RegisteredModel

View File

@ -8251,6 +8251,383 @@ class ModelRegistryServiceApi:
_request_auth=_request_auth,
)
@validate_call
async def get_experiment_runs_metric_history(
self,
filter_query: Annotated[
Optional[StrictStr],
Field(
description='A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=` - Pattern matching: `LIKE`, `ILIKE` (case-insensitive) - Set membership: `IN` - Logical: `AND`, `OR` - Grouping: `()` for complex expressions **Data Types:** - Strings: `"value"` or `\'value\'` - Numbers: `42`, `3.14`, `1e-5` - Booleans: `true`, `false` (case-insensitive) **Property Access:** - Standard properties: `name`, `id`, `state`, `createTimeSinceEpoch` - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: `` `custom-property` `` - Type-specific access: `property.string_value`, `property.double_value`, `property.int_value`, `property.bool_value` **Examples:** - Basic: `name = "my-model"` - Comparison: `accuracy > 0.95` - Pattern: `name LIKE "%tensorflow%"` - Complex: `(name = "model-a" OR name = "model-b") AND state = "LIVE"` - Custom property: `framework.string_value = "pytorch"` - Escaped property: `` `mlflow.source.type` = "notebook" `` '
),
] = None,
name: Annotated[Optional[StrictStr], Field(description="Name of entity to search.")] = None,
step_ids: Annotated[
Optional[StrictStr], Field(description="Comma-separated list of step IDs to filter metrics by.")
] = None,
page_size: Annotated[Optional[StrictStr], Field(description="Number of entities in each page.")] = None,
order_by: Annotated[
Optional[OrderByField], Field(description="Specifies the order by criteria for listing entities.")
] = None,
sort_order: Annotated[
Optional[SortOrder], Field(description="Specifies the sort order for listing entities, defaults to ASC.")
] = None,
next_page_token: Annotated[
Optional[StrictStr], Field(description="Token to use to retrieve next page of results.")
] = None,
_request_timeout: Union[
None,
Annotated[StrictFloat, Field(gt=0)],
tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
] = None,
_request_auth: Optional[dict[StrictStr, Any]] = None,
_content_type: Optional[StrictStr] = None,
_headers: Optional[dict[StrictStr, Any]] = None,
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
) -> MetricList:
r"""Get metric history for multiple ExperimentRuns.
Gets the metric history for multiple `ExperimentRun` entities with optional filtering by metric name, step IDs, and experiment run IDs.
:param filter_query: A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=` - Pattern matching: `LIKE`, `ILIKE` (case-insensitive) - Set membership: `IN` - Logical: `AND`, `OR` - Grouping: `()` for complex expressions **Data Types:** - Strings: `\"value\"` or `'value'` - Numbers: `42`, `3.14`, `1e-5` - Booleans: `true`, `false` (case-insensitive) **Property Access:** - Standard properties: `name`, `id`, `state`, `createTimeSinceEpoch` - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: `` `custom-property` `` - Type-specific access: `property.string_value`, `property.double_value`, `property.int_value`, `property.bool_value` **Examples:** - Basic: `name = \"my-model\"` - Comparison: `accuracy > 0.95` - Pattern: `name LIKE \"%tensorflow%\"` - Complex: `(name = \"model-a\" OR name = \"model-b\") AND state = \"LIVE\"` - Custom property: `framework.string_value = \"pytorch\"` - Escaped property: `` `mlflow.source.type` = \"notebook\" ``
:type filter_query: str
:param name: Name of entity to search.
:type name: str
:param step_ids: Comma-separated list of step IDs to filter metrics by.
:type step_ids: str
:param page_size: Number of entities in each page.
:type page_size: str
:param order_by: Specifies the order by criteria for listing entities.
:type order_by: OrderByField
:param sort_order: Specifies the sort order for listing entities, defaults to ASC.
:type sort_order: SortOrder
:param next_page_token: Token to use to retrieve next page of results.
:type next_page_token: str
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:type _request_timeout: int, tuple(int, int), optional
:param _request_auth: set to override the auth_settings for an a single
request; this effectively ignores the
authentication in the spec for a single request.
:type _request_auth: dict, optional
:param _content_type: force content-type for the request.
:type _content_type: str, Optional
:param _headers: set to override the headers for a single
request; this effectively ignores the headers
in the spec for a single request.
:type _headers: dict, optional
:param _host_index: set to override the host_index for a single
request; this effectively ignores the host_index
in the spec for a single request.
:type _host_index: int, optional
:return: Returns the result object.
""" # noqa: E501
_param = self._get_experiment_runs_metric_history_serialize(
filter_query=filter_query,
name=name,
step_ids=step_ids,
page_size=page_size,
order_by=order_by,
sort_order=sort_order,
next_page_token=next_page_token,
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index,
)
_response_types_map: dict[str, Optional[str]] = {
"200": "MetricList",
"401": "Error",
"404": "Error",
"500": "Error",
"503": "Error",
}
response_data = await self.api_client.call_api(*_param, _request_timeout=_request_timeout)
await response_data.read()
return self.api_client.response_deserialize(
response_data=response_data,
response_types_map=_response_types_map,
).data
@validate_call
async def get_experiment_runs_metric_history_with_http_info(
self,
filter_query: Annotated[
Optional[StrictStr],
Field(
description='A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=` - Pattern matching: `LIKE`, `ILIKE` (case-insensitive) - Set membership: `IN` - Logical: `AND`, `OR` - Grouping: `()` for complex expressions **Data Types:** - Strings: `"value"` or `\'value\'` - Numbers: `42`, `3.14`, `1e-5` - Booleans: `true`, `false` (case-insensitive) **Property Access:** - Standard properties: `name`, `id`, `state`, `createTimeSinceEpoch` - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: `` `custom-property` `` - Type-specific access: `property.string_value`, `property.double_value`, `property.int_value`, `property.bool_value` **Examples:** - Basic: `name = "my-model"` - Comparison: `accuracy > 0.95` - Pattern: `name LIKE "%tensorflow%"` - Complex: `(name = "model-a" OR name = "model-b") AND state = "LIVE"` - Custom property: `framework.string_value = "pytorch"` - Escaped property: `` `mlflow.source.type` = "notebook" `` '
),
] = None,
name: Annotated[Optional[StrictStr], Field(description="Name of entity to search.")] = None,
step_ids: Annotated[
Optional[StrictStr], Field(description="Comma-separated list of step IDs to filter metrics by.")
] = None,
page_size: Annotated[Optional[StrictStr], Field(description="Number of entities in each page.")] = None,
order_by: Annotated[
Optional[OrderByField], Field(description="Specifies the order by criteria for listing entities.")
] = None,
sort_order: Annotated[
Optional[SortOrder], Field(description="Specifies the sort order for listing entities, defaults to ASC.")
] = None,
next_page_token: Annotated[
Optional[StrictStr], Field(description="Token to use to retrieve next page of results.")
] = None,
_request_timeout: Union[
None,
Annotated[StrictFloat, Field(gt=0)],
tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
] = None,
_request_auth: Optional[dict[StrictStr, Any]] = None,
_content_type: Optional[StrictStr] = None,
_headers: Optional[dict[StrictStr, Any]] = None,
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
) -> ApiResponse[MetricList]:
r"""Get metric history for multiple ExperimentRuns.
Gets the metric history for multiple `ExperimentRun` entities with optional filtering by metric name, step IDs, and experiment run IDs.
:param filter_query: A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=` - Pattern matching: `LIKE`, `ILIKE` (case-insensitive) - Set membership: `IN` - Logical: `AND`, `OR` - Grouping: `()` for complex expressions **Data Types:** - Strings: `\"value\"` or `'value'` - Numbers: `42`, `3.14`, `1e-5` - Booleans: `true`, `false` (case-insensitive) **Property Access:** - Standard properties: `name`, `id`, `state`, `createTimeSinceEpoch` - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: `` `custom-property` `` - Type-specific access: `property.string_value`, `property.double_value`, `property.int_value`, `property.bool_value` **Examples:** - Basic: `name = \"my-model\"` - Comparison: `accuracy > 0.95` - Pattern: `name LIKE \"%tensorflow%\"` - Complex: `(name = \"model-a\" OR name = \"model-b\") AND state = \"LIVE\"` - Custom property: `framework.string_value = \"pytorch\"` - Escaped property: `` `mlflow.source.type` = \"notebook\" ``
:type filter_query: str
:param name: Name of entity to search.
:type name: str
:param step_ids: Comma-separated list of step IDs to filter metrics by.
:type step_ids: str
:param page_size: Number of entities in each page.
:type page_size: str
:param order_by: Specifies the order by criteria for listing entities.
:type order_by: OrderByField
:param sort_order: Specifies the sort order for listing entities, defaults to ASC.
:type sort_order: SortOrder
:param next_page_token: Token to use to retrieve next page of results.
:type next_page_token: str
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:type _request_timeout: int, tuple(int, int), optional
:param _request_auth: set to override the auth_settings for an a single
request; this effectively ignores the
authentication in the spec for a single request.
:type _request_auth: dict, optional
:param _content_type: force content-type for the request.
:type _content_type: str, Optional
:param _headers: set to override the headers for a single
request; this effectively ignores the headers
in the spec for a single request.
:type _headers: dict, optional
:param _host_index: set to override the host_index for a single
request; this effectively ignores the host_index
in the spec for a single request.
:type _host_index: int, optional
:return: Returns the result object.
""" # noqa: E501
_param = self._get_experiment_runs_metric_history_serialize(
filter_query=filter_query,
name=name,
step_ids=step_ids,
page_size=page_size,
order_by=order_by,
sort_order=sort_order,
next_page_token=next_page_token,
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index,
)
_response_types_map: dict[str, Optional[str]] = {
"200": "MetricList",
"401": "Error",
"404": "Error",
"500": "Error",
"503": "Error",
}
response_data = await self.api_client.call_api(*_param, _request_timeout=_request_timeout)
await response_data.read()
return self.api_client.response_deserialize(
response_data=response_data,
response_types_map=_response_types_map,
)
@validate_call
async def get_experiment_runs_metric_history_without_preload_content(
self,
filter_query: Annotated[
Optional[StrictStr],
Field(
description='A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=` - Pattern matching: `LIKE`, `ILIKE` (case-insensitive) - Set membership: `IN` - Logical: `AND`, `OR` - Grouping: `()` for complex expressions **Data Types:** - Strings: `"value"` or `\'value\'` - Numbers: `42`, `3.14`, `1e-5` - Booleans: `true`, `false` (case-insensitive) **Property Access:** - Standard properties: `name`, `id`, `state`, `createTimeSinceEpoch` - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: `` `custom-property` `` - Type-specific access: `property.string_value`, `property.double_value`, `property.int_value`, `property.bool_value` **Examples:** - Basic: `name = "my-model"` - Comparison: `accuracy > 0.95` - Pattern: `name LIKE "%tensorflow%"` - Complex: `(name = "model-a" OR name = "model-b") AND state = "LIVE"` - Custom property: `framework.string_value = "pytorch"` - Escaped property: `` `mlflow.source.type` = "notebook" `` '
),
] = None,
name: Annotated[Optional[StrictStr], Field(description="Name of entity to search.")] = None,
step_ids: Annotated[
Optional[StrictStr], Field(description="Comma-separated list of step IDs to filter metrics by.")
] = None,
page_size: Annotated[Optional[StrictStr], Field(description="Number of entities in each page.")] = None,
order_by: Annotated[
Optional[OrderByField], Field(description="Specifies the order by criteria for listing entities.")
] = None,
sort_order: Annotated[
Optional[SortOrder], Field(description="Specifies the sort order for listing entities, defaults to ASC.")
] = None,
next_page_token: Annotated[
Optional[StrictStr], Field(description="Token to use to retrieve next page of results.")
] = None,
_request_timeout: Union[
None,
Annotated[StrictFloat, Field(gt=0)],
tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
] = None,
_request_auth: Optional[dict[StrictStr, Any]] = None,
_content_type: Optional[StrictStr] = None,
_headers: Optional[dict[StrictStr, Any]] = None,
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
) -> RESTResponseType:
r"""Get metric history for multiple ExperimentRuns.
Gets the metric history for multiple `ExperimentRun` entities with optional filtering by metric name, step IDs, and experiment run IDs.
:param filter_query: A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=` - Pattern matching: `LIKE`, `ILIKE` (case-insensitive) - Set membership: `IN` - Logical: `AND`, `OR` - Grouping: `()` for complex expressions **Data Types:** - Strings: `\"value\"` or `'value'` - Numbers: `42`, `3.14`, `1e-5` - Booleans: `true`, `false` (case-insensitive) **Property Access:** - Standard properties: `name`, `id`, `state`, `createTimeSinceEpoch` - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: `` `custom-property` `` - Type-specific access: `property.string_value`, `property.double_value`, `property.int_value`, `property.bool_value` **Examples:** - Basic: `name = \"my-model\"` - Comparison: `accuracy > 0.95` - Pattern: `name LIKE \"%tensorflow%\"` - Complex: `(name = \"model-a\" OR name = \"model-b\") AND state = \"LIVE\"` - Custom property: `framework.string_value = \"pytorch\"` - Escaped property: `` `mlflow.source.type` = \"notebook\" ``
:type filter_query: str
:param name: Name of entity to search.
:type name: str
:param step_ids: Comma-separated list of step IDs to filter metrics by.
:type step_ids: str
:param page_size: Number of entities in each page.
:type page_size: str
:param order_by: Specifies the order by criteria for listing entities.
:type order_by: OrderByField
:param sort_order: Specifies the sort order for listing entities, defaults to ASC.
:type sort_order: SortOrder
:param next_page_token: Token to use to retrieve next page of results.
:type next_page_token: str
:param _request_timeout: timeout setting for this request. If one
number provided, it will be total request
timeout. It can also be a pair (tuple) of
(connection, read) timeouts.
:type _request_timeout: int, tuple(int, int), optional
:param _request_auth: set to override the auth_settings for an a single
request; this effectively ignores the
authentication in the spec for a single request.
:type _request_auth: dict, optional
:param _content_type: force content-type for the request.
:type _content_type: str, Optional
:param _headers: set to override the headers for a single
request; this effectively ignores the headers
in the spec for a single request.
:type _headers: dict, optional
:param _host_index: set to override the host_index for a single
request; this effectively ignores the host_index
in the spec for a single request.
:type _host_index: int, optional
:return: Returns the result object.
""" # noqa: E501
_param = self._get_experiment_runs_metric_history_serialize(
filter_query=filter_query,
name=name,
step_ids=step_ids,
page_size=page_size,
order_by=order_by,
sort_order=sort_order,
next_page_token=next_page_token,
_request_auth=_request_auth,
_content_type=_content_type,
_headers=_headers,
_host_index=_host_index,
)
_response_types_map: dict[str, Optional[str]] = {
"200": "MetricList",
"401": "Error",
"404": "Error",
"500": "Error",
"503": "Error",
}
response_data = await self.api_client.call_api(*_param, _request_timeout=_request_timeout)
return response_data.response
def _get_experiment_runs_metric_history_serialize(
self,
filter_query,
name,
step_ids,
page_size,
order_by,
sort_order,
next_page_token,
_request_auth,
_content_type,
_headers,
_host_index,
) -> RequestSerialized:
_host = None
_collection_formats: dict[str, str] = {}
_path_params: dict[str, str] = {}
_query_params: list[tuple[str, str]] = []
_header_params: dict[str, Optional[str]] = _headers or {}
_form_params: list[tuple[str, str]] = []
_files: dict[str, Union[str, bytes]] = {}
_body_params: Optional[bytes] = None
# process the path parameters
# process the query parameters
if filter_query is not None:
_query_params.append(("filterQuery", filter_query))
if name is not None:
_query_params.append(("name", name))
if step_ids is not None:
_query_params.append(("stepIds", step_ids))
if page_size is not None:
_query_params.append(("pageSize", page_size))
if order_by is not None:
_query_params.append(("orderBy", order_by.value))
if sort_order is not None:
_query_params.append(("sortOrder", sort_order.value))
if next_page_token is not None:
_query_params.append(("nextPageToken", next_page_token))
# process the header parameters
# process the form parameters
# process the body parameter
# set the HTTP header `Accept`
_header_params["Accept"] = self.api_client.select_header_accept(["application/json"])
# authentication setting
_auth_settings: list[str] = ["Bearer"]
return self.api_client.param_serialize(
method="GET",
resource_path="/api/model_registry/v1alpha3/experiment_runs/metric_history",
path_params=_path_params,
query_params=_query_params,
header_params=_header_params,
body=_body_params,
post_params=_form_params,
files=_files,
auth_settings=_auth_settings,
collection_formats=_collection_formats,
_host=_host,
_request_auth=_request_auth,
)
@validate_call
async def get_experiments(
self,

View File

@ -239,22 +239,24 @@ func (b *ModelRegistryService) GetExperimentRunArtifacts(artifactType openapi.Ar
func (b *ModelRegistryService) GetExperimentRunMetricHistory(name *string, stepIds *string, listOptions api.ListOptions, experimentRunId *string) (*openapi.MetricList, error) {
// Validate experiment run exists
if experimentRunId == nil {
return nil, fmt.Errorf("experiment run ID is required: %w", api.ErrBadRequest)
}
var experimentRunIdInt32Ptr *int32
// Validate experiment run exists
_, err := b.GetExperimentRunById(*experimentRunId)
if err != nil {
return nil, fmt.Errorf("experiment run not found: %w", err)
}
// If experimentRunId is provided, validate it exists and convert to int32
if experimentRunId != nil {
// Validate experiment run exists
_, err := b.GetExperimentRunById(*experimentRunId)
if err != nil {
return nil, fmt.Errorf("experiment run not found: %w", err)
}
// Convert experiment run ID to int32 for repository queries
experimentRunIdInt32, err := apiutils.ValidateIDAsInt32(*experimentRunId, "experiment run")
if err != nil {
return nil, err
// Convert experiment run ID to int32 for repository queries
experimentRunIdInt32, err := apiutils.ValidateIDAsInt32(*experimentRunId, "experiment run")
if err != nil {
return nil, err
}
experimentRunIdInt32Ptr = &experimentRunIdInt32
}
// If experimentRunId is nil, experimentRunIdInt32Ptr remains nil for bulk query
listOptsCopy := models.MetricHistoryListOptions{
Pagination: models.Pagination{
@ -264,7 +266,7 @@ func (b *ModelRegistryService) GetExperimentRunMetricHistory(name *string, stepI
NextPageToken: listOptions.NextPageToken,
FilterQuery: listOptions.FilterQuery,
},
ExperimentRunID: &experimentRunIdInt32,
ExperimentRunID: experimentRunIdInt32Ptr,
}
// Add name filter if provided
@ -354,6 +356,17 @@ func (b *ModelRegistryService) InsertMetricHistory(metric *openapi.Metric, exper
// Clear the external ID to avoid duplicate key error
metricHistory.ExternalId = nil
// Set experiment properties on the metric before converting
// This ensures the experiment context is available as custom properties for the converter
experimentRun, err := b.GetExperimentRunById(experimentRunId)
if err != nil {
return fmt.Errorf("failed to get experiment run: %w", err)
}
// Create a temporary artifact to use the existing helper function
tempArtifact := &openapi.Artifact{Metric: &metricHistory}
b.setExperimentPropertiesOnArtifact(tempArtifact, experimentRun.ExperimentId, experimentRunId)
// Create the MetricHistory entity with the correct TypeID
// Get the metric history type ID from the types map
metricHistoryTypeID, exists := b.typesMap[defaults.MetricHistoryTypeName]
@ -373,15 +386,15 @@ func (b *ModelRegistryService) InsertMetricHistory(metric *openapi.Metric, exper
}
// Map properties from metric to metric history using the converter
metricProperties, err := converter.MapMetricPropertiesEmbedMD(metric)
metricProperties, err := converter.MapMetricPropertiesEmbedMD(&metricHistory)
if err != nil {
return fmt.Errorf("failed to map metric properties: %w", err)
}
metricHistoryEntity.Properties = metricProperties
// Handle custom properties using the converter
if metric.CustomProperties != nil {
customProps, err := converter.MapOpenAPICustomPropertiesEmbedMD(metric.CustomProperties)
// Handle custom properties using the converter - use the updated custom properties from tempArtifact
if tempArtifact.Metric.CustomProperties != nil {
customProps, err := converter.MapOpenAPICustomPropertiesEmbedMD(tempArtifact.Metric.CustomProperties)
if err != nil {
return fmt.Errorf("failed to map custom properties: %w", err)
}

View File

@ -381,18 +381,23 @@ func TestGetExperimentRunMetricHistoryWithPagination(t *testing.T) {
assert.Equal(t, pageSize, result.PageSize, "should have correct page size")
}
func TestGetExperimentRunMetricHistoryBulkQuery(t *testing.T) {
service, cleanup := SetupModelRegistryService(t)
defer cleanup()
// Test with nil experiment run ID should work (bulk query)
result, err := service.GetExperimentRunMetricHistory(nil, nil, api.ListOptions{}, nil)
assert.NoError(t, err, "should not return error for nil experiment run ID (bulk query)")
assert.NotNil(t, result, "should return result for bulk query")
}
func TestGetExperimentRunMetricHistoryWithInvalidExperimentRunId(t *testing.T) {
service, cleanup := SetupModelRegistryService(t)
defer cleanup()
// Test with nil experiment run ID
_, err := service.GetExperimentRunMetricHistory(nil, nil, api.ListOptions{}, nil)
assert.Error(t, err, "should return error for nil experiment run ID")
assert.Contains(t, err.Error(), "experiment run ID is required")
// Test with non-existent experiment run ID
nonExistentId := "999999"
_, err = service.GetExperimentRunMetricHistory(nil, nil, api.ListOptions{}, &nonExistentId)
_, err := service.GetExperimentRunMetricHistory(nil, nil, api.ListOptions{}, &nonExistentId)
assert.Error(t, err, "should return error for non-existent experiment run ID")
assert.Contains(t, err.Error(), "experiment run not found")
}
@ -603,6 +608,137 @@ func TestGetExperimentRunMetricHistoryWithStepIdsFilter(t *testing.T) {
}
}
func TestGetExperimentRunsMetricHistoryBulk(t *testing.T) {
service, cleanup := SetupModelRegistryService(t)
defer cleanup()
// Create experiment
experiment := &openapi.Experiment{
Name: "test-experiment-bulk",
Description: apiutils.Of("Test experiment for bulk metric history"),
}
savedExperiment, err := service.UpsertExperiment(experiment)
require.NoError(t, err)
// Create two experiment runs
experimentRun1 := &openapi.ExperimentRun{
Name: apiutils.Of("test-experiment-run-1"),
Description: apiutils.Of("Test experiment run 1 for bulk metric history"),
}
savedExperimentRun1, err := service.UpsertExperimentRun(experimentRun1, savedExperiment.Id)
require.NoError(t, err)
experimentRun2 := &openapi.ExperimentRun{
Name: apiutils.Of("test-experiment-run-2"),
Description: apiutils.Of("Test experiment run 2 for bulk metric history"),
}
savedExperimentRun2, err := service.UpsertExperimentRun(experimentRun2, savedExperiment.Id)
require.NoError(t, err)
// Create metrics for first experiment run
metric1Run1 := &openapi.Metric{
Name: apiutils.Of("accuracy"),
Value: apiutils.Of(0.85),
Timestamp: apiutils.Of("1234567890"),
Step: apiutils.Of(int64(1)),
}
metric2Run1 := &openapi.Metric{
Name: apiutils.Of("loss"),
Value: apiutils.Of(0.15),
Timestamp: apiutils.Of("1234567891"),
Step: apiutils.Of(int64(1)),
}
// Create metrics for second experiment run
metric1Run2 := &openapi.Metric{
Name: apiutils.Of("accuracy"),
Value: apiutils.Of(0.90),
Timestamp: apiutils.Of("1234567892"),
Step: apiutils.Of(int64(2)),
}
metric2Run2 := &openapi.Metric{
Name: apiutils.Of("loss"),
Value: apiutils.Of(0.10),
Timestamp: apiutils.Of("1234567893"),
Step: apiutils.Of(int64(2)),
}
// Insert metric history for both runs
err = service.InsertMetricHistory(metric1Run1, *savedExperimentRun1.Id)
require.NoError(t, err, "error inserting metric 1 for run 1")
err = service.InsertMetricHistory(metric2Run1, *savedExperimentRun1.Id)
require.NoError(t, err, "error inserting metric 2 for run 1")
err = service.InsertMetricHistory(metric1Run2, *savedExperimentRun2.Id)
require.NoError(t, err, "error inserting metric 1 for run 2")
err = service.InsertMetricHistory(metric2Run2, *savedExperimentRun2.Id)
require.NoError(t, err, "error inserting metric 2 for run 2")
// Test getting all metric history for all experiment runs (bulk endpoint)
result, err := service.GetExperimentRunMetricHistory(nil, nil, api.ListOptions{}, nil)
require.NoError(t, err, "error getting bulk metric history")
assert.GreaterOrEqual(t, int(result.Size), 4, "should return at least 4 metric history records")
assert.GreaterOrEqual(t, len(result.Items), 4, "should have at least 4 items in the result")
// Debug: print information about returned metrics
t.Logf("Found %d total metrics in bulk query", len(result.Items))
for i, item := range result.Items {
nameStr := "<nil>"
if item.Name != nil {
nameStr = *item.Name
}
expRunIdStr := "<nil>"
if item.ExperimentRunId != nil {
expRunIdStr = *item.ExperimentRunId
}
expIdStr := "<nil>"
if item.ExperimentId != nil {
expIdStr = *item.ExperimentId
}
t.Logf("Metric %d: name=%s, experimentRunId=%s, experimentId=%s",
i, nameStr, expRunIdStr, expIdStr)
}
// Verify we have metrics from both experiment runs
run1MetricsFound := 0
run2MetricsFound := 0
for _, item := range result.Items {
// For metrics we inserted, experiment fields should be populated
// But bulk query might return other metrics too, so we only check our specific ones
if item.ExperimentRunId != nil {
switch *item.ExperimentRunId {
case *savedExperimentRun1.Id:
run1MetricsFound++
// Verify experiment fields are populated for our metrics
assert.Equal(t, savedExperiment.Id, item.ExperimentId, "experimentId should be populated for run 1 metrics")
case *savedExperimentRun2.Id:
run2MetricsFound++
// Verify experiment fields are populated for our metrics
assert.Equal(t, savedExperiment.Id, item.ExperimentId, "experimentId should be populated for run 2 metrics")
}
}
}
assert.GreaterOrEqual(t, run1MetricsFound, 2, "should find at least 2 metrics from experiment run 1")
assert.GreaterOrEqual(t, run2MetricsFound, 2, "should find at least 2 metrics from experiment run 2")
// Test filtering by name in bulk mode
accuracyName := "accuracy"
result, err = service.GetExperimentRunMetricHistory(&accuracyName, nil, api.ListOptions{}, nil)
require.NoError(t, err, "error getting bulk metric history with name filter")
assert.GreaterOrEqual(t, int(result.Size), 2, "should return at least 2 accuracy metrics")
for _, item := range result.Items {
assert.Equal(t, "accuracy", *item.Name, "all returned metrics should be accuracy metrics")
}
// Test filtering by step IDs in bulk mode
stepIds := "1"
result, err = service.GetExperimentRunMetricHistory(nil, &stepIds, api.ListOptions{}, nil)
require.NoError(t, err, "error getting bulk metric history with step filter")
assert.GreaterOrEqual(t, int(result.Size), 2, "should return at least 2 metrics from step 1")
for _, item := range result.Items {
assert.Equal(t, int64(1), *item.Step, "all returned metrics should be from step 1")
}
}
func TestGetExperimentRunMetricHistoryExperimentFields(t *testing.T) {
service, cleanup := SetupModelRegistryService(t)
defer cleanup()

View File

@ -1,5 +1,7 @@
package models
import "github.com/kubeflow/model-registry/internal/db/filter"
const MetricHistoryType = "metric-history"
type MetricHistoryListOptions struct {
@ -10,6 +12,11 @@ type MetricHistoryListOptions struct {
StepIds *string
}
// GetRestEntityType implements the FilterApplier interface
func (m *MetricHistoryListOptions) GetRestEntityType() filter.RestEntityType {
return filter.RestEntityMetric // Metric history uses the same filtering rules as metrics
}
type MetricHistoryAttributes struct {
Name *string
URI *string

View File

@ -48,13 +48,14 @@ func applyMetricHistoryListFilters(query *gorm.DB, listOptions *models.MetricHis
query = query.Where("Artifact.external_id = ?", listOptions.ExternalID)
}
// Add step IDs filter if provided
// Add step IDs filter if provided - use unique alias to avoid conflicts with filterQuery joins
if listOptions.StepIds != nil && *listOptions.StepIds != "" {
query = query.Joins("JOIN ArtifactProperty ON ArtifactProperty.artifact_id = Artifact.id").
Where("ArtifactProperty.name = ? AND ArtifactProperty.int_value IN (?)",
query = query.Joins("JOIN ArtifactProperty AS step_props ON step_props.artifact_id = Artifact.id").
Where("step_props.name = ? AND step_props.int_value IN (?)",
"step", strings.Split(*listOptions.StepIds, ","))
}
// Join with Attribution table only when filtering by experiment run ID
if listOptions.ExperimentRunID != nil {
query = query.Joins("JOIN Attribution ON Attribution.artifact_id = Artifact.id").
Where("Attribution.context_id = ?", listOptions.ExperimentRunID)

View File

@ -50,6 +50,7 @@ type ModelRegistryServiceAPIRouter interface {
GetExperimentRunArtifacts(http.ResponseWriter, *http.Request)
GetExperimentRunMetricHistory(http.ResponseWriter, *http.Request)
GetExperimentRuns(http.ResponseWriter, *http.Request)
GetExperimentRunsMetricHistory(http.ResponseWriter, *http.Request)
GetExperiments(http.ResponseWriter, *http.Request)
GetInferenceService(http.ResponseWriter, *http.Request)
GetInferenceServiceModel(http.ResponseWriter, *http.Request)
@ -112,6 +113,7 @@ type ModelRegistryServiceAPIServicer interface {
GetExperimentRunArtifacts(context.Context, string, string, string, string, model.ArtifactTypeQueryParam, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
GetExperimentRunMetricHistory(context.Context, string, string, string, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
GetExperimentRuns(context.Context, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
GetExperimentRunsMetricHistory(context.Context, string, string, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
GetExperiments(context.Context, string, string, model.OrderByField, model.SortOrder, string) (ImplResponse, error)
GetInferenceService(context.Context, string) (ImplResponse, error)
GetInferenceServiceModel(context.Context, string) (ImplResponse, error)

View File

@ -198,6 +198,11 @@ func (c *ModelRegistryServiceAPIController) Routes() Routes {
"/api/model_registry/v1alpha3/experiment_runs",
c.GetExperimentRuns,
},
"GetExperimentRunsMetricHistory": Route{
strings.ToUpper("Get"),
"/api/model_registry/v1alpha3/experiment_runs/metric_history",
c.GetExperimentRunsMetricHistory,
},
"GetExperiments": Route{
strings.ToUpper("Get"),
"/api/model_registry/v1alpha3/experiments",
@ -945,6 +950,26 @@ func (c *ModelRegistryServiceAPIController) GetExperimentRuns(w http.ResponseWri
EncodeJSONResponse(result.Body, &result.Code, w)
}
// GetExperimentRunsMetricHistory - Get metric history for multiple ExperimentRuns
func (c *ModelRegistryServiceAPIController) GetExperimentRunsMetricHistory(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
filterQueryParam := query.Get("filterQuery")
nameParam := query.Get("name")
stepIdsParam := query.Get("stepIds")
pageSizeParam := query.Get("pageSize")
orderByParam := query.Get("orderBy")
sortOrderParam := query.Get("sortOrder")
nextPageTokenParam := query.Get("nextPageToken")
result, err := c.service.GetExperimentRunsMetricHistory(r.Context(), filterQueryParam, nameParam, stepIdsParam, pageSizeParam, model.OrderByField(orderByParam), model.SortOrder(sortOrderParam), nextPageTokenParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
// If no error, encode the body and the result code
EncodeJSONResponse(result.Body, &result.Code, w)
}
// GetExperiments - List All Experiments
func (c *ModelRegistryServiceAPIController) GetExperiments(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()

View File

@ -791,6 +791,19 @@ func (s *ModelRegistryServiceAPIService) UpsertExperimentRunArtifact(ctx context
// GetExperimentRunMetricHistory - Get metric history for an ExperimentRun
func (s *ModelRegistryServiceAPIService) GetExperimentRunMetricHistory(ctx context.Context, experimentrunId string,
filterQuery string, name string, stepIds string, pageSize string, orderBy model.OrderByField, sortOrder model.SortOrder, nextPageToken string) (ImplResponse, error) {
return s.getMetricHistoryHelper(ctx, apiutils.StrPtr(experimentrunId), filterQuery, name, stepIds, pageSize, orderBy, sortOrder, nextPageToken)
}
// GetExperimentRunsMetricHistory - Get metric history for multiple ExperimentRuns
func (s *ModelRegistryServiceAPIService) GetExperimentRunsMetricHistory(ctx context.Context,
filterQuery string, name string, stepIds string, pageSize string, orderBy model.OrderByField, sortOrder model.SortOrder, nextPageToken string) (ImplResponse, error) {
// Pass nil for experimentRunId to get metrics for all experiment runs
return s.getMetricHistoryHelper(ctx, nil, filterQuery, name, stepIds, pageSize, orderBy, sortOrder, nextPageToken)
}
// getMetricHistoryHelper handles the common logic for getting metric history
func (s *ModelRegistryServiceAPIService) getMetricHistoryHelper(ctx context.Context, experimentRunId *string,
filterQuery string, name string, stepIds string, pageSize string, orderBy model.OrderByField, sortOrder model.SortOrder, nextPageToken string) (ImplResponse, error) {
listOpts, err := s.buildListOption(filterQuery, pageSize, orderBy, sortOrder, nextPageToken)
if err != nil {
@ -807,7 +820,7 @@ func (s *ModelRegistryServiceAPIService) GetExperimentRunMetricHistory(ctx conte
stepIdsPtr = &stepIds
}
result, err := s.coreApi.GetExperimentRunMetricHistory(namePtr, stepIdsPtr, listOpts, apiutils.StrPtr(experimentrunId))
result, err := s.coreApi.GetExperimentRunMetricHistory(namePtr, stepIdsPtr, listOpts, experimentRunId)
if err != nil {
return ErrorResponse(api.ErrToStatus(err), err), err
}

View File

@ -5229,6 +5229,219 @@ func (a *ModelRegistryServiceAPIService) GetExperimentRunsExecute(r ApiGetExperi
return localVarReturnValue, localVarHTTPResponse, nil
}
type ApiGetExperimentRunsMetricHistoryRequest struct {
ctx context.Context
ApiService *ModelRegistryServiceAPIService
filterQuery *string
name *string
stepIds *string
pageSize *string
orderBy *OrderByField
sortOrder *SortOrder
nextPageToken *string
}
// A SQL-like query string to filter the list of entities. The query supports rich filtering capabilities with automatic type inference. **Supported Operators:** - Comparison: &#x60;&#x3D;&#x60;, &#x60;!&#x3D;&#x60;, &#x60;&lt;&gt;&#x60;, &#x60;&gt;&#x60;, &#x60;&lt;&#x60;, &#x60;&gt;&#x3D;&#x60;, &#x60;&lt;&#x3D;&#x60; - Pattern matching: &#x60;LIKE&#x60;, &#x60;ILIKE&#x60; (case-insensitive) - Set membership: &#x60;IN&#x60; - Logical: &#x60;AND&#x60;, &#x60;OR&#x60; - Grouping: &#x60;()&#x60; for complex expressions **Data Types:** - Strings: &#x60;\&quot;value\&quot;&#x60; or &#x60;&#39;value&#39;&#x60; - Numbers: &#x60;42&#x60;, &#x60;3.14&#x60;, &#x60;1e-5&#x60; - Booleans: &#x60;true&#x60;, &#x60;false&#x60; (case-insensitive) **Property Access:** - Standard properties: &#x60;name&#x60;, &#x60;id&#x60;, &#x60;state&#x60;, &#x60;createTimeSinceEpoch&#x60; - Custom properties: Any user-defined property name - Escaped properties: Use backticks for special characters: &#x60;&#x60; &#x60;custom-property&#x60; &#x60;&#x60; - Type-specific access: &#x60;property.string_value&#x60;, &#x60;property.double_value&#x60;, &#x60;property.int_value&#x60;, &#x60;property.bool_value&#x60; **Examples:** - Basic: &#x60;name &#x3D; \&quot;my-model\&quot;&#x60; - Comparison: &#x60;accuracy &gt; 0.95&#x60; - Pattern: &#x60;name LIKE \&quot;%tensorflow%\&quot;&#x60; - Complex: &#x60;(name &#x3D; \&quot;model-a\&quot; OR name &#x3D; \&quot;model-b\&quot;) AND state &#x3D; \&quot;LIVE\&quot;&#x60; - Custom property: &#x60;framework.string_value &#x3D; \&quot;pytorch\&quot;&#x60; - Escaped property: &#x60;&#x60; &#x60;mlflow.source.type&#x60; &#x3D; \&quot;notebook\&quot; &#x60;&#x60;
func (r ApiGetExperimentRunsMetricHistoryRequest) FilterQuery(filterQuery string) ApiGetExperimentRunsMetricHistoryRequest {
r.filterQuery = &filterQuery
return r
}
// Name of entity to search.
func (r ApiGetExperimentRunsMetricHistoryRequest) Name(name string) ApiGetExperimentRunsMetricHistoryRequest {
r.name = &name
return r
}
// Comma-separated list of step IDs to filter metrics by.
func (r ApiGetExperimentRunsMetricHistoryRequest) StepIds(stepIds string) ApiGetExperimentRunsMetricHistoryRequest {
r.stepIds = &stepIds
return r
}
// Number of entities in each page.
func (r ApiGetExperimentRunsMetricHistoryRequest) PageSize(pageSize string) ApiGetExperimentRunsMetricHistoryRequest {
r.pageSize = &pageSize
return r
}
// Specifies the order by criteria for listing entities.
func (r ApiGetExperimentRunsMetricHistoryRequest) OrderBy(orderBy OrderByField) ApiGetExperimentRunsMetricHistoryRequest {
r.orderBy = &orderBy
return r
}
// Specifies the sort order for listing entities, defaults to ASC.
func (r ApiGetExperimentRunsMetricHistoryRequest) SortOrder(sortOrder SortOrder) ApiGetExperimentRunsMetricHistoryRequest {
r.sortOrder = &sortOrder
return r
}
// Token to use to retrieve next page of results.
func (r ApiGetExperimentRunsMetricHistoryRequest) NextPageToken(nextPageToken string) ApiGetExperimentRunsMetricHistoryRequest {
r.nextPageToken = &nextPageToken
return r
}
func (r ApiGetExperimentRunsMetricHistoryRequest) Execute() (*MetricList, *http.Response, error) {
return r.ApiService.GetExperimentRunsMetricHistoryExecute(r)
}
/*
GetExperimentRunsMetricHistory Get metric history for multiple ExperimentRuns
Gets the metric history for multiple `ExperimentRun` entities with optional filtering by metric name, step IDs, and experiment run IDs.
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
@return ApiGetExperimentRunsMetricHistoryRequest
*/
func (a *ModelRegistryServiceAPIService) GetExperimentRunsMetricHistory(ctx context.Context) ApiGetExperimentRunsMetricHistoryRequest {
return ApiGetExperimentRunsMetricHistoryRequest{
ApiService: a,
ctx: ctx,
}
}
// Execute executes the request
//
// @return MetricList
func (a *ModelRegistryServiceAPIService) GetExperimentRunsMetricHistoryExecute(r ApiGetExperimentRunsMetricHistoryRequest) (*MetricList, *http.Response, error) {
var (
localVarHTTPMethod = http.MethodGet
localVarPostBody interface{}
formFiles []formFile
localVarReturnValue *MetricList
)
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ModelRegistryServiceAPIService.GetExperimentRunsMetricHistory")
if err != nil {
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
}
localVarPath := localBasePath + "/api/model_registry/v1alpha3/experiment_runs/metric_history"
localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
localVarFormParams := url.Values{}
if r.filterQuery != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "filterQuery", r.filterQuery, "")
}
if r.name != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "name", r.name, "")
}
if r.stepIds != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "stepIds", r.stepIds, "")
}
if r.pageSize != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "pageSize", r.pageSize, "")
}
if r.orderBy != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "orderBy", r.orderBy, "")
}
if r.sortOrder != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "sortOrder", r.sortOrder, "")
}
if r.nextPageToken != nil {
parameterAddToHeaderOrQuery(localVarQueryParams, "nextPageToken", r.nextPageToken, "")
}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{}
// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}
// to determine the Accept header
localVarHTTPHeaderAccepts := []string{"application/json"}
// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
if err != nil {
return localVarReturnValue, nil, err
}
localVarHTTPResponse, err := a.client.callAPI(req)
if err != nil || localVarHTTPResponse == nil {
return localVarReturnValue, localVarHTTPResponse, err
}
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
localVarHTTPResponse.Body.Close()
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
if err != nil {
return localVarReturnValue, localVarHTTPResponse, err
}
if localVarHTTPResponse.StatusCode >= 300 {
newErr := &GenericOpenAPIError{
body: localVarBody,
error: localVarHTTPResponse.Status,
}
if localVarHTTPResponse.StatusCode == 401 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarReturnValue, localVarHTTPResponse, newErr
}
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
newErr.model = v
return localVarReturnValue, localVarHTTPResponse, newErr
}
if localVarHTTPResponse.StatusCode == 404 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarReturnValue, localVarHTTPResponse, newErr
}
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
newErr.model = v
return localVarReturnValue, localVarHTTPResponse, newErr
}
if localVarHTTPResponse.StatusCode == 500 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarReturnValue, localVarHTTPResponse, newErr
}
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
newErr.model = v
return localVarReturnValue, localVarHTTPResponse, newErr
}
if localVarHTTPResponse.StatusCode == 503 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return localVarReturnValue, localVarHTTPResponse, newErr
}
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
newErr.model = v
}
return localVarReturnValue, localVarHTTPResponse, newErr
}
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr := &GenericOpenAPIError{
body: localVarBody,
error: err.Error(),
}
return localVarReturnValue, localVarHTTPResponse, newErr
}
return localVarReturnValue, localVarHTTPResponse, nil
}
type ApiGetExperimentsRequest struct {
ctx context.Context
ApiService *ModelRegistryServiceAPIService