From b0efb2cfc034e4e938455289fd6085cd737b2d31 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Tue, 12 May 2026 15:10:55 +0530 Subject: [PATCH 01/14] SDK operations for Models, Unit tests and Sample notebook --- .../azure-ai-projects/apiview-properties.json | 19 +- .../azure/ai/projects/_utils/utils.py | 1 + .../ai/projects/aio/operations/_operations.py | 1266 ++++++++++++++--- .../azure/ai/projects/models/__init__.py | 34 +- .../azure/ai/projects/models/_enums.py | 72 +- .../azure/ai/projects/models/_models.py | 428 +++++- .../ai/projects/operations/_operations.py | 1198 +++++++++++++++- .../azure/ai/projects/operations/_patch.py | 6 + .../ai/projects/operations/_patch_models.py | 240 ++++ sdk/ai/azure-ai-projects/pyproject.toml | 18 +- .../samples/models/sample_models.ipynb | 307 ++++ .../tests/models/test_models.py | 140 ++ .../tests/models/test_models_async.py | 97 ++ .../tests/models/test_patch_models.py | 331 +++++ sdk/ai/azure-ai-projects/tests/test_base.py | 6 + .../tests/test_data/models/config.json | 1 + .../tests/test_data/models/weights.bin | 1 + 17 files changed, 3853 insertions(+), 312 deletions(-) create mode 100644 sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py create mode 100644 sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb create mode 100644 sdk/ai/azure-ai-projects/tests/models/test_models.py create mode 100644 sdk/ai/azure-ai-projects/tests/models/test_models_async.py create mode 100644 sdk/ai/azure-ai-projects/tests/models/test_patch_models.py create mode 100644 sdk/ai/azure-ai-projects/tests/test_data/models/config.json create mode 100644 sdk/ai/azure-ai-projects/tests/test_data/models/weights.bin diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index 354cbc4b7d65..f2c8016f920e 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -32,8 +32,9 @@ "azure.ai.projects.models.ApiKeyCredentials": "Azure.AI.Projects.ApiKeyCredentials", "azure.ai.projects.models.ApplyPatchToolParam": "OpenAI.ApplyPatchToolParam", "azure.ai.projects.models.ApproximateLocation": "OpenAI.ApproximateLocation", + "azure.ai.projects.models.ArtifactProfile": "Azure.AI.Projects.ArtifactProfile", "azure.ai.projects.models.AutoCodeInterpreterToolParam": "OpenAI.AutoCodeInterpreterToolParam", - "azure.ai.projects.models.Target": "Azure.AI.Projects.Target", + "azure.ai.projects.models.EvaluationTarget": "Azure.AI.Projects.Target", "azure.ai.projects.models.AzureAIAgentTarget": "Azure.AI.Projects.AzureAIAgentTarget", "azure.ai.projects.models.AzureAIModelTarget": "Azure.AI.Projects.AzureAIModelTarget", "azure.ai.projects.models.Index": "Azure.AI.Projects.Index", @@ -45,7 +46,7 @@ "azure.ai.projects.models.AzureFunctionDefinitionFunction": "Azure.AI.Projects.AzureFunctionDefinition.function.anonymous", "azure.ai.projects.models.AzureFunctionStorageQueue": "Azure.AI.Projects.AzureFunctionStorageQueue", "azure.ai.projects.models.AzureFunctionTool": "Azure.AI.Projects.AzureFunctionTool", - "azure.ai.projects.models.TargetConfig": "Azure.AI.Projects.TargetConfig", + "azure.ai.projects.models.RedTeamTargetConfig": "Azure.AI.Projects.RedTeamTargetConfig", "azure.ai.projects.models.AzureOpenAIModelConfiguration": "Azure.AI.Projects.AzureOpenAIModelConfiguration", "azure.ai.projects.models.BingCustomSearchConfiguration": "Azure.AI.Projects.BingCustomSearchConfiguration", "azure.ai.projects.models.BingCustomSearchPreviewTool": "Azure.AI.Projects.BingCustomSearchPreviewTool", @@ -148,6 +149,7 @@ "azure.ai.projects.models.VersionSelectionRule": "Azure.AI.Projects.VersionSelectionRule", "azure.ai.projects.models.FixedRatioVersionSelectionRule": "Azure.AI.Projects.FixedRatioVersionSelectionRule", "azure.ai.projects.models.FolderDatasetVersion": "Azure.AI.Projects.FolderDatasetVersion", + "azure.ai.projects.models.FoundryModelWarning": "Azure.AI.Projects.FoundryModelWarning", "azure.ai.projects.models.FunctionShellToolParam": "OpenAI.FunctionShellToolParam", "azure.ai.projects.models.FunctionShellToolParamEnvironmentContainerReferenceParam": "OpenAI.FunctionShellToolParamEnvironmentContainerReferenceParam", "azure.ai.projects.models.FunctionShellToolParamEnvironmentLocalEnvironmentParam": "OpenAI.FunctionShellToolParamEnvironmentLocalEnvironmentParam", @@ -170,6 +172,7 @@ "azure.ai.projects.models.InsightSummary": "Azure.AI.Projects.InsightSummary", "azure.ai.projects.models.LocalShellToolParam": "OpenAI.LocalShellToolParam", "azure.ai.projects.models.LocalSkillParam": "OpenAI.LocalSkillParam", + "azure.ai.projects.models.LoraConfig": "Azure.AI.Projects.LoraConfig", "azure.ai.projects.models.ManagedAgentIdentityBlueprintReference": "Azure.AI.Projects.ManagedAgentIdentityBlueprintReference", "azure.ai.projects.models.ManagedAzureAISearchIndex": "Azure.AI.Projects.ManagedAzureAISearchIndex", "azure.ai.projects.models.MCPTool": "OpenAI.MCPTool", @@ -189,9 +192,12 @@ "azure.ai.projects.models.MemoryStoreUpdateCompletedResult": "Azure.AI.Projects.MemoryStoreUpdateCompletedResult", "azure.ai.projects.models.MemoryStoreUpdateResult": "Azure.AI.Projects.MemoryStoreUpdateResponse", "azure.ai.projects.models.MicrosoftFabricPreviewTool": "Azure.AI.Projects.MicrosoftFabricPreviewTool", + "azure.ai.projects.models.ModelCredentialRequest": "Azure.AI.Projects.ModelCredentialRequest", "azure.ai.projects.models.ModelDeployment": "Azure.AI.Projects.ModelDeployment", "azure.ai.projects.models.ModelDeploymentSku": "Azure.AI.Projects.Sku", "azure.ai.projects.models.ModelSamplingParams": "Azure.AI.Projects.ModelSamplingParams", + "azure.ai.projects.models.ModelSourceData": "Azure.AI.Projects.ModelSourceData", + "azure.ai.projects.models.ModelVersion": "Azure.AI.Projects.ModelVersion", "azure.ai.projects.models.MonthlyRecurrenceSchedule": "Azure.AI.Projects.MonthlyRecurrenceSchedule", "azure.ai.projects.models.NoAuthenticationCredentials": "Azure.AI.Projects.NoAuthenticationCredentials", "azure.ai.projects.models.OneTimeTrigger": "Azure.AI.Projects.OneTimeTrigger", @@ -240,6 +246,7 @@ "azure.ai.projects.models.SpecificFunctionShellParam": "OpenAI.SpecificFunctionShellParam", "azure.ai.projects.models.StructuredInputDefinition": "Azure.AI.Projects.StructuredInputDefinition", "azure.ai.projects.models.StructuredOutputDefinition": "Azure.AI.Projects.StructuredOutputDefinition", + "azure.ai.projects.models.SystemDataV3": "Azure.AI.Projects.SystemDataV3", "azure.ai.projects.models.TaxonomyCategory": "Azure.AI.Projects.TaxonomyCategory", "azure.ai.projects.models.TaxonomySubCategory": "Azure.AI.Projects.TaxonomySubCategory", "azure.ai.projects.models.TelemetryConfig": "Azure.AI.Projects.TelemetryConfig", @@ -267,6 +274,7 @@ "azure.ai.projects.models.TracesDataGenerationJobOptions": "Azure.AI.Projects.TracesDataGenerationJobOptions", "azure.ai.projects.models.TracesDataGenerationJobSource": "Azure.AI.Projects.TracesDataGenerationJobSource", "azure.ai.projects.models.TracesEvaluatorGenerationJobSource": "Azure.AI.Projects.TracesEvaluatorGenerationJobSource", + "azure.ai.projects.models.UpdateModelVersionRequest": "Azure.AI.Projects.UpdateModelVersionRequest", "azure.ai.projects.models.UpdateToolboxRequest": "Azure.AI.Projects.UpdateToolboxRequest", "azure.ai.projects.models.UserProfileMemoryItem": "Azure.AI.Projects.UserProfileMemoryItem", "azure.ai.projects.models.VersionIndicator": "Azure.AI.Projects.VersionIndicator", @@ -330,6 +338,12 @@ "azure.ai.projects.models.MemoryStoreKind": "Azure.AI.Projects.MemoryStoreKind", "azure.ai.projects.models.MemoryItemKind": "Azure.AI.Projects.MemoryItemKind", "azure.ai.projects.models.MemoryOperationKind": "Azure.AI.Projects.MemoryOperationKind", + "azure.ai.projects.models.FoundryModelWeightType": "Azure.AI.Projects.FoundryModelWeightType", + "azure.ai.projects.models.FoundryModelSourceType": "Azure.AI.Projects.FoundryModelSourceType", + "azure.ai.projects.models.FoundryModelArtifactProfileCategory": "Azure.AI.Projects.FoundryModelArtifactProfileCategory", + "azure.ai.projects.models.FoundryModelArtifactProfileSignal": "Azure.AI.Projects.FoundryModelArtifactProfileSignal", + "azure.ai.projects.models.FoundryModelWarningCode": "Azure.AI.Projects.FoundryModelWarningCode", + "azure.ai.projects.models.PendingUploadType": "Azure.AI.Projects.PendingUploadType", "azure.ai.projects.models.AttackStrategy": "Azure.AI.Projects.AttackStrategy", "azure.ai.projects.models.ScheduleProvisioningStatus": "Azure.AI.Projects.ScheduleProvisioningStatus", "azure.ai.projects.models.TriggerType": "Azure.AI.Projects.TriggerType", @@ -346,7 +360,6 @@ "azure.ai.projects.models.ConnectionType": "Azure.AI.Projects.ConnectionType", "azure.ai.projects.models.CredentialType": "Azure.AI.Projects.CredentialType", "azure.ai.projects.models.DatasetType": "Azure.AI.Projects.DatasetType", - "azure.ai.projects.models.PendingUploadType": "Azure.AI.Projects.PendingUploadType", "azure.ai.projects.models.DeploymentType": "Azure.AI.Projects.DeploymentType", "azure.ai.projects.models.IndexType": "Azure.AI.Projects.IndexType", "azure.ai.projects.models.MemoryStoreUpdateStatus": "Azure.AI.Projects.MemoryStoreUpdateStatus", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py index 707b7d8fac75..bd821750f4c6 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py @@ -10,6 +10,7 @@ from .._utils.model_base import Model, SdkJSONEncoder + # file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)` FileContent = Union[str, bytes, IO[str], IO[bytes]] diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index 98ac9d539ab0..8f5fcc038dcc 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -91,6 +91,14 @@ build_beta_memory_stores_search_memories_request, build_beta_memory_stores_update_memories_request, build_beta_memory_stores_update_request, + build_beta_models_create_async_request, + build_beta_models_delete_request, + build_beta_models_get_credentials_request, + build_beta_models_get_request, + build_beta_models_list_request, + build_beta_models_list_versions_request, + build_beta_models_pending_upload_request, + build_beta_models_update_request, build_beta_red_teams_create_request, build_beta_red_teams_get_request, build_beta_red_teams_list_request, @@ -170,6 +178,7 @@ def __init__(self, *args, **kwargs) -> None: self.evaluators = BetaEvaluatorsOperations(self._client, self._config, self._serialize, self._deserialize) self.insights = BetaInsightsOperations(self._client, self._config, self._serialize, self._deserialize) self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) + self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) self.red_teams = BetaRedTeamsOperations(self._client, self._config, self._serialize, self._deserialize) self.schedules = BetaSchedulesOperations(self._client, self._config, self._serialize, self._deserialize) self.toolboxes = BetaToolboxesOperations(self._client, self._config, self._serialize, self._deserialize) @@ -4005,23 +4014,29 @@ async def get_session_log_stream( Each SSE frame contains: * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) + * `data`: a plain-text log line (currently JSON-formatted, but the schema + is not contractual and may include additional keys or change format + over time — clients should treat it as an opaque string) Example SSE frames: .. code-block:: event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting + FoundryCBAgent server on port 8088"} event: log - data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application + startup complete."} event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully + connected to container"} event: log - data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since + last 60 seconds"} The stream remains open until the client disconnects or the server terminates the connection. Clients should handle reconnection as needed. @@ -4063,7 +4078,7 @@ async def get_session_log_stream( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = True + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -4524,10 +4539,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -4957,10 +4969,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -5060,10 +5069,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -6252,10 +6258,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -6923,7 +6926,7 @@ async def _search_memories( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items": items, + "items_property": items, "options": options, "previous_search_id": previous_search_id, "scope": scope, @@ -7009,7 +7012,7 @@ async def _update_memories_initial( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items": items, + "items_property": items, "previous_update_id": previous_update_id, "scope": scope, "update_delay": update_delay, @@ -7332,14 +7335,14 @@ async def delete_scope( return deserialized # type: ignore -class BetaRedTeamsOperations: +class BetaModelsOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`red_teams` attribute. + :attr:`models` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -7349,16 +7352,21 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: - """Get a redteam by name. + @distributed_trace + def list_versions(self, name: str, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: + """List all versions of the given ModelVersion. - :param name: Identifier of the red team run. Required. + :param name: The name of the resource. Required. :type name: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -7367,61 +7375,83 @@ async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + def prepare_request(next_link=None): + if not next_link: - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + _request = build_beta_models_list_versions_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_red_teams_get_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + return _request - response = pipeline_response.http_response + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ModelVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + async def get_next(next_link=None): + _request = prepare_request(next_link) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.RedTeam, response.json()) + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - return deserialized # type: ignore + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) @distributed_trace - def list(self, **kwargs: Any) -> AsyncItemPaged["_models.RedTeam"]: - """List a redteam by name. + def list(self, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: + """List the latest version of each ModelVersion. - :return: An iterator like instance of RedTeam - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.RedTeam] + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -7434,7 +7464,7 @@ def list(self, **kwargs: Any) -> AsyncItemPaged["_models.RedTeam"]: def prepare_request(next_link=None): if not next_link: - _request = build_beta_red_teams_list_request( + _request = build_beta_models_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -7457,10 +7487,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -7474,7 +7501,7 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.RedTeam], + List[_models.ModelVersion], deserialized.get("value", []), ) if cls: @@ -7498,61 +7525,17 @@ async def get_next(next_link=None): return AsyncItemPaged(get_next, extract_data) - @overload - async def create( - self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: ~azure.ai.projects.models.RedTeam - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def create( - self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace_async - async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + async def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: + """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the + ModelVersion does not exist. - :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] - Required. - :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the ModelVersion to retrieve. Required. + :type version: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7563,23 +7546,15 @@ async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwar } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(red_team, (IOBase, bytes)): - _content = red_team - else: - _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) - _request = build_beta_red_teams_create_request( - content_type=content_type, + _request = build_beta_models_get_request( + name=name, + version=version, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -7596,53 +7571,34 @@ async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwar response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RedTeam, response.json()) + deserialized = _deserialize(_models.ModelVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - -class BetaSchedulesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`schedules` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace_async - async def delete(self, schedule_id: str, **kwargs: Any) -> None: - """Delete a schedule. + async def delete(self, name: str, version: str, **kwargs: Any) -> None: + """Delete the specific version of the ModelVersion. The service returns 204 No Content if the + ModelVersion was deleted successfully or if the ModelVersion does not exist. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the ModelVersion to delete. Required. + :type version: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -7660,8 +7616,9 @@ async def delete(self, schedule_id: str, **kwargs: Any) -> None: cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_schedules_delete_request( - schedule_id=schedule_id, + _request = build_beta_models_delete_request( + name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7685,18 +7642,951 @@ async def delete(self, schedule_id: str, **kwargs: Any) -> None: if cls: return cls(pipeline_response, None, {}) # type: ignore - @distributed_trace_async - async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: - """Get a schedule by id. + @overload + async def update( + self, + name: str, + version: str, + body: _models.UpdateModelVersionRequest, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :raises ~azure.core.exceptions.HttpResponseError: """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, + + @overload + async def update( + self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update( + self, + name: str, + version: str, + body: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def update( + self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: + UpdateModelVersionRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + + content_type = content_type or "application/merge-patch+json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_update_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + async def create_async( + self, + name: str, + version: str, + body: _models.ModelVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: ~azure.ai.projects.models.ModelVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_async( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_async( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_async( + self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Is one of the following types: ModelVersion, JSON, + IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_create_async_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + response_headers = {} + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @overload + async def pending_upload( + self, + name: str, + version: str, + body: _models.PendingUploadRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.PendingUploadRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def pending_upload( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def pending_upload( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def pending_upload( + self, name: str, version: str, body: Union[_models.PendingUploadRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: PendingUploadRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.PendingUploadRequest or JSON or IO[bytes] + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.PendingUploadResult] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_pending_upload_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.PendingUploadResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + async def get_credentials( + self, + name: str, + version: str, + body: _models.ModelCredentialRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def get_credentials( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def get_credentials( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def get_credentials( + self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_get_credentials_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DatasetCredential, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +class BetaRedTeamsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`red_teams` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: + """Get a redteam by name. + + :param name: Identifier of the red team run. Required. + :type name: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + + _request = build_beta_red_teams_get_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.RedTeam, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list(self, **kwargs: Any) -> AsyncItemPaged["_models.RedTeam"]: + """List a redteam by name. + + :return: An iterator like instance of RedTeam + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.RedTeam] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_red_teams_list_request( + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.RedTeam], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + @overload + async def create( + self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.RedTeam: + """Creates a redteam run. + + :param red_team: Redteam to be run. Required. + :type red_team: ~azure.ai.projects.models.RedTeam + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. + + :param red_team: Redteam to be run. Required. + :type red_team: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create( + self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.RedTeam: + """Creates a redteam run. + + :param red_team: Redteam to be run. Required. + :type red_team: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. + + :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] + Required. + :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(red_team, (IOBase, bytes)): + _content = red_team + else: + _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_red_teams_create_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.RedTeam, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +class BetaSchedulesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`schedules` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def delete(self, schedule_id: str, **kwargs: Any) -> None: + """Delete a schedule. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_schedules_delete_request( + schedule_id=schedule_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace_async + async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: + """Get a schedule by id. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, 304: ResourceNotModifiedError, @@ -7806,10 +8696,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -8109,10 +8996,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py index 58d3839bdce5..afefa8c51f7d 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py @@ -38,6 +38,7 @@ ApiKeyCredentials, ApplyPatchToolParam, ApproximateLocation, + ArtifactProfile, AutoCodeInterpreterToolParam, AzureAIAgentTarget, AzureAIModelTarget, @@ -129,6 +130,7 @@ EvaluationRunClusterInsightRequest, EvaluationRunClusterInsightResult, EvaluationScheduleTask, + EvaluationTarget, EvaluationTaxonomy, EvaluationTaxonomyInput, EvaluatorDefinition, @@ -148,6 +150,7 @@ FileSearchTool, FixedRatioVersionSelectionRule, FolderDatasetVersion, + FoundryModelWarning, FunctionShellToolParam, FunctionShellToolParamEnvironment, FunctionShellToolParamEnvironmentContainerReferenceParam, @@ -174,6 +177,7 @@ InsightsMetadata, LocalShellToolParam, LocalSkillParam, + LoraConfig, MCPTool, MCPToolFilter, MCPToolRequireApproval, @@ -194,9 +198,12 @@ MemoryStoreUpdateCompletedResult, MemoryStoreUpdateResult, MicrosoftFabricPreviewTool, + ModelCredentialRequest, ModelDeployment, ModelDeploymentSku, ModelSamplingParams, + ModelSourceData, + ModelVersion, MonthlyRecurrenceSchedule, NoAuthenticationCredentials, OneTimeTrigger, @@ -224,6 +231,7 @@ RecurrenceSchedule, RecurrenceTrigger, RedTeam, + RedTeamTargetConfig, ResponseUsageInputTokensDetails, ResponseUsageOutputTokensDetails, RubricBasedEvaluatorDefinition, @@ -245,8 +253,7 @@ SpecificFunctionShellParam, StructuredInputDefinition, StructuredOutputDefinition, - Target, - TargetConfig, + SystemDataV3, TaxonomyCategory, TaxonomySubCategory, TelemetryConfig, @@ -279,6 +286,7 @@ TracesDataGenerationJobSource, TracesEvaluatorGenerationJobSource, Trigger, + UpdateModelVersionRequest, UpdateToolboxRequest, UserProfileMemoryItem, VersionIndicator, @@ -330,6 +338,11 @@ EvaluatorMetricDirection, EvaluatorMetricType, EvaluatorType, + FoundryModelArtifactProfileCategory, + FoundryModelArtifactProfileSignal, + FoundryModelSourceType, + FoundryModelWarningCode, + FoundryModelWeightType, FunctionShellToolParamEnvironmentType, GrammarSyntax1, ImageGenAction, @@ -396,6 +409,7 @@ "ApiKeyCredentials", "ApplyPatchToolParam", "ApproximateLocation", + "ArtifactProfile", "AutoCodeInterpreterToolParam", "AzureAIAgentTarget", "AzureAIModelTarget", @@ -487,6 +501,7 @@ "EvaluationRunClusterInsightRequest", "EvaluationRunClusterInsightResult", "EvaluationScheduleTask", + "EvaluationTarget", "EvaluationTaxonomy", "EvaluationTaxonomyInput", "EvaluatorDefinition", @@ -506,6 +521,7 @@ "FileSearchTool", "FixedRatioVersionSelectionRule", "FolderDatasetVersion", + "FoundryModelWarning", "FunctionShellToolParam", "FunctionShellToolParamEnvironment", "FunctionShellToolParamEnvironmentContainerReferenceParam", @@ -532,6 +548,7 @@ "InsightsMetadata", "LocalShellToolParam", "LocalSkillParam", + "LoraConfig", "MCPTool", "MCPToolFilter", "MCPToolRequireApproval", @@ -552,9 +569,12 @@ "MemoryStoreUpdateCompletedResult", "MemoryStoreUpdateResult", "MicrosoftFabricPreviewTool", + "ModelCredentialRequest", "ModelDeployment", "ModelDeploymentSku", "ModelSamplingParams", + "ModelSourceData", + "ModelVersion", "MonthlyRecurrenceSchedule", "NoAuthenticationCredentials", "OneTimeTrigger", @@ -582,6 +602,7 @@ "RecurrenceSchedule", "RecurrenceTrigger", "RedTeam", + "RedTeamTargetConfig", "ResponseUsageInputTokensDetails", "ResponseUsageOutputTokensDetails", "RubricBasedEvaluatorDefinition", @@ -603,8 +624,7 @@ "SpecificFunctionShellParam", "StructuredInputDefinition", "StructuredOutputDefinition", - "Target", - "TargetConfig", + "SystemDataV3", "TaxonomyCategory", "TaxonomySubCategory", "TelemetryConfig", @@ -637,6 +657,7 @@ "TracesDataGenerationJobSource", "TracesEvaluatorGenerationJobSource", "Trigger", + "UpdateModelVersionRequest", "UpdateToolboxRequest", "UserProfileMemoryItem", "VersionIndicator", @@ -685,6 +706,11 @@ "EvaluatorMetricDirection", "EvaluatorMetricType", "EvaluatorType", + "FoundryModelArtifactProfileCategory", + "FoundryModelArtifactProfileSignal", + "FoundryModelSourceType", + "FoundryModelWarningCode", + "FoundryModelWeightType", "FunctionShellToolParamEnvironmentType", "GrammarSyntax1", "ImageGenAction", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py index 40648951bbda..6ba8cea31bc6 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py @@ -1,3 +1,4 @@ +# pylint: disable=too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. @@ -71,8 +72,8 @@ class AgentEndpointProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """ACTIVITY.""" RESPONSES = "responses" """RESPONSES.""" - A2A = "a2a" - """A2A.""" + A2_A = "a2a" + """A2_A.""" INVOCATIONS = "invocations" """INVOCATIONS.""" @@ -526,6 +527,61 @@ class EvaluatorType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Custom evaluator.""" +class FoundryModelArtifactProfileCategory(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The artifact profile category.""" + + DATA_ONLY = "DataOnly" + """Data only artifacts.""" + RUNTIME_DEPENDENT = "RuntimeDependent" + """Runtime dependent artifacts.""" + UNKNOWN = "Unknown" + """Unknown category.""" + + +class FoundryModelArtifactProfileSignal(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Signals detected in the model artifact.""" + + PICKLE_DESERIALIZATION = "PickleDeserialization" + """Pickle deserialization detected.""" + CUSTOM_PYTHON_CODE = "CustomPythonCode" + """Custom Python code detected.""" + DYNAMIC_OPS = "DynamicOps" + """Dynamic operations detected.""" + NATIVE_BINARY = "NativeBinary" + """Native binary code detected.""" + UNKNOWN_FORMAT = "UnknownFormat" + """Unknown format detected.""" + + +class FoundryModelSourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The source type of the model.""" + + LOCAL_UPLOAD = "LocalUpload" + """Model was uploaded locally.""" + TRAINING_JOB = "TrainingJob" + """Model was produced by a training job.""" + + +class FoundryModelWarningCode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Warning code for model artifacts.""" + + RUNTIME_DEPENDENT_ARTIFACT = "RuntimeDependentArtifact" + """Runtime dependent artifact warning.""" + UNCLASSIFIED_ARTIFACT = "UnclassifiedArtifact" + """Unclassified artifact warning.""" + + +class FoundryModelWeightType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The weight type of the model.""" + + FULL_WEIGHT = "FullWeight" + """Full weight model.""" + LO_RA = "LoRA" + """LoRA adapter weights.""" + DRAFT_MODEL = "DraftModel" + """Draft model weights.""" + + class FunctionShellToolParamEnvironmentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of FunctionShellToolParamEnvironmentType.""" @@ -705,8 +761,8 @@ class PendingUploadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): NONE = "None" """No pending upload.""" - BLOB_REFERENCE = "BlobReference" - """Blob Reference is the only supported type.""" + TEMPORARY_BLOB_REFERENCE = "TemporaryBlobReference" + """Temporary blob reference.""" class RankerVersionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -714,8 +770,8 @@ class RankerVersionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): AUTO = "auto" """AUTO.""" - DEFAULT_2024_11_15 = "default-2024-11-15" - """DEFAULT_2024_11_15.""" + DEFAULT2024_11_15 = "default-2024-11-15" + """DEFAULT2024_11_15.""" class RecurrenceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -882,8 +938,8 @@ class ToolChoiceParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """WEB_SEARCH_PREVIEW.""" COMPUTER_USE_PREVIEW = "computer_use_preview" """COMPUTER_USE_PREVIEW.""" - WEB_SEARCH_PREVIEW_2025_03_11 = "web_search_preview_2025_03_11" - """WEB_SEARCH_PREVIEW_2025_03_11.""" + WEB_SEARCH_PREVIEW2025_03_11 = "web_search_preview_2025_03_11" + """WEB_SEARCH_PREVIEW2025_03_11.""" IMAGE_GENERATION = "image_generation" """IMAGE_GENERATION.""" CODE_INTERPRETER = "code_interpreter" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py index 3606e0a5d9b8..c41674a2d9d4 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py @@ -1003,14 +1003,14 @@ class AgentTaxonomyInput(EvaluationTaxonomyInput, discriminator="agent"): :ivar type: Input type of the evaluation taxonomy. Required. Agent. :vartype type: str or ~azure.ai.projects.models.AGENT :ivar target: Target configuration for the agent. Required. - :vartype target: ~azure.ai.projects.models.Target + :vartype target: ~azure.ai.projects.models.EvaluationTarget :ivar risk_categories: List of risk categories to evaluate against. Required. :vartype risk_categories: list[str or ~azure.ai.projects.models.RiskCategory] """ type: Literal[EvaluationTaxonomyInputType.AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Input type of the evaluation taxonomy. Required. Agent.""" - target: "_models.Target" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + target: "_models.EvaluationTarget" = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Target configuration for the agent. Required.""" risk_categories: list[Union[str, "_models.RiskCategory"]] = rest_field( name="riskCategories", visibility=["read", "create", "update", "delete", "query"] @@ -1021,7 +1021,7 @@ class AgentTaxonomyInput(EvaluationTaxonomyInput, discriminator="agent"): def __init__( self, *, - target: "_models.Target", + target: "_models.EvaluationTarget", risk_categories: list[Union[str, "_models.RiskCategory"]], ) -> None: ... @@ -1392,6 +1392,45 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type: Literal["approximate"] = "approximate" +class ArtifactProfile(_Model): + """Artifact profile of the model. + + :ivar category: The category of the artifact profile. Required. Known values are: "DataOnly", + "RuntimeDependent", and "Unknown". + :vartype category: str or ~azure.ai.projects.models.FoundryModelArtifactProfileCategory + :ivar signals: Signals detected in the model artifact. + :vartype signals: list[str or ~azure.ai.projects.models.FoundryModelArtifactProfileSignal] + """ + + category: Union[str, "_models.FoundryModelArtifactProfileCategory"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The category of the artifact profile. Required. Known values are: \"DataOnly\", + \"RuntimeDependent\", and \"Unknown\".""" + signals: Optional[list[Union[str, "_models.FoundryModelArtifactProfileSignal"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Signals detected in the model artifact.""" + + @overload + def __init__( + self, + *, + category: Union[str, "_models.FoundryModelArtifactProfileCategory"], + signals: Optional[list[Union[str, "_models.FoundryModelArtifactProfileSignal"]]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class AutoCodeInterpreterToolParam(_Model): """Automatic Code Interpreter Tool Parameters. @@ -1438,7 +1477,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type: Literal["auto"] = "auto" -class Target(_Model): +class EvaluationTarget(_Model): """Base class for targets with discriminator support. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -1470,7 +1509,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AzureAIAgentTarget(Target, discriminator="azure_ai_agent"): +class AzureAIAgentTarget(EvaluationTarget, discriminator="azure_ai_agent"): """Represents a target specifying an Azure AI agent. :ivar type: The type of target, always ``azure_ai_agent``. Required. Default value is @@ -1517,7 +1556,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = "azure_ai_agent" # type: ignore -class AzureAIModelTarget(Target, discriminator="azure_ai_model"): +class AzureAIModelTarget(EvaluationTarget, discriminator="azure_ai_model"): """Represents a target specifying an Azure AI model for operations requiring model selection. :ivar type: The type of target, always ``azure_ai_model``. Required. Default value is @@ -1942,7 +1981,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolType.AZURE_FUNCTION # type: ignore -class TargetConfig(_Model): +class RedTeamTargetConfig(_Model): """Abstract class for target configuration. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -1974,7 +2013,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AzureOpenAIModelConfiguration(TargetConfig, discriminator="AzureOpenAIModel"): +class AzureOpenAIModelConfiguration(RedTeamTargetConfig, discriminator="AzureOpenAIModel"): """Azure OpenAI model configuration. The API version would be selected by the service for querying the model. @@ -6449,6 +6488,42 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = DatasetType.URI_FOLDER # type: ignore +class FoundryModelWarning(_Model): + """A warning associated with a model. + + :ivar code: The warning code. Known values are: "RuntimeDependentArtifact" and + "UnclassifiedArtifact". + :vartype code: str or ~azure.ai.projects.models.FoundryModelWarningCode + :ivar message: The warning message. + :vartype message: str + """ + + code: Optional[Union[str, "_models.FoundryModelWarningCode"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The warning code. Known values are: \"RuntimeDependentArtifact\" and \"UnclassifiedArtifact\".""" + message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The warning message.""" + + @overload + def __init__( + self, + *, + code: Optional[Union[str, "_models.FoundryModelWarningCode"]] = None, + message: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class FunctionShellToolParam(Tool, discriminator="shell"): """Shell tool. @@ -7497,6 +7572,54 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class LoraConfig(_Model): + """Adapter-specific metadata for LoRA models. Drives serving engine configuration at deployment + time. + + :ivar rank: LoRA rank (r). Positive integer. Common values: 8, 16, 32, 64. + :vartype rank: int + :ivar alpha: LoRA scaling factor (α). Positive integer; typically 2× the rank. + :vartype alpha: int + :ivar target_modules: Model layers modified by the adapter (e.g., q_proj, v_proj). + Auto-detected from adapter_config.json if omitted. + :vartype target_modules: list[str] + :ivar dropout: Dropout rate used during training. Informational — not used at serving time. + :vartype dropout: float + """ + + rank: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """LoRA rank (r). Positive integer. Common values: 8, 16, 32, 64.""" + alpha: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """LoRA scaling factor (α). Positive integer; typically 2× the rank.""" + target_modules: Optional[list[str]] = rest_field( + name="targetModules", visibility=["read", "create", "update", "delete", "query"] + ) + """Model layers modified by the adapter (e.g., q_proj, v_proj). Auto-detected from + adapter_config.json if omitted.""" + dropout: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Dropout rate used during training. Informational — not used at serving time.""" + + @overload + def __init__( + self, + *, + rank: Optional[int] = None, + alpha: Optional[int] = None, + target_modules: Optional[list[str]] = None, + dropout: Optional[float] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class ManagedAgentIdentityBlueprintReference(AgentBlueprintReference, discriminator="ManagedAgentIdentityBlueprint"): """ManagedAgentIdentityBlueprintReference. @@ -8414,6 +8537,34 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolType.FABRIC_DATAAGENT_PREVIEW # type: ignore +class ModelCredentialRequest(_Model): + """Request to fetch credentials for a model asset. + + :ivar blob_uri: Blob URI of the model asset to fetch credentials for. Required. + :vartype blob_uri: str + """ + + blob_uri: str = rest_field(name="blobUri", visibility=["read", "create", "update", "delete", "query"]) + """Blob URI of the model asset to fetch credentials for. Required.""" + + @overload + def __init__( + self, + *, + blob_uri: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class ModelDeployment(Deployment, discriminator="ModelDeployment"): """Model Deployment Definition. @@ -8559,6 +8710,131 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class ModelSourceData(_Model): + """Source information for the model. + + :ivar source_type: The source type of the model. Known values are: "LocalUpload" and + "TrainingJob". + :vartype source_type: str or ~azure.ai.projects.models.FoundryModelSourceType + :ivar job_id: The job ID that produced this model. + :vartype job_id: str + """ + + source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = rest_field( + name="sourceType", visibility=["read", "create", "update", "delete", "query"] + ) + """The source type of the model. Known values are: \"LocalUpload\" and \"TrainingJob\".""" + job_id: Optional[str] = rest_field(name="jobId", visibility=["read", "create", "update", "delete", "query"]) + """The job ID that produced this model.""" + + @overload + def __init__( + self, + *, + source_type: Optional[Union[str, "_models.FoundryModelSourceType"]] = None, + job_id: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class ModelVersion(_Model): + """Model Version Definition. + + :ivar system_data: System related metadata. + :vartype system_data: ~azure.ai.projects.models.SystemDataV3 + :ivar blob_uri: URI of the model artifact in blob storage. Required. + :vartype blob_uri: str + :ivar weight_type: The weight type of the model. Known values are: "FullWeight", "LoRA", and + "DraftModel". + :vartype weight_type: str or ~azure.ai.projects.models.FoundryModelWeightType + :ivar base_model: Base model asset ID. + :vartype base_model: str + :ivar source: The source of the model. + :vartype source: ~azure.ai.projects.models.ModelSourceData + :ivar lora_config: Adapter-specific configuration. Required when weight_type is lora; ignored + otherwise. May be auto-populated from adapter_config.json when present in the uploaded files — + user-provided values take precedence over auto-detected values. + :vartype lora_config: ~azure.ai.projects.models.LoraConfig + :ivar artifact_profile: The artifact profile of the model. + :vartype artifact_profile: ~azure.ai.projects.models.ArtifactProfile + :ivar warnings: Service-computed advisory warnings derived from the artifact profile. + :vartype warnings: list[~azure.ai.projects.models.FoundryModelWarning] + :ivar id: Asset ID, a unique identifier for the asset. + :vartype id: str + :ivar name: The name of the resource. Required. + :vartype name: str + :ivar version: The version of the resource. Required. + :vartype version: str + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] + """ + + system_data: Optional["_models.SystemDataV3"] = rest_field(name="systemData", visibility=["read"]) + """System related metadata.""" + blob_uri: str = rest_field(name="blobUri", visibility=["read", "create", "update", "delete", "query"]) + """URI of the model artifact in blob storage. Required.""" + weight_type: Optional[Union[str, "_models.FoundryModelWeightType"]] = rest_field( + name="weightType", visibility=["read", "create", "update", "delete", "query"] + ) + """The weight type of the model. Known values are: \"FullWeight\", \"LoRA\", and \"DraftModel\".""" + base_model: Optional[str] = rest_field(name="baseModel", visibility=["read", "create"]) + """Base model asset ID.""" + source: Optional["_models.ModelSourceData"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source of the model.""" + lora_config: Optional["_models.LoraConfig"] = rest_field(name="loraConfig", visibility=["read", "create"]) + """Adapter-specific configuration. Required when weight_type is lora; ignored otherwise. May be + auto-populated from adapter_config.json when present in the uploaded files — user-provided + values take precedence over auto-detected values.""" + artifact_profile: Optional["_models.ArtifactProfile"] = rest_field(name="artifactProfile", visibility=["read"]) + """The artifact profile of the model.""" + warnings: Optional[list["_models.FoundryModelWarning"]] = rest_field(visibility=["read"]) + """Service-computed advisory warnings derived from the artifact profile.""" + id: Optional[str] = rest_field(visibility=["read"]) + """Asset ID, a unique identifier for the asset.""" + name: str = rest_field(visibility=["read"]) + """The name of the resource. Required.""" + version: str = rest_field(visibility=["read"]) + """The version of the resource. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update"]) + """Tag dictionary. Tags can be added, removed, and updated.""" + + @overload + def __init__( + self, + *, + blob_uri: str, + weight_type: Optional[Union[str, "_models.FoundryModelWeightType"]] = None, + base_model: Optional[str] = None, + source: Optional["_models.ModelSourceData"] = None, + lora_config: Optional["_models.LoraConfig"] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class MonthlyRecurrenceSchedule(RecurrenceSchedule, discriminator="Monthly"): """Monthly recurrence schedule. @@ -9085,9 +9361,9 @@ class PendingUploadRequest(_Model): :ivar connection_name: Azure Storage Account connection name to use for generating temporary SAS token. :vartype connection_name: str - :ivar pending_upload_type: BlobReference is the only supported type. Required. Blob Reference - is the only supported type. - :vartype pending_upload_type: str or ~azure.ai.projects.models.BLOB_REFERENCE + :ivar pending_upload_type: TemporaryBlobReference is the only supported type. Required. + Temporary blob reference. + :vartype pending_upload_type: str or ~azure.ai.projects.models.TEMPORARY_BLOB_REFERENCE """ pending_upload_id: Optional[str] = rest_field( @@ -9098,16 +9374,16 @@ class PendingUploadRequest(_Model): name="connectionName", visibility=["read", "create", "update", "delete", "query"] ) """Azure Storage Account connection name to use for generating temporary SAS token.""" - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] = rest_field( + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] ) - """BlobReference is the only supported type. Required. Blob Reference is the only supported type.""" + """TemporaryBlobReference is the only supported type. Required. Temporary blob reference.""" @overload def __init__( self, *, - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], pending_upload_id: Optional[str] = None, connection_name: Optional[str] = None, ) -> None: ... @@ -9133,9 +9409,9 @@ class PendingUploadResult(_Model): :ivar version: Version of asset to be created if user did not specify version when initially creating upload. :vartype version: str - :ivar pending_upload_type: BlobReference is the only supported type. Required. Blob Reference - is the only supported type. - :vartype pending_upload_type: str or ~azure.ai.projects.models.BLOB_REFERENCE + :ivar pending_upload_type: TemporaryBlobReference is the only supported type. Required. + Temporary blob reference. + :vartype pending_upload_type: str or ~azure.ai.projects.models.TEMPORARY_BLOB_REFERENCE """ blob_reference: "_models.BlobReference" = rest_field( @@ -9148,10 +9424,10 @@ class PendingUploadResult(_Model): """ID for this upload request. Required.""" version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Version of asset to be created if user did not specify version when initially creating upload.""" - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] = rest_field( + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] ) - """BlobReference is the only supported type. Required. Blob Reference is the only supported type.""" + """TemporaryBlobReference is the only supported type. Required. Temporary blob reference.""" @overload def __init__( @@ -9159,7 +9435,7 @@ def __init__( *, blob_reference: "_models.BlobReference", pending_upload_id: str, - pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], version: Optional[str] = None, ) -> None: ... @@ -9683,7 +9959,7 @@ class RedTeam(_Model): :ivar status: Status of the red-team. It is set by service and is read-only. :vartype status: str :ivar target: Target configuration for the red-team run. Required. - :vartype target: ~azure.ai.projects.models.TargetConfig + :vartype target: ~azure.ai.projects.models.RedTeamTargetConfig """ name: str = rest_field(name="id", visibility=["read"]) @@ -9718,14 +9994,14 @@ class RedTeam(_Model): removed.""" status: Optional[str] = rest_field(visibility=["read"]) """Status of the red-team. It is set by service and is read-only.""" - target: "_models.TargetConfig" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + target: "_models.RedTeamTargetConfig" = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Target configuration for the red-team run. Required.""" @overload def __init__( self, *, - target: "_models.TargetConfig", + target: "_models.RedTeamTargetConfig", display_name: Optional[str] = None, num_turns: Optional[int] = None, attack_strategies: Optional[list[Union[str, "_models.AttackStrategy"]]] = None, @@ -10210,10 +10486,12 @@ class SessionLogEvent(_Model): .. code-block:: event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting server on port 18080"} + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting server + on port 18080"} event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully + connected to container"}. :ivar event: The SSE event type. Currently ``log``, but additional event types may be added in the future. Clients should ignore unrecognized event types. Required. "log" @@ -10657,6 +10935,55 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class SystemDataV3(_Model): + """System metadata for a resource. + + :ivar created_at: Timestamp of resource creation. + :vartype created_at: ~datetime.datetime + :ivar created_by: Identity that created the resource. + :vartype created_by: str + :ivar created_by_type: Type of identity that created the resource. + :vartype created_by_type: str + :ivar last_modified_at: Timestamp of last resource modification. + :vartype last_modified_at: ~datetime.datetime + """ + + created_at: Optional[datetime.datetime] = rest_field( + name="createdAt", visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """Timestamp of resource creation.""" + created_by: Optional[str] = rest_field(name="createdBy", visibility=["read", "create", "update", "delete", "query"]) + """Identity that created the resource.""" + created_by_type: Optional[str] = rest_field( + name="createdByType", visibility=["read", "create", "update", "delete", "query"] + ) + """Type of identity that created the resource.""" + last_modified_at: Optional[datetime.datetime] = rest_field( + name="lastModifiedAt", visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """Timestamp of last resource modification.""" + + @overload + def __init__( + self, + *, + created_at: Optional[datetime.datetime] = None, + created_by: Optional[str] = None, + created_by_type: Optional[str] = None, + last_modified_at: Optional[datetime.datetime] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class TaxonomyCategory(_Model): """Taxonomy category definition. @@ -11141,7 +11468,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): or a Literal["required"] type. :vartype mode: str or str :ivar tools: A list of tool definitions that the model should be allowed to call. For the - Responses API, the list of tool definitions might look like the following. Required. + Responses API, the list of tool definitions might look like: .. code-block:: json @@ -11149,7 +11476,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): { "type": "function", "name": "get_weather" }, { "type": "mcp", "server_label": "deepwiki" }, { "type": "image_generation" } - ] + ]. Required. :vartype tools: list[dict[str, any]] """ @@ -11162,7 +11489,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): Literal[\"required\"] type.""" tools: list[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A list of tool definitions that the model should be allowed to call. For the Responses API, the - list of tool definitions might look like the following. Required. + list of tool definitions might look like: .. code-block:: json @@ -11170,7 +11497,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): { \"type\": \"function\", \"name\": \"get_weather\" }, { \"type\": \"mcp\", \"server_label\": \"deepwiki\" }, { \"type\": \"image_generation\" } - ]""" + ]. Required.""" @overload def __init__( @@ -11439,12 +11766,12 @@ class ToolChoiceWebSearchPreview20250311(ToolChoiceParam, discriminator="web_sea """Indicates that the model should use a built-in tool to generate a response. `Learn more about built-in tools `_. - :ivar type: Required. WEB_SEARCH_PREVIEW_2025_03_11. - :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW_2025_03_11 + :ivar type: Required. WEB_SEARCH_PREVIEW2025_03_11. + :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW2025_03_11 """ - type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. WEB_SEARCH_PREVIEW_2025_03_11.""" + type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW2025_03_11] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. WEB_SEARCH_PREVIEW2025_03_11.""" @overload def __init__( @@ -11460,7 +11787,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11 # type: ignore + self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW2025_03_11 # type: ignore class ToolDescription(_Model): @@ -11756,6 +12083,39 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = EvaluatorGenerationJobSourceType.TRACES # type: ignore +class UpdateModelVersionRequest(_Model): + """Request body for updating a model version. Only description and tags can be modified. + + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] + """ + + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Tag dictionary. Tags can be added, removed, and updated.""" + + @overload + def __init__( + self, + *, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class UpdateToolboxRequest(_Model): """UpdateToolboxRequest. diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index 72b85abdab2f..e3fdf13fa077 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -1927,6 +1927,204 @@ def build_beta_memory_stores_delete_scope_request( # pylint: disable=name-too-l return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) +def build_beta_models_list_versions_request(name: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/models/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_models_list_request(**kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/models" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_models_get_request(name: str, version: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/models/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_models_delete_request(name: str, version: str, **kwargs: Any) -> HttpRequest: + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + # Construct URL + _url = "/models/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + + +def build_beta_models_update_request(name: str, version: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/models/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_models_create_async_request(name: str, version: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + # Construct URL + _url = "/models/{name}/versions/{version}/createAsync" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_models_pending_upload_request(name: str, version: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/models/{name}/versions/{version}/startPendingUpload" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_models_get_credentials_request( # pylint: disable=name-too-long + name: str, version: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/models/{name}/versions/{version}/credentials" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + def build_beta_red_teams_get_request(name: str, **kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -2703,6 +2901,7 @@ def __init__(self, *args, **kwargs) -> None: self.evaluators = BetaEvaluatorsOperations(self._client, self._config, self._serialize, self._deserialize) self.insights = BetaInsightsOperations(self._client, self._config, self._serialize, self._deserialize) self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) + self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) self.red_teams = BetaRedTeamsOperations(self._client, self._config, self._serialize, self._deserialize) self.schedules = BetaSchedulesOperations(self._client, self._config, self._serialize, self._deserialize) self.toolboxes = BetaToolboxesOperations(self._client, self._config, self._serialize, self._deserialize) @@ -6536,23 +6735,29 @@ def get_session_log_stream( Each SSE frame contains: * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) + * `data`: a plain-text log line (currently JSON-formatted, but the schema + is not contractual and may include additional keys or change format + over time — clients should treat it as an opaque string) Example SSE frames: .. code-block:: event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting + FoundryCBAgent server on port 8088"} event: log - data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application + startup complete."} event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully + connected to container"} event: log - data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since + last 60 seconds"} The stream remains open until the client disconnects or the server terminates the connection. Clients should handle reconnection as needed. @@ -6594,7 +6799,7 @@ def get_session_log_stream( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = True + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -7055,10 +7260,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -7488,10 +7690,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -7591,10 +7790,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -8780,10 +8976,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -9451,7 +9644,7 @@ def _search_memories( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items": items, + "items_property": items, "options": options, "previous_search_id": previous_search_id, "scope": scope, @@ -9537,7 +9730,7 @@ def _update_memories_initial( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items": items, + "items_property": items, "previous_update_id": previous_update_id, "scope": scope, "update_delay": update_delay, @@ -9859,14 +10052,14 @@ def delete_scope( return deserialized # type: ignore -class BetaRedTeamsOperations: +class BetaModelsOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`red_teams` attribute. + :attr:`models` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -9877,15 +10070,20 @@ def __init__(self, *args, **kwargs) -> None: self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.RedTeam: - """Get a redteam by name. + def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: + """List all versions of the given ModelVersion. - :param name: Identifier of the red team run. Required. + :param name: The name of the resource. Required. :type name: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -9894,29 +10092,914 @@ def get(self, name: str, **kwargs: Any) -> _models.RedTeam: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + def prepare_request(next_link=None): + if not next_link: - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + _request = build_beta_models_list_versions_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_red_teams_get_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + return _request - response = pipeline_response.http_response + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ModelVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: + """List the latest version of each ModelVersion. + + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_models_list_request( + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ModelVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: + """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the + ModelVersion does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the ModelVersion to retrieve. Required. + :type version: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + + _request = build_beta_models_get_request( + name=name, + version=version, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete the specific version of the ModelVersion. The service returns 204 No Content if the + ModelVersion was deleted successfully or if the ModelVersion does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the ModelVersion to delete. Required. + :type version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_models_delete_request( + name=name, + version=version, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @overload + def update( + self, + name: str, + version: str, + body: _models.UpdateModelVersionRequest, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update( + self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update( + self, + name: str, + version: str, + body: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def update( + self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: + UpdateModelVersionRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + + content_type = content_type or "application/merge-patch+json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_update_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200, 201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelVersion, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def create_async( + self, + name: str, + version: str, + body: _models.ModelVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: ~azure.ai.projects.models.ModelVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_async( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_async( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_async( # pylint: disable=inconsistent-return-statements + self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any + ) -> None: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Is one of the following types: ModelVersion, JSON, + IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_create_async_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + response_headers = {} + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @overload + def pending_upload( + self, + name: str, + version: str, + body: _models.PendingUploadRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.PendingUploadRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def pending_upload( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def pending_upload( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def pending_upload( + self, name: str, version: str, body: Union[_models.PendingUploadRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.PendingUploadResult: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: PendingUploadRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.PendingUploadRequest or JSON or IO[bytes] + :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.PendingUploadResult + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.PendingUploadResult] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_pending_upload_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.PendingUploadResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def get_credentials( + self, + name: str, + version: str, + body: _models.ModelCredentialRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def get_credentials( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def get_credentials( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def get_credentials( + self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_get_credentials_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DatasetCredential, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + +class BetaRedTeamsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`red_teams` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def get(self, name: str, **kwargs: Any) -> _models.RedTeam: + """Get a redteam by name. + + :param name: Identifier of the red team run. Required. + :type name: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + + _request = build_beta_red_teams_get_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response if response.status_code not in [200]: if _stream: @@ -9984,10 +11067,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -10331,10 +11411,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( @@ -10634,10 +11711,7 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, + "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params ) path_format_arguments = { "endpoint": self._serialize.url( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index 784a8ba6b182..f492bee8e9ae 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -18,6 +18,7 @@ from ._patch_telemetry import TelemetryOperations from ._patch_connections import ConnectionsOperations from ._patch_memories import BetaMemoryStoresOperations +from ._patch_models import BetaModelsOperations from ._patch_sessions import BetaAgentsOperations from ._operations import ( BetaDatasetsOperations, @@ -105,6 +106,8 @@ class BetaOperations(GeneratedBetaOperations): """:class:`~azure.ai.projects.operations.BetaInsightsOperations` operations""" memory_stores: BetaMemoryStoresOperations """:class:`~azure.ai.projects.operations.BetaMemoryStoresOperations` operations""" + models: BetaModelsOperations + """:class:`~azure.ai.projects.operations.BetaModelsOperations` operations""" red_teams: BetaRedTeamsOperations """:class:`~azure.ai.projects.operations.BetaRedTeamsOperations` operations""" schedules: BetaSchedulesOperations @@ -124,6 +127,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) # Replace with patched class that includes begin_update_memories self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) + # Replace with patched class that includes register_model (3-step upload helper) + self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) for property_name, foundry_features_value in _BETA_OPERATION_FEATURE_HEADERS.items(): setattr( @@ -141,6 +146,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: "BetaEvaluatorsOperations", "BetaInsightsOperations", "BetaMemoryStoresOperations", + "BetaModelsOperations", "BetaOperations", "BetaRedTeamsOperations", "BetaSchedulesOperations", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py new file mode 100644 index 000000000000..9a07763bc823 --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -0,0 +1,240 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" + +import logging +import os +import shutil +import subprocess +import time +from pathlib import Path +from typing import Any, Optional, Union + +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.core.tracing.decorator import distributed_trace + +from ._operations import BetaModelsOperations as BetaModelsOperationsGenerated +from ..models._models import ( + ModelVersion, + PendingUploadRequest, + PendingUploadResult, + PendingUploadType, +) + +logger = logging.getLogger(__name__) + + +class BetaModelsOperations(BetaModelsOperationsGenerated): + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`beta.models ` attribute. + """ + + @staticmethod + def _extract_pending_upload_targets( + response: Union[PendingUploadResult, dict], + ) -> "tuple[str, str, Optional[str]]": + """Return ``(sas_uri, container_blob_uri, pending_upload_id)`` from a pending-upload response. + + The service currently returns the raw datastore-style payload + (``blobReferenceForConsumption`` / ``temporaryDataReferenceId``) for some + Foundry deployments rather than the SDK-modeled ``PendingUploadResult`` + shape (``blobReference`` / ``pendingUploadId``). Tolerate both wire + shapes so callers don't have to. + """ + payload = response.as_dict() if hasattr(response, "as_dict") else dict(response) + + blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} + sas_uri = (blob_ref.get("credential") or {}).get("sasUri") + container_blob_uri = blob_ref.get("blobUri") + pending_upload_id = payload.get("temporaryDataReferenceId") or payload.get("pendingUploadId") + + if not sas_uri or not container_blob_uri: + raise ValueError("Could not locate SAS URI / blob URI in pending_upload response: " f"{payload!r}") + return sas_uri, container_blob_uri, pending_upload_id + + @staticmethod + def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None) -> None: + """Shell out to ``azcopy copy`` to upload ``source`` to the SAS container.""" + azcopy = azcopy_path or shutil.which("azcopy") + if not azcopy: + raise RuntimeError( + "`azcopy` was not found on PATH. Install AzCopy " + "(https://aka.ms/downloadazcopy) and ensure it is on PATH, or " + "pass `azcopy_path=` explicitly." + ) + + if source.is_dir(): + src_arg = str(source / "*") + elif source.is_file(): + src_arg = str(source) + else: + raise ValueError(f"Upload source does not exist: {source}") + + cmd = [ + azcopy, + "copy", + src_arg, + sas_uri, + "--from-to", + "LocalBlob", + "--recursive", + ] + + # Don't log the SAS query string — it's a credential. + redacted = cmd.copy() + redacted[3] = sas_uri.split("?", 1)[0] + "?" + logger.info("[register_model] running: %s", " ".join(redacted)) + + completed = subprocess.run(cmd, check=False, capture_output=True, text=True) + if completed.stdout: + logger.debug("[register_model] azcopy stdout:\n%s", completed.stdout) + if completed.stderr: + logger.debug("[register_model] azcopy stderr:\n%s", completed.stderr) + if completed.returncode != 0: + raise RuntimeError( + f"azcopy exited with code {completed.returncode}.\n" + f"stdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" + ) + + @distributed_trace + def register_model( + self, + *, + name: str, + version: str, + source: Union[str, "os.PathLike[str]"], + weight_type: Optional[str] = None, + base_model: Optional[str] = None, + description: Optional[str] = None, + tags: Optional["dict[str, str]"] = None, + azcopy_path: Optional[str] = None, + wait_for_commit: bool = True, + polling_timeout: float = 300.0, + polling_interval: float = 2.0, + **kwargs: Any, + ) -> Optional[ModelVersion]: + """Register a local model by running the full upload-first sequence. + + This wraps the three mandatory steps of the model-registration spec + into a single call: + + 1. :meth:`pending_upload` — provision a project-managed blob container + and obtain a SAS URI. + 2. ``azcopy copy`` — upload the local weight files directly to the + SAS container. + 3. :meth:`create_async` — finalize registration with the + ``ModelVersion`` body (``blob_uri``, ``weight_type``, ``base_model``, + ``description``, ``tags``). + + :keyword name: Name of the model to register. Required. + :paramtype name: str + :keyword version: Version identifier for the model. Required. + :paramtype version: str + :keyword source: Local file or directory containing the model weights. + If a directory, its contents are uploaded recursively to the SAS + container root. Required. + :paramtype source: str or os.PathLike[str] + :keyword weight_type: Optional weight type (e.g. ``"FullWeight"``, + ``"LoRA"``, ``"DraftModel"``). + :paramtype weight_type: str + :keyword base_model: Optional base model asset ID. + :paramtype base_model: str + :keyword description: Optional asset description. + :paramtype description: str + :keyword tags: Optional asset tags. + :paramtype tags: dict[str, str] + :keyword azcopy_path: Optional explicit path to the azcopy executable. + Defaults to ``shutil.which("azcopy")``. + :paramtype azcopy_path: str + :keyword wait_for_commit: When True (default) poll :meth:`get` until + the committed ``ModelVersion`` is observable, and return it. + When False, return ``None`` after the async commit is accepted. + :paramtype wait_for_commit: bool + :keyword polling_timeout: Total seconds to poll for commit completion. + :paramtype polling_timeout: float + :keyword polling_interval: Seconds between poll attempts. + :paramtype polling_interval: float + :return: The committed :class:`~azure.ai.projects.models.ModelVersion` + when ``wait_for_commit`` is True, otherwise ``None``. + :rtype: ~azure.ai.projects.models.ModelVersion or None + :raises ValueError: If ``source`` does not exist or the pending-upload + response is missing the SAS / blob URI. + :raises RuntimeError: If ``azcopy`` is not on PATH or exits with a + non-zero status, or the registration does not commit before + ``polling_timeout`` elapses. + """ + source_path = Path(os.fspath(source)) + if not source_path.exists(): + raise ValueError(f"Upload source does not exist: {source_path}") + + # --- Step 1: StartPendingUpload -------------------------------------- + logger.info( + "[register_model] step 1/3 pending_upload(name=%r, version=%r)", + name, + version, + ) + pending = self.pending_upload( + name=name, + version=version, + body=PendingUploadRequest( + pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, + ), + **kwargs, + ) + sas_uri, container_blob_uri, pending_upload_id = self._extract_pending_upload_targets(pending) + logger.info( + "[register_model] pending_upload_id=%s blob_uri=%s", + pending_upload_id, + container_blob_uri, + ) + + # --- Step 2: Upload via azcopy --------------------------------------- + logger.info("[register_model] step 2/3 azcopy upload from %s", source_path) + self._run_azcopy(source_path, sas_uri, azcopy_path=azcopy_path) + + # --- Step 3: Commit registration ------------------------------------- + body = ModelVersion( + blob_uri=container_blob_uri, + weight_type=weight_type, + base_model=base_model, + description=description, + tags=tags or {}, + ) + logger.info( + "[register_model] step 3/3 create_async(name=%r, version=%r)", + name, + version, + ) + self.create_async(name=name, version=version, body=body, **kwargs) + + if not wait_for_commit: + return None + + # The async op returns 202; the service materializes the ModelVersion + # asynchronously. Poll get() until it appears or we time out. + deadline = time.monotonic() + polling_timeout + last_exc: Optional[BaseException] = None + while True: + try: + return self.get(name=name, version=version, **kwargs) + except ResourceNotFoundError as ex: + last_exc = ex + if time.monotonic() >= deadline: + raise RuntimeError( + f"Model {name!r}@{version!r} did not appear within " f"{polling_timeout}s after create_async." + ) from last_exc + time.sleep(polling_interval) + + +__all__ = ["BetaModelsOperations"] diff --git a/sdk/ai/azure-ai-projects/pyproject.toml b/sdk/ai/azure-ai-projects/pyproject.toml index 26eac48e1123..fe16fe054548 100644 --- a/sdk/ai/azure-ai-projects/pyproject.toml +++ b/sdk/ai/azure-ai-projects/pyproject.toml @@ -14,10 +14,10 @@ name = "azure-ai-projects" authors = [ { name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com" }, ] -description = "Microsoft Corporation Azure AI Projects Client Library for Python" +description = "Microsoft Corporation Azure Ai Projects Client Library for Python" license = "MIT" classifiers = [ - "Development Status :: 5 - Production/Stable", + "Development Status :: 4 - Beta", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", @@ -26,7 +26,6 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", ] requires-python = ">=3.9" keywords = ["azure", "azure sdk"] @@ -44,7 +43,7 @@ dynamic = [ ] [project.urls] -repository = "https://aka.ms/azsdk/azure-ai-projects-v2/python/code" +repository = "https://github.com/Azure/azure-sdk-for-python" [tool.setuptools.dynamic] version = {attr = "azure.ai.projects._version.VERSION"} @@ -52,13 +51,13 @@ readme = {file = ["README.md", "CHANGELOG.md"], content-type = "text/markdown"} [tool.setuptools.packages.find] exclude = [ - "azure.ai", - "azure", - "doc*", - "generated_samples*", + "tests*", "generated_tests*", "samples*", - "tests*", + "generated_samples*", + "doc*", + "azure", + "azure.ai", ] [tool.setuptools.package-data] @@ -69,4 +68,3 @@ verifytypes = false [tool.azure-sdk-conda] in_bundle = false - diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb b/sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb new file mode 100644 index 000000000000..852b2aa3b0f0 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb @@ -0,0 +1,307 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ef8034da", + "metadata": {}, + "source": [ + "# Microsoft Foundry — Models (`project_client.beta.models`)\n", + "\n", + "This notebook demonstrates how to use the synchronous `.beta.models` operations on `AIProjectClient` to register a local model with the project, list and inspect model versions, retrieve storage credentials, update metadata, and delete a model version.\n", + "\n", + "## Operations covered\n", + "\n", + "| Method | Purpose |\n", + "| --- | --- |\n", + "| `register_model` | End-to-end helper: provisions blob storage, uploads weights via `azcopy`, and commits the registration. **Recommended entry point.** |\n", + "| `list` | List the latest version of every registered model. |\n", + "| `list_versions` | List all versions of a single model. |\n", + "| `get` | Fetch a specific `ModelVersion`. |\n", + "| `get_credentials` | Retrieve a SAS URI for the blob container backing a registered version. |\n", + "| `update` | Merge-patch the `description` / `tags` of an existing model version. |\n", + "| `delete` | Delete a specific model version. |\n", + "| `pending_upload` / `create_async` | Lower-level building blocks used internally by `register_model`. |\n", + "\n", + "## Prerequisites\n", + "\n", + "```bash\n", + "pip install \"azure-ai-projects>=2.2.0\" azure-identity python-dotenv\n", + "```\n", + "\n", + "[**AzCopy**](https://aka.ms/downloadazcopy) must be installed and on `PATH` (used by `register_model` to upload weight files):\n", + "\n", + "```powershell\n", + "winget install --id Microsoft.Azure.AZCopy.10 -e\n", + "```\n", + "\n", + "Set the following environment variables (a `.env` file is supported):\n", + "\n", + "* `FOUNDRY_PROJECT_ENDPOINT` — required. The Azure AI Project endpoint shown on the Microsoft Foundry project Overview page.\n", + "* `MODEL_NAME` — optional. Defaults to `\"sample-model\"`.\n", + "* `MODEL_VERSION` — optional. Defaults to `\"1\"`." + ] + }, + { + "cell_type": "markdown", + "id": "23ed3eec", + "metadata": {}, + "source": [ + "## 1. Set up the client\n", + "\n", + "Create an `AIProjectClient` using `DefaultAzureCredential`. We also create a tiny temp folder with two dummy \"weight\" files to register." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0b03dde", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pathlib\n", + "import tempfile\n", + "\n", + "from dotenv import load_dotenv\n", + "from azure.identity import DefaultAzureCredential\n", + "from azure.ai.projects import AIProjectClient\n", + "\n", + "load_dotenv()\n", + "\n", + "endpoint = os.environ[\"FOUNDRY_PROJECT_ENDPOINT\"]\n", + "model_name = os.environ.get(\"MODEL_NAME\", \"sample-model\")\n", + "model_version = os.environ.get(\"MODEL_VERSION\", \"1\")\n", + "\n", + "credential = DefaultAzureCredential()\n", + "project_client = AIProjectClient(endpoint=endpoint, credential=credential)\n", + "\n", + "# Build a tiny throw-away source folder with two files to upload.\n", + "source_dir = pathlib.Path(tempfile.mkdtemp(prefix=\"sample-model-\"))\n", + "(source_dir / \"weights.bin\").write_bytes(b\"hello-foundry-model\")\n", + "(source_dir / \"config.json\").write_text('{\"sample\": true}')\n", + "print(f\"Source folder: {source_dir}\")\n", + "for f in sorted(source_dir.rglob(\"*\")):\n", + " if f.is_file():\n", + " print(f\" - {f.relative_to(source_dir)} ({f.stat().st_size} bytes)\")" + ] + }, + { + "cell_type": "markdown", + "id": "ff0bc195", + "metadata": {}, + "source": [ + "## 2. Register a local model — `register_model`\n", + "\n", + "`register_model` is the recommended way to create a new model version from local files. It packs the spec's three required steps into a single call:\n", + "\n", + "1. `pending_upload(...)` — provision a project-managed blob container and obtain a SAS URI.\n", + "2. `azcopy copy ...` — upload the local weight files directly to that container.\n", + "3. `create_async(...)` — commit the registration, then poll `get()` until the new `ModelVersion` is observable.\n", + "\n", + "The `weight_type` parameter accepts the `FoundryModelWeightType` enum (`FULL_WEIGHT`, `LO_RA`, `DRAFT_MODEL`) or the equivalent string. The committed `ModelVersion` also exposes service-populated fields such as `artifact_profile`, `source`, and `warnings`.\n", + "\n", + "Use the lower-level `pending_upload` / `create_async` methods directly only if you need to customize one of those steps (for example, to use your own upload tool)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02e1d051", + "metadata": {}, + "outputs": [], + "source": [ + "from azure.ai.projects.models import FoundryModelWeightType\n", + "\n", + "model = project_client.beta.models.register_model(\n", + " name=model_name,\n", + " version=model_version,\n", + " source=source_dir,\n", + " weight_type=FoundryModelWeightType.FULL_WEIGHT,\n", + " description=\"Sample model registered from sample_models.ipynb\",\n", + " tags={\"source\": \"sample_models.ipynb\"},\n", + ")\n", + "\n", + "print(f\"Registered: {model.name}@{model.version}\")\n", + "print(f\" id = {model.id}\")\n", + "print(f\" blob_uri = {model.blob_uri}\")\n", + "print(f\" weight_type = {model.weight_type}\")\n", + "print(f\" description = {model.description}\")\n", + "print(f\" tags = {model.tags}\")\n", + "print(f\" source = {model.source}\")\n", + "print(f\" artifact_profile = {model.artifact_profile}\")\n", + "print(f\" warnings = {model.warnings}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a2466321", + "metadata": {}, + "source": [ + "## 3. Get a specific model version — `get`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bec4ee7b", + "metadata": {}, + "outputs": [], + "source": [ + "fetched = project_client.beta.models.get(name=model_name, version=model_version)\n", + "print(f\"{fetched.name}@{fetched.version} -> {fetched.id}\")" + ] + }, + { + "cell_type": "markdown", + "id": "6d347100", + "metadata": {}, + "source": [ + "## 4. List all versions of a model — `list_versions`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "599248cb", + "metadata": {}, + "outputs": [], + "source": [ + "print(f\"Versions of {model_name!r}:\")\n", + "for mv in project_client.beta.models.list_versions(name=model_name):\n", + " print(f\" - {mv.version}\")" + ] + }, + { + "cell_type": "markdown", + "id": "12de6668", + "metadata": {}, + "source": [ + "## 5. List the latest version of every model — `list`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13d73415", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Latest version of every registered model in this project:\")\n", + "for mv in project_client.beta.models.list():\n", + " print(f\" - {mv.name}@{mv.version}\")" + ] + }, + { + "cell_type": "markdown", + "id": "18f1563b", + "metadata": {}, + "source": [ + "## 6. Get blob credentials for a model version — `get_credentials`\n", + "\n", + "Returns a short-lived SAS URI that can be used to read the blob container backing the registered model. The SAS query string is sensitive — treat it like a credential." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8920c93", + "metadata": {}, + "outputs": [], + "source": [ + "from azure.ai.projects.models import ModelCredentialRequest\n", + "\n", + "creds = project_client.beta.models.get_credentials(\n", + " name=model_name,\n", + " version=model_version,\n", + " body=ModelCredentialRequest(blob_uri=model.blob_uri),\n", + ")\n", + "blob_ref = getattr(creds, \"blob_reference_for_consumption\", None) or getattr(creds, \"blob_reference\", None)\n", + "if blob_ref is not None:\n", + " sas_uri = (blob_ref.credential.sas_uri if blob_ref.credential else None) or \"\"\n", + " print(f\" blob_uri = {blob_ref.blob_uri}\")\n", + " print(f\" sas_uri = {sas_uri.split('?', 1)[0]}?\")\n", + "else:\n", + " print(creds)" + ] + }, + { + "cell_type": "markdown", + "id": "e9fb0fdb", + "metadata": {}, + "source": [ + "## 7. Update an existing model version — `update`\n", + "\n", + "`update` issues a merge-patch (`PATCH /models/{name}/versions/{version}`) and accepts an `UpdateModelVersionRequest` body containing only the patchable fields (`description`, `tags`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc9d2fd", + "metadata": {}, + "outputs": [], + "source": [ + "from azure.ai.projects.models import UpdateModelVersionRequest\n", + "\n", + "updated = project_client.beta.models.update(\n", + " name=model_name,\n", + " version=model_version,\n", + " body=UpdateModelVersionRequest(\n", + " description=\"Updated description\",\n", + " tags={\"source\": \"sample_models.ipynb\", \"updated\": \"true\"},\n", + " ),\n", + ")\n", + "print(f\"Updated: {updated.name}@{updated.version}\")\n", + "print(f\" description = {updated.description}\")\n", + "print(f\" tags = {updated.tags}\")" + ] + }, + { + "cell_type": "markdown", + "id": "9d8397e8", + "metadata": {}, + "source": [ + "## 8. Delete a model version — `delete`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ce968d2", + "metadata": {}, + "outputs": [], + "source": [ + "project_client.beta.models.delete(name=model_name, version=model_version)\n", + "print(f\"Deleted {model_name}@{model_version}.\")" + ] + }, + { + "cell_type": "markdown", + "id": "49ed4aa3", + "metadata": {}, + "source": [ + "## Cleanup\n", + "\n", + "Close the client and credential." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a18aa29", + "metadata": {}, + "outputs": [], + "source": [ + "project_client.close()\n", + "credential.close()" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models.py b/sdk/ai/azure-ai-projects/tests/models/test_models.py new file mode 100644 index 000000000000..694a7e7ccf8b --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/models/test_models.py @@ -0,0 +1,140 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Live, recorded tests for ``project_client.beta.models``. + +These tests exercise the generated ``BetaModelsOperations`` (``list``, +``list_versions``, ``get``, ``pending_upload``, ``get_credentials``, ``delete``) +and the patched ``register_model`` end-to-end helper. They follow the same +"upload + record" pattern used by ``test_datasets.py``. + +``create_or_update`` is intentionally not tested here. The Foundry data plane +currently returns ``404 Not Found`` for that route even when ``GET`` for the +same name/version succeeds. The cell will be re-enabled once the service-side +issue is fixed. +""" +import os + +import pytest +from devtools_testutils import ( + add_general_regex_sanitizer, + is_live, + is_live_and_not_recording, + recorded_by_proxy, +) +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError + +from test_base import TestBase, servicePreparer + +# Construct the path to the data folder used in this test +script_dir = os.path.dirname(os.path.abspath(__file__)) +data_folder = os.environ.get("DATA_FOLDER", os.path.join(script_dir, "../test_data/models")) + + +@pytest.mark.skipif( + not is_live_and_not_recording(), + reason="Skipped when using recordings due to flakiness of recording blob storage calls", +) +class TestModels(TestBase): + + # cls & pytest tests\models\test_models.py::TestModels::test_models_register_model -s + @servicePreparer() + @recorded_by_proxy + def test_models_register_model(self, **kwargs): + """End-to-end: pending_upload -> azcopy -> create_async -> get/list/delete.""" + model_name = self.test_models_params["model_name_1"] + model_version = self.test_models_params["model_version"] + expected_model_name = model_name if is_live() else "sanitized-model-name" + add_general_regex_sanitizer(regex=r"test-model-name-\d{5}", value="sanitized-model-name", function_scoped=True) + + with self.create_client(**kwargs) as project_client: + + print(f"[test_models_register_model] register_model {model_name}@{model_version}") + registered = project_client.beta.models.register_model( + name=model_name, + version=model_version, + source=data_folder, + weight_type="FullWeight", + description="Registered by test_models_register_model", + tags={"source": "test_models.py"}, + ) + assert registered is not None + assert registered.name == expected_model_name + assert registered.version == model_version + assert registered.blob_uri, "blob_uri should be populated after register_model" + + print(f"[test_models_register_model] get {model_name}@{model_version}") + fetched = project_client.beta.models.get(name=model_name, version=model_version) + assert fetched.id == registered.id + assert fetched.name == expected_model_name + assert fetched.version == model_version + + print(f"[test_models_register_model] list_versions({model_name!r})") + versions = list(project_client.beta.models.list_versions(name=model_name)) + assert any( + mv.version == model_version for mv in versions + ), f"version {model_version!r} not found in list_versions" + + print("[test_models_register_model] list (latest of every model)") + empty = True + for mv in project_client.beta.models.list(): + empty = False + assert mv.name and mv.version + assert not empty, "list() returned no models even though we just registered one" + + print(f"[test_models_register_model] get_credentials {model_name}@{model_version}") + from azure.ai.projects.models import ModelCredentialRequest + + creds = project_client.beta.models.get_credentials( + name=model_name, + version=model_version, + body=ModelCredentialRequest(blob_uri=registered.blob_uri), + ) + blob_ref = getattr(creds, "blob_reference_for_consumption", None) or getattr(creds, "blob_reference", None) + assert blob_ref is not None, f"no blob reference in credentials response: {creds!r}" + assert blob_ref.blob_uri + assert blob_ref.credential is not None + assert blob_ref.credential.sas_uri + + print(f"[test_models_register_model] delete {model_name}@{model_version}") + try: + project_client.beta.models.delete(name=model_name, version=model_version) + except HttpResponseError as ex: + # The service currently returns 200 OK for a successful DELETE while + # the generated operation only allow-lists 204. Tolerate that here. + if ex.status_code != 200: + raise + + print(f"[test_models_register_model] get on deleted {model_name}@{model_version} should 404") + with pytest.raises((ResourceNotFoundError, HttpResponseError)): + project_client.beta.models.get(name=model_name, version=model_version) + + # cls & pytest tests\models\test_models.py::TestModels::test_models_pending_upload -s + @servicePreparer() + @recorded_by_proxy + def test_models_pending_upload(self, **kwargs): + """Lower-level: ``pending_upload`` returns a usable SAS URI.""" + from azure.ai.projects.models import PendingUploadRequest, PendingUploadType + + model_name = self.test_models_params["model_name_2"] + model_version = self.test_models_params["model_version"] + add_general_regex_sanitizer(regex=r"test-model-name-\d{5}", value="sanitized-model-name", function_scoped=True) + + with self.create_client(**kwargs) as project_client: + + print(f"[test_models_pending_upload] pending_upload {model_name}@{model_version}") + pending = project_client.beta.models.pending_upload( + name=model_name, + version=model_version, + body=PendingUploadRequest( + pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, + ), + ) + payload = pending.as_dict() if hasattr(pending, "as_dict") else dict(pending) + blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} + assert (blob_ref.get("credential") or {}).get( + "sasUri" + ), f"pending_upload response missing SAS URI: {payload!r}" + assert blob_ref.get("blobUri"), f"pending_upload response missing blobUri: {payload!r}" diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py new file mode 100644 index 000000000000..241b374d0ee3 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py @@ -0,0 +1,97 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Live, recorded async tests for ``project_client.beta.models``. + +Mirrors :mod:`tests.models.test_models` for the async client. ``register_model`` +itself is implemented only on the sync client (it shells out to ``azcopy``); the +async surface is exercised via ``list``, ``list_versions``, ``get`` and +``delete`` against a model registered with the sync helper as part of the +fixture. +""" +import os + +import pytest +from devtools_testutils import ( + add_general_regex_sanitizer, + is_live, + is_live_and_not_recording, +) +from devtools_testutils.aio import recorded_by_proxy_async +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError + +from test_base import TestBase, servicePreparer + +script_dir = os.path.dirname(os.path.abspath(__file__)) +data_folder = os.environ.get("DATA_FOLDER", os.path.join(script_dir, "../test_data/models")) + + +@pytest.mark.skipif( + not is_live_and_not_recording(), + reason="Skipped when using recordings due to flakiness of recording blob storage calls", +) +class TestModelsAsync(TestBase): + + # cls & pytest tests\models\test_models_async.py::TestModelsAsync::test_models_async_list_get_delete -s + @servicePreparer() + @recorded_by_proxy_async + async def test_models_async_list_get_delete(self, **kwargs): + """Register a model with the sync helper, then drive list/get/delete async.""" + from azure.ai.projects import AIProjectClient as SyncAIProjectClient + + model_name = self.test_models_params["model_name_1"] + model_version = self.test_models_params["model_version"] + expected_model_name = model_name if is_live() else "sanitized-model-name" + add_general_regex_sanitizer(regex=r"test-model-name-\d{5}", value="sanitized-model-name", function_scoped=True) + + endpoint = kwargs["foundry_project_endpoint"] + + # Set up: register a model using the sync helper (azcopy is sync). + with SyncAIProjectClient( + endpoint=endpoint, + credential=self.get_credential(SyncAIProjectClient, is_async=False), + ) as sync_client: + registered = sync_client.beta.models.register_model( + name=model_name, + version=model_version, + source=data_folder, + weight_type="FullWeight", + description="Registered by test_models_async", + tags={"source": "test_models_async.py"}, + ) + assert registered is not None + assert registered.name == expected_model_name + + # Exercise: drive the async client. + async with self.create_async_client(**kwargs) as project_client: + + print(f"[test_models_async] get {model_name}@{model_version}") + fetched = await project_client.beta.models.get(name=model_name, version=model_version) + assert fetched.name == expected_model_name + assert fetched.version == model_version + + print(f"[test_models_async] list_versions({model_name!r})") + versions = [] + async for mv in project_client.beta.models.list_versions(name=model_name): + versions.append(mv) + assert any(mv.version == model_version for mv in versions) + + print("[test_models_async] list (latest of every model)") + seen = 0 + async for mv in project_client.beta.models.list(): + seen += 1 + assert mv.name and mv.version + assert seen > 0 + + print(f"[test_models_async] delete {model_name}@{model_version}") + try: + await project_client.beta.models.delete(name=model_name, version=model_version) + except HttpResponseError as ex: + if ex.status_code != 200: + raise + + print(f"[test_models_async] get on deleted {model_name}@{model_version} should 404") + with pytest.raises((ResourceNotFoundError, HttpResponseError)): + await project_client.beta.models.get(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py new file mode 100644 index 000000000000..8eb9b8365374 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py @@ -0,0 +1,331 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Offline unit tests for ``azure.ai.projects.operations._patch_models``. + +These tests do not contact the Foundry service. They cover the patch helpers +``_extract_pending_upload_targets`` and ``_run_azcopy``, and the orchestration +performed by ``register_model`` (mocking ``pending_upload``, ``create_async`` +and ``get`` on the base class). +""" +from __future__ import annotations + +import os +import subprocess +from pathlib import Path +from types import SimpleNamespace +from unittest import mock + +import pytest + +from azure.core.exceptions import ResourceNotFoundError + +from azure.ai.projects.operations._patch_models import BetaModelsOperations + + +# --------------------------------------------------------------------------- +# _extract_pending_upload_targets +# --------------------------------------------------------------------------- + + +class TestExtractPendingUploadTargets: + def test_datastore_wire_shape(self): + """The service currently returns ``blobReferenceForConsumption``.""" + payload = { + "blobReferenceForConsumption": { + "blobUri": "https://acct.blob.core.windows.net/c/path", + "credential": {"sasUri": "https://acct.blob.core.windows.net/c/path?sig=abc"}, + }, + "temporaryDataReferenceId": "abc-123", + } + sas, blob, pid = BetaModelsOperations._extract_pending_upload_targets(payload) + assert sas == payload["blobReferenceForConsumption"]["credential"]["sasUri"] + assert blob == payload["blobReferenceForConsumption"]["blobUri"] + assert pid == "abc-123" + + def test_modeled_wire_shape(self): + """The SDK-modeled shape uses ``blobReference`` / ``pendingUploadId``.""" + payload = { + "blobReference": { + "blobUri": "https://acct.blob.core.windows.net/c/path", + "credential": {"sasUri": "https://acct.blob.core.windows.net/c/path?sig=xyz"}, + }, + "pendingUploadId": "modeled-id", + } + sas, blob, pid = BetaModelsOperations._extract_pending_upload_targets(payload) + assert sas == payload["blobReference"]["credential"]["sasUri"] + assert blob == payload["blobReference"]["blobUri"] + assert pid == "modeled-id" + + def test_response_object_with_as_dict(self): + """Accept anything exposing ``.as_dict()`` (the modeled response type).""" + payload = { + "blobReference": { + "blobUri": "https://x/y", + "credential": {"sasUri": "https://x/y?sas"}, + }, + "pendingUploadId": "id1", + } + response = SimpleNamespace(as_dict=lambda: payload) + sas, blob, pid = BetaModelsOperations._extract_pending_upload_targets(response) + assert (sas, blob, pid) == ("https://x/y?sas", "https://x/y", "id1") + + def test_missing_sas_uri_raises(self): + payload = { + "blobReferenceForConsumption": {"blobUri": "https://x/y", "credential": {}}, + } + with pytest.raises(ValueError, match="SAS URI / blob URI"): + BetaModelsOperations._extract_pending_upload_targets(payload) + + def test_missing_blob_uri_raises(self): + payload = { + "blobReferenceForConsumption": {"credential": {"sasUri": "https://x?sas"}}, + } + with pytest.raises(ValueError, match="SAS URI / blob URI"): + BetaModelsOperations._extract_pending_upload_targets(payload) + + def test_missing_pending_upload_id_is_none(self): + payload = { + "blobReferenceForConsumption": { + "blobUri": "https://x/y", + "credential": {"sasUri": "https://x/y?sas"}, + }, + } + sas, blob, pid = BetaModelsOperations._extract_pending_upload_targets(payload) + assert pid is None + assert (sas, blob) == ("https://x/y?sas", "https://x/y") + + +# --------------------------------------------------------------------------- +# _run_azcopy +# --------------------------------------------------------------------------- + + +class TestRunAzcopy: + def test_missing_azcopy_raises_runtime_error(self, tmp_path): + src = tmp_path / "weights.bin" + src.write_bytes(b"x") + with mock.patch("azure.ai.projects.operations._patch_models.shutil.which", return_value=None): + with pytest.raises(RuntimeError, match="azcopy"): + BetaModelsOperations._run_azcopy(src, "https://x?sas") + + def test_explicit_path_overrides_shutil_which(self, tmp_path): + src = tmp_path / "weights.bin" + src.write_bytes(b"x") + completed = SimpleNamespace(returncode=0, stdout="", stderr="") + with mock.patch( + "azure.ai.projects.operations._patch_models.subprocess.run", + return_value=completed, + ) as run, mock.patch("azure.ai.projects.operations._patch_models.shutil.which", return_value=None): + BetaModelsOperations._run_azcopy(src, "https://x?sas", azcopy_path="/opt/azcopy") + assert run.call_args.args[0][0] == "/opt/azcopy" + + def test_directory_source_uses_glob_arg(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + completed = SimpleNamespace(returncode=0, stdout="", stderr="") + with mock.patch( + "azure.ai.projects.operations._patch_models.subprocess.run", + return_value=completed, + ) as run, mock.patch("azure.ai.projects.operations._patch_models.shutil.which", return_value="/usr/bin/azcopy"): + BetaModelsOperations._run_azcopy(tmp_path, "https://x?sas") + cmd = run.call_args.args[0] + assert cmd[0] == "/usr/bin/azcopy" + assert cmd[1] == "copy" + assert cmd[2] == str(tmp_path / "*") + assert cmd[3] == "https://x?sas" + assert "--from-to" in cmd + assert cmd[cmd.index("--from-to") + 1] == "LocalBlob" + assert "--recursive" in cmd + + def test_file_source_uses_file_arg(self, tmp_path): + src = tmp_path / "weights.bin" + src.write_bytes(b"x") + completed = SimpleNamespace(returncode=0, stdout="", stderr="") + with mock.patch( + "azure.ai.projects.operations._patch_models.subprocess.run", + return_value=completed, + ) as run, mock.patch("azure.ai.projects.operations._patch_models.shutil.which", return_value="/usr/bin/azcopy"): + BetaModelsOperations._run_azcopy(src, "https://x?sas") + assert run.call_args.args[0][2] == str(src) + + def test_missing_source_raises_value_error(self, tmp_path): + ghost = tmp_path / "does-not-exist" + with mock.patch("azure.ai.projects.operations._patch_models.shutil.which", return_value="/usr/bin/azcopy"): + with pytest.raises(ValueError, match="does not exist"): + BetaModelsOperations._run_azcopy(ghost, "https://x?sas") + + def test_nonzero_exit_raises_runtime_error(self, tmp_path): + src = tmp_path / "weights.bin" + src.write_bytes(b"x") + completed = SimpleNamespace(returncode=1, stdout="oops-stdout", stderr="oops-stderr") + with mock.patch( + "azure.ai.projects.operations._patch_models.subprocess.run", + return_value=completed, + ), mock.patch("azure.ai.projects.operations._patch_models.shutil.which", return_value="/usr/bin/azcopy"): + with pytest.raises(RuntimeError, match="exited with code 1"): + BetaModelsOperations._run_azcopy(src, "https://x?sas") + + +# --------------------------------------------------------------------------- +# register_model orchestration +# --------------------------------------------------------------------------- + + +def _make_ops() -> BetaModelsOperations: + """Build a ``BetaModelsOperations`` without going through the client wiring.""" + return BetaModelsOperations.__new__(BetaModelsOperations) + + +def _pending_payload() -> dict: + return { + "blobReferenceForConsumption": { + "blobUri": "https://acct.blob.core.windows.net/c/path", + "credential": {"sasUri": "https://acct.blob.core.windows.net/c/path?sig=abc"}, + }, + "temporaryDataReferenceId": "pending-id-1", + } + + +class TestRegisterModelOrchestration: + def test_register_model_runs_three_steps_in_order_and_returns_get_result(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + ops = _make_ops() + + committed = SimpleNamespace( + id="model/abc", + name="my-model", + version="1", + blob_uri="https://acct.blob.core.windows.net/c/path", + ) + calls: list[str] = [] + + def fake_pending_upload(**kwargs): + calls.append("pending_upload") + assert kwargs["name"] == "my-model" + assert kwargs["version"] == "1" + return _pending_payload() + + def fake_run_azcopy(source, sas_uri, *, azcopy_path=None): # noqa: ARG001 + calls.append("azcopy") + assert Path(source) == tmp_path + assert sas_uri.startswith("https://") + assert azcopy_path == "/custom/azcopy" + + def fake_create_async(**kwargs): + calls.append("create_async") + assert kwargs["name"] == "my-model" + assert kwargs["version"] == "1" + body = kwargs["body"] + # The blob_uri from the pending response is plumbed into the commit body. + assert body.blob_uri == "https://acct.blob.core.windows.net/c/path" + assert body.weight_type == "FullWeight" + assert body.description == "desc" + assert body.tags == {"k": "v"} + + def fake_get(**kwargs): + calls.append("get") + assert kwargs["name"] == "my-model" + assert kwargs["version"] == "1" + return committed + + with mock.patch.object(ops, "pending_upload", side_effect=fake_pending_upload), mock.patch.object( + BetaModelsOperations, "_run_azcopy", staticmethod(fake_run_azcopy) + ), mock.patch.object(ops, "create_async", side_effect=fake_create_async), mock.patch.object( + ops, "get", side_effect=fake_get + ): + result = ops.register_model( + name="my-model", + version="1", + source=tmp_path, + weight_type="FullWeight", + description="desc", + tags={"k": "v"}, + azcopy_path="/custom/azcopy", + ) + + assert result is committed + assert calls == ["pending_upload", "azcopy", "create_async", "get"] + + def test_register_model_wait_for_commit_false_returns_none_and_does_not_poll(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + ops = _make_ops() + get_mock = mock.Mock() + + with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( + BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) + ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object(ops, "get", get_mock): + result = ops.register_model( + name="m", + version="1", + source=tmp_path, + wait_for_commit=False, + ) + + assert result is None + get_mock.assert_not_called() + + def test_register_model_polls_until_get_succeeds(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + ops = _make_ops() + committed = SimpleNamespace(name="m", version="1") + + get_mock = mock.Mock( + side_effect=[ + ResourceNotFoundError(message="not yet"), + ResourceNotFoundError(message="still not yet"), + committed, + ] + ) + + with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( + BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) + ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object( + ops, "get", get_mock + ), mock.patch( + "azure.ai.projects.operations._patch_models.time.sleep" + ) as sleep: + result = ops.register_model( + name="m", + version="1", + source=tmp_path, + polling_interval=0.01, + ) + + assert result is committed + assert get_mock.call_count == 3 + assert sleep.call_count == 2 + + def test_register_model_polling_timeout_raises_runtime_error(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + ops = _make_ops() + + # First a real time.monotonic call (start), then an over-the-deadline one. + times = iter([1000.0, 1000.0, 9999.0]) + with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( + BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) + ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object( + ops, "get", side_effect=ResourceNotFoundError(message="never") + ), mock.patch( + "azure.ai.projects.operations._patch_models.time.monotonic", + side_effect=lambda: next(times), + ), mock.patch( + "azure.ai.projects.operations._patch_models.time.sleep" + ): + with pytest.raises(RuntimeError, match="did not appear within"): + ops.register_model( + name="m", + version="1", + source=tmp_path, + polling_timeout=1.0, + ) + + def test_register_model_missing_source_raises_before_calling_service(self, tmp_path): + ops = _make_ops() + ghost = tmp_path / "does-not-exist" + pending = mock.Mock() + with mock.patch.object(ops, "pending_upload", pending): + with pytest.raises(ValueError, match="does not exist"): + ops.register_model(name="m", version="1", source=ghost) + pending.assert_not_called() diff --git a/sdk/ai/azure-ai-projects/tests/test_base.py b/sdk/ai/azure-ai-projects/tests/test_base.py index 1fb8abbc1c3c..7787af4baa8c 100644 --- a/sdk/ai/azure-ai-projects/tests/test_base.py +++ b/sdk/ai/azure-ai-projects/tests/test_base.py @@ -204,6 +204,12 @@ class TestBase(AzureRecordedTestCase): "connection_name": "balapvbyostoragecanary", } + test_models_params = { + "model_name_1": f"test-model-name-{random.randint(0, 99999):05d}", + "model_name_2": f"test-model-name-{random.randint(0, 99999):05d}", + "model_version": "1", + } + test_files_params = { "test_file_name": "test_file.jsonl", "file_purpose": "fine-tune", diff --git a/sdk/ai/azure-ai-projects/tests/test_data/models/config.json b/sdk/ai/azure-ai-projects/tests/test_data/models/config.json new file mode 100644 index 000000000000..a60e008113c0 --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/test_data/models/config.json @@ -0,0 +1 @@ +{"sample": true} diff --git a/sdk/ai/azure-ai-projects/tests/test_data/models/weights.bin b/sdk/ai/azure-ai-projects/tests/test_data/models/weights.bin new file mode 100644 index 000000000000..06a01532107f --- /dev/null +++ b/sdk/ai/azure-ai-projects/tests/test_data/models/weights.bin @@ -0,0 +1 @@ +test-weight-bytes From bce90ad7546015a60cd30166c1ddb5d6118c6096 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Tue, 12 May 2026 16:30:21 +0530 Subject: [PATCH 02/14] modifying sample to .py instead of .ipynb and update changelog --- sdk/ai/azure-ai-projects/CHANGELOG.md | 5 + .../samples/models/sample_models.ipynb | 307 ------------------ .../samples/models/sample_models.py | 123 +++++++ .../models/sample_models_without_patch.py | 141 ++++++++ 4 files changed, 269 insertions(+), 307 deletions(-) delete mode 100644 sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb create mode 100644 sdk/ai/azure-ai-projects/samples/models/sample_models.py create mode 100644 sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py diff --git a/sdk/ai/azure-ai-projects/CHANGELOG.md b/sdk/ai/azure-ai-projects/CHANGELOG.md index 1caa7949ab75..00db87eb046c 100644 --- a/sdk/ai/azure-ai-projects/CHANGELOG.md +++ b/sdk/ai/azure-ai-projects/CHANGELOG.md @@ -11,6 +11,8 @@ * New evaluator generation job operations on `.beta.evaluators`: `create_generation_job`, `get_generation_job`, `list_generation_jobs`, `cancel_generation_job`, `delete_generation_job`. * New methods on `.beta.agents` sub-client for code-based hosted agents: `update_agent_from_code()`, `create_agent_version_from_code()`, `download_agent_version_code()`, `download_agent_code()`. * New read-only property `content_hash` on `CodeConfiguration`, returning the SHA-256 hex digest of the uploaded code zip. +* New `.beta.models` sub-client for registering and managing local model weights as Foundry `ModelVersion` resources, with operations: `register_model`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `create_async`, `get_credentials`. +* New convenience method `.beta.models.register_model()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `create_async`) and polls `get()` until the new `ModelVersion` is observable. ### Breaking Changes @@ -39,6 +41,9 @@ Breaking changes in beta classes: * Added Hosted Agent creation sample `sample_hosted_agent_create.py`, demonstrating hosted agent version creation and retrieval with `AIProjectClient`. * The Hosted Agent creation sample also demonstrates assigning the hosted agent managed identity the Azure AI User RBAC role on the backing Azure AI account. * Updated the other Hosted Agent samples to reuse an existing Hosted Agent as a prerequisite, instead of creating a new hosted agent version in each sample. +* Added `.beta.models` samples under `samples/models/`: + * `sample_models.py` — end-to-end registration via the `register_model` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + * `sample_models_pending_upload.py` — alternative registration that hand-rolls the spec's three-step flow (`pending_upload` → upload via `azure-storage-blob` → `create_async` + poll), without taking a dependency on `azcopy`. ## 2.1.0 (2026-04-20) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb b/sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb deleted file mode 100644 index 852b2aa3b0f0..000000000000 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models.ipynb +++ /dev/null @@ -1,307 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "ef8034da", - "metadata": {}, - "source": [ - "# Microsoft Foundry — Models (`project_client.beta.models`)\n", - "\n", - "This notebook demonstrates how to use the synchronous `.beta.models` operations on `AIProjectClient` to register a local model with the project, list and inspect model versions, retrieve storage credentials, update metadata, and delete a model version.\n", - "\n", - "## Operations covered\n", - "\n", - "| Method | Purpose |\n", - "| --- | --- |\n", - "| `register_model` | End-to-end helper: provisions blob storage, uploads weights via `azcopy`, and commits the registration. **Recommended entry point.** |\n", - "| `list` | List the latest version of every registered model. |\n", - "| `list_versions` | List all versions of a single model. |\n", - "| `get` | Fetch a specific `ModelVersion`. |\n", - "| `get_credentials` | Retrieve a SAS URI for the blob container backing a registered version. |\n", - "| `update` | Merge-patch the `description` / `tags` of an existing model version. |\n", - "| `delete` | Delete a specific model version. |\n", - "| `pending_upload` / `create_async` | Lower-level building blocks used internally by `register_model`. |\n", - "\n", - "## Prerequisites\n", - "\n", - "```bash\n", - "pip install \"azure-ai-projects>=2.2.0\" azure-identity python-dotenv\n", - "```\n", - "\n", - "[**AzCopy**](https://aka.ms/downloadazcopy) must be installed and on `PATH` (used by `register_model` to upload weight files):\n", - "\n", - "```powershell\n", - "winget install --id Microsoft.Azure.AZCopy.10 -e\n", - "```\n", - "\n", - "Set the following environment variables (a `.env` file is supported):\n", - "\n", - "* `FOUNDRY_PROJECT_ENDPOINT` — required. The Azure AI Project endpoint shown on the Microsoft Foundry project Overview page.\n", - "* `MODEL_NAME` — optional. Defaults to `\"sample-model\"`.\n", - "* `MODEL_VERSION` — optional. Defaults to `\"1\"`." - ] - }, - { - "cell_type": "markdown", - "id": "23ed3eec", - "metadata": {}, - "source": [ - "## 1. Set up the client\n", - "\n", - "Create an `AIProjectClient` using `DefaultAzureCredential`. We also create a tiny temp folder with two dummy \"weight\" files to register." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a0b03dde", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import pathlib\n", - "import tempfile\n", - "\n", - "from dotenv import load_dotenv\n", - "from azure.identity import DefaultAzureCredential\n", - "from azure.ai.projects import AIProjectClient\n", - "\n", - "load_dotenv()\n", - "\n", - "endpoint = os.environ[\"FOUNDRY_PROJECT_ENDPOINT\"]\n", - "model_name = os.environ.get(\"MODEL_NAME\", \"sample-model\")\n", - "model_version = os.environ.get(\"MODEL_VERSION\", \"1\")\n", - "\n", - "credential = DefaultAzureCredential()\n", - "project_client = AIProjectClient(endpoint=endpoint, credential=credential)\n", - "\n", - "# Build a tiny throw-away source folder with two files to upload.\n", - "source_dir = pathlib.Path(tempfile.mkdtemp(prefix=\"sample-model-\"))\n", - "(source_dir / \"weights.bin\").write_bytes(b\"hello-foundry-model\")\n", - "(source_dir / \"config.json\").write_text('{\"sample\": true}')\n", - "print(f\"Source folder: {source_dir}\")\n", - "for f in sorted(source_dir.rglob(\"*\")):\n", - " if f.is_file():\n", - " print(f\" - {f.relative_to(source_dir)} ({f.stat().st_size} bytes)\")" - ] - }, - { - "cell_type": "markdown", - "id": "ff0bc195", - "metadata": {}, - "source": [ - "## 2. Register a local model — `register_model`\n", - "\n", - "`register_model` is the recommended way to create a new model version from local files. It packs the spec's three required steps into a single call:\n", - "\n", - "1. `pending_upload(...)` — provision a project-managed blob container and obtain a SAS URI.\n", - "2. `azcopy copy ...` — upload the local weight files directly to that container.\n", - "3. `create_async(...)` — commit the registration, then poll `get()` until the new `ModelVersion` is observable.\n", - "\n", - "The `weight_type` parameter accepts the `FoundryModelWeightType` enum (`FULL_WEIGHT`, `LO_RA`, `DRAFT_MODEL`) or the equivalent string. The committed `ModelVersion` also exposes service-populated fields such as `artifact_profile`, `source`, and `warnings`.\n", - "\n", - "Use the lower-level `pending_upload` / `create_async` methods directly only if you need to customize one of those steps (for example, to use your own upload tool)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "02e1d051", - "metadata": {}, - "outputs": [], - "source": [ - "from azure.ai.projects.models import FoundryModelWeightType\n", - "\n", - "model = project_client.beta.models.register_model(\n", - " name=model_name,\n", - " version=model_version,\n", - " source=source_dir,\n", - " weight_type=FoundryModelWeightType.FULL_WEIGHT,\n", - " description=\"Sample model registered from sample_models.ipynb\",\n", - " tags={\"source\": \"sample_models.ipynb\"},\n", - ")\n", - "\n", - "print(f\"Registered: {model.name}@{model.version}\")\n", - "print(f\" id = {model.id}\")\n", - "print(f\" blob_uri = {model.blob_uri}\")\n", - "print(f\" weight_type = {model.weight_type}\")\n", - "print(f\" description = {model.description}\")\n", - "print(f\" tags = {model.tags}\")\n", - "print(f\" source = {model.source}\")\n", - "print(f\" artifact_profile = {model.artifact_profile}\")\n", - "print(f\" warnings = {model.warnings}\")" - ] - }, - { - "cell_type": "markdown", - "id": "a2466321", - "metadata": {}, - "source": [ - "## 3. Get a specific model version — `get`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bec4ee7b", - "metadata": {}, - "outputs": [], - "source": [ - "fetched = project_client.beta.models.get(name=model_name, version=model_version)\n", - "print(f\"{fetched.name}@{fetched.version} -> {fetched.id}\")" - ] - }, - { - "cell_type": "markdown", - "id": "6d347100", - "metadata": {}, - "source": [ - "## 4. List all versions of a model — `list_versions`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "599248cb", - "metadata": {}, - "outputs": [], - "source": [ - "print(f\"Versions of {model_name!r}:\")\n", - "for mv in project_client.beta.models.list_versions(name=model_name):\n", - " print(f\" - {mv.version}\")" - ] - }, - { - "cell_type": "markdown", - "id": "12de6668", - "metadata": {}, - "source": [ - "## 5. List the latest version of every model — `list`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "13d73415", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Latest version of every registered model in this project:\")\n", - "for mv in project_client.beta.models.list():\n", - " print(f\" - {mv.name}@{mv.version}\")" - ] - }, - { - "cell_type": "markdown", - "id": "18f1563b", - "metadata": {}, - "source": [ - "## 6. Get blob credentials for a model version — `get_credentials`\n", - "\n", - "Returns a short-lived SAS URI that can be used to read the blob container backing the registered model. The SAS query string is sensitive — treat it like a credential." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8920c93", - "metadata": {}, - "outputs": [], - "source": [ - "from azure.ai.projects.models import ModelCredentialRequest\n", - "\n", - "creds = project_client.beta.models.get_credentials(\n", - " name=model_name,\n", - " version=model_version,\n", - " body=ModelCredentialRequest(blob_uri=model.blob_uri),\n", - ")\n", - "blob_ref = getattr(creds, \"blob_reference_for_consumption\", None) or getattr(creds, \"blob_reference\", None)\n", - "if blob_ref is not None:\n", - " sas_uri = (blob_ref.credential.sas_uri if blob_ref.credential else None) or \"\"\n", - " print(f\" blob_uri = {blob_ref.blob_uri}\")\n", - " print(f\" sas_uri = {sas_uri.split('?', 1)[0]}?\")\n", - "else:\n", - " print(creds)" - ] - }, - { - "cell_type": "markdown", - "id": "e9fb0fdb", - "metadata": {}, - "source": [ - "## 7. Update an existing model version — `update`\n", - "\n", - "`update` issues a merge-patch (`PATCH /models/{name}/versions/{version}`) and accepts an `UpdateModelVersionRequest` body containing only the patchable fields (`description`, `tags`)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ecc9d2fd", - "metadata": {}, - "outputs": [], - "source": [ - "from azure.ai.projects.models import UpdateModelVersionRequest\n", - "\n", - "updated = project_client.beta.models.update(\n", - " name=model_name,\n", - " version=model_version,\n", - " body=UpdateModelVersionRequest(\n", - " description=\"Updated description\",\n", - " tags={\"source\": \"sample_models.ipynb\", \"updated\": \"true\"},\n", - " ),\n", - ")\n", - "print(f\"Updated: {updated.name}@{updated.version}\")\n", - "print(f\" description = {updated.description}\")\n", - "print(f\" tags = {updated.tags}\")" - ] - }, - { - "cell_type": "markdown", - "id": "9d8397e8", - "metadata": {}, - "source": [ - "## 8. Delete a model version — `delete`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ce968d2", - "metadata": {}, - "outputs": [], - "source": [ - "project_client.beta.models.delete(name=model_name, version=model_version)\n", - "print(f\"Deleted {model_name}@{model_version}.\")" - ] - }, - { - "cell_type": "markdown", - "id": "49ed4aa3", - "metadata": {}, - "source": [ - "## Cleanup\n", - "\n", - "Close the client and credential." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6a18aa29", - "metadata": {}, - "outputs": [], - "source": [ - "project_client.close()\n", - "credential.close()" - ] - } - ], - "metadata": { - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models.py b/sdk/ai/azure-ai-projects/samples/models/sample_models.py new file mode 100644 index 000000000000..602e7157da56 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models.py @@ -0,0 +1,123 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Given an AIProjectClient, this sample demonstrates how to use the synchronous + `.beta.models` operations to register a local model with a Microsoft Foundry + project, list and inspect model versions, retrieve storage credentials, + update version metadata, and delete a model version. + + The recommended entry point is the patched helper + `project_client.beta.models.register_model(...)`, which packs the spec's + three required steps (`pending_upload` -> `azcopy copy` -> `create_async`) + into a single call and polls until the new ModelVersion is observable. + +USAGE: + python sample_models.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity python-dotenv + + AzCopy must also be installed and on PATH (used by `register_model` to + upload weight files): + + winget install --id Microsoft.Azure.AZCopy.10 -e + + See https://aka.ms/downloadazcopy for other platforms. + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as + found in the overview page of your Microsoft Foundry project. + 2) MODEL_NAME - Optional. The name of the model to register. Defaults to + "sample-model". + 3) MODEL_VERSION - Optional. The version of the model to register. + Defaults to "1". + 4) DATA_FOLDER - Optional. The folder containing the local weight files + to upload. Defaults to a temp folder created with two tiny dummy files. +""" + +import os +import pathlib +import tempfile + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + FoundryModelWeightType, + ModelCredentialRequest, + UpdateModelVersionRequest, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ.get("MODEL_NAME", "sample-model") +model_version = os.environ.get("MODEL_VERSION", "1") + +# Construct the path to the local folder of weight files used in this sample. +data_folder = os.environ.get("DATA_FOLDER") +if not data_folder: + data_folder = tempfile.mkdtemp(prefix="sample-model-") + (pathlib.Path(data_folder) / "weights.bin").write_bytes(b"hello-foundry-model") + (pathlib.Path(data_folder) / "config.json").write_text('{"sample": true}') + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, +): + + print( + f"Register a local model named `{model_name}` version `{model_version}` " + f"by uploading the contents of `{data_folder}` via `register_model`." + ) + model = project_client.beta.models.register_model( + name=model_name, + version=model_version, + source=data_folder, + weight_type=FoundryModelWeightType.FULL_WEIGHT, + description="Sample model registered from sample_models.py", + tags={"source": "sample_models.py"}, + ) + print(model) + + print(f"Get a specific model version `{model_name}`@`{model_version}`:") + fetched = project_client.beta.models.get(name=model_name, version=model_version) + print(fetched) + + print(f"List all versions of model `{model_name}`:") + for mv in project_client.beta.models.list_versions(name=model_name): + print(f" - {mv.version}") + + print("List the latest version of every registered model in this project:") + for mv in project_client.beta.models.list(): + print(f" - {mv.name}@{mv.version}") + + print(f"Get blob credentials for `{model_name}`@`{model_version}`:") + creds = project_client.beta.models.get_credentials( + name=model_name, + version=model_version, + body=ModelCredentialRequest(blob_uri=model.blob_uri), + ) + print(creds) + + print(f"Update description and tags on `{model_name}`@`{model_version}`:") + updated = project_client.beta.models.update( + name=model_name, + version=model_version, + body=UpdateModelVersionRequest( + description="Updated description", + tags={"source": "sample_models.py", "updated": "true"}, + ), + ) + print(updated) + + print(f"Delete the model version created above (`{model_name}`@`{model_version}`):") + project_client.beta.models.delete(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py new file mode 100644 index 000000000000..8377b835a88c --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py @@ -0,0 +1,141 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Given an AIProjectClient, this sample demonstrates how to register a local + model with a Microsoft Foundry project WITHOUT relying on the + `register_model` helper or the `azcopy` CLI. It hand-rolls the spec's + three-step upload-first sequence using only the generated `.beta.models` + operations and `azure-storage-blob`: + + 1) `pending_upload(...)` -- the service provisions a project-managed + blob container and returns a SAS URI. + 2) Upload the local weight files directly to that SAS container using + `azure.storage.blob.ContainerClient`. + 3) `create_async(...)` -- commit the registration. The service returns + 202 Accepted and finalizes the ModelVersion asynchronously, so we + poll `get(...)` until the new version is observable. + + This is useful when `azcopy` is not available, or when callers want to + integrate the upload step with their own progress reporting / retry logic. + +USAGE: + python sample_models_pending_upload.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity azure-storage-blob python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as + found in the overview page of your Microsoft Foundry project. + 2) MODEL_NAME - Optional. The name of the model to register. Defaults to + "sample-model-pending-upload". + 3) MODEL_VERSION - Optional. The version of the model to register. + Defaults to "1". + 4) DATA_FOLDER - Optional. The folder containing the local weight files + to upload. Defaults to a temp folder created with two tiny dummy files. +""" + +import os +import pathlib +import tempfile +import time + +from dotenv import load_dotenv + +from azure.identity import DefaultAzureCredential +from azure.core.exceptions import ResourceNotFoundError +from azure.storage.blob import ContainerClient + +from azure.ai.projects import AIProjectClient +from azure.ai.projects.models import ( + FoundryModelWeightType, + ModelVersion, + PendingUploadRequest, + PendingUploadType, +) + +load_dotenv() + +endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] +model_name = os.environ.get("MODEL_NAME", "sample-model-pending-upload") +model_version = os.environ.get("MODEL_VERSION", "1") + +# Construct the path to the local folder of weight files used in this sample. +data_folder = os.environ.get("DATA_FOLDER") +if not data_folder: + data_folder = tempfile.mkdtemp(prefix="sample-model-") + (pathlib.Path(data_folder) / "weights.bin").write_bytes(b"hello-foundry-model") + (pathlib.Path(data_folder) / "config.json").write_text('{"sample": true}') +source_dir = pathlib.Path(data_folder) + +with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, +): + + print(f"Step 1/3: pending_upload(name=`{model_name}`, version=`{model_version}`)") + pending = project_client.beta.models.pending_upload( + name=model_name, + version=model_version, + body=PendingUploadRequest( + pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, + ), + ) + # The wire payload uses the datastore-style `blobReferenceForConsumption` + # shape on some Foundry deployments and the SDK-modeled `blobReference` + # shape on others. Tolerate both. + payload = pending.as_dict() + blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} + sas_uri = (blob_ref.get("credential") or {}).get("sasUri") + container_blob_uri = blob_ref.get("blobUri") + if not sas_uri or not container_blob_uri: + raise RuntimeError(f"pending_upload response missing SAS / blob URI: {payload!r}") + print(f" blob_uri = {container_blob_uri}") + print(f" sas_uri = {sas_uri.split('?', 1)[0]}?") + + print(f"Step 2/3: upload contents of `{source_dir}` to the SAS container") + container_client = ContainerClient.from_container_url(sas_uri) + files = [p for p in source_dir.rglob("*") if p.is_file()] + for f in files: + rel = f.relative_to(source_dir).as_posix() + with f.open("rb") as fp: + container_client.upload_blob(name=rel, data=fp, overwrite=True) + print(f" uploaded {rel} ({f.stat().st_size} bytes)") + + print(f"Step 3/3: create_async(name=`{model_name}`, version=`{model_version}`)") + project_client.beta.models.create_async( + name=model_name, + version=model_version, + body=ModelVersion( + blob_uri=container_blob_uri, + weight_type=FoundryModelWeightType.FULL_WEIGHT, + description="Sample model registered from sample_models_pending_upload.py", + tags={"source": "sample_models_pending_upload.py"}, + ), + ) + + # `create_async` returns 202 Accepted; poll `get` until the committed + # ModelVersion is observable. + print(f"Polling get(`{model_name}`, `{model_version}`) until the ModelVersion is committed...") + deadline = time.monotonic() + 300.0 + model = None + while True: + try: + model = project_client.beta.models.get(name=model_name, version=model_version) + break + except ResourceNotFoundError: + if time.monotonic() >= deadline: + raise RuntimeError( + f"Model `{model_name}`@`{model_version}` did not appear within 300s after create_async." + ) + time.sleep(2.0) + print(model) + + print(f"Delete the model version created above (`{model_name}`@`{model_version}`):") + project_client.beta.models.delete(name=model_name, version=model_version) From a8d028b5c552c64878ac06aecd15f97e99b09996 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Wed, 13 May 2026 15:57:23 +0530 Subject: [PATCH 03/14] post emitter fixes and resolving review comments --- sdk/ai/azure-ai-projects/CHANGELOG.md | 9 +- sdk/ai/azure-ai-projects/README.md | 2 + .../azure/ai/projects/_utils/utils.py | 1 - .../ai/projects/aio/operations/_operations.py | 67 ++++--- .../azure/ai/projects/models/_enums.py | 12 +- .../azure/ai/projects/models/_models.py | 24 ++- .../ai/projects/operations/_operations.py | 67 ++++--- .../azure/ai/projects/operations/_patch.py | 2 +- .../ai/projects/operations/_patch_models.py | 85 +++++++-- .../samples/models/sample_models.py | 8 +- .../samples/models/sample_models_async.py | 177 ++++++++++++++++++ .../models/sample_models_without_patch.py | 2 +- .../tests/models/test_models.py | 27 +-- .../tests/models/test_models_async.py | 5 +- .../tests/models/test_patch_models.py | 137 ++++++++++++-- .../tests/samples/llm_instructions.py | 32 +--- 16 files changed, 513 insertions(+), 144 deletions(-) create mode 100644 sdk/ai/azure-ai-projects/samples/models/sample_models_async.py diff --git a/sdk/ai/azure-ai-projects/CHANGELOG.md b/sdk/ai/azure-ai-projects/CHANGELOG.md index 00db87eb046c..ded0186f2313 100644 --- a/sdk/ai/azure-ai-projects/CHANGELOG.md +++ b/sdk/ai/azure-ai-projects/CHANGELOG.md @@ -11,8 +11,8 @@ * New evaluator generation job operations on `.beta.evaluators`: `create_generation_job`, `get_generation_job`, `list_generation_jobs`, `cancel_generation_job`, `delete_generation_job`. * New methods on `.beta.agents` sub-client for code-based hosted agents: `update_agent_from_code()`, `create_agent_version_from_code()`, `download_agent_version_code()`, `download_agent_code()`. * New read-only property `content_hash` on `CodeConfiguration`, returning the SHA-256 hex digest of the uploaded code zip. -* New `.beta.models` sub-client for registering and managing local model weights as Foundry `ModelVersion` resources, with operations: `register_model`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `create_async`, `get_credentials`. -* New convenience method `.beta.models.register_model()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `create_async`) and polls `get()` until the new `ModelVersion` is observable. +* New `.beta.models` sub-client for registering and managing local model weights as Foundry `ModelVersion` resources. Generated operations: `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `create_async`, `get_credentials`. +* New convenience method `.beta.models.models_create()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `create_async`) and polls `get()` until the new `ModelVersion` is observable. ### Breaking Changes @@ -42,8 +42,9 @@ Breaking changes in beta classes: * The Hosted Agent creation sample also demonstrates assigning the hosted agent managed identity the Azure AI User RBAC role on the backing Azure AI account. * Updated the other Hosted Agent samples to reuse an existing Hosted Agent as a prerequisite, instead of creating a new hosted agent version in each sample. * Added `.beta.models` samples under `samples/models/`: - * `sample_models.py` — end-to-end registration via the `register_model` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. - * `sample_models_pending_upload.py` — alternative registration that hand-rolls the spec's three-step flow (`pending_upload` → upload via `azure-storage-blob` → `create_async` + poll), without taking a dependency on `azcopy`. + * `sample_models.py` — synchronous end-to-end registration via the `models_create` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + * `sample_models_without_patch.py` — alternative synchronous registration that hand-rolls the spec's three-step flow (`pending_upload` → upload via `azure-storage-blob` → `create_async` + poll), without taking a dependency on `azcopy`. + * `sample_models_async.py` — asynchronous version of the same three-step flow using `azure.ai.projects.aio.AIProjectClient` and `azure.storage.blob.aio.ContainerClient`. ## 2.1.0 (2026-04-20) diff --git a/sdk/ai/azure-ai-projects/README.md b/sdk/ai/azure-ai-projects/README.md index a442f76d91fc..8a8bbdfddce8 100644 --- a/sdk/ai/azure-ai-projects/README.md +++ b/sdk/ai/azure-ai-projects/README.md @@ -34,6 +34,7 @@ resources in your Microsoft Foundry Project. Use it to: * **Enumerate AI Models** deployed to your Foundry Project using `.deployments` operations. * **Enumerate connected Azure resources** in your Foundry project using `.connections` operations. * **Upload documents and create Datasets** to reference them using `.datasets` operations. +* **Register and manage local model weights** as Foundry `ModelVersion` resources using `.beta.models` operations, including the `models_create` end-to-end helper. * **Create and enumerate Search Indexes** using `.indexes` operations. The client library uses version `v1` of the Microsoft Foundry [data plane REST APIs](https://aka.ms/azsdk/azure-ai-projects-v2/api-reference-v1). @@ -165,6 +166,7 @@ Full descriptions and working code for all of the above are available in: | Deployments | [Deployment types](https://learn.microsoft.com/azure/foundry/foundry-models/concepts/deployment-types) | `samples/deployments/` | | Connections | [Connections operations](https://learn.microsoft.com/python/api/overview/azure/ai-projects-readme?view=azure-python#connections-operations) | `samples/connections/` | | Datasets | [Dataset operations](https://learn.microsoft.com/python/api/overview/azure/ai-projects-readme?view=azure-python#dataset-operations) | `samples/datasets/` | +| Models (preview) | Register local model weights as Foundry `ModelVersion` resources via `.beta.models` (`models_create`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `create_async`, `get_credentials`). | `samples/models/` | | Indexes | [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) | `samples/indexes/` | | Files (upload, retrieve, list, delete) | [OpenAI Files API](https://platform.openai.com/docs/api-reference/files) | `samples/files/` | | Fine-tuning | [Fine-Tuning in AI Foundry](https://github.com/microsoft-foundry/fine-tuning) | `samples/finetuning/` | diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py index bd821750f4c6..707b7d8fac75 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_utils/utils.py @@ -10,7 +10,6 @@ from .._utils.model_base import Model, SdkJSONEncoder - # file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)` FileContent = Union[str, bytes, IO[str], IO[bytes]] diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index 8f5fcc038dcc..8b0e9bc2ed4f 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -4014,29 +4014,23 @@ async def get_session_log_stream( Each SSE frame contains: * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema - is not contractual and may include additional keys or change format - over time — clients should treat it as an opaque string) + * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) Example SSE frames: .. code-block:: event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting - FoundryCBAgent server on port 8088"} + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} event: log - data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application - startup complete."} + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully - connected to container"} + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} event: log - data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since - last 60 seconds"} + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} The stream remains open until the client disconnects or the server terminates the connection. Clients should handle reconnection as needed. @@ -4078,7 +4072,7 @@ async def get_session_log_stream( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = True pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -4539,7 +4533,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -4969,7 +4966,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -5069,7 +5069,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -6258,7 +6261,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -6926,7 +6932,7 @@ async def _search_memories( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items_property": items, + "items": items, "options": options, "previous_search_id": previous_search_id, "scope": scope, @@ -7012,7 +7018,7 @@ async def _update_memories_initial( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items_property": items, + "items": items, "previous_update_id": previous_update_id, "scope": scope, "update_delay": update_delay, @@ -7402,7 +7408,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -7487,7 +7496,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -8350,7 +8362,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -8696,7 +8711,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -8996,7 +9014,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py index 6ba8cea31bc6..b65c38c1fa73 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py @@ -72,8 +72,8 @@ class AgentEndpointProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """ACTIVITY.""" RESPONSES = "responses" """RESPONSES.""" - A2_A = "a2a" - """A2_A.""" + A2A = "a2a" + """A2A.""" INVOCATIONS = "invocations" """INVOCATIONS.""" @@ -770,8 +770,8 @@ class RankerVersionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): AUTO = "auto" """AUTO.""" - DEFAULT2024_11_15 = "default-2024-11-15" - """DEFAULT2024_11_15.""" + DEFAULT_2024_11_15 = "default-2024-11-15" + """DEFAULT_2024_11_15.""" class RecurrenceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -938,8 +938,8 @@ class ToolChoiceParamType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """WEB_SEARCH_PREVIEW.""" COMPUTER_USE_PREVIEW = "computer_use_preview" """COMPUTER_USE_PREVIEW.""" - WEB_SEARCH_PREVIEW2025_03_11 = "web_search_preview_2025_03_11" - """WEB_SEARCH_PREVIEW2025_03_11.""" + WEB_SEARCH_PREVIEW_2025_03_11 = "web_search_preview_2025_03_11" + """WEB_SEARCH_PREVIEW_2025_03_11.""" IMAGE_GENERATION = "image_generation" """IMAGE_GENERATION.""" CODE_INTERPRETER = "code_interpreter" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py index c41674a2d9d4..ca04b06b7543 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py @@ -10486,12 +10486,10 @@ class SessionLogEvent(_Model): .. code-block:: event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting server - on port 18080"} + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting server on port 18080"} event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully - connected to container"}. + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} :ivar event: The SSE event type. Currently ``log``, but additional event types may be added in the future. Clients should ignore unrecognized event types. Required. "log" @@ -11468,7 +11466,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): or a Literal["required"] type. :vartype mode: str or str :ivar tools: A list of tool definitions that the model should be allowed to call. For the - Responses API, the list of tool definitions might look like: + Responses API, the list of tool definitions might look like the following. Required. .. code-block:: json @@ -11476,7 +11474,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): { "type": "function", "name": "get_weather" }, { "type": "mcp", "server_label": "deepwiki" }, { "type": "image_generation" } - ]. Required. + ] :vartype tools: list[dict[str, any]] """ @@ -11489,7 +11487,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): Literal[\"required\"] type.""" tools: list[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """A list of tool definitions that the model should be allowed to call. For the Responses API, the - list of tool definitions might look like: + list of tool definitions might look like the following. Required. .. code-block:: json @@ -11497,7 +11495,7 @@ class ToolChoiceAllowed(ToolChoiceParam, discriminator="allowed_tools"): { \"type\": \"function\", \"name\": \"get_weather\" }, { \"type\": \"mcp\", \"server_label\": \"deepwiki\" }, { \"type\": \"image_generation\" } - ]. Required.""" + ]""" @overload def __init__( @@ -11766,12 +11764,12 @@ class ToolChoiceWebSearchPreview20250311(ToolChoiceParam, discriminator="web_sea """Indicates that the model should use a built-in tool to generate a response. `Learn more about built-in tools `_. - :ivar type: Required. WEB_SEARCH_PREVIEW2025_03_11. - :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW2025_03_11 + :ivar type: Required. WEB_SEARCH_PREVIEW_2025_03_11. + :vartype type: str or ~azure.ai.projects.models.WEB_SEARCH_PREVIEW_2025_03_11 """ - type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW2025_03_11] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. WEB_SEARCH_PREVIEW2025_03_11.""" + type: Literal[ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. WEB_SEARCH_PREVIEW_2025_03_11.""" @overload def __init__( @@ -11787,7 +11785,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW2025_03_11 # type: ignore + self.type = ToolChoiceParamType.WEB_SEARCH_PREVIEW_2025_03_11 # type: ignore class ToolDescription(_Model): diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index e3fdf13fa077..78aa8bbfb245 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -6735,29 +6735,23 @@ def get_session_log_stream( Each SSE frame contains: * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema - is not contractual and may include additional keys or change format - over time — clients should treat it as an opaque string) + * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) Example SSE frames: .. code-block:: event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting - FoundryCBAgent server on port 8088"} + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} event: log - data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application - startup complete."} + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully - connected to container"} + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} event: log - data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since - last 60 seconds"} + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} The stream remains open until the client disconnects or the server terminates the connection. Clients should handle reconnection as needed. @@ -6799,7 +6793,7 @@ def get_session_log_stream( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = True pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -7260,7 +7254,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -7690,7 +7687,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -7790,7 +7790,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -8976,7 +8979,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -9644,7 +9650,7 @@ def _search_memories( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items_property": items, + "items": items, "options": options, "previous_search_id": previous_search_id, "scope": scope, @@ -9730,7 +9736,7 @@ def _update_memories_initial( if scope is _Unset: raise TypeError("missing required argument: scope") body = { - "items_property": items, + "items": items, "previous_update_id": previous_update_id, "scope": scope, "update_delay": update_delay, @@ -10119,7 +10125,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -10204,7 +10213,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -11067,7 +11079,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -11411,7 +11426,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( @@ -11711,7 +11729,10 @@ def prepare_request(next_link=None): ) _next_request_params["api-version"] = self._config.api_version _request = HttpRequest( - "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, ) path_format_arguments = { "endpoint": self._serialize.url( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index f492bee8e9ae..c280d73d0b6f 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -127,7 +127,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) # Replace with patched class that includes begin_update_memories self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) - # Replace with patched class that includes register_model (3-step upload helper) + # Replace with patched class that includes models_create (3-step upload helper) self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) for property_name, foundry_features_value in _BETA_OPERATION_FEATURE_HEADERS.items(): diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py index 9a07763bc823..3afcca8655c7 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -64,8 +64,8 @@ def _extract_pending_upload_targets( return sas_uri, container_blob_uri, pending_upload_id @staticmethod - def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None) -> None: - """Shell out to ``azcopy copy`` to upload ``source`` to the SAS container.""" + def _resolve_azcopy(azcopy_path: Optional[str] = None) -> str: + """Locate the ``azcopy`` executable or raise ``RuntimeError``.""" azcopy = azcopy_path or shutil.which("azcopy") if not azcopy: raise RuntimeError( @@ -73,6 +73,51 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None "(https://aka.ms/downloadazcopy) and ensure it is on PATH, or " "pass `azcopy_path=` explicitly." ) + return azcopy + + @staticmethod + def _validate_models_create_inputs( + *, + name: str, + version: str, + source: Union[str, "os.PathLike[str]"], + azcopy_path: Optional[str], + wait_for_commit: bool, + polling_timeout: float, + polling_interval: float, + ) -> Path: + """Validate ``models_create`` inputs up-front, before any service call. + + Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for + bad inputs and ``RuntimeError`` if ``azcopy`` cannot be located. + """ + if not isinstance(name, str) or not name.strip(): + raise ValueError("`name` must be a non-empty string.") + if not isinstance(version, str) or not version.strip(): + raise ValueError("`version` must be a non-empty string.") + + source_path = Path(os.fspath(source)) + if not source_path.exists(): + raise ValueError(f"Upload source does not exist: {source_path}") + if source_path.is_dir() and not any(p.is_file() for p in source_path.rglob("*")): + raise ValueError(f"Upload source directory is empty: {source_path}") + if source_path.is_file() and source_path.stat().st_size == 0: + raise ValueError(f"Upload source file is empty: {source_path}") + + if wait_for_commit: + if polling_timeout <= 0: + raise ValueError("`polling_timeout` must be > 0 when `wait_for_commit` is True.") + if polling_interval <= 0: + raise ValueError("`polling_interval` must be > 0 when `wait_for_commit` is True.") + + # Fail fast if azcopy isn't installed, before we provision a SAS container. + BetaModelsOperations._resolve_azcopy(azcopy_path) + return source_path + + @staticmethod + def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None) -> None: + """Shell out to ``azcopy copy`` to upload ``source`` to the SAS container.""" + azcopy = BetaModelsOperations._resolve_azcopy(azcopy_path) if source.is_dir(): src_arg = str(source / "*") @@ -94,13 +139,13 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None # Don't log the SAS query string — it's a credential. redacted = cmd.copy() redacted[3] = sas_uri.split("?", 1)[0] + "?" - logger.info("[register_model] running: %s", " ".join(redacted)) + logger.info("[models_create] running: %s", " ".join(redacted)) completed = subprocess.run(cmd, check=False, capture_output=True, text=True) if completed.stdout: - logger.debug("[register_model] azcopy stdout:\n%s", completed.stdout) + logger.debug("[models_create] azcopy stdout:\n%s", completed.stdout) if completed.stderr: - logger.debug("[register_model] azcopy stderr:\n%s", completed.stderr) + logger.debug("[models_create] azcopy stderr:\n%s", completed.stderr) if completed.returncode != 0: raise RuntimeError( f"azcopy exited with code {completed.returncode}.\n" @@ -108,7 +153,7 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None ) @distributed_trace - def register_model( + def models_create( self, *, name: str, @@ -168,19 +213,29 @@ def register_model( :return: The committed :class:`~azure.ai.projects.models.ModelVersion` when ``wait_for_commit`` is True, otherwise ``None``. :rtype: ~azure.ai.projects.models.ModelVersion or None - :raises ValueError: If ``source`` does not exist or the pending-upload - response is missing the SAS / blob URI. + :raises ValueError: If ``name``/``version`` are empty, ``source`` does + not exist or is empty, polling parameters are non-positive, or the + pending-upload response is missing the SAS / blob URI. :raises RuntimeError: If ``azcopy`` is not on PATH or exits with a non-zero status, or the registration does not commit before ``polling_timeout`` elapses. """ - source_path = Path(os.fspath(source)) - if not source_path.exists(): - raise ValueError(f"Upload source does not exist: {source_path}") + # --- Step 0: validate inputs up-front -------------------------------- + # Cheap local checks so we don't provision a SAS container or run + # azcopy when something obviously wrong was passed in. + source_path = self._validate_models_create_inputs( + name=name, + version=version, + source=source, + azcopy_path=azcopy_path, + wait_for_commit=wait_for_commit, + polling_timeout=polling_timeout, + polling_interval=polling_interval, + ) # --- Step 1: StartPendingUpload -------------------------------------- logger.info( - "[register_model] step 1/3 pending_upload(name=%r, version=%r)", + "[models_create] step 1/3 pending_upload(name=%r, version=%r)", name, version, ) @@ -194,13 +249,13 @@ def register_model( ) sas_uri, container_blob_uri, pending_upload_id = self._extract_pending_upload_targets(pending) logger.info( - "[register_model] pending_upload_id=%s blob_uri=%s", + "[models_create] pending_upload_id=%s blob_uri=%s", pending_upload_id, container_blob_uri, ) # --- Step 2: Upload via azcopy --------------------------------------- - logger.info("[register_model] step 2/3 azcopy upload from %s", source_path) + logger.info("[models_create] step 2/3 azcopy upload from %s", source_path) self._run_azcopy(source_path, sas_uri, azcopy_path=azcopy_path) # --- Step 3: Commit registration ------------------------------------- @@ -212,7 +267,7 @@ def register_model( tags=tags or {}, ) logger.info( - "[register_model] step 3/3 create_async(name=%r, version=%r)", + "[models_create] step 3/3 create_async(name=%r, version=%r)", name, version, ) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models.py b/sdk/ai/azure-ai-projects/samples/models/sample_models.py index 602e7157da56..75c9f7712042 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models.py @@ -12,7 +12,7 @@ update version metadata, and delete a model version. The recommended entry point is the patched helper - `project_client.beta.models.register_model(...)`, which packs the spec's + `project_client.beta.models.models_create(...)`, which packs the spec's three required steps (`pending_upload` -> `azcopy copy` -> `create_async`) into a single call and polls until the new ModelVersion is observable. @@ -23,7 +23,7 @@ pip install "azure-ai-projects>=2.2.0" azure-identity python-dotenv - AzCopy must also be installed and on PATH (used by `register_model` to + AzCopy must also be installed and on PATH (used by `models_create` to upload weight files): winget install --id Microsoft.Azure.AZCopy.10 -e @@ -76,9 +76,9 @@ print( f"Register a local model named `{model_name}` version `{model_version}` " - f"by uploading the contents of `{data_folder}` via `register_model`." + f"by uploading the contents of `{data_folder}` via `models_create`." ) - model = project_client.beta.models.register_model( + model = project_client.beta.models.models_create( name=model_name, version=model_version, source=data_folder, diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py new file mode 100644 index 000000000000..10925bc65a87 --- /dev/null +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py @@ -0,0 +1,177 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +""" +DESCRIPTION: + Given an asynchronous AIProjectClient, this sample demonstrates how to + register a local model with a Microsoft Foundry project and exercise the + asynchronous `.beta.models` operations: `pending_upload`, `create_async`, + `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + + The async client does not expose the `models_create` convenience helper + (which shells out to the synchronous `azcopy` CLI). This sample instead + drives the spec's three-step upload-first sequence directly: + + 1) `pending_upload(...)` -- the service provisions a project-managed + blob container and returns a SAS URI. + 2) Upload the local weight files to that SAS container using + `azure.storage.blob.aio.ContainerClient`. + 3) `create_async(...)` -- commit the registration. The service returns + 202 Accepted and finalizes the ModelVersion asynchronously, so we + poll `get(...)` until the new version is observable. + +USAGE: + python sample_models_async.py + + Before running the sample: + + pip install "azure-ai-projects>=2.2.0" azure-identity azure-storage-blob aiohttp python-dotenv + + Set these environment variables with your own values: + 1) FOUNDRY_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as + found in the overview page of your Microsoft Foundry project. + 2) MODEL_NAME - Optional. The name of the model to register. Defaults to + "sample-model-async". + 3) MODEL_VERSION - Optional. The version of the model to register. + Defaults to "1". + 4) DATA_FOLDER - Optional. The folder containing the local weight files + to upload. Defaults to a temp folder created with two tiny dummy files. +""" + +import asyncio +import os +import pathlib +import tempfile +import time + +from dotenv import load_dotenv + +from azure.core.exceptions import ResourceNotFoundError +from azure.identity.aio import DefaultAzureCredential +from azure.storage.blob.aio import ContainerClient + +from azure.ai.projects.aio import AIProjectClient +from azure.ai.projects.models import ( + FoundryModelWeightType, + ModelCredentialRequest, + ModelVersion, + PendingUploadRequest, + PendingUploadType, + UpdateModelVersionRequest, +) + +load_dotenv() + + +async def main() -> None: + + endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"] + model_name = os.environ.get("MODEL_NAME", "sample-model-async") + model_version = os.environ.get("MODEL_VERSION", "1") + + # Construct the path to the local folder of weight files used in this sample. + data_folder = os.environ.get("DATA_FOLDER") + if not data_folder: + data_folder = tempfile.mkdtemp(prefix="sample-model-async-") + (pathlib.Path(data_folder) / "weights.bin").write_bytes(b"hello-foundry-model") + (pathlib.Path(data_folder) / "config.json").write_text('{"sample": true}') + source_dir = pathlib.Path(data_folder) + + async with ( + DefaultAzureCredential() as credential, + AIProjectClient(endpoint=endpoint, credential=credential) as project_client, + ): + + print(f"Step 1/3: pending_upload(name=`{model_name}`, version=`{model_version}`)") + pending = await project_client.beta.models.pending_upload( + name=model_name, + version=model_version, + body=PendingUploadRequest( + pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, + ), + ) + # The wire payload uses the datastore-style `blobReferenceForConsumption` + # shape on some Foundry deployments and the SDK-modeled `blobReference` + # shape on others. Tolerate both. + payload = pending.as_dict() + blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} + sas_uri = (blob_ref.get("credential") or {}).get("sasUri") + container_blob_uri = blob_ref.get("blobUri") + if not sas_uri or not container_blob_uri: + raise RuntimeError(f"pending_upload response missing SAS / blob URI: {payload!r}") + print(f" blob_uri = {container_blob_uri}") + print(f" sas_uri = {sas_uri.split('?', 1)[0]}?") + + print(f"Step 2/3: upload contents of `{source_dir}` to the SAS container") + async with ContainerClient.from_container_url(sas_uri) as container_client: + for f in [p for p in source_dir.rglob("*") if p.is_file()]: + rel = f.relative_to(source_dir).as_posix() + with f.open("rb") as fp: + await container_client.upload_blob(name=rel, data=fp, overwrite=True) + print(f" uploaded {rel} ({f.stat().st_size} bytes)") + + print(f"Step 3/3: create_async(name=`{model_name}`, version=`{model_version}`)") + await project_client.beta.models.create_async( + name=model_name, + version=model_version, + body=ModelVersion( + blob_uri=container_blob_uri, + weight_type=FoundryModelWeightType.FULL_WEIGHT, + description="Sample model registered from sample_models_async.py", + tags={"source": "sample_models_async.py"}, + ), + ) + + # `create_async` returns 202 Accepted; poll `get` until the committed + # ModelVersion is observable. + print(f"Polling get(`{model_name}`, `{model_version}`) until the ModelVersion is committed...") + deadline = time.monotonic() + 300.0 + model: ModelVersion + while True: + try: + model = await project_client.beta.models.get(name=model_name, version=model_version) + break + except ResourceNotFoundError: + if time.monotonic() >= deadline: + raise RuntimeError( + f"Model `{model_name}`@`{model_version}` did not appear within 300s after create_async." + ) + await asyncio.sleep(2.0) + print(model) + + print(f"List all versions of model `{model_name}`:") + async for mv in project_client.beta.models.list_versions(name=model_name): + print(f" - {mv.version}") + + print("List the latest version of every registered model in this project:") + async for mv in project_client.beta.models.list(): + print(f" - {mv.name}@{mv.version}") + + print(f"Get blob credentials for `{model_name}`@`{model_version}`:") + creds = await project_client.beta.models.get_credentials( + name=model_name, + version=model_version, + body=ModelCredentialRequest(blob_uri=model.blob_uri), + ) + print(creds) + + print(f"Update description and tags on `{model_name}`@`{model_version}`:") + updated = await project_client.beta.models.update( + name=model_name, + version=model_version, + body=UpdateModelVersionRequest( + description="Updated description", + tags={"source": "sample_models_async.py", "updated": "true"}, + ), + ) + print(updated) + + print(f"Delete the model version created above (`{model_name}`@`{model_version}`):") + await project_client.beta.models.delete(name=model_name, version=model_version) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py index 8377b835a88c..9bc181654810 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py @@ -8,7 +8,7 @@ DESCRIPTION: Given an AIProjectClient, this sample demonstrates how to register a local model with a Microsoft Foundry project WITHOUT relying on the - `register_model` helper or the `azcopy` CLI. It hand-rolls the spec's + `models_create` helper or the `azcopy` CLI. It hand-rolls the spec's three-step upload-first sequence using only the generated `.beta.models` operations and `azure-storage-blob`: diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models.py b/sdk/ai/azure-ai-projects/tests/models/test_models.py index 694a7e7ccf8b..cc7c1e402e6c 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models.py @@ -7,7 +7,7 @@ These tests exercise the generated ``BetaModelsOperations`` (``list``, ``list_versions``, ``get``, ``pending_upload``, ``get_credentials``, ``delete``) -and the patched ``register_model`` end-to-end helper. They follow the same +and the patched ``models_create`` end-to-end helper. They follow the same "upload + record" pattern used by ``test_datasets.py``. ``create_or_update`` is intentionally not tested here. The Foundry data plane @@ -15,6 +15,7 @@ same name/version succeeds. The cell will be re-enabled once the service-side issue is fixed. """ + import os import pytest @@ -39,10 +40,10 @@ ) class TestModels(TestBase): - # cls & pytest tests\models\test_models.py::TestModels::test_models_register_model -s + # cls & pytest tests\models\test_models.py::TestModels::test_models_models_create -s @servicePreparer() @recorded_by_proxy - def test_models_register_model(self, **kwargs): + def test_models_models_create(self, **kwargs): """End-to-end: pending_upload -> azcopy -> create_async -> get/list/delete.""" model_name = self.test_models_params["model_name_1"] model_version = self.test_models_params["model_version"] @@ -51,40 +52,40 @@ def test_models_register_model(self, **kwargs): with self.create_client(**kwargs) as project_client: - print(f"[test_models_register_model] register_model {model_name}@{model_version}") - registered = project_client.beta.models.register_model( + print(f"[test_models_models_create] models_create {model_name}@{model_version}") + registered = project_client.beta.models.models_create( name=model_name, version=model_version, source=data_folder, weight_type="FullWeight", - description="Registered by test_models_register_model", + description="Registered by test_models_models_create", tags={"source": "test_models.py"}, ) assert registered is not None assert registered.name == expected_model_name assert registered.version == model_version - assert registered.blob_uri, "blob_uri should be populated after register_model" + assert registered.blob_uri, "blob_uri should be populated after models_create" - print(f"[test_models_register_model] get {model_name}@{model_version}") + print(f"[test_models_models_create] get {model_name}@{model_version}") fetched = project_client.beta.models.get(name=model_name, version=model_version) assert fetched.id == registered.id assert fetched.name == expected_model_name assert fetched.version == model_version - print(f"[test_models_register_model] list_versions({model_name!r})") + print(f"[test_models_models_create] list_versions({model_name!r})") versions = list(project_client.beta.models.list_versions(name=model_name)) assert any( mv.version == model_version for mv in versions ), f"version {model_version!r} not found in list_versions" - print("[test_models_register_model] list (latest of every model)") + print("[test_models_models_create] list (latest of every model)") empty = True for mv in project_client.beta.models.list(): empty = False assert mv.name and mv.version assert not empty, "list() returned no models even though we just registered one" - print(f"[test_models_register_model] get_credentials {model_name}@{model_version}") + print(f"[test_models_models_create] get_credentials {model_name}@{model_version}") from azure.ai.projects.models import ModelCredentialRequest creds = project_client.beta.models.get_credentials( @@ -98,7 +99,7 @@ def test_models_register_model(self, **kwargs): assert blob_ref.credential is not None assert blob_ref.credential.sas_uri - print(f"[test_models_register_model] delete {model_name}@{model_version}") + print(f"[test_models_models_create] delete {model_name}@{model_version}") try: project_client.beta.models.delete(name=model_name, version=model_version) except HttpResponseError as ex: @@ -107,7 +108,7 @@ def test_models_register_model(self, **kwargs): if ex.status_code != 200: raise - print(f"[test_models_register_model] get on deleted {model_name}@{model_version} should 404") + print(f"[test_models_models_create] get on deleted {model_name}@{model_version} should 404") with pytest.raises((ResourceNotFoundError, HttpResponseError)): project_client.beta.models.get(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py index 241b374d0ee3..1f7575926b59 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py @@ -5,12 +5,13 @@ # ------------------------------------ """Live, recorded async tests for ``project_client.beta.models``. -Mirrors :mod:`tests.models.test_models` for the async client. ``register_model`` +Mirrors :mod:`tests.models.test_models` for the async client. ``models_create`` itself is implemented only on the sync client (it shells out to ``azcopy``); the async surface is exercised via ``list``, ``list_versions``, ``get`` and ``delete`` against a model registered with the sync helper as part of the fixture. """ + import os import pytest @@ -53,7 +54,7 @@ async def test_models_async_list_get_delete(self, **kwargs): endpoint=endpoint, credential=self.get_credential(SyncAIProjectClient, is_async=False), ) as sync_client: - registered = sync_client.beta.models.register_model( + registered = sync_client.beta.models.models_create( name=model_name, version=model_version, source=data_folder, diff --git a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py index 8eb9b8365374..774abc5b14ae 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py @@ -7,9 +7,10 @@ These tests do not contact the Foundry service. They cover the patch helpers ``_extract_pending_upload_targets`` and ``_run_azcopy``, and the orchestration -performed by ``register_model`` (mocking ``pending_upload``, ``create_async`` +performed by ``models_create`` (mocking ``pending_upload``, ``create_async`` and ``get`` on the base class). """ + from __future__ import annotations import os @@ -24,7 +25,6 @@ from azure.ai.projects.operations._patch_models import BetaModelsOperations - # --------------------------------------------------------------------------- # _extract_pending_upload_targets # --------------------------------------------------------------------------- @@ -169,7 +169,7 @@ def test_nonzero_exit_raises_runtime_error(self, tmp_path): # --------------------------------------------------------------------------- -# register_model orchestration +# models_create orchestration # --------------------------------------------------------------------------- @@ -188,8 +188,17 @@ def _pending_payload() -> dict: } -class TestRegisterModelOrchestration: - def test_register_model_runs_three_steps_in_order_and_returns_get_result(self, tmp_path): +class TestModelsCreateOrchestration: + @pytest.fixture(autouse=True) + def _stub_azcopy_on_path(self): + """Pretend azcopy is installed so the up-front validator passes.""" + with mock.patch( + "azure.ai.projects.operations._patch_models.shutil.which", + return_value="/usr/bin/azcopy", + ): + yield + + def test_models_create_runs_three_steps_in_order_and_returns_get_result(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") ops = _make_ops() @@ -235,7 +244,7 @@ def fake_get(**kwargs): ), mock.patch.object(ops, "create_async", side_effect=fake_create_async), mock.patch.object( ops, "get", side_effect=fake_get ): - result = ops.register_model( + result = ops.models_create( name="my-model", version="1", source=tmp_path, @@ -248,7 +257,7 @@ def fake_get(**kwargs): assert result is committed assert calls == ["pending_upload", "azcopy", "create_async", "get"] - def test_register_model_wait_for_commit_false_returns_none_and_does_not_poll(self, tmp_path): + def test_models_create_wait_for_commit_false_returns_none_and_does_not_poll(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") ops = _make_ops() get_mock = mock.Mock() @@ -256,7 +265,7 @@ def test_register_model_wait_for_commit_false_returns_none_and_does_not_poll(sel with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object(ops, "get", get_mock): - result = ops.register_model( + result = ops.models_create( name="m", version="1", source=tmp_path, @@ -266,7 +275,7 @@ def test_register_model_wait_for_commit_false_returns_none_and_does_not_poll(sel assert result is None get_mock.assert_not_called() - def test_register_model_polls_until_get_succeeds(self, tmp_path): + def test_models_create_polls_until_get_succeeds(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") ops = _make_ops() committed = SimpleNamespace(name="m", version="1") @@ -286,7 +295,7 @@ def test_register_model_polls_until_get_succeeds(self, tmp_path): ), mock.patch( "azure.ai.projects.operations._patch_models.time.sleep" ) as sleep: - result = ops.register_model( + result = ops.models_create( name="m", version="1", source=tmp_path, @@ -297,7 +306,7 @@ def test_register_model_polls_until_get_succeeds(self, tmp_path): assert get_mock.call_count == 3 assert sleep.call_count == 2 - def test_register_model_polling_timeout_raises_runtime_error(self, tmp_path): + def test_models_create_polling_timeout_raises_runtime_error(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") ops = _make_ops() @@ -314,18 +323,118 @@ def test_register_model_polling_timeout_raises_runtime_error(self, tmp_path): "azure.ai.projects.operations._patch_models.time.sleep" ): with pytest.raises(RuntimeError, match="did not appear within"): - ops.register_model( + ops.models_create( name="m", version="1", source=tmp_path, polling_timeout=1.0, ) - def test_register_model_missing_source_raises_before_calling_service(self, tmp_path): + def test_models_create_missing_source_raises_before_calling_service(self, tmp_path): ops = _make_ops() ghost = tmp_path / "does-not-exist" pending = mock.Mock() with mock.patch.object(ops, "pending_upload", pending): with pytest.raises(ValueError, match="does not exist"): - ops.register_model(name="m", version="1", source=ghost) + ops.models_create(name="m", version="1", source=ghost) + pending.assert_not_called() + + +# --------------------------------------------------------------------------- +# _validate_models_create_inputs +# --------------------------------------------------------------------------- + + +class TestValidateModelsCreateInputs: + @pytest.fixture(autouse=True) + def _stub_azcopy_on_path(self): + with mock.patch( + "azure.ai.projects.operations._patch_models.shutil.which", + return_value="/usr/bin/azcopy", + ): + yield + + def _kwargs(self, **overrides): + defaults = dict( + name="m", + version="1", + source="/tmp/x", + azcopy_path=None, + wait_for_commit=True, + polling_timeout=300.0, + polling_interval=2.0, + ) + defaults.update(overrides) + return defaults + + def test_valid_directory_source_returns_path(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + result = BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=tmp_path)) + assert result == tmp_path + + @pytest.mark.parametrize("bad_name", ["", " ", None, 123]) + def test_empty_or_non_string_name_raises(self, tmp_path, bad_name): + (tmp_path / "weights.bin").write_bytes(b"x") + with pytest.raises(ValueError, match="`name`"): + BetaModelsOperations._validate_models_create_inputs(**self._kwargs(name=bad_name, source=tmp_path)) + + @pytest.mark.parametrize("bad_version", ["", " ", None, 1]) + def test_empty_or_non_string_version_raises(self, tmp_path, bad_version): + (tmp_path / "weights.bin").write_bytes(b"x") + with pytest.raises(ValueError, match="`version`"): + BetaModelsOperations._validate_models_create_inputs(**self._kwargs(version=bad_version, source=tmp_path)) + + def test_empty_directory_raises(self, tmp_path): + with pytest.raises(ValueError, match="directory is empty"): + BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=tmp_path)) + + def test_empty_file_raises(self, tmp_path): + empty = tmp_path / "weights.bin" + empty.write_bytes(b"") + with pytest.raises(ValueError, match="file is empty"): + BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=empty)) + + @pytest.mark.parametrize("bad_timeout", [0, -1.0]) + def test_non_positive_polling_timeout_raises(self, tmp_path, bad_timeout): + (tmp_path / "weights.bin").write_bytes(b"x") + with pytest.raises(ValueError, match="polling_timeout"): + BetaModelsOperations._validate_models_create_inputs( + **self._kwargs(source=tmp_path, polling_timeout=bad_timeout) + ) + + @pytest.mark.parametrize("bad_interval", [0, -1.0]) + def test_non_positive_polling_interval_raises(self, tmp_path, bad_interval): + (tmp_path / "weights.bin").write_bytes(b"x") + with pytest.raises(ValueError, match="polling_interval"): + BetaModelsOperations._validate_models_create_inputs( + **self._kwargs(source=tmp_path, polling_interval=bad_interval) + ) + + def test_polling_params_skipped_when_wait_for_commit_false(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + # Negative polling values are tolerated when not waiting for commit. + result = BetaModelsOperations._validate_models_create_inputs( + **self._kwargs(source=tmp_path, wait_for_commit=False, polling_timeout=-1, polling_interval=-1) + ) + assert result == tmp_path + + def test_missing_azcopy_raises(self, tmp_path): + (tmp_path / "weights.bin").write_bytes(b"x") + with mock.patch( + "azure.ai.projects.operations._patch_models.shutil.which", + return_value=None, + ): + with pytest.raises(RuntimeError, match="azcopy"): + BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=tmp_path)) + + def test_models_create_validates_before_calling_pending_upload(self, tmp_path): + """Validation runs before any service operation.""" + (tmp_path / "weights.bin").write_bytes(b"x") + ops = _make_ops() + pending = mock.Mock() + with mock.patch.object(ops, "pending_upload", pending), mock.patch( + "azure.ai.projects.operations._patch_models.shutil.which", return_value=None + ): + with pytest.raises(RuntimeError, match="azcopy"): + ops.models_create(name="m", version="1", source=tmp_path) pending.assert_not_called() diff --git a/sdk/ai/azure-ai-projects/tests/samples/llm_instructions.py b/sdk/ai/azure-ai-projects/tests/samples/llm_instructions.py index 0e0f776441cf..af98d794a98d 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/llm_instructions.py +++ b/sdk/ai/azure-ai-projects/tests/samples/llm_instructions.py @@ -18,8 +18,7 @@ from typing import Final -agent_tools_instructions: Final[str] = ( - """ +agent_tools_instructions: Final[str] = """ We just ran Python code and captured print/log output in an attached log file (TXT). Validate whether sample execution/output is correct for a tool-driven assistant workflow. @@ -44,11 +43,9 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) -memories_instructions: Final[str] = ( - """ +memories_instructions: Final[str] = """ We just ran Python code and captured print/log output in an attached log file (TXT). Validate whether sample execution/output is correct for a memories workflow. @@ -73,11 +70,9 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) -agents_instructions: Final[str] = ( - """ +agents_instructions: Final[str] = """ We just ran Python code and captured print/log output in an attached log file (TXT). Validate whether sample execution/output is correct. @@ -108,11 +103,9 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) -chat_completions_instructions: Final[str] = ( - """ +chat_completions_instructions: Final[str] = """ We just ran Python code and captured print/log output in an attached log file (TXT). Validate whether sample execution/output is correct for Chat Completions scenarios. @@ -131,11 +124,9 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) -resource_management_instructions: Final[str] = ( - """ +resource_management_instructions: Final[str] = """ We just ran Python code and captured print/log output in an attached log file (TXT). Validate whether sample execution/output is correct for resource-management samples (for example connections, files, and deployments). @@ -161,11 +152,9 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) -fine_tuning_instructions: Final[str] = ( - """ +fine_tuning_instructions: Final[str] = """ We just ran Python code and captured print/log output in an attached log file (TXT). Validate whether sample execution/output is correct for a fine-tuning workflow. @@ -189,11 +178,9 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) -evaluations_instructions: Final[str] = ( - """ +evaluations_instructions: Final[str] = """ We just ran Python code for an evaluation sample and captured print/log output in an attached log file (TXT). Your job: determine if the sample code executed to completion WITHOUT throwing an unhandled exception. @@ -215,11 +202,9 @@ Always respond with `reason` indicating the reason for the response. """.strip() -) -hosted_agents_instructions: Final[str] = ( - """ +hosted_agents_instructions: Final[str] = """ We just ran Python code for a hosted-agent sample and captured print/log output in an attached log file (TXT). Validate whether the sample executed correctly. @@ -241,7 +226,6 @@ Always include `reason` with a concise explanation tied to the observed print output. """.strip() -) # Folder (under samples/) -> instructions. From 5aec13cddf26520f688cce4212b6df5d18c03c2d Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Wed, 13 May 2026 18:35:10 +0530 Subject: [PATCH 04/14] fix cpell - azcopy --- sdk/ai/azure-ai-projects/cspell.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/ai/azure-ai-projects/cspell.json b/sdk/ai/azure-ai-projects/cspell.json index 7decf206d14a..e26c824b5807 100644 --- a/sdk/ai/azure-ai-projects/cspell.json +++ b/sdk/ai/azure-ai-projects/cspell.json @@ -6,6 +6,8 @@ "aiservices", "ansii", "aread", + "azcopy", + "Azcopy", "azureai", "azureopenai", "balapvbyostoragecanary", From c2a550a09d2c035ba0fa90b352a5543e20de4379 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Thu, 14 May 2026 12:14:21 +0530 Subject: [PATCH 05/14] re emit from typespec for PendingUploadType changes --- .../azure-ai-projects/apiview-properties.json | 82 +- .../azure/ai/projects/_client.py | 6 + .../azure/ai/projects/_types.py | 2 + .../azure/ai/projects/aio/_client.py | 6 + .../ai/projects/aio/operations/__init__.py | 2 + .../ai/projects/aio/operations/_operations.py | 8270 ++++++++-------- .../ai/projects/aio/operations/_patch.py | 4 - .../azure/ai/projects/models/__init__.py | 128 +- .../azure/ai/projects/models/_enums.py | 115 +- .../azure/ai/projects/models/_models.py | 2628 +++-- .../azure/ai/projects/models/_patch.py | 2 +- .../azure/ai/projects/operations/__init__.py | 2 + .../ai/projects/operations/_operations.py | 8821 ++++++++--------- .../azure/ai/projects/operations/_patch.py | 4 - .../ai/projects/operations/_patch_models.py | 10 +- .../samples/models/sample_models_async.py | 4 +- .../models/sample_models_without_patch.py | 4 +- .../foundry_features_header_test_base.py | 2 +- .../tests/models/test_models.py | 4 +- sdk/ai/azure-ai-projects/tsp-location.yaml | 2 +- 20 files changed, 9747 insertions(+), 10351 deletions(-) diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index f2c8016f920e..bfcdf1dd3134 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -10,14 +10,10 @@ "azure.ai.projects.models.AgentClusterInsightRequest": "Azure.AI.Projects.AgentClusterInsightRequest", "azure.ai.projects.models.InsightResult": "Azure.AI.Projects.InsightResult", "azure.ai.projects.models.AgentClusterInsightResult": "Azure.AI.Projects.AgentClusterInsightResult", - "azure.ai.projects.models.DataGenerationJobSource": "Azure.AI.Projects.DataGenerationJobSource", - "azure.ai.projects.models.AgentDataGenerationJobSource": "Azure.AI.Projects.AgentDataGenerationJobSource", "azure.ai.projects.models.AgentDefinition": "Azure.AI.Projects.AgentDefinition", "azure.ai.projects.models.AgentDetails": "Azure.AI.Projects.AgentObject", "azure.ai.projects.models.AgentEndpointAuthorizationScheme": "Azure.AI.Projects.AgentEndpointAuthorizationScheme", "azure.ai.projects.models.AgentEndpointConfig": "Azure.AI.Projects.AgentEndpointConfig", - "azure.ai.projects.models.EvaluatorGenerationJobSource": "Azure.AI.Projects.EvaluatorGenerationJobSource", - "azure.ai.projects.models.AgentEvaluatorGenerationJobSource": "Azure.AI.Projects.AgentEvaluatorGenerationJobSource", "azure.ai.projects.models.BaseCredentials": "Azure.AI.Projects.BaseCredentials", "azure.ai.projects.models.AgenticIdentityPreviewCredentials": "Azure.AI.Projects.AgenticIdentityPreviewCredentials", "azure.ai.projects.models.AgentIdentity": "Azure.AI.Projects.AgentIdentity", @@ -88,6 +84,9 @@ "azure.ai.projects.models.CosmosDBIndex": "Azure.AI.Projects.CosmosDBIndex", "azure.ai.projects.models.CreateAgentVersionFromCodeContent": "Azure.AI.Projects.CreateAgentVersionFromCodeContent", "azure.ai.projects.models.CreateAgentVersionFromCodeMetadata": "Azure.AI.Projects.CreateAgentVersionFromCodeMetadata", + "azure.ai.projects.models.CreateAsyncResponse": "Azure.AI.Projects.createAsync.Response.anonymous", + "azure.ai.projects.models.CreateEvalCompletionsRunDataSourceInputMessagesItemReference": "OpenAI.CreateEvalCompletionsRunDataSourceInputMessagesItemReference", + "azure.ai.projects.models.CreateEvalResponsesRunDataSourceInputMessagesTemplate": "OpenAI.CreateEvalResponsesRunDataSourceInputMessagesTemplate", "azure.ai.projects.models.Trigger": "Azure.AI.Projects.Trigger", "azure.ai.projects.models.CronTrigger": "Azure.AI.Projects.CronTrigger", "azure.ai.projects.models.CustomCredential": "Azure.AI.Projects.CustomCredential", @@ -97,18 +96,7 @@ "azure.ai.projects.models.CustomToolParam": "OpenAI.CustomToolParam", "azure.ai.projects.models.RecurrenceSchedule": "Azure.AI.Projects.RecurrenceSchedule", "azure.ai.projects.models.DailyRecurrenceSchedule": "Azure.AI.Projects.DailyRecurrenceSchedule", - "azure.ai.projects.models.DataGenerationJob": "Azure.AI.Projects.DataGenerationJob", - "azure.ai.projects.models.DataGenerationJobInputs": "Azure.AI.Projects.DataGenerationJobInputs", - "azure.ai.projects.models.DataGenerationJobOptions": "Azure.AI.Projects.DataGenerationJobOptions", - "azure.ai.projects.models.DataGenerationJobOutput": "Azure.AI.Projects.DataGenerationJobOutput", - "azure.ai.projects.models.DataGenerationJobResult": "Azure.AI.Projects.DataGenerationJobResult", - "azure.ai.projects.models.DataGenerationModelOptions": "Azure.AI.Projects.DataGenerationModelOptions", - "azure.ai.projects.models.DataGenerationTokenUsage": "Azure.AI.Projects.DataGenerationTokenUsage", "azure.ai.projects.models.DatasetCredential": "Azure.AI.Projects.AssetCredentialResponse", - "azure.ai.projects.models.DatasetDataGenerationJobOutput": "Azure.AI.Projects.DatasetDataGenerationJobOutput", - "azure.ai.projects.models.DatasetDataGenerationJobSource": "Azure.AI.Projects.DatasetDataGenerationJobSource", - "azure.ai.projects.models.DatasetEvaluatorGenerationJobSource": "Azure.AI.Projects.DatasetEvaluatorGenerationJobSource", - "azure.ai.projects.models.DatasetReference": "Azure.AI.Projects.DatasetReference", "azure.ai.projects.models.DatasetVersion": "Azure.AI.Projects.DatasetVersion", "azure.ai.projects.models.DeleteAgentResponse": "Azure.AI.Projects.DeleteAgentResponse", "azure.ai.projects.models.DeleteAgentVersionResponse": "Azure.AI.Projects.DeleteAgentVersionResponse", @@ -118,12 +106,24 @@ "azure.ai.projects.models.EmbeddingConfiguration": "Azure.AI.Projects.EmbeddingConfiguration", "azure.ai.projects.models.EntraAuthorizationScheme": "Azure.AI.Projects.EntraAuthorizationScheme", "azure.ai.projects.models.EntraIDCredentials": "Azure.AI.Projects.EntraIDCredentials", + "azure.ai.projects.models.EvalGraderLabelModel": "OpenAI.EvalGraderLabelModel", + "azure.ai.projects.models.EvalGraderPython": "OpenAI.EvalGraderPython", + "azure.ai.projects.models.EvalGraderScoreModel": "OpenAI.EvalGraderScoreModel", + "azure.ai.projects.models.EvalGraderScoreModelSamplingParams": "OpenAI.EvalGraderScoreModelSamplingParams", + "azure.ai.projects.models.EvalGraderStringCheck": "OpenAI.EvalGraderStringCheck", + "azure.ai.projects.models.EvalGraderTextSimilarity": "OpenAI.EvalGraderTextSimilarity", + "azure.ai.projects.models.EvalItem": "OpenAI.EvalItem", + "azure.ai.projects.models.EvalItemContentItemObject": "OpenAI.EvalItemContentItemObject", + "azure.ai.projects.models.EvalItemContentItemObjectInputTextContent": "OpenAI.EvalItemContentItemObjectInputTextContent", + "azure.ai.projects.models.EvalItemContentOutputText": "OpenAI.EvalItemContentOutputText", + "azure.ai.projects.models.EvalItemInputImage": "OpenAI.EvalItemInputImage", "azure.ai.projects.models.EvalResult": "Azure.AI.Projects.EvalResult", "azure.ai.projects.models.EvalRunResultCompareItem": "Azure.AI.Projects.EvalRunResultCompareItem", "azure.ai.projects.models.EvalRunResultComparison": "Azure.AI.Projects.EvalRunResultComparison", "azure.ai.projects.models.EvalRunResultSummary": "Azure.AI.Projects.EvalRunResultSummary", "azure.ai.projects.models.EvaluationComparisonInsightRequest": "Azure.AI.Projects.EvaluationComparisonInsightRequest", "azure.ai.projects.models.EvaluationComparisonInsightResult": "Azure.AI.Projects.EvaluationComparisonInsightResult", + "azure.ai.projects.models.EvaluationDatasetReference": "Azure.AI.Projects.EvaluationDatasetReference", "azure.ai.projects.models.InsightSample": "Azure.AI.Projects.InsightSample", "azure.ai.projects.models.EvaluationResultSample": "Azure.AI.Projects.EvaluationResultSample", "azure.ai.projects.models.EvaluationRule": "Azure.AI.Projects.EvaluationRule", @@ -132,18 +132,17 @@ "azure.ai.projects.models.EvaluationRunClusterInsightResult": "Azure.AI.Projects.EvaluationRunClusterInsightResult", "azure.ai.projects.models.ScheduleTask": "Azure.AI.Projects.ScheduleTask", "azure.ai.projects.models.EvaluationScheduleTask": "Azure.AI.Projects.EvaluationScheduleTask", + "azure.ai.projects.models.EvaluationSuiteRunRequest": "Azure.AI.Projects.EvaluationSuiteRunRequest", + "azure.ai.projects.models.EvaluationSuiteRunResponse": "Azure.AI.Projects.EvaluationSuiteRunResponse", + "azure.ai.projects.models.EvaluationSuiteRunResult": "Azure.AI.Projects.EvaluationSuiteRunResult", + "azure.ai.projects.models.EvaluationSuiteVersion": "Azure.AI.Projects.EvaluationSuiteVersion", + "azure.ai.projects.models.EvaluationSuiteVersionInputMessagesTemplate1": "Azure.AI.Projects.EvaluationSuiteVersion.input_messages.template.anonymous", "azure.ai.projects.models.EvaluationTaxonomy": "Azure.AI.Projects.EvaluationTaxonomy", - "azure.ai.projects.models.EvaluatorGenerationArtifacts": "Azure.AI.Projects.EvaluatorGenerationArtifacts", - "azure.ai.projects.models.EvaluatorGenerationInputs": "Azure.AI.Projects.EvaluatorGenerationInputs", - "azure.ai.projects.models.EvaluatorGenerationJob": "Azure.AI.Projects.EvaluatorGenerationJob", - "azure.ai.projects.models.EvaluatorGenerationTokenUsage": "Azure.AI.Projects.EvaluatorGenerationTokenUsage", "azure.ai.projects.models.EvaluatorMetric": "Azure.AI.Projects.EvaluatorMetric", "azure.ai.projects.models.EvaluatorVersion": "Azure.AI.Projects.EvaluatorVersion", "azure.ai.projects.models.FabricDataAgentToolParameters": "Azure.AI.Projects.FabricDataAgentToolParameters", "azure.ai.projects.models.FabricIQPreviewTool": "Azure.AI.Projects.FabricIQPreviewTool", "azure.ai.projects.models.FieldMapping": "Azure.AI.Projects.FieldMapping", - "azure.ai.projects.models.FileDataGenerationJobOutput": "Azure.AI.Projects.FileDataGenerationJobOutput", - "azure.ai.projects.models.FileDataGenerationJobSource": "Azure.AI.Projects.FileDataGenerationJobSource", "azure.ai.projects.models.FileDatasetVersion": "Azure.AI.Projects.FileDatasetVersion", "azure.ai.projects.models.FileSearchTool": "OpenAI.FileSearchTool", "azure.ai.projects.models.VersionSelectionRule": "Azure.AI.Projects.VersionSelectionRule", @@ -164,6 +163,8 @@ "azure.ai.projects.models.ImageGenToolInputImageMask": "OpenAI.ImageGenToolInputImageMask", "azure.ai.projects.models.InlineSkillParam": "OpenAI.InlineSkillParam", "azure.ai.projects.models.InlineSkillSourceParam": "OpenAI.InlineSkillSourceParam", + "azure.ai.projects.models.InputAudio": "OpenAI.InputAudio", + "azure.ai.projects.models.InputAudioInputAudio": "OpenAI.InputAudioInputAudio", "azure.ai.projects.models.Insight": "Azure.AI.Projects.Insight", "azure.ai.projects.models.InsightCluster": "Azure.AI.Projects.InsightCluster", "azure.ai.projects.models.InsightModelConfiguration": "Azure.AI.Projects.InsightModelConfiguration", @@ -195,6 +196,8 @@ "azure.ai.projects.models.ModelCredentialRequest": "Azure.AI.Projects.ModelCredentialRequest", "azure.ai.projects.models.ModelDeployment": "Azure.AI.Projects.ModelDeployment", "azure.ai.projects.models.ModelDeploymentSku": "Azure.AI.Projects.Sku", + "azure.ai.projects.models.ModelPendingUploadRequest": "Azure.AI.Projects.ModelPendingUploadRequest", + "azure.ai.projects.models.ModelPendingUploadResponse": "Azure.AI.Projects.ModelPendingUploadResponse", "azure.ai.projects.models.ModelSamplingParams": "Azure.AI.Projects.ModelSamplingParams", "azure.ai.projects.models.ModelSourceData": "Azure.AI.Projects.ModelSourceData", "azure.ai.projects.models.ModelVersion": "Azure.AI.Projects.ModelVersion", @@ -217,8 +220,6 @@ "azure.ai.projects.models.PromptAgentDefinition": "Azure.AI.Projects.PromptAgentDefinition", "azure.ai.projects.models.PromptAgentDefinitionTextOptions": "Azure.AI.Projects.PromptAgentDefinitionTextOptions", "azure.ai.projects.models.PromptBasedEvaluatorDefinition": "Azure.AI.Projects.PromptBasedEvaluatorDefinition", - "azure.ai.projects.models.PromptDataGenerationJobSource": "Azure.AI.Projects.PromptDataGenerationJobSource", - "azure.ai.projects.models.PromptEvaluatorGenerationJobSource": "Azure.AI.Projects.PromptEvaluatorGenerationJobSource", "azure.ai.projects.models.ProtocolVersionRecord": "Azure.AI.Projects.ProtocolVersionRecord", "azure.ai.projects.models.RaiConfig": "Azure.AI.Projects.RaiConfig", "azure.ai.projects.models.RankingOptions": "OpenAI.RankingOptions", @@ -227,8 +228,6 @@ "azure.ai.projects.models.RedTeam": "Azure.AI.Projects.RedTeam", "azure.ai.projects.models.ResponseUsageInputTokensDetails": "OpenAI.ResponseUsageInputTokensDetails", "azure.ai.projects.models.ResponseUsageOutputTokensDetails": "OpenAI.ResponseUsageOutputTokensDetails", - "azure.ai.projects.models.RubricBasedEvaluatorDefinition": "Azure.AI.Projects.RubricBasedEvaluatorDefinition", - "azure.ai.projects.models.RubricCriterion": "Azure.AI.Projects.RubricCriterion", "azure.ai.projects.models.SASCredentials": "Azure.AI.Projects.SASCredentials", "azure.ai.projects.models.Schedule": "Azure.AI.Projects.Schedule", "azure.ai.projects.models.ScheduleRun": "Azure.AI.Projects.ScheduleRun", @@ -238,7 +237,6 @@ "azure.ai.projects.models.SessionLogEvent": "Azure.AI.Projects.SessionLogEvent", "azure.ai.projects.models.SharepointGroundingToolParameters": "Azure.AI.Projects.SharepointGroundingToolParameters", "azure.ai.projects.models.SharepointPreviewTool": "Azure.AI.Projects.SharepointPreviewTool", - "azure.ai.projects.models.SimpleQnADataGenerationJobOptions": "Azure.AI.Projects.SimpleQnADataGenerationJobOptions", "azure.ai.projects.models.SkillDetails": "Azure.AI.Projects.SkillObject", "azure.ai.projects.models.SkillReferenceParam": "OpenAI.SkillReferenceParam", "azure.ai.projects.models.ToolChoiceParam": "OpenAI.ToolChoiceParam", @@ -250,6 +248,7 @@ "azure.ai.projects.models.TaxonomyCategory": "Azure.AI.Projects.TaxonomyCategory", "azure.ai.projects.models.TaxonomySubCategory": "Azure.AI.Projects.TaxonomySubCategory", "azure.ai.projects.models.TelemetryConfig": "Azure.AI.Projects.TelemetryConfig", + "azure.ai.projects.models.TestingCriterionAzureAIEvaluator": "Azure.AI.Projects.TestingCriterionAzureAIEvaluator", "azure.ai.projects.models.TextResponseFormat": "OpenAI.TextResponseFormatConfiguration", "azure.ai.projects.models.TextResponseFormatJsonObject": "OpenAI.TextResponseFormatConfigurationResponseFormatJsonObject", "azure.ai.projects.models.TextResponseFormatJsonSchema": "OpenAI.TextResponseFormatJsonSchema", @@ -270,10 +269,6 @@ "azure.ai.projects.models.ToolChoiceWebSearchPreview20250311": "OpenAI.ToolChoiceWebSearchPreview20250311", "azure.ai.projects.models.ToolDescription": "Azure.AI.Projects.ToolDescription", "azure.ai.projects.models.ToolProjectConnection": "Azure.AI.Projects.ToolProjectConnection", - "azure.ai.projects.models.ToolUseFineTuningDataGenerationJobOptions": "Azure.AI.Projects.ToolUseFineTuningDataGenerationJobOptions", - "azure.ai.projects.models.TracesDataGenerationJobOptions": "Azure.AI.Projects.TracesDataGenerationJobOptions", - "azure.ai.projects.models.TracesDataGenerationJobSource": "Azure.AI.Projects.TracesDataGenerationJobSource", - "azure.ai.projects.models.TracesEvaluatorGenerationJobSource": "Azure.AI.Projects.TracesEvaluatorGenerationJobSource", "azure.ai.projects.models.UpdateModelVersionRequest": "Azure.AI.Projects.UpdateModelVersionRequest", "azure.ai.projects.models.UpdateToolboxRequest": "Azure.AI.Projects.UpdateToolboxRequest", "azure.ai.projects.models.UserProfileMemoryItem": "Azure.AI.Projects.UserProfileMemoryItem", @@ -328,8 +323,6 @@ "azure.ai.projects.models.EvaluatorDefinitionType": "Azure.AI.Projects.EvaluatorDefinitionType", "azure.ai.projects.models.EvaluatorMetricType": "Azure.AI.Projects.EvaluatorMetricType", "azure.ai.projects.models.EvaluatorMetricDirection": "Azure.AI.Projects.EvaluatorMetricDirection", - "azure.ai.projects.models.EvaluatorGenerationJobSourceType": "Azure.AI.Projects.EvaluatorGenerationJobSourceType", - "azure.ai.projects.models.JobStatus": "Azure.AI.Projects.JobStatus", "azure.ai.projects.models.OperationState": "Azure.Core.Foundations.OperationState", "azure.ai.projects.models.InsightType": "Azure.AI.Projects.InsightType", "azure.ai.projects.models.SampleType": "Azure.AI.Projects.SampleType", @@ -350,11 +343,6 @@ "azure.ai.projects.models.RecurrenceType": "Azure.AI.Projects.RecurrenceType", "azure.ai.projects.models.DayOfWeek": "Azure.AI.Projects.DayOfWeek", "azure.ai.projects.models.ScheduleTaskType": "Azure.AI.Projects.ScheduleTaskType", - "azure.ai.projects.models.DataGenerationJobSourceType": "Azure.AI.Projects.DataGenerationJobSourceType", - "azure.ai.projects.models.DataGenerationJobType": "Azure.AI.Projects.DataGenerationJobType", - "azure.ai.projects.models.SimpleQnAFineTuningQuestionType": "Azure.AI.Projects.SimpleQnAFineTuningQuestionType", - "azure.ai.projects.models.DataGenerationJobScenario": "Azure.AI.Projects.DataGenerationJobScenario", - "azure.ai.projects.models.DataGenerationJobOutputType": "Azure.AI.Projects.DataGenerationJobOutputType", "azure.ai.projects.models.EvaluationRuleActionType": "Azure.AI.Projects.EvaluationRuleActionType", "azure.ai.projects.models.EvaluationRuleEventType": "Azure.AI.Projects.EvaluationRuleEventType", "azure.ai.projects.models.ConnectionType": "Azure.AI.Projects.ConnectionType", @@ -362,6 +350,10 @@ "azure.ai.projects.models.DatasetType": "Azure.AI.Projects.DatasetType", "azure.ai.projects.models.DeploymentType": "Azure.AI.Projects.DeploymentType", "azure.ai.projects.models.IndexType": "Azure.AI.Projects.IndexType", + "azure.ai.projects.models.EvaluationSuiteSubtype": "Azure.AI.Projects.EvaluationSuiteSubtype", + "azure.ai.projects.models.EvalItemContentItemObjectType": "OpenAI.EvalItemContentItemObjectType", + "azure.ai.projects.models.EvaluationLevel": "Azure.AI.Projects.EvaluationLevel", + "azure.ai.projects.models.JobStatus": "Azure.AI.Projects.JobStatus", "azure.ai.projects.models.MemoryStoreUpdateStatus": "Azure.AI.Projects.MemoryStoreUpdateStatus", "azure.ai.projects.operations.AgentsOperations.get": "Azure.AI.Projects.Agents.getAgent", "azure.ai.projects.aio.operations.AgentsOperations.get": "Azure.AI.Projects.Agents.getAgent", @@ -416,6 +408,20 @@ "azure.ai.projects.operations.IndexesOperations.delete": "Azure.AI.Projects.Indexes.deleteVersion", "azure.ai.projects.aio.operations.IndexesOperations.delete": "Azure.AI.Projects.Indexes.deleteVersion", "azure.ai.projects.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion", - "azure.ai.projects.aio.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion" + "azure.ai.projects.aio.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion", + "azure.ai.projects.operations.EvaluationSuitesOperations.list_versions": "Azure.AI.Projects.EvaluationSuites.listVersions", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.list_versions": "Azure.AI.Projects.EvaluationSuites.listVersions", + "azure.ai.projects.operations.EvaluationSuitesOperations.list_latest": "Azure.AI.Projects.EvaluationSuites.listLatest", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.list_latest": "Azure.AI.Projects.EvaluationSuites.listLatest", + "azure.ai.projects.operations.EvaluationSuitesOperations.get_version": "Azure.AI.Projects.EvaluationSuites.getVersion", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.get_version": "Azure.AI.Projects.EvaluationSuites.getVersion", + "azure.ai.projects.operations.EvaluationSuitesOperations.delete_version": "Azure.AI.Projects.EvaluationSuites.deleteVersion", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.delete_version": "Azure.AI.Projects.EvaluationSuites.deleteVersion", + "azure.ai.projects.operations.EvaluationSuitesOperations.create_or_update_version": "Azure.AI.Projects.EvaluationSuites.createOrUpdateVersion", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.create_or_update_version": "Azure.AI.Projects.EvaluationSuites.createOrUpdateVersion", + "azure.ai.projects.operations.EvaluationSuitesOperations.create_evaluation_suite_version": "Azure.AI.Projects.EvaluationSuites.createEvaluationSuiteVersion", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.create_evaluation_suite_version": "Azure.AI.Projects.EvaluationSuites.createEvaluationSuiteVersion", + "azure.ai.projects.operations.EvaluationSuitesOperations.run": "Azure.AI.Projects.EvaluationSuites.run", + "azure.ai.projects.aio.operations.EvaluationSuitesOperations.run": "Azure.AI.Projects.EvaluationSuites.run" } } \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py index 318f549168a8..c20cfd7223c6 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py @@ -23,6 +23,7 @@ DatasetsOperations, DeploymentsOperations, EvaluationRulesOperations, + EvaluationSuitesOperations, IndexesOperations, ) @@ -47,6 +48,8 @@ class AIProjectClient: # pylint: disable=too-many-instance-attributes :vartype deployments: azure.ai.projects.operations.DeploymentsOperations :ivar indexes: IndexesOperations operations :vartype indexes: azure.ai.projects.operations.IndexesOperations + :ivar evaluation_suites: EvaluationSuitesOperations operations + :vartype evaluation_suites: azure.ai.projects.operations.EvaluationSuitesOperations :param endpoint: Foundry Project endpoint in the form "https://{ai-services-account-name}.services.ai.azure.com/api/projects/{project-name}". If you only have one Project in your Foundry Hub, or to target the default Project in your Hub, use @@ -102,6 +105,9 @@ def __init__( self.datasets = DatasetsOperations(self._client, self._config, self._serialize, self._deserialize) self.deployments = DeploymentsOperations(self._client, self._config, self._serialize, self._deserialize) self.indexes = IndexesOperations(self._client, self._config, self._serialize, self._deserialize) + self.evaluation_suites = EvaluationSuitesOperations( + self._client, self._config, self._serialize, self._deserialize + ) def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: Any) -> HttpResponse: """Runs the network request through the client's chained policies. diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py index 5e23b3911701..4cad4f8c3efe 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py @@ -11,3 +11,5 @@ if TYPE_CHECKING: from . import models as _models Filters = Union["_models.ComparisonFilter", "_models.CompoundFilter"] +EvalItemContentItem = Union[str, "_models.EvalItemContentItemObject"] +EvalItemContent = Union["_types.EvalItemContentItem", list["_types.EvalItemContentItem"]] diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py index e92b1057b268..19c25c051357 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py @@ -23,6 +23,7 @@ DatasetsOperations, DeploymentsOperations, EvaluationRulesOperations, + EvaluationSuitesOperations, IndexesOperations, ) @@ -47,6 +48,8 @@ class AIProjectClient: # pylint: disable=too-many-instance-attributes :vartype deployments: azure.ai.projects.aio.operations.DeploymentsOperations :ivar indexes: IndexesOperations operations :vartype indexes: azure.ai.projects.aio.operations.IndexesOperations + :ivar evaluation_suites: EvaluationSuitesOperations operations + :vartype evaluation_suites: azure.ai.projects.aio.operations.EvaluationSuitesOperations :param endpoint: Foundry Project endpoint in the form "https://{ai-services-account-name}.services.ai.azure.com/api/projects/{project-name}". If you only have one Project in your Foundry Hub, or to target the default Project in your Hub, use @@ -102,6 +105,9 @@ def __init__( self.datasets = DatasetsOperations(self._client, self._config, self._serialize, self._deserialize) self.deployments = DeploymentsOperations(self._client, self._config, self._serialize, self._deserialize) self.indexes = IndexesOperations(self._client, self._config, self._serialize, self._deserialize) + self.evaluation_suites = EvaluationSuitesOperations( + self._client, self._config, self._serialize, self._deserialize + ) def send_request( self, request: HttpRequest, *, stream: bool = False, **kwargs: Any diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py index 1a1c0ffec86c..546fdb068dcc 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py @@ -19,6 +19,7 @@ from ._operations import DatasetsOperations # type: ignore from ._operations import DeploymentsOperations # type: ignore from ._operations import IndexesOperations # type: ignore +from ._operations import EvaluationSuitesOperations # type: ignore from ._patch import __all__ as _patch_all from ._patch import * @@ -32,6 +33,7 @@ "DatasetsOperations", "DeploymentsOperations", "IndexesOperations", + "EvaluationSuitesOperations", ] __all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index 8b0e9bc2ed4f..fa795ede4aa4 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -59,24 +59,14 @@ build_beta_agents_patch_agent_details_request, build_beta_agents_update_agent_from_code_request, build_beta_agents_upload_session_file_request, - build_beta_datasets_cancel_generation_job_request, - build_beta_datasets_create_generation_job_request, - build_beta_datasets_delete_generation_job_request, - build_beta_datasets_get_generation_job_request, - build_beta_datasets_list_generation_jobs_request, build_beta_evaluation_taxonomies_create_request, build_beta_evaluation_taxonomies_delete_request, build_beta_evaluation_taxonomies_get_request, build_beta_evaluation_taxonomies_list_request, build_beta_evaluation_taxonomies_update_request, - build_beta_evaluators_cancel_generation_job_request, - build_beta_evaluators_create_generation_job_request, build_beta_evaluators_create_version_request, - build_beta_evaluators_delete_generation_job_request, build_beta_evaluators_delete_version_request, - build_beta_evaluators_get_generation_job_request, build_beta_evaluators_get_version_request, - build_beta_evaluators_list_generation_jobs_request, build_beta_evaluators_list_request, build_beta_evaluators_list_versions_request, build_beta_evaluators_update_version_request, @@ -139,6 +129,13 @@ build_evaluation_rules_delete_request, build_evaluation_rules_get_request, build_evaluation_rules_list_request, + build_evaluation_suites_create_evaluation_suite_version_request, + build_evaluation_suites_create_or_update_version_request, + build_evaluation_suites_delete_version_request, + build_evaluation_suites_get_version_request, + build_evaluation_suites_list_latest_request, + build_evaluation_suites_list_versions_request, + build_evaluation_suites_run_request, build_indexes_create_or_update_request, build_indexes_delete_request, build_indexes_get_request, @@ -183,7 +180,6 @@ def __init__(self, *args, **kwargs) -> None: self.schedules = BetaSchedulesOperations(self._client, self._config, self._serialize, self._deserialize) self.toolboxes = BetaToolboxesOperations(self._client, self._config, self._serialize, self._deserialize) self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) - self.datasets = BetaDatasetsOperations(self._client, self._config, self._serialize, self._deserialize) class AgentsOperations: @@ -3020,14 +3016,14 @@ async def create_or_update( return deserialized # type: ignore -class BetaAgentsOperations: +class EvaluationSuitesOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`agents` attribute. + :attr:`evaluation_suites` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -3037,91 +3033,204 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - async def update_agent_from_code( - self, - agent_name: str, - content: _models.CreateAgentVersionFromCodeContent, - *, - code_zip_sha256: str, - **kwargs: Any - ) -> _models.AgentDetails: - """Updates a code-based agent by uploading new code and creating a new version. If the code and - definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing - version. The request body is multipart/form-data with a JSON metadata part and a binary code - part (part order is irrelevant). Maximum upload size is 250 MB. - - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + @distributed_trace + def list_versions(self, name: str, **kwargs: Any) -> AsyncItemPaged["_models.EvaluationSuiteVersion"]: + """List all versions of the given EvaluationSuiteVersion. - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :param name: The name of the resource. Required. + :type name: str + :return: An iterator like instance of EvaluationSuiteVersion + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluationSuiteVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - async def update_agent_from_code( - self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any - ) -> _models.AgentDetails: - """Updates a code-based agent by uploading new code and creating a new version. If the code and - definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing - version. The request body is multipart/form-data with a JSON metadata part and a binary code - part (part order is irrelevant). Maximum upload size is 250 MB. + cls: ClsType[List[_models.EvaluationSuiteVersion]] = kwargs.pop("cls", None) - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + def prepare_request(next_link=None): + if not next_link: + + _request = build_evaluation_suites_list_versions_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluationSuiteVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + @distributed_trace + def list_latest( + self, *, agent_name: Optional[str] = None, **kwargs: Any + ) -> AsyncItemPaged["_models.EvaluationSuiteVersion"]: + """List the latest version of each EvaluationSuiteVersion. + + :keyword agent_name: Filter by associated Foundry agent name (from target). Default value is + None. + :paramtype agent_name: str + :return: An iterator like instance of EvaluationSuiteVersion + :rtype: + ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluationSuiteVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @distributed_trace_async - async def update_agent_from_code( - self, - agent_name: str, - content: Union[_models.CreateAgentVersionFromCodeContent, JSON], - *, - code_zip_sha256: str, - **kwargs: Any - ) -> _models.AgentDetails: - """Updates a code-based agent by uploading new code and creating a new version. If the code and - definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing - version. The request body is multipart/form-data with a JSON metadata part and a binary code - part (part order is irrelevant). Maximum upload size is 250 MB. + cls: ClsType[List[_models.EvaluationSuiteVersion]] = kwargs.pop("cls", None) - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + def prepare_request(next_link=None): + if not next_link: + + _request = build_evaluation_suites_list_latest_request( + agent_name=agent_name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluationSuiteVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + @distributed_trace_async + async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.EvaluationSuiteVersion: + """Get the specific version of the EvaluationSuiteVersion. The service returns 404 Not Found error + if the EvaluationSuiteVersion does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to retrieve. Required. + :type version: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3135,18 +3244,12 @@ async def update_agent_from_code( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) - - _body = content.as_dict() if isinstance(content, _Model) else content - _file_fields: list[str] = ["code"] - _data_fields: list[str] = ["metadata"] - _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + cls: ClsType[_models.EvaluationSuiteVersion] = kwargs.pop("cls", None) - _request = build_beta_agents_update_agent_from_code_request( - agent_name=agent_name, - code_zip_sha256=code_zip_sha256, + _request = build_evaluation_suites_get_version_request( + name=name, + version=version, api_version=self._config.api_version, - files=_files, headers=_headers, params=_params, ) @@ -3170,106 +3273,173 @@ async def update_agent_from_code( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentDetails, response.json()) + deserialized = _deserialize(_models.EvaluationSuiteVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace_async + async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: + """Delete the specific version of the EvaluationSuiteVersion. The service returns 204 No Content + if the EvaluationSuiteVersion was deleted successfully or if the EvaluationSuiteVersion does + not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluationSuiteVersion to delete. Required. + :type version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_evaluation_suites_delete_version_request( + name=name, + version=version, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + @overload - async def patch_agent_details( + async def create_or_update_version( self, - agent_name: str, + name: str, + version: str, + evaluation_suite_version: _models.EvaluationSuiteVersion, *, content_type: str = "application/merge-patch+json", - agent_endpoint: Optional[_models.AgentEndpointConfig] = None, - agent_card: Optional[_models.AgentCard] = None, **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. - :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig - :keyword agent_card: Optional agent card for the agent. Default value is None. - :paramtype agent_card: ~azure.ai.projects.models.AgentCard - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def patch_agent_details( - self, agent_name: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + async def create_or_update_version( + self, + name: str, + version: str, + evaluation_suite_version: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :param body: Required. - :type body: JSON + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Required. + :type evaluation_suite_version: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def patch_agent_details( - self, agent_name: str, body: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + async def create_or_update_version( + self, + name: str, + version: str, + evaluation_suite_version: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :param body: Required. - :type body: IO[bytes] + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Required. + :type evaluation_suite_version: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def patch_agent_details( + async def create_or_update_version( self, - agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - agent_endpoint: Optional[_models.AgentEndpointConfig] = None, - agent_card: Optional[_models.AgentCard] = None, + name: str, + version: str, + evaluation_suite_version: Union[_models.EvaluationSuiteVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. - :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig - :keyword agent_card: Optional agent card for the agent. Default value is None. - :paramtype agent_card: ~azure.ai.projects.models.AgentCard - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Is one of the + following types: EvaluationSuiteVersion, JSON, IO[bytes] Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion or JSON or + IO[bytes] + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3284,20 +3454,18 @@ async def patch_agent_details( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationSuiteVersion] = kwargs.pop("cls", None) - if body is _Unset: - body = {"agent_card": agent_card, "agent_endpoint": agent_endpoint} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/merge-patch+json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(evaluation_suite_version, (IOBase, bytes)): + _content = evaluation_suite_version else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(evaluation_suite_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_patch_agent_details_request( - agent_name=agent_name, + _request = build_evaluation_suites_create_or_update_version_request( + name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -3317,23 +3485,19 @@ async def patch_agent_details( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [200, 201]: if _stream: try: await response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentDetails, response.json()) + deserialized = _deserialize(_models.EvaluationSuiteVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3341,81 +3505,78 @@ async def patch_agent_details( return deserialized # type: ignore @overload - async def create_agent_version_from_code( + async def create_evaluation_suite_version( self, - agent_name: str, - content: _models.CreateAgentVersionFromCodeContent, + name: str, + evaluation_suite_version: _models.EvaluationSuiteVersion, *, - code_zip_sha256: str, + content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentVersionDetails: - """create_agent_version_from_code. + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. - - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_agent_version_from_code( - self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any - ) -> _models.AgentVersionDetails: - """create_agent_version_from_code. + async def create_evaluation_suite_version( + self, name: str, evaluation_suite_version: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Required. + :type evaluation_suite_version: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + @overload + async def create_evaluation_suite_version( + self, name: str, evaluation_suite_version: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Required. + :type evaluation_suite_version: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_agent_version_from_code( - self, - agent_name: str, - content: Union[_models.CreateAgentVersionFromCodeContent, JSON], - *, - code_zip_sha256: str, - **kwargs: Any - ) -> _models.AgentVersionDetails: - """create_agent_version_from_code. + async def create_evaluation_suite_version( + self, name: str, evaluation_suite_version: Union[_models.EvaluationSuiteVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. - - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Is one of the + following types: EvaluationSuiteVersion, JSON, IO[bytes] Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion or JSON or + IO[bytes] + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3426,21 +3587,24 @@ async def create_agent_version_from_code( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.AgentVersionDetails] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluationSuiteVersion] = kwargs.pop("cls", None) - _body = content.as_dict() if isinstance(content, _Model) else content - _file_fields: list[str] = ["code"] - _data_fields: list[str] = ["metadata"] - _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + content_type = content_type or "application/json" + _content = None + if isinstance(evaluation_suite_version, (IOBase, bytes)): + _content = evaluation_suite_version + else: + _content = json.dumps(evaluation_suite_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_create_agent_version_from_code_request( - agent_name=agent_name, - code_zip_sha256=code_zip_sha256, + _request = build_evaluation_suites_create_evaluation_suite_version_request( + name=name, + content_type=content_type, api_version=self._config.api_version, - files=_files, + content=_content, headers=_headers, params=_params, ) @@ -3457,7 +3621,7 @@ async def create_agent_version_from_code( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -3473,27 +3637,89 @@ async def create_agent_version_from_code( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentVersionDetails, response.json()) + deserialized = _deserialize(_models.EvaluationSuiteVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + async def run( + self, + name: str, + body: _models.EvaluationSuiteRunRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Required. + :type body: ~azure.ai.projects.models.EvaluationSuiteRunRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def run( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def run( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace_async - async def download_agent_version_code( - self, agent_name: str, agent_version: str, **kwargs: Any - ) -> AsyncIterator[bytes]: - """Download the code zip for a specific version of a code-based hosted agent. Returns the - previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches - the ``content_hash`` on the agent version's ``code_configuration``. + async def run( + self, name: str, body: Union[_models.EvaluationSuiteRunRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. - :param agent_name: The name of the agent. Required. - :type agent_name: str - :param agent_version: The version of the agent whose code zip should be downloaded. Required. - :type agent_version: str - :return: AsyncIterator[bytes] - :rtype: AsyncIterator[bytes] + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Is one of the following types: + EvaluationSuiteRunRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.EvaluationSuiteRunRequest or JSON or IO[bytes] + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3504,15 +3730,24 @@ async def download_agent_version_code( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluationSuiteRunResponse] = kwargs.pop("cls", None) - _request = build_beta_agents_download_agent_version_code_request( - agent_name=agent_name, - agent_version=agent_version, + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_evaluation_suites_run_request( + name=name, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -3522,14 +3757,14 @@ async def download_agent_version_code( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -3542,27 +3777,119 @@ async def download_agent_version_code( ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.EvaluationSuiteRunResponse, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaAgentsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`agents` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + async def update_agent_from_code( + self, + agent_name: str, + content: _models.CreateAgentVersionFromCodeContent, + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentDetails: + """Updates a code-based agent by uploading new code and creating a new version. If the code and + definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing + version. The request body is multipart/form-data with a JSON metadata part and a binary code + part (part order is irrelevant). Maximum upload size is 250 MB. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update_agent_from_code( + self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any + ) -> _models.AgentDetails: + """Updates a code-based agent by uploading new code and creating a new version. If the code and + definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing + version. The request body is multipart/form-data with a JSON metadata part and a binary code + part (part order is irrelevant). Maximum upload size is 250 MB. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace_async - async def download_agent_code(self, agent_name: str, **kwargs: Any) -> AsyncIterator[bytes]: - """Download the code zip for the latest version of a code-based hosted agent. Returns the - previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches - the ``content_hash`` on the latest version's ``code_configuration``. + async def update_agent_from_code( + self, + agent_name: str, + content: Union[_models.CreateAgentVersionFromCodeContent, JSON], + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentDetails: + """Updates a code-based agent by uploading new code and creating a new version. If the code and + definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing + version. The request body is multipart/form-data with a JSON metadata part and a binary code + part (part order is irrelevant). Maximum upload size is 250 MB. - :param agent_name: The name of the agent whose latest-version code zip should be downloaded. - Required. + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. :type agent_name: str - :return: AsyncIterator[bytes] - :rtype: AsyncIterator[bytes] + :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3576,11 +3903,18 @@ async def download_agent_code(self, agent_name: str, **kwargs: Any) -> AsyncIter _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) - _request = build_beta_agents_download_agent_code_request( + _body = content.as_dict() if isinstance(content, _Model) else content + _file_fields: list[str] = ["code"] + _data_fields: list[str] = ["metadata"] + _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + + _request = build_beta_agents_update_agent_from_code_request( agent_name=agent_name, + code_zip_sha256=code_zip_sha256, api_version=self._config.api_version, + files=_files, headers=_headers, params=_params, ) @@ -3590,7 +3924,7 @@ async def download_agent_code(self, agent_name: str, **kwargs: Any) -> AsyncIter _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -3610,110 +3944,100 @@ async def download_agent_code(self, agent_name: str, **kwargs: Any) -> AsyncIter ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.AgentDetails, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore @overload - async def create_session( + async def patch_agent_details( self, agent_name: str, *, - version_indicator: _models.VersionIndicator, - content_type: str = "application/json", - agent_session_id: Optional[str] = None, + content_type: str = "application/merge-patch+json", + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, + agent_card: Optional[_models.AgentCard] = None, **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str - :keyword version_indicator: Determines which agent version backs the session. Required. - :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique - within the agent endpoint. Auto-generated if omitted. Default value is None. - :paramtype agent_session_id: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. + :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig + :keyword agent_card: Optional agent card for the agent. Default value is None. + :paramtype agent_card: ~azure.ai.projects.models.AgentCard + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_session( - self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + async def patch_agent_details( + self, agent_name: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_session( - self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + async def patch_agent_details( + self, agent_name: str, body: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_session( + async def patch_agent_details( self, agent_name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - version_indicator: _models.VersionIndicator = _Unset, - agent_session_id: Optional[str] = None, + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, + agent_card: Optional[_models.AgentCard] = None, **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword version_indicator: Determines which agent version backs the session. Required. - :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator - :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique - within the agent endpoint. Auto-generated if omitted. Default value is None. - :paramtype agent_session_id: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. + :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig + :keyword agent_card: Optional agent card for the agent. Default value is None. + :paramtype agent_card: ~azure.ai.projects.models.AgentCard + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3728,21 +4052,19 @@ async def create_session( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) if body is _Unset: - if version_indicator is _Unset: - raise TypeError("missing required argument: version_indicator") - body = {"agent_session_id": agent_session_id, "version_indicator": version_indicator} + body = {"agent_card": agent_card, "agent_endpoint": agent_endpoint} body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" + content_type = content_type or "application/merge-patch+json" _content = None if isinstance(body, (IOBase, bytes)): _content = body else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_create_session_request( + _request = build_beta_agents_patch_agent_details_request( agent_name=agent_name, content_type=content_type, api_version=self._config.api_version, @@ -3763,7 +4085,7 @@ async def create_session( response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -3779,23 +4101,89 @@ async def create_session( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentSessionResource, response.json()) + deserialized = _deserialize(_models.AgentDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + async def create_agent_version_from_code( + self, + agent_name: str, + content: _models.CreateAgentVersionFromCodeContent, + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_agent_version_from_code. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_agent_version_from_code( + self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_agent_version_from_code. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace_async - async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _models.AgentSessionResource: - """Retrieves a session by ID. + async def create_agent_version_from_code( + self, + agent_name: str, + content: Union[_models.CreateAgentVersionFromCodeContent, JSON], + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_agent_version_from_code. - :param agent_name: The name of the agent. Required. + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. :type agent_name: str - :param session_id: The session identifier. Required. - :type session_id: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3809,12 +4197,18 @@ async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentVersionDetails] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_request( + _body = content.as_dict() if isinstance(content, _Model) else content + _file_fields: list[str] = ["code"] + _data_fields: list[str] = ["metadata"] + _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + + _request = build_beta_agents_create_agent_version_from_code_request( agent_name=agent_name, - session_id=session_id, + code_zip_sha256=code_zip_sha256, api_version=self._config.api_version, + files=_files, headers=_headers, params=_params, ) @@ -3847,7 +4241,7 @@ async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentSessionResource, response.json()) + deserialized = _deserialize(_models.AgentVersionDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -3855,16 +4249,19 @@ async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> return deserialized # type: ignore @distributed_trace_async - async def delete_session(self, agent_name: str, session_id: str, **kwargs: Any) -> None: - """Deletes a session synchronously. Returns 204 No Content when the session is deleted or does not - exist. + async def download_agent_version_code( + self, agent_name: str, agent_version: str, **kwargs: Any + ) -> AsyncIterator[bytes]: + """Download the code zip for a specific version of a code-based hosted agent. Returns the + previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches + the ``content_hash`` on the agent version's ``code_configuration``. :param agent_name: The name of the agent. Required. :type agent_name: str - :param session_id: The session identifier. Required. - :type session_id: str - :return: None - :rtype: None + :param agent_version: The version of the agent whose code zip should be downloaded. Required. + :type agent_version: str + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -3878,11 +4275,11 @@ async def delete_session(self, agent_name: str, session_id: str, **kwargs: Any) _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_agents_delete_session_request( + _request = build_beta_agents_download_agent_version_code_request( agent_name=agent_name, - session_id=session_id, + agent_version=agent_version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -3892,14 +4289,20 @@ async def delete_session(self, agent_name: str, session_id: str, **kwargs: Any) } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -3907,46 +4310,29 @@ async def delete_session(self, agent_name: str, session_id: str, **kwargs: Any) ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore - @distributed_trace - def list_sessions( - self, - agent_name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.AgentSessionResource"]: - """Returns a list of sessions for the specified agent. + return deserialized # type: ignore - :param agent_name: The name of the agent. Required. + @distributed_trace_async + async def download_agent_code(self, agent_name: str, **kwargs: Any) -> AsyncIterator[bytes]: + """Download the code zip for the latest version of a code-based hosted agent. Returns the + previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches + the ``content_hash`` on the latest version's ``code_configuration``. + + :param agent_name: The name of the agent whose latest-version code zip should be downloaded. + Required. :type agent_name: str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of AgentSessionResource - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.AgentSessionResource] + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.AgentSessionResource]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -3955,113 +4341,13 @@ def list_sessions( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _request = build_beta_agents_list_sessions_request( - agent_name=agent_name, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.AgentSessionResource], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) - - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return AsyncItemPaged(get_next, extract_data) - - @distributed_trace_async - async def get_session_log_stream( - self, agent_name: str, agent_version: str, session_id: str, **kwargs: Any - ) -> _models.SessionLogEvent: - """Streams console logs (stdout / stderr) for a specific hosted agent session - as a Server-Sent Events (SSE) stream. - - Each SSE frame contains: - - * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) - - Example SSE frames: - - .. code-block:: - - event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} - - event: log - data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} - - event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} - - event: log - data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} - - The stream remains open until the client disconnects or the server - terminates the connection. Clients should handle reconnection as needed. - - :param agent_name: The name of the hosted agent. Required. - :type agent_name: str - :param agent_version: The version of the agent. Required. - :type agent_version: str - :param session_id: The session ID (maps to an ADC sandbox). Required. - :type session_id: str - :return: SessionLogEvent. The SessionLogEvent is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionLogEvent - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.SessionLogEvent] = kwargs.pop("cls", None) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_log_stream_request( + _request = build_beta_agents_download_agent_code_request( agent_name=agent_name, - agent_version=agent_version, - session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4072,7 +4358,7 @@ async def get_session_log_stream( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = True + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -4095,34 +4381,107 @@ async def get_session_log_stream( response_headers = {} response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SessionLogEvent, response.text()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore + @overload + async def create_session( + self, + agent_name: str, + *, + version_indicator: _models.VersionIndicator, + content_type: str = "application/json", + agent_session_id: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. + + :param agent_name: The name of the agent to create a session for. Required. + :type agent_name: str + :keyword version_indicator: Determines which agent version backs the session. Required. + :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique + within the agent endpoint. Auto-generated if omitted. Default value is None. + :paramtype agent_session_id: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_session( + self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. + + :param agent_name: The name of the agent to create a session for. Required. + :type agent_name: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_session( + self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. + + :param agent_name: The name of the agent to create a session for. Required. + :type agent_name: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace_async - async def _upload_session_file( - self, agent_name: str, agent_session_id: str, content: bytes, *, path: str, **kwargs: Any - ) -> _models.SessionFileWriteResult: - """Upload a file to the session sandbox via binary stream. Maximum file size is 50 MB. Uploads - exceeding this limit return 413 Payload Too Large. + async def create_session( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + version_indicator: _models.VersionIndicator = _Unset, + agent_session_id: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the agent to create a session for. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :param content: Required. - :type content: bytes - :keyword path: The destination file path within the sandbox, relative to the session home - directory. Required. - :paramtype path: str - :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionFileWriteResult + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword version_indicator: Determines which agent version backs the session. Required. + :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique + within the agent endpoint. Auto-generated if omitted. Default value is None. + :paramtype agent_session_id: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4136,15 +4495,23 @@ async def _upload_session_file( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) - cls: ClsType[_models.SessionFileWriteResult] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) - _content = content + if body is _Unset: + if version_indicator is _Unset: + raise TypeError("missing required argument: version_indicator") + body = {"agent_session_id": agent_session_id, "version_indicator": version_indicator} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_upload_session_file_request( + _request = build_beta_agents_create_session_request( agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -4180,7 +4547,7 @@ async def _upload_session_file( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SessionFileWriteResult, response.json()) + deserialized = _deserialize(_models.AgentSessionResource, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -4188,20 +4555,15 @@ async def _upload_session_file( return deserialized # type: ignore @distributed_trace_async - async def download_session_file( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any - ) -> AsyncIterator[bytes]: - """Download a file from the session sandbox as a binary stream. + async def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _models.AgentSessionResource: + """Retrieves a session by ID. :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :keyword path: The file path to download from the sandbox, relative to the session home - directory. Required. - :paramtype path: str - :return: AsyncIterator[bytes] - :rtype: AsyncIterator[bytes] + :param session_id: The session identifier. Required. + :type session_id: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4215,12 +4577,11 @@ async def download_session_file( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) - _request = build_beta_agents_download_session_file_request( + _request = build_beta_agents_get_session_request( agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, + session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4231,7 +4592,7 @@ async def download_session_file( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -4251,7 +4612,10 @@ async def download_session_file( ) raise HttpResponseError(response=response, model=error) - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.AgentSessionResource, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -4259,21 +4623,16 @@ async def download_session_file( return deserialized # type: ignore @distributed_trace_async - async def get_session_files( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any - ) -> _models.SessionDirectoryListResult: - """List files and directories at a given path in the session sandbox. Returns only the immediate - children of the specified directory (non-recursive). + async def delete_session(self, agent_name: str, session_id: str, **kwargs: Any) -> None: + """Deletes a session synchronously. Returns 204 No Content when the session is deleted or does not + exist. :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :keyword path: The directory path to list, relative to the session home directory. Required. - :paramtype path: str - :return: SessionDirectoryListResult. The SessionDirectoryListResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.SessionDirectoryListResult + :param session_id: The session identifier. Required. + :type session_id: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4287,12 +4646,11 @@ async def get_session_files( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SessionDirectoryListResult] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_files_request( + _request = build_beta_agents_delete_session_request( agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, + session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4302,20 +4660,14 @@ async def get_session_files( } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -4323,37 +4675,46 @@ async def get_session_files( ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SessionDirectoryListResult, response.json()) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore - @distributed_trace_async - async def delete_session_file( - self, agent_name: str, agent_session_id: str, *, path: str, recursive: Optional[bool] = None, **kwargs: Any - ) -> None: - """Delete a file or directory from the session sandbox. If ``recursive`` is false (default) and - the target is a non-empty directory, the API returns 409 Conflict. + @distributed_trace + def list_sessions( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.AgentSessionResource"]: + """Returns a list of sessions for the specified agent. :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :keyword path: The file or directory path to delete, relative to the session home directory. - Required. - :paramtype path: str - :keyword recursive: Whether to recursively delete directory contents. Defaults to false. + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. Default value is None. - :paramtype recursive: bool - :return: None - :rtype: None + :paramtype before: str + :return: An iterator like instance of AgentSessionResource + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.AgentSessionResource] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.AgentSessionResource]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -4362,69 +4723,94 @@ async def delete_session_file( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) + def prepare_request(_continuation_token=None): - _request = build_beta_agents_delete_session_file_request( - agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, - recursive=recursive, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _request = build_beta_agents_list_sessions_request( + agent_name=agent_name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.AgentSessionResource], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) - response = pipeline_response.http_response + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [204]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) + response = pipeline_response.http_response - if cls: - return cls(pipeline_response, None, {}) # type: ignore + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + return pipeline_response -class BetaEvaluationTaxonomiesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + return AsyncItemPaged(get_next, extract_data) - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`evaluation_taxonomies` attribute. - """ + @distributed_trace_async + async def get_session_log_stream( + self, agent_name: str, agent_version: str, session_id: str, **kwargs: Any + ) -> _models.SessionLogEvent: + """Streams console logs (stdout / stderr) for a specific hosted agent session + as a Server-Sent Events (SSE) stream. - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + Each SSE frame contains: - @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: - """Get an evaluation run by name. + * `event`: always `"log"` + * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) - :param name: The name of the resource. Required. - :type name: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + Example SSE frames: + + .. code-block:: + + event: log + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} + + event: log + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} + + event: log + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} + + event: log + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} + + The stream remains open until the client disconnects or the server + terminates the connection. Clients should handle reconnection as needed. + + :param agent_name: The name of the hosted agent. Required. + :type agent_name: str + :param agent_version: The version of the agent. Required. + :type agent_version: str + :param session_id: The session ID (maps to an ADC sandbox). Required. + :type session_id: str + :return: SessionLogEvent. The SessionLogEvent is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SessionLogEvent :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4438,10 +4824,12 @@ async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) + cls: ClsType[_models.SessionLogEvent] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_get_request( - name=name, + _request = build_beta_agents_get_session_log_stream_request( + agent_name=agent_name, + agent_version=agent_version, + session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -4452,7 +4840,7 @@ async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = True pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -4466,122 +4854,43 @@ async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) + deserialized = _deserialize(_models.SessionLogEvent, response.text()) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( - self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.EvaluationTaxonomy"]: - """List evaluation taxonomies. - - :keyword input_name: Filter by the evaluation input name. Default value is None. - :paramtype input_name: str - :keyword input_type: Filter by taxonomy input type. Default value is None. - :paramtype input_type: str - :return: An iterator like instance of EvaluationTaxonomy - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluationTaxonomy] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.EvaluationTaxonomy]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_evaluation_taxonomies_list_request( - input_name=input_name, - input_type=input_type, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.EvaluationTaxonomy], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - - async def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - return pipeline_response - - return AsyncItemPaged(get_next, extract_data) - @distributed_trace_async - async def delete(self, name: str, **kwargs: Any) -> None: - """Delete an evaluation taxonomy by name. + async def _upload_session_file( + self, agent_name: str, agent_session_id: str, content: bytes, *, path: str, **kwargs: Any + ) -> _models.SessionFileWriteResult: + """Upload a file to the session sandbox via binary stream. Maximum file size is 50 MB. Uploads + exceeding this limit return 413 Payload Too Large. - :param name: The name of the resource. Required. - :type name: str - :return: None - :rtype: None + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :param content: Required. + :type content: bytes + :keyword path: The destination file path within the sandbox, relative to the session home + directory. Required. + :paramtype path: str + :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SessionFileWriteResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4592,14 +4901,21 @@ async def delete(self, name: str, **kwargs: Any) -> None: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) + cls: ClsType[_models.SessionFileWriteResult] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_delete_request( - name=name, + _content = content + + _request = build_beta_agents_upload_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -4608,87 +4924,52 @@ async def delete(self, name: str, **kwargs: Any) -> None: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore - - @overload - async def create( - self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. - - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def create( - self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SessionFileWriteResult, response.json()) - @overload - async def create( - self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + return deserialized # type: ignore @distributed_trace_async - async def create( - self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + async def download_session_file( + self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + ) -> AsyncIterator[bytes]: + """Download a file from the session sandbox as a binary stream. - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, - JSON, IO[bytes] Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :keyword path: The file path to download from the sandbox, relative to the session home + directory. Required. + :paramtype path: str + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4699,24 +4980,16 @@ async def create( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(taxonomy, (IOBase, bytes)): - _content = taxonomy - else: - _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_create_request( - name=name, - content_type=content_type, + _request = build_beta_agents_download_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -4726,99 +4999,49 @@ async def create( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200, 201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - async def update( - self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. - - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def update( - self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. - - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def update( - self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. - - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace_async - async def update( - self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + async def get_session_files( + self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + ) -> _models.SessionDirectoryListResult: + """List files and directories at a given path in the session sandbox. Returns only the immediate + children of the specified directory (non-recursive). - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, - JSON, IO[bytes] Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :keyword path: The directory path to list, relative to the session home directory. Required. + :paramtype path: str + :return: SessionDirectoryListResult. The SessionDirectoryListResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.SessionDirectoryListResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -4829,24 +5052,16 @@ async def update( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(taxonomy, (IOBase, bytes)): - _content = taxonomy - else: - _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.SessionDirectoryListResult] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_update_request( - name=name, - content_type=content_type, + _request = build_beta_agents_get_session_files_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -4870,27 +5085,97 @@ async def update( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) + deserialized = _deserialize(_models.SessionDirectoryListResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace_async + async def delete_session_file( + self, agent_name: str, agent_session_id: str, *, path: str, recursive: Optional[bool] = None, **kwargs: Any + ) -> None: + """Delete a file or directory from the session sandbox. If ``recursive`` is false (default) and + the target is a non-empty directory, the API returns 409 Conflict. -class BetaEvaluatorsOperations: + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :keyword path: The file or directory path to delete, relative to the session home directory. + Required. + :paramtype path: str + :keyword recursive: Whether to recursively delete directory contents. Defaults to false. + Default value is None. + :paramtype recursive: bool + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_agents_delete_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, + recursive=recursive, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + +class BetaEvaluationTaxonomiesOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`evaluators` attribute. + :attr:`evaluation_taxonomies` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -4900,35 +5185,16 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace - def list_versions( - self, - name: str, - *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.EvaluatorVersion"]: - """List all versions of the given evaluator. + @distributed_trace_async + async def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: + """Get an evaluation run by name. :param name: The name of the resource. Required. :type name: str - :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one - of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default - value is None. - :paramtype type: str or str or str or str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. Default value is None. - :paramtype limit: int - :return: An iterator like instance of EvaluatorVersion - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluatorVersion] + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -4937,101 +5203,67 @@ def list_versions( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_evaluators_list_versions_request( - name=name, - type=type, - limit=limit, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - return _request + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.EvaluatorVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + _request = build_beta_evaluation_taxonomies_get_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - async def get_next(next_link=None): - _request = prepare_request(next_link) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + response = pipeline_response.http_response - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - return pipeline_response + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) - return AsyncItemPaged(get_next, extract_data) + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace def list( - self, - *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.EvaluatorVersion"]: - """List the latest version of each evaluator. + self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any + ) -> AsyncItemPaged["_models.EvaluationTaxonomy"]: + """List evaluation taxonomies. - :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one - of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default - value is None. - :paramtype type: str or str or str or str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. Default value is None. - :paramtype limit: int - :return: An iterator like instance of EvaluatorVersion - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluatorVersion] + :keyword input_name: Filter by the evaluation input name. Default value is None. + :paramtype input_name: str + :keyword input_type: Filter by taxonomy input type. Default value is None. + :paramtype input_type: str + :return: An iterator like instance of EvaluationTaxonomy + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluationTaxonomy] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.EvaluationTaxonomy]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -5044,9 +5276,9 @@ def list( def prepare_request(next_link=None): if not next_link: - _request = build_beta_evaluators_list_request( - type=type, - limit=limit, + _request = build_beta_evaluation_taxonomies_list_request( + input_name=input_name, + input_type=input_type, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5086,7 +5318,7 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.EvaluatorVersion], + List[_models.EvaluationTaxonomy], deserialized.get("value", []), ) if cls: @@ -5111,79 +5343,11 @@ async def get_next(next_link=None): return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.EvaluatorVersion: - """Get the specific version of the EvaluatorVersion. The service returns 404 Not Found error if - the EvaluatorVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the EvaluatorVersion to retrieve. Required. - :type version: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) - - _request = build_beta_evaluators_get_version_request( - name=name, - version=version, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace_async - async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: - """Delete the specific version of the EvaluatorVersion. The service returns 204 No Content if the - EvaluatorVersion was deleted successfully or if the EvaluatorVersion does not exist. + async def delete(self, name: str, **kwargs: Any) -> None: + """Delete an evaluation taxonomy by name. :param name: The name of the resource. Required. :type name: str - :param version: The version of the EvaluatorVersion to delete. Required. - :type version: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -5201,9 +5365,8 @@ async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_evaluators_delete_version_request( + _request = build_beta_evaluation_taxonomies_delete_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5228,77 +5391,72 @@ async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore @overload - async def create_version( - self, - name: str, - evaluator_version: _models.EvaluatorVersion, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + async def create( + self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_version( - self, name: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + async def create( + self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: JSON + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_version( - self, name: str, evaluator_version: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + async def create( + self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: IO[bytes] + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_version( - self, name: str, evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + async def create( + self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Is one of the following types: EvaluatorVersion, JSON, IO[bytes] - Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, + JSON, IO[bytes] Required. + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5313,16 +5471,16 @@ async def create_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(evaluator_version, (IOBase, bytes)): - _content = evaluator_version + if isinstance(taxonomy, (IOBase, bytes)): + _content = taxonomy else: - _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluators_create_version_request( + _request = build_beta_evaluation_taxonomies_create_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -5343,7 +5501,7 @@ async def create_version( response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200, 201]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -5355,7 +5513,7 @@ async def create_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -5363,96 +5521,72 @@ async def create_version( return deserialized # type: ignore @overload - async def update_version( - self, - name: str, - version: str, - evaluator_version: _models.EvaluatorVersion, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + async def update( + self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update_version( - self, name: str, version: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + async def update( + self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Required. - :type evaluator_version: JSON + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update_version( - self, - name: str, - version: str, - evaluator_version: IO[bytes], - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + async def update( + self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Required. - :type evaluator_version: IO[bytes] + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def update_version( - self, - name: str, - version: str, - evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + async def update( + self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Is one of the following types: EvaluatorVersion, + :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, JSON, IO[bytes] Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5467,18 +5601,17 @@ async def update_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(evaluator_version, (IOBase, bytes)): - _content = evaluator_version + if isinstance(taxonomy, (IOBase, bytes)): + _content = taxonomy else: - _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluators_update_version_request( + _request = build_beta_evaluation_taxonomies_update_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -5510,112 +5643,60 @@ async def update_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - async def create_generation_job( - self, - job: _models.EvaluatorGenerationJob, - *, - operation_id: Optional[str] = None, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. +class BetaEvaluatorsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - :param job: The job to create. Required. - :type job: ~azure.ai.projects.models.EvaluatorGenerationJob - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`evaluators` attribute. + """ - @overload - async def create_generation_job( - self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. - - :param job: The job to create. Required. - :type job: JSON - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - async def create_generation_job( + @distributed_trace + def list_versions( self, - job: IO[bytes], + name: str, *, - operation_id: Optional[str] = None, - content_type: str = "application/json", + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, + limit: Optional[int] = None, **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. + ) -> AsyncItemPaged["_models.EvaluatorVersion"]: + """List all versions of the given evaluator. - :param job: The job to create. Required. - :type job: IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob + :param name: The name of the resource. Required. + :type name: str + :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one + of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default + value is None. + :paramtype type: str or str or str or str + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. Default value is None. + :paramtype limit: int + :return: An iterator like instance of EvaluatorVersion + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluatorVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @distributed_trace_async - async def create_generation_job( - self, - job: Union[_models.EvaluatorGenerationJob, JSON, IO[bytes]], - *, - operation_id: Optional[str] = None, - **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) - :param job: The job to create. Is one of the following types: EvaluatorGenerationJob, JSON, - IO[bytes] Required. - :type job: ~azure.ai.projects.models.EvaluatorGenerationJob or JSON or IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -5624,177 +5705,101 @@ async def create_generation_job( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(job, (IOBase, bytes)): - _content = job - else: - _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + def prepare_request(next_link=None): + if not next_link: - _request = build_beta_evaluators_create_generation_job_request( - operation_id=operation_id, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _request = build_beta_evaluators_list_versions_request( + name=name, + type=type, + limit=limit, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - response = pipeline_response.http_response + return _request - if response.status_code not in [201]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluatorVersion], + deserialized.get("value", []), ) - raise HttpResponseError(response=response, model=error) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) - - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @distributed_trace_async - async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: - """Get info about an evaluator generation job. - - Gets the details of an evaluator generation job by its ID. - - :param job_id: The ID of the job. Required. - :type job_id: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - - _request = build_beta_evaluators_get_generation_job_request( - job_id=job_id, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response + async def get_next(next_link=None): + _request = prepare_request(next_link) - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + response = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return pipeline_response - return deserialized # type: ignore + return AsyncItemPaged(get_next, extract_data) @distributed_trace - def list_generation_jobs( + def list( self, *, + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - category: Optional[Union[str, _models.EvaluatorCategory]] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.EvaluatorGenerationJob"]: - """Returns a list of evaluator generation jobs. - - Returns a list of evaluator generation jobs. + ) -> AsyncItemPaged["_models.EvaluatorVersion"]: + """List the latest version of each evaluator. + :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one + of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default + value is None. + :paramtype type: str or str or str or str :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. + 100, and the default is 20. Default value is None. :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :keyword category: Filter evaluator generation jobs by category. Known values are: "quality", - "safety", and "agents". Default value is None. - :paramtype category: str or ~azure.ai.projects.models.EvaluatorCategory - :return: An iterator like instance of EvaluatorGenerationJob - :rtype: - ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluatorGenerationJob] + :return: An iterator like instance of EvaluatorVersion + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.EvaluatorVersion] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.EvaluatorGenerationJob]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -5804,36 +5809,60 @@ def list_generation_jobs( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_evaluators_list_request( + type=type, + limit=limit, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_evaluators_list_generation_jobs_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - category=category, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.EvaluatorGenerationJob], - deserialized.get("data", []), + List[_models.EvaluatorVersion], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + async def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access @@ -5843,26 +5872,23 @@ async def get_next(_continuation_token=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) return pipeline_response return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: - """Cancels an evaluator generation job. - - Cancels an evaluator generation job by its ID. + async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.EvaluatorVersion: + """Get the specific version of the EvaluatorVersion. The service returns 404 Not Found error if + the EvaluatorVersion does not exist. - :param job_id: The ID of the job to cancel. Required. - :type job_id: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to retrieve. Required. + :type version: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5876,10 +5902,11 @@ async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Eva _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) - _request = build_beta_evaluators_cancel_generation_job_request( - job_id=job_id, + _request = build_beta_evaluators_get_version_request( + name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5904,16 +5931,12 @@ async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Eva except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -5921,12 +5944,14 @@ async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Eva return deserialized # type: ignore @distributed_trace_async - async def delete_generation_job(self, job_id: str, **kwargs: Any) -> None: - """Deletes an evaluator generation job by its ID. Deletes the job record only; the generated - evaluator (if any) is preserved. + async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: + """Delete the specific version of the EvaluatorVersion. The service returns 204 No Content if the + EvaluatorVersion was deleted successfully or if the EvaluatorVersion does not exist. - :param job_id: The ID of the job to delete. Required. - :type job_id: str + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to delete. Required. + :type version: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -5944,8 +5969,9 @@ async def delete_generation_job(self, job_id: str, **kwargs: Any) -> None: cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_evaluators_delete_generation_job_request( - job_id=job_id, + _request = build_beta_evaluators_delete_version_request( + name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -5964,93 +5990,83 @@ async def delete_generation_job(self, job_id: str, **kwargs: Any) -> None: if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if cls: return cls(pipeline_response, None, {}) # type: ignore - -class BetaInsightsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`insights` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - async def generate( - self, insight: _models.Insight, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Insight: - """Generate Insights. + async def create_version( + self, + name: str, + evaluator_version: _models.EvaluatorVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: ~azure.ai.projects.models.Insight + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def generate( - self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Insight: - """Generate Insights. - - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: JSON + async def create_version( + self, name: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. + + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Required. + :type evaluator_version: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def generate( - self, insight: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Insight: - """Generate Insights. + async def create_version( + self, name: str, evaluator_version: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: IO[bytes] + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Required. + :type evaluator_version: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: - """Generate Insights. + async def create_version( + self, name: str, evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Is one of the following types: Insight, JSON, IO[bytes] Required. - :type insight: ~azure.ai.projects.models.Insight or JSON or IO[bytes] - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Is one of the following types: EvaluatorVersion, JSON, IO[bytes] + Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6065,16 +6081,17 @@ async def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwa _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.Insight] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(insight, (IOBase, bytes)): - _content = insight + if isinstance(evaluator_version, (IOBase, bytes)): + _content = evaluator_version else: - _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_insights_generate_request( + _request = build_beta_evaluators_create_version_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -6101,35 +6118,109 @@ async def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwa except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Insight, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + async def update_version( + self, + name: str, + version: str, + evaluator_version: _models.EvaluatorVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update_version( + self, name: str, version: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Required. + :type evaluator_version: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update_version( + self, + name: str, + version: str, + evaluator_version: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Required. + :type evaluator_version: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace_async - async def get( - self, insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any - ) -> _models.Insight: - """Get a specific insight by Id. + async def update_version( + self, + name: str, + version: str, + evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. - :param insight_id: The unique identifier for the insights report. Required. - :type insight_id: str - :keyword include_coordinates: Whether to include coordinates for visualization in the response. - Defaults to false. Default value is None. - :paramtype include_coordinates: bool - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Is one of the following types: EvaluatorVersion, + JSON, IO[bytes] Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6140,15 +6231,25 @@ async def get( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Insight] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) - _request = build_beta_insights_get_request( - insight_id=insight_id, - include_coordinates=include_coordinates, + content_type = content_type or "application/json" + _content = None + if isinstance(evaluator_version, (IOBase, bytes)): + _content = evaluator_version + else: + _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_evaluators_update_version_request( + name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -6172,246 +6273,96 @@ async def get( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Insight, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( - self, - *, - type: Optional[Union[str, _models.InsightType]] = None, - eval_id: Optional[str] = None, - run_id: Optional[str] = None, - agent_name: Optional[str] = None, - include_coordinates: Optional[bool] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.Insight"]: - """List all insights in reverse chronological order (newest first). - - :keyword type: Filter by the type of analysis. Known values are: "EvaluationRunClusterInsight", - "AgentClusterInsight", and "EvaluationComparison". Default value is None. - :paramtype type: str or ~azure.ai.projects.models.InsightType - :keyword eval_id: Filter by the evaluation ID. Default value is None. - :paramtype eval_id: str - :keyword run_id: Filter by the evaluation run ID. Default value is None. - :paramtype run_id: str - :keyword agent_name: Filter by the agent name. Default value is None. - :paramtype agent_name: str - :keyword include_coordinates: Whether to include coordinates for visualization in the response. - Defaults to false. Default value is None. - :paramtype include_coordinates: bool - :return: An iterator like instance of Insight - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.Insight] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) +class BetaInsightsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`insights` attribute. + """ - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_insights_list_request( - type=type, - eval_id=eval_id, - run_id=run_id, - agent_name=agent_name, - include_coordinates=include_coordinates, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Insight], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - - async def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return AsyncItemPaged(get_next, extract_data) - - -class BetaMemoryStoresOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`memory_stores` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @overload - async def create( - self, - *, - name: str, - definition: _models.MemoryStoreDefinition, - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + async def generate( + self, insight: _models.Insight, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - :keyword name: The name of the memory store. Required. - :paramtype name: str - :keyword definition: The memory store definition. Required. - :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Required. + :type insight: ~azure.ai.projects.models.Insight :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create( - self, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + async def generate( + self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - :param body: Required. - :type body: JSON + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Required. + :type insight: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create( - self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + async def generate( + self, insight: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - :param body: Required. - :type body: IO[bytes] + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Required. + :type insight: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create( - self, - body: Union[JSON, IO[bytes]] = _Unset, - *, - name: str = _Unset, - definition: _models.MemoryStoreDefinition = _Unset, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + async def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: + """Generate Insights. - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword name: The name of the memory store. Required. - :paramtype name: str - :keyword definition: The memory store definition. Required. - :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Is one of the following types: Insight, JSON, IO[bytes] Required. + :type insight: ~azure.ai.projects.models.Insight or JSON or IO[bytes] + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6426,23 +6377,16 @@ async def create( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.Insight] = kwargs.pop("cls", None) - if body is _Unset: - if name is _Unset: - raise TypeError("missing required argument: name") - if definition is _Unset: - raise TypeError("missing required argument: definition") - body = {"definition": definition, "description": description, "metadata": metadata, "name": name} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(insight, (IOBase, bytes)): + _content = insight else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_create_request( + _request = build_beta_insights_generate_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -6462,7 +6406,7 @@ async def create( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -6478,194 +6422,44 @@ async def create( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - async def update( - self, - name: str, - *, - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + @distributed_trace_async + async def get( + self, insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any + ) -> _models.Insight: + """Get a specific insight by Id. - :param name: The name of the memory store to update. Required. - :type name: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :param insight_id: The unique identifier for the insights report. Required. + :type insight_id: str + :keyword include_coordinates: Whether to include coordinates for visualization in the response. + Defaults to false. Default value is None. + :paramtype include_coordinates: bool + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - @overload - async def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. - - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @distributed_trace_async - async def update( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. - - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - - if body is _Unset: - body = {"description": description, "metadata": metadata} - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_update_request( - name=name, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: - """Retrieve a memory store. - - :param name: The name of the memory store to retrieve. Required. - :type name: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.Insight] = kwargs.pop("cls", None) - _request = build_beta_memory_stores_get_request( - name=name, + _request = build_beta_insights_get_request( + insight_id=insight_id, + include_coordinates=include_coordinates, api_version=self._config.api_version, headers=_headers, params=_params, @@ -6699,7 +6493,7 @@ async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6710,35 +6504,35 @@ async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: def list( self, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + type: Optional[Union[str, _models.InsightType]] = None, + eval_id: Optional[str] = None, + run_id: Optional[str] = None, + agent_name: Optional[str] = None, + include_coordinates: Optional[bool] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.MemoryStoreDetails"]: - """List all memory stores. + ) -> AsyncItemPaged["_models.Insight"]: + """List all insights in reverse chronological order (newest first). - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of MemoryStoreDetails - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.MemoryStoreDetails] + :keyword type: Filter by the type of analysis. Known values are: "EvaluationRunClusterInsight", + "AgentClusterInsight", and "EvaluationComparison". Default value is None. + :paramtype type: str or ~azure.ai.projects.models.InsightType + :keyword eval_id: Filter by the evaluation ID. Default value is None. + :paramtype eval_id: str + :keyword run_id: Filter by the evaluation run ID. Default value is None. + :paramtype run_id: str + :keyword agent_name: Filter by the agent name. Default value is None. + :paramtype agent_name: str + :keyword include_coordinates: Whether to include coordinates for visualization in the response. + Defaults to false. Default value is None. + :paramtype include_coordinates: bool + :return: An iterator like instance of Insight + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.Insight] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.MemoryStoreDetails]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -6748,35 +6542,63 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_insights_list_request( + type=type, + eval_id=eval_id, + run_id=run_id, + agent_name=agent_name, + include_coordinates=include_coordinates, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_memory_stores_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.MemoryStoreDetails], - deserialized.get("data", []), + List[_models.Insight], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + async def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access @@ -6796,478 +6618,112 @@ async def get_next(_continuation_token=None): return AsyncItemPaged(get_next, extract_data) - @distributed_trace_async - async def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: - """Delete a memory store. - - :param name: The name of the memory store to delete. Required. - :type name: str - :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.DeleteMemoryStoreResult] = kwargs.pop("cls", None) - - _request = build_beta_memory_stores_delete_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DeleteMemoryStoreResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @overload - async def _search_memories( - self, - name: str, - *, - scope: str, - content_type: str = "application/json", - items: Optional[List[dict[str, Any]]] = None, - previous_search_id: Optional[str] = None, - options: Optional[_models.MemorySearchOptions] = None, - **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... - @overload - async def _search_memories( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... - @overload - async def _search_memories( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... - - @distributed_trace_async - async def _search_memories( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_search_id: Optional[str] = None, - options: Optional[_models.MemorySearchOptions] = None, - **kwargs: Any - ) -> _models.MemoryStoreSearchResult: - """Search for relevant memories from a memory store based on conversation context. - :param name: The name of the memory store to search. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. - Required. - :paramtype scope: str - :keyword items: Items for which to search for relevant memories. Default value is None. - :paramtype items: list[dict[str, any]] - :keyword previous_search_id: The unique ID of the previous search request, enabling incremental - memory search from where the last operation left off. Default value is None. - :paramtype previous_search_id: str - :keyword options: Memory search options. Default value is None. - :paramtype options: ~azure.ai.projects.models.MemorySearchOptions - :return: MemoryStoreSearchResult. The MemoryStoreSearchResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreSearchResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreSearchResult] = kwargs.pop("cls", None) - - if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = { - "items": items, - "options": options, - "previous_search_id": previous_search_id, - "scope": scope, - } - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_search_memories_request( - name=name, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.MemoryStoreSearchResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - async def _update_memories_initial( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_update_id: Optional[str] = None, - update_delay: Optional[int] = None, - **kwargs: Any - ) -> AsyncIterator[bytes]: - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - - if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = { - "items": items, - "previous_update_id": previous_update_id, - "scope": scope, - "update_delay": update_delay, - } - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_update_memories_request( - name=name, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = True - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [202]: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @overload - async def _begin_update_memories( - self, - name: str, - *, - scope: str, - content_type: str = "application/json", - items: Optional[List[dict[str, Any]]] = None, - previous_update_id: Optional[str] = None, - update_delay: Optional[int] = None, - **kwargs: Any - ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: ... - @overload - async def _begin_update_memories( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: ... - @overload - async def _begin_update_memories( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: ... - - @distributed_trace_async - async def _begin_update_memories( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_update_id: Optional[str] = None, - update_delay: Optional[int] = None, - **kwargs: Any - ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: - """Update memory store with conversation memories. - - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. - Required. - :paramtype scope: str - :keyword items: Conversation items to be stored in memory. Default value is None. - :paramtype items: list[dict[str, any]] - :keyword previous_update_id: The unique ID of the previous update request, enabling incremental - memory updates from where the last operation left off. Default value is None. - :paramtype previous_update_id: str - :keyword update_delay: Timeout period before processing the memory update in seconds. - If a new update request is received during this period, it will cancel the current request and - reset the timeout. - Set to 0 to immediately trigger the update without delay. - Defaults to 300 (5 minutes). Default value is None. - :paramtype update_delay: int - :return: An instance of AsyncLROPoller that returns MemoryStoreUpdateCompletedResult. The - MemoryStoreUpdateCompletedResult is compatible with MutableMapping - :rtype: - ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.MemoryStoreUpdateCompletedResult] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreUpdateCompletedResult] = kwargs.pop("cls", None) - polling: Union[bool, AsyncPollingMethod] = kwargs.pop("polling", True) - lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token: Optional[str] = kwargs.pop("continuation_token", None) - if cont_token is None: - raw_result = await self._update_memories_initial( - name=name, - body=body, - scope=scope, - items=items, - previous_update_id=previous_update_id, - update_delay=update_delay, - content_type=content_type, - cls=lambda x, y, z: x, - headers=_headers, - params=_params, - **kwargs - ) - await raw_result.http_response.read() # type: ignore - kwargs.pop("error_map", None) - - def get_long_running_output(pipeline_response): - response_headers = {} - response = pipeline_response.http_response - response_headers["Operation-Location"] = self._deserialize( - "str", response.headers.get("Operation-Location") - ) - - deserialized = _deserialize(_models.MemoryStoreUpdateCompletedResult, response.json().get("result", {})) - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - return deserialized +class BetaMemoryStoresOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`memory_stores` attribute. + """ - if polling is True: - polling_method: AsyncPollingMethod = cast( - AsyncPollingMethod, - AsyncLROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs), - ) - elif polling is False: - polling_method = cast(AsyncPollingMethod, AsyncNoPolling()) - else: - polling_method = polling - if cont_token: - return AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult].from_continuation_token( - polling_method=polling_method, - continuation_token=cont_token, - client=self._client, - deserialization_callback=get_long_running_output, - ) - return AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]( - self._client, raw_result, get_long_running_output, polling_method # type: ignore - ) + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @overload - async def delete_scope( - self, name: str, *, scope: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + async def create( + self, + *, + name: str, + definition: _models.MemoryStoreDefinition, + content_type: str = "application/json", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str - :keyword scope: The namespace that logically groups and isolates memories to delete, such as a - user ID. Required. - :paramtype scope: str + :keyword name: The name of the memory store. Required. + :paramtype name: str + :keyword definition: The memory store definition. Required. + :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def delete_scope( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + async def create( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def delete_scope( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + async def create( + self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def delete_scope( - self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, scope: str = _Unset, **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + async def create( + self, + body: Union[JSON, IO[bytes]] = _Unset, + *, + name: str = _Unset, + definition: _models.MemoryStoreDefinition = _Unset, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword scope: The namespace that logically groups and isolates memories to delete, such as a - user ID. Required. - :paramtype scope: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :keyword name: The name of the memory store. Required. + :paramtype name: str + :keyword definition: The memory store definition. Required. + :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7282,12 +6738,14 @@ async def delete_scope( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreDeleteScopeResult] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = {"scope": scope} + if name is _Unset: + raise TypeError("missing required argument: name") + if definition is _Unset: + raise TypeError("missing required argument: definition") + body = {"definition": definition, "description": description, "metadata": metadata, "name": name} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -7296,8 +6754,7 @@ async def delete_scope( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_delete_scope_request( - name=name, + _request = build_beta_memory_stores_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7333,135 +6790,101 @@ async def delete_scope( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.MemoryStoreDeleteScopeResult, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + async def update( + self, + name: str, + *, + content_type: str = "application/json", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. -class BetaModelsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`models` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - - @distributed_trace - def list_versions(self, name: str, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: - """List all versions of the given ModelVersion. - - :param name: The name of the resource. Required. + :param name: The name of the memory store to update. Required. :type name: str - :return: An iterator like instance of ModelVersion - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ModelVersion] + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_models_list_versions_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ModelVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - - async def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - return pipeline_response + @overload + async def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. - return AsyncItemPaged(get_next, extract_data) + :param name: The name of the memory store to update. Required. + :type name: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ - @distributed_trace - def list(self, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: - """List the latest version of each ModelVersion. + @overload + async def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. - :return: An iterator like instance of ModelVersion - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ModelVersion] + :param name: The name of the memory store to update. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + @distributed_trace_async + async def update( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. + :param name: The name of the memory store to update. Required. + :type name: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -7470,84 +6893,74 @@ def list(self, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - _request = build_beta_models_list_request( - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + if body is _Unset: + body = {"description": description, "metadata": metadata} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - return _request + _request = build_beta_memory_stores_update_request( + name=name, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ModelVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - async def get_next(next_link=None): - _request = prepare_request(next_link) + response = pipeline_response.http_response - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, ) - response = pipeline_response.http_response + raise HttpResponseError(response=response, model=error) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - return AsyncItemPaged(get_next, extract_data) + return deserialized # type: ignore @distributed_trace_async - async def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: - """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the - ModelVersion does not exist. + async def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: + """Retrieve a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store to retrieve. Required. :type name: str - :param version: The specific version id of the ModelVersion to retrieve. Required. - :type version: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7561,11 +6974,10 @@ async def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVers _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - _request = build_beta_models_get_request( + _request = build_beta_memory_stores_get_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7590,29 +7002,120 @@ async def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVers except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ModelVersion, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.MemoryStoreDetails"]: + """List all memory stores. + + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of MemoryStoreDetails + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.MemoryStoreDetails] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.MemoryStoreDetails]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_memory_stores_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.MemoryStoreDetails], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) + + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - return deserialized # type: ignore + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def delete(self, name: str, version: str, **kwargs: Any) -> None: - """Delete the specific version of the ModelVersion. The service returns 204 No Content if the - ModelVersion was deleted successfully or if the ModelVersion does not exist. + async def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: + """Delete a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store to delete. Required. :type name: str - :param version: The version of the ModelVersion to delete. Required. - :type version: str - :return: None - :rtype: None + :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7626,11 +7129,10 @@ async def delete(self, name: str, version: str, **kwargs: Any) -> None: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.DeleteMemoryStoreResult] = kwargs.pop("cls", None) - _request = build_beta_models_delete_request( + _request = build_beta_memory_stores_delete_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7640,111 +7142,88 @@ async def delete(self, name: str, version: str, **kwargs: Any) -> None: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DeleteMemoryStoreResult, response.json()) if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @overload - async def update( + async def _search_memories( self, name: str, - version: str, - body: _models.UpdateModelVersionRequest, *, - content_type: str = "application/merge-patch+json", + scope: str, + content_type: str = "application/json", + items: Optional[List[dict[str, Any]]] = None, + previous_search_id: Optional[str] = None, + options: Optional[_models.MemorySearchOptions] = None, **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: ~azure.ai.projects.models.UpdateModelVersionRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/merge-patch+json". - :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - + ) -> _models.MemoryStoreSearchResult: ... @overload - async def update( - self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/merge-patch+json". - :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - + async def _search_memories( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreSearchResult: ... @overload - async def update( + async def _search_memories( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreSearchResult: ... + + @distributed_trace_async + async def _search_memories( self, name: str, - version: str, - body: IO[bytes], + body: Union[JSON, IO[bytes]] = _Unset, *, - content_type: str = "application/merge-patch+json", + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_search_id: Optional[str] = None, + options: Optional[_models.MemorySearchOptions] = None, **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/merge-patch+json". - :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @distributed_trace_async - async def update( - self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. + ) -> _models.MemoryStoreSearchResult: + """Search for relevant memories from a memory store based on conversation context. - :param name: The name of the resource. Required. + :param name: The name of the memory store to search. Required. :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: - UpdateModelVersionRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :paramtype scope: str + :keyword items: Items for which to search for relevant memories. Default value is None. + :paramtype items: list[dict[str, any]] + :keyword previous_search_id: The unique ID of the previous search request, enabling incremental + memory search from where the last operation left off. Default value is None. + :paramtype previous_search_id: str + :keyword options: Memory search options. Default value is None. + :paramtype options: ~azure.ai.projects.models.MemorySearchOptions + :return: MemoryStoreSearchResult. The MemoryStoreSearchResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreSearchResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7759,18 +7238,27 @@ async def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreSearchResult] = kwargs.pop("cls", None) - content_type = content_type or "application/merge-patch+json" + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = { + "items": items, + "options": options, + "previous_search_id": previous_search_id, + "scope": scope, + } + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): _content = body else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_update_request( + _request = build_beta_memory_stores_search_memories_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7786,116 +7274,44 @@ async def update( _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200, 201]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.ModelVersion, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @overload - async def create_async( - self, - name: str, - version: str, - body: _models.ModelVersion, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: ~azure.ai.projects.models.ModelVersion - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def create_async( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ + ) - @overload - async def create_async( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + response = pipeline_response.http_response - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - @distributed_trace_async - async def create_async( - self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.MemoryStoreSearchResult, response.json()) - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Is one of the following types: ModelVersion, JSON, - IO[bytes] Required. - :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + async def _update_memories_initial( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, + **kwargs: Any + ) -> AsyncIterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -7908,8 +7324,18 @@ async def create_async( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = { + "items": items, + "previous_update_id": previous_update_id, + "scope": scope, + "update_delay": update_delay, + } + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -7917,9 +7343,8 @@ async def create_async( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_create_async_request( + _request = build_beta_memory_stores_update_memories_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -7931,7 +7356,8 @@ async def create_async( } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = True pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -7939,239 +7365,221 @@ async def create_async( response = pipeline_response.http_response if response.status_code not in [202]: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: - return cls(pipeline_response, None, response_headers) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @overload - async def pending_upload( + async def _begin_update_memories( self, name: str, - version: str, - body: _models.PendingUploadRequest, *, + scope: str, content_type: str = "application/json", + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: ~azure.ai.projects.models.PendingUploadRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - + ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: ... @overload - async def pending_upload( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - + async def _begin_update_memories( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: ... @overload - async def pending_upload( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult - :raises ~azure.core.exceptions.HttpResponseError: - """ + async def _begin_update_memories( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: ... @distributed_trace_async - async def pending_upload( - self, name: str, version: str, body: Union[_models.PendingUploadRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. + async def _begin_update_memories( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, + **kwargs: Any + ) -> AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]: + """Update memory store with conversation memories. - :param name: Name of the model. Required. + :param name: The name of the memory store to update. Required. :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Is one of the following types: PendingUploadRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.PendingUploadRequest or JSON or IO[bytes] - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. + Required. + :paramtype scope: str + :keyword items: Conversation items to be stored in memory. Default value is None. + :paramtype items: list[dict[str, any]] + :keyword previous_update_id: The unique ID of the previous update request, enabling incremental + memory updates from where the last operation left off. Default value is None. + :paramtype previous_update_id: str + :keyword update_delay: Timeout period before processing the memory update in seconds. + If a new update request is received during this period, it will cancel the current request and + reset the timeout. + Set to 0 to immediately trigger the update without delay. + Defaults to 300 (5 minutes). Default value is None. + :paramtype update_delay: int + :return: An instance of AsyncLROPoller that returns MemoryStoreUpdateCompletedResult. The + MemoryStoreUpdateCompletedResult is compatible with MutableMapping + :rtype: + ~azure.core.polling.AsyncLROPoller[~azure.ai.projects.models.MemoryStoreUpdateCompletedResult] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.PendingUploadResult] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreUpdateCompletedResult] = kwargs.pop("cls", None) + polling: Union[bool, AsyncPollingMethod] = kwargs.pop("polling", True) + lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) + cont_token: Optional[str] = kwargs.pop("continuation_token", None) + if cont_token is None: + raw_result = await self._update_memories_initial( + name=name, + body=body, + scope=scope, + items=items, + previous_update_id=previous_update_id, + update_delay=update_delay, + content_type=content_type, + cls=lambda x, y, z: x, + headers=_headers, + params=_params, + **kwargs + ) + await raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + def get_long_running_output(pipeline_response): + response_headers = {} + response = pipeline_response.http_response + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + + deserialized = _deserialize(_models.MemoryStoreUpdateCompletedResult, response.json().get("result", {})) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized - _request = build_beta_models_pending_upload_request( - name=name, - version=version, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) path_format_arguments = { "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if polling is True: + polling_method: AsyncPollingMethod = cast( + AsyncPollingMethod, + AsyncLROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs), + ) + elif polling is False: + polling_method = cast(AsyncPollingMethod, AsyncNoPolling()) else: - deserialized = _deserialize(_models.PendingUploadResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + polling_method = polling + if cont_token: + return AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return AsyncLROPoller[_models.MemoryStoreUpdateCompletedResult]( + self._client, raw_result, get_long_running_output, polling_method # type: ignore + ) @overload - async def get_credentials( - self, - name: str, - version: str, - body: _models.ModelCredentialRequest, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + async def delete_scope( + self, name: str, *, scope: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: ~azure.ai.projects.models.ModelCredentialRequest + :keyword scope: The namespace that logically groups and isolates memories to delete, such as a + user ID. Required. + :paramtype scope: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def get_credentials( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + async def delete_scope( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def get_credentials( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + async def delete_scope( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def get_credentials( - self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + async def delete_scope( + self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, scope: str = _Unset, **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword scope: The namespace that logically groups and isolates memories to delete, such as a + user ID. Required. + :paramtype scope: str + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8186,8 +7594,13 @@ async def get_credentials( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreDeleteScopeResult] = kwargs.pop("cls", None) + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = {"scope": scope} + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -8195,9 +7608,8 @@ async def get_credentials( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_get_credentials_request( + _request = build_beta_memory_stores_delete_scope_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8224,12 +7636,16 @@ async def get_credentials( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DatasetCredential, response.json()) + deserialized = _deserialize(_models.MemoryStoreDeleteScopeResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -8237,14 +7653,14 @@ async def get_credentials( return deserialized # type: ignore -class BetaRedTeamsOperations: +class BetaModelsOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`red_teams` attribute. + :attr:`models` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -8254,16 +7670,21 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: - """Get a redteam by name. + @distributed_trace + def list_versions(self, name: str, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: + """List all versions of the given ModelVersion. - :param name: Identifier of the red team run. Required. + :param name: The name of the resource. Required. :type name: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -8272,61 +7693,86 @@ async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + def prepare_request(next_link=None): + if not next_link: - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + _request = build_beta_models_list_versions_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_red_teams_get_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + return _request - response = pipeline_response.http_response + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ModelVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + async def get_next(next_link=None): + _request = prepare_request(next_link) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.RedTeam, response.json()) + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - return deserialized # type: ignore + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) @distributed_trace - def list(self, **kwargs: Any) -> AsyncItemPaged["_models.RedTeam"]: - """List a redteam by name. + def list(self, **kwargs: Any) -> AsyncItemPaged["_models.ModelVersion"]: + """List the latest version of each ModelVersion. - :return: An iterator like instance of RedTeam - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.RedTeam] + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -8339,7 +7785,7 @@ def list(self, **kwargs: Any) -> AsyncItemPaged["_models.RedTeam"]: def prepare_request(next_link=None): if not next_link: - _request = build_beta_red_teams_list_request( + _request = build_beta_models_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -8379,7 +7825,7 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.RedTeam], + List[_models.ModelVersion], deserialized.get("value", []), ) if cls: @@ -8403,61 +7849,17 @@ async def get_next(next_link=None): return AsyncItemPaged(get_next, extract_data) - @overload - async def create( - self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: ~azure.ai.projects.models.RedTeam - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - async def create( - self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace_async - async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + async def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: + """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the + ModelVersion does not exist. - :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] - Required. - :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the ModelVersion to retrieve. Required. + :type version: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8468,23 +7870,15 @@ async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwar } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(red_team, (IOBase, bytes)): - _content = red_team - else: - _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) - _request = build_beta_red_teams_create_request( - content_type=content_type, + _request = build_beta_models_get_request( + name=name, + version=version, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -8501,55 +7895,168 @@ async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwar response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RedTeam, response.json()) + deserialized = _deserialize(_models.ModelVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace_async + async def delete(self, name: str, version: str, **kwargs: Any) -> None: + """Delete the specific version of the ModelVersion. The service returns 200 OK if the ModelVersion + was deleted successfully or if the ModelVersion does not exist. -class BetaSchedulesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the ModelVersion to delete. Required. + :type version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`schedules` attribute. - """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_models_delete_request( + name=name, + version=version, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @overload + async def update( + self, + name: str, + version: str, + body: _models.UpdateModelVersionRequest, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update( + self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def update( + self, + name: str, + version: str, + body: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace_async - async def delete(self, schedule_id: str, **kwargs: Any) -> None: - """Delete a schedule. + async def update( + self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: None - :rtype: None + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: + UpdateModelVersionRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8560,14 +8067,25 @@ async def delete(self, schedule_id: str, **kwargs: Any) -> None: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) - _request = build_beta_schedules_delete_request( - schedule_id=schedule_id, + content_type = content_type or "application/merge-patch+json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_update_request( + name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -8576,28 +8094,118 @@ async def delete(self, schedule_id: str, **kwargs: Any) -> None: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200, 201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelVersion, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + async def create_async( + self, + name: str, + version: str, + body: _models.ModelVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: ~azure.ai.projects.models.ModelVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_async( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_async( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace_async - async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: - """Get a schedule by id. + async def create_async( + self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Is one of the following types: ModelVersion, JSON, + IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8608,14 +8216,25 @@ async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.CreateAsyncResponse] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_request( - schedule_id=schedule_id, + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_create_async_request( + name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -8632,7 +8251,7 @@ async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [202]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -8641,40 +8260,106 @@ async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) + response_headers = {} + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Schedule, response.json()) + deserialized = _deserialize(_models.CreateAsyncResponse, response.json()) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( + @overload + async def pending_upload( self, + name: str, + version: str, + body: _models.ModelPendingUploadRequest, *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, + content_type: str = "application/json", **kwargs: Any - ) -> AsyncItemPaged["_models.Schedule"]: - """List all schedules. + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. - :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". - Default value is None. - :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of Schedule - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.Schedule] + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.ModelPendingUploadRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.Schedule]] = kwargs.pop("cls", None) + @overload + async def pending_upload( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def pending_upload( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def pending_upload( + self, name: str, version: str, body: Union[_models.ModelPendingUploadRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: ModelPendingUploadRequest, JSON, IO[bytes] + Required. + :type body: ~azure.ai.projects.models.ModelPendingUploadRequest or JSON or IO[bytes] + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -8683,142 +8368,140 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_schedules_list_request( - type=type, - enabled=enabled, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelPendingUploadResponse] = kwargs.pop("cls", None) - return _request + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Schedule], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + _request = build_beta_models_pending_upload_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - async def get_next(next_link=None): - _request = prepare_request(next_link) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + response = pipeline_response.http_response - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - return pipeline_response + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelPendingUploadResponse, response.json()) - return AsyncItemPaged(get_next, extract_data) + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @overload - async def create_or_update( - self, schedule_id: str, schedule: _models.Schedule, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + async def get_credentials( + self, + name: str, + version: str, + body: _models.ModelCredentialRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: ~azure.ai.projects.models.Schedule + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_or_update( - self, schedule_id: str, schedule: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + async def get_credentials( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: JSON + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_or_update( - self, schedule_id: str, schedule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + async def get_credentials( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: IO[bytes] + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_or_update( - self, schedule_id: str, schedule: Union[_models.Schedule, JSON, IO[bytes]], **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + async def get_credentials( + self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Is one of the following types: Schedule, JSON, - IO[bytes] Required. - :type schedule: ~azure.ai.projects.models.Schedule or JSON or IO[bytes] - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8833,17 +8516,18 @@ async def create_or_update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(schedule, (IOBase, bytes)): - _content = schedule + if isinstance(body, (IOBase, bytes)): + _content = body else: - _content = json.dumps(schedule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_schedules_create_or_update_request( - schedule_id=schedule_id, + _request = build_beta_models_get_credentials_request( + name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8863,7 +8547,7 @@ async def create_or_update( response = pipeline_response.http_response - if response.status_code not in [200, 201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -8875,23 +8559,39 @@ async def create_or_update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Schedule, response.json()) + deserialized = _deserialize(_models.DatasetCredential, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaRedTeamsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`red_teams` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @distributed_trace_async - async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: - """Get a schedule run by id. + async def get(self, name: str, **kwargs: Any) -> _models.RedTeam: + """Get a redteam by name. - :param schedule_id: The unique identifier of the schedule. Required. - :type schedule_id: str - :param run_id: The unique identifier of the schedule run. Required. - :type run_id: str - :return: ScheduleRun. The ScheduleRun is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ScheduleRun + :param name: Identifier of the red team run. Required. + :type name: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8905,11 +8605,10 @@ async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ScheduleRun] = kwargs.pop("cls", None) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_run_request( - schedule_id=schedule_id, - run_id=run_id, + _request = build_beta_red_teams_get_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -8934,48 +8633,30 @@ async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ScheduleRun, response.json()) + deserialized = _deserialize(_models.RedTeam, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list_runs( - self, - schedule_id: str, - *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.ScheduleRun"]: - """List all schedule runs. + @distributed_trace + def list(self, **kwargs: Any) -> AsyncItemPaged["_models.RedTeam"]: + """List a redteam by name. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". - Default value is None. - :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of ScheduleRun - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ScheduleRun] + :return: An iterator like instance of RedTeam + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.RedTeam] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ScheduleRun]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -8988,10 +8669,7 @@ def list_runs( def prepare_request(next_link=None): if not next_link: - _request = build_beta_schedules_list_runs_request( - schedule_id=schedule_id, - type=type, - enabled=enabled, + _request = build_beta_red_teams_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -9031,7 +8709,7 @@ def prepare_request(next_link=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.ScheduleRun], + List[_models.RedTeam], deserialized.get("value", []), ) if cls: @@ -9055,126 +8733,61 @@ async def get_next(next_link=None): return AsyncItemPaged(get_next, extract_data) - -class BetaToolboxesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`toolboxes` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - async def create_version( - self, - name: str, - *, - tools: List[_models.Tool], - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - policies: Optional[_models.ToolboxPolicies] = None, - **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + async def create( + self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. - :type name: str - :keyword tools: The list of tools to include in this version. Required. - :paramtype tools: list[~azure.ai.projects.models.Tool] + :param red_team: Redteam to be run. Required. + :type red_team: ~azure.ai.projects.models.RedTeam :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the toolbox. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is - None. - :paramtype metadata: dict[str, str] - :keyword policies: Policy configuration for this toolbox version. Default value is None. - :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_version( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + async def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. - :type name: str - :param body: Required. - :type body: JSON + :param red_team: Redteam to be run. Required. + :type red_team: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_version( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + async def create( + self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. - :type name: str - :param body: Required. - :type body: IO[bytes] + :param red_team: Redteam to be run. Required. + :type red_team: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_version( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - tools: List[_models.Tool] = _Unset, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - policies: Optional[_models.ToolboxPolicies] = None, - **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + async def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword tools: The list of tools to include in this version. Required. - :paramtype tools: list[~azure.ai.projects.models.Tool] - :keyword description: A human-readable description of the toolbox. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is - None. - :paramtype metadata: dict[str, str] - :keyword policies: Policy configuration for this toolbox version. Default value is None. - :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9189,22 +8802,16 @@ async def create_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - if body is _Unset: - if tools is _Unset: - raise TypeError("missing required argument: tools") - body = {"description": description, "metadata": metadata, "policies": policies, "tools": tools} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(red_team, (IOBase, bytes)): + _content = red_team else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_toolboxes_create_version_request( - name=name, + _request = build_beta_red_teams_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -9224,7 +8831,7 @@ async def create_version( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -9240,21 +8847,39 @@ async def create_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) + deserialized = _deserialize(_models.RedTeam, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaSchedulesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`schedules` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: - """Retrieve a toolbox. + async def delete(self, schedule_id: str, **kwargs: Any) -> None: + """Delete a schedule. - :param name: The name of the toolbox to retrieve. Required. - :type name: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9268,10 +8893,58 @@ async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_request( - name=name, + _request = build_beta_schedules_delete_request( + schedule_id=schedule_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace_async + async def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: + """Get a schedule by id. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + + _request = build_beta_schedules_get_request( + schedule_id=schedule_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -9293,19 +8966,15 @@ async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: if _stream: try: await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) + deserialized = _deserialize(_models.Schedule, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -9316,35 +8985,25 @@ async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: def list( self, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.ToolboxObject"]: - """List all toolboxes. + ) -> AsyncItemPaged["_models.Schedule"]: + """List all schedules. - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. + :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". Default value is None. - :paramtype before: str - :return: An iterator like instance of ToolboxObject - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ToolboxObject] + :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of Schedule + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.Schedule] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ToolboxObject]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Schedule]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -9354,35 +9013,60 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_schedules_list_request( + type=type, + enabled=enabled, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_toolboxes_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.ToolboxObject], - deserialized.get("data", []), + List[_models.Schedule], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + async def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access @@ -9392,53 +9076,81 @@ async def get_next(_continuation_token=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) return pipeline_response return AsyncItemPaged(get_next, extract_data) - @distributed_trace - def list_versions( - self, - name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.ToolboxVersionObject"]: - """List all versions of a toolbox. + @overload + async def create_or_update( + self, schedule_id: str, schedule: _models.Schedule, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. - :param name: The name of the toolbox to list versions for. Required. - :type name: str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of ToolboxVersionObject - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ToolboxVersionObject] + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: ~azure.ai.projects.models.Schedule + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ToolboxVersionObject]] = kwargs.pop("cls", None) + @overload + async def create_or_update( + self, schedule_id: str, schedule: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_or_update( + self, schedule_id: str, schedule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_or_update( + self, schedule_id: str, schedule: Union[_models.Schedule, JSON, IO[bytes]], **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Is one of the following types: Schedule, JSON, + IO[bytes] Required. + :type schedule: ~azure.ai.projects.models.Schedule or JSON or IO[bytes] + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -9447,65 +9159,69 @@ def list_versions( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - _request = build_beta_toolboxes_list_versions_request( - name=name, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ToolboxVersionObject], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) + content_type = content_type or "application/json" + _content = None + if isinstance(schedule, (IOBase, bytes)): + _content = schedule + else: + _content = json.dumps(schedule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_schedules_create_or_update_request( + schedule_id=schedule_id, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + response = pipeline_response.http_response - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + if response.status_code not in [200, 201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.Schedule, response.json()) - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - return AsyncItemPaged(get_next, extract_data) + return deserialized # type: ignore @distributed_trace_async - async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.ToolboxVersionObject: - """Retrieve a specific version of a toolbox. + async def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: + """Get a schedule run by id. - :param name: The name of the toolbox. Required. - :type name: str - :param version: The version identifier to retrieve. Required. - :type version: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :param schedule_id: The unique identifier of the schedule. Required. + :type schedule_id: str + :param run_id: The unique identifier of the schedule run. Required. + :type run_id: str + :return: ScheduleRun. The ScheduleRun is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ScheduleRun :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9519,11 +9235,11 @@ async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.T _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) + cls: ClsType[_models.ScheduleRun] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_version_request( - name=name, - version=version, + _request = build_beta_schedules_get_run_request( + schedule_id=schedule_id, + run_id=run_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -9557,83 +9273,238 @@ async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.T if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) + deserialized = _deserialize(_models.ScheduleRun, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace + def list_runs( + self, + schedule_id: str, + *, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.ScheduleRun"]: + """List all schedule runs. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". + Default value is None. + :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of ScheduleRun + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ScheduleRun] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ScheduleRun]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_schedules_list_runs_request( + schedule_id=schedule_id, + type=type, + enabled=enabled, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ScheduleRun], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, AsyncList(list_of_elem) + + async def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + +class BetaToolboxesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`toolboxes` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @overload - async def update( - self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + async def create_version( + self, + name: str, + *, + tools: List[_models.Tool], + content_type: str = "application/json", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + policies: Optional[_models.ToolboxPolicies] = None, + **kwargs: Any + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str - :keyword default_version: The version identifier that the toolbox should point to. When set, - the toolbox's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str + :keyword tools: The list of tools to include in this version. Required. + :paramtype tools: list[~azure.ai.projects.models.Tool] :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :keyword description: A human-readable description of the toolbox. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is + None. + :paramtype metadata: dict[str, str] + :keyword policies: Policy configuration for this toolbox version. Default value is None. + :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update( + async def create_version( self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def update( + async def create_version( self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def update( - self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, default_version: str = _Unset, **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + async def create_version( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + tools: List[_models.Tool] = _Unset, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + policies: Optional[_models.ToolboxPolicies] = None, + **kwargs: Any + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword default_version: The version identifier that the toolbox should point to. When set, - the toolbox's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :keyword tools: The list of tools to include in this version. Required. + :paramtype tools: list[~azure.ai.projects.models.Tool] + :keyword description: A human-readable description of the toolbox. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is + None. + :paramtype metadata: dict[str, str] + :keyword policies: Policy configuration for this toolbox version. Default value is None. + :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9648,12 +9519,12 @@ async def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) if body is _Unset: - if default_version is _Unset: - raise TypeError("missing required argument: default_version") - body = {"default_version": default_version} + if tools is _Unset: + raise TypeError("missing required argument: tools") + body = {"description": description, "metadata": metadata, "policies": policies, "tools": tools} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -9662,7 +9533,7 @@ async def update( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_toolboxes_update_request( + _request = build_beta_toolboxes_create_version_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -9699,7 +9570,7 @@ async def update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) + deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -9707,13 +9578,13 @@ async def update( return deserialized # type: ignore @distributed_trace_async - async def delete(self, name: str, **kwargs: Any) -> None: - """Delete a toolbox and all its versions. + async def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: + """Retrieve a toolbox. - :param name: The name of the toolbox to delete. Required. + :param name: The name of the toolbox to retrieve. Required. :type name: str - :return: None - :rtype: None + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9727,9 +9598,9 @@ async def delete(self, name: str, **kwargs: Any) -> None: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_delete_request( + _request = build_beta_toolboxes_get_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -9740,14 +9611,20 @@ async def delete(self, name: str, **kwargs: Any) -> None: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -9755,19 +9632,210 @@ async def delete(self, name: str, **kwargs: Any) -> None: ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ToolboxObject, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.ToolboxObject"]: + """List all toolboxes. + + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of ToolboxObject + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ToolboxObject] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ToolboxObject]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_toolboxes_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ToolboxObject], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) + + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + @distributed_trace + def list_versions( + self, + name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.ToolboxVersionObject"]: + """List all versions of a toolbox. + + :param name: The name of the toolbox to list versions for. Required. + :type name: str + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of ToolboxVersionObject + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.ToolboxVersionObject] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ToolboxVersionObject]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_toolboxes_list_versions_request( + name=name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ToolboxVersionObject], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) + + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) @distributed_trace_async - async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: - """Delete a specific version of a toolbox. + async def get_version(self, name: str, version: str, **kwargs: Any) -> _models.ToolboxVersionObject: + """Retrieve a specific version of a toolbox. :param name: The name of the toolbox. Required. :type name: str - :param version: The version identifier to delete. Required. + :param version: The version identifier to retrieve. Required. :type version: str - :return: None - :rtype: None + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9781,9 +9849,9 @@ async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_delete_version_request( + _request = build_beta_toolboxes_get_version_request( name=name, version=version, api_version=self._config.api_version, @@ -9795,14 +9863,20 @@ async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -9810,125 +9884,86 @@ async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: ) raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, None, {}) # type: ignore - - -class BetaSkillsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`skills` attribute. - """ + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + return deserialized # type: ignore @overload - async def create( - self, - *, - name: str, - content_type: str = "application/json", - description: Optional[str] = None, - instructions: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.SkillDetails: - """Creates a skill. + async def update( + self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. - :keyword name: The unique name of the skill. Required. - :paramtype name: str + :param name: The name of the toolbox to update. Required. + :type name: str + :keyword default_version: The version identifier that the toolbox should point to. When set, + the toolbox's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create( - self, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Creates a skill. + async def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. + :param name: The name of the toolbox to update. Required. + :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create( - self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Creates a skill. + async def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. + :param name: The name of the toolbox to update. Required. + :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create( - self, - body: Union[JSON, IO[bytes]] = _Unset, - *, - name: str = _Unset, - description: Optional[str] = None, - instructions: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.SkillDetails: - """Creates a skill. + async def update( + self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, default_version: str = _Unset, **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. + :param name: The name of the toolbox to update. Required. + :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword name: The unique name of the skill. Required. - :paramtype name: str - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :keyword default_version: The version identifier that the toolbox should point to. When set, + the toolbox's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: str + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9943,12 +9978,12 @@ async def create( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) if body is _Unset: - if name is _Unset: - raise TypeError("missing required argument: name") - body = {"description": description, "instructions": instructions, "metadata": metadata, "name": name} + if default_version is _Unset: + raise TypeError("missing required argument: default_version") + body = {"default_version": default_version} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -9957,76 +9992,8 @@ async def create( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_skills_create_request( - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [201]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SkillDetails, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace_async - async def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: - """Creates a skill from a zip package. - - :param content: The zip package used to create the skill. Required. - :type content: bytes - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/zip")) - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - - _content = content - - _request = build_beta_skills_create_from_package_request( + _request = build_beta_toolboxes_update_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10046,7 +10013,7 @@ async def create_from_package(self, content: bytes, **kwargs: Any) -> _models.Sk response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -10062,7 +10029,7 @@ async def create_from_package(self, content: bytes, **kwargs: Any) -> _models.Sk if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + deserialized = _deserialize(_models.ToolboxObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -10070,13 +10037,13 @@ async def create_from_package(self, content: bytes, **kwargs: Any) -> _models.Sk return deserialized # type: ignore @distributed_trace_async - async def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: - """Retrieves a skill. + async def delete(self, name: str, **kwargs: Any) -> None: + """Delete a toolbox and all its versions. - :param name: The unique name of the skill. Required. + :param name: The name of the toolbox to delete. Required. :type name: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10090,9 +10057,9 @@ async def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_skills_get_request( + _request = build_beta_toolboxes_delete_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -10103,20 +10070,14 @@ async def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -10124,24 +10085,19 @@ async def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SkillDetails, response.json()) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace_async - async def download(self, name: str, **kwargs: Any) -> AsyncIterator[bytes]: - """Downloads a skill package. + async def delete_version(self, name: str, version: str, **kwargs: Any) -> None: + """Delete a specific version of a toolbox. - :param name: The unique name of the skill. Required. + :param name: The name of the toolbox. Required. :type name: str - :return: AsyncIterator[bytes] - :rtype: AsyncIterator[bytes] + :param version: The version identifier to delete. Required. + :type version: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10155,10 +10111,11 @@ async def download(self, name: str, **kwargs: Any) -> AsyncIterator[bytes]: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_skills_download_request( + _request = build_beta_toolboxes_delete_version_request( name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -10168,20 +10125,14 @@ async def download(self, name: str, **kwargs: Any) -> AsyncIterator[bytes]: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = False pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - await response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -10189,121 +10140,42 @@ async def download(self, name: str, **kwargs: Any) -> AsyncIterator[bytes]: ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def list( - self, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> AsyncItemPaged["_models.SkillDetails"]: - """Returns the list of all skills. - - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of SkillDetails - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.SkillDetails] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(_continuation_token=None): - - _request = build_beta_skills_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - async def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.SkillDetails], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, AsyncList(list_of_elem) - - async def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + return cls(pipeline_response, None, {}) # type: ignore - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) +class BetaSkillsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - return pipeline_response + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`skills` attribute. + """ - return AsyncItemPaged(get_next, extract_data) + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @overload - async def update( + async def create( self, - name: str, *, + name: str, content_type: str = "application/json", description: Optional[str] = None, instructions: Optional[str] = None, metadata: Optional[dict[str, str]] = None, **kwargs: Any ) -> _models.SkillDetails: - """Updates an existing skill. + """Creates a skill. - :param name: The unique name of the skill. Required. - :type name: str + :keyword name: The unique name of the skill. Required. + :paramtype name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str @@ -10325,13 +10197,11 @@ async def update( """ @overload - async def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + async def create( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any ) -> _models.SkillDetails: - """Updates an existing skill. + """Creates a skill. - :param name: The unique name of the skill. Required. - :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. @@ -10343,13 +10213,11 @@ async def update( """ @overload - async def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + async def create( + self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any ) -> _models.SkillDetails: - """Updates an existing skill. + """Creates a skill. - :param name: The unique name of the skill. Required. - :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. @@ -10361,34 +10229,113 @@ async def update( """ @distributed_trace_async - async def update( + async def create( self, - name: str, body: Union[JSON, IO[bytes]] = _Unset, *, + name: str = _Unset, description: Optional[str] = None, instructions: Optional[str] = None, metadata: Optional[dict[str, str]] = None, **kwargs: Any ) -> _models.SkillDetails: - """Updates an existing skill. + """Creates a skill. + + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword name: The unique name of the skill. Required. + :paramtype name: str + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + + if body is _Unset: + if name is _Unset: + raise TypeError("missing required argument: name") + body = {"description": description, "instructions": instructions, "metadata": metadata, "name": name} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_skills_create_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - :param name: The unique name of the skill. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: + """Creates a skill from a zip package. + + :param content: The zip package used to create the skill. Required. + :type content: bytes :return: SkillDetails. The SkillDetails is compatible with MutableMapping :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: @@ -10404,21 +10351,12 @@ async def update( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/zip")) cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - if body is _Unset: - body = {"description": description, "instructions": instructions, "metadata": metadata} - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = content - _request = build_beta_skills_update_request( - name=name, + _request = build_beta_skills_create_from_package_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10438,7 +10376,7 @@ async def update( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -10462,13 +10400,13 @@ async def update( return deserialized # type: ignore @distributed_trace_async - async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: - """Deletes a skill. + async def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: + """Retrieves a skill. :param name: The unique name of the skill. Required. :type name: str - :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillResult + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10482,9 +10420,9 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - _request = build_beta_skills_delete_request( + _request = build_beta_skills_get_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -10519,41 +10457,21 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteSkillResult, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - -class BetaDatasetsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`datasets` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace_async - async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: - """Get info about a data generation job. - - Gets the details of a data generation job by its ID. + async def download(self, name: str, **kwargs: Any) -> AsyncIterator[bytes]: + """Downloads a skill package. - :param job_id: The ID of the job. Required. - :type job_id: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :param name: The unique name of the skill. Required. + :type name: str + :return: AsyncIterator[bytes] + :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10567,10 +10485,10 @@ async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGe _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_datasets_get_generation_job_request( - job_id=job_id, + _request = build_beta_skills_download_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -10581,7 +10499,7 @@ async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGe _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -10602,12 +10520,9 @@ async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGe raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DataGenerationJob, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -10615,19 +10530,15 @@ async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGe return deserialized # type: ignore @distributed_trace - def list_generation_jobs( + def list( self, *, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, - scenario: Optional[Union[str, _models.DataGenerationJobScenario]] = None, - type: Optional[List[Union[str, _models.DataGenerationJobType]]] = None, **kwargs: Any - ) -> AsyncItemPaged["_models.DataGenerationJob"]: - """Returns a list of data generation jobs. - - Returns a list of data generation jobs. + ) -> AsyncItemPaged["_models.SkillDetails"]: + """Returns the list of all skills. :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the @@ -10643,19 +10554,14 @@ def list_generation_jobs( subsequent call can include before=obj_foo in order to fetch the previous page of the list. Default value is None. :paramtype before: str - :keyword scenario: Filter data generation jobs by their scenario. Known values are: - "supervised_finetuning", "reinforcement_finetuning", and "evaluation". Default value is None. - :paramtype scenario: str or ~azure.ai.projects.models.DataGenerationJobScenario - :keyword type: Filter data generation jobs by their type. Default value is None. - :paramtype type: list[str or ~azure.ai.projects.models.DataGenerationJobType] - :return: An iterator like instance of DataGenerationJob - :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.DataGenerationJob] + :return: An iterator like instance of SkillDetails + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.SkillDetails] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.DataGenerationJob]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -10667,13 +10573,11 @@ def list_generation_jobs( def prepare_request(_continuation_token=None): - _request = build_beta_datasets_list_generation_jobs_request( + _request = build_beta_skills_list_request( limit=limit, order=order, after=_continuation_token, before=before, - scenario=scenario, - type=type, api_version=self._config.api_version, headers=_headers, params=_params, @@ -10687,7 +10591,7 @@ def prepare_request(_continuation_token=None): async def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.DataGenerationJob], + List[_models.SkillDetails], deserialized.get("data", []), ) if cls: @@ -10716,98 +10620,107 @@ async def get_next(_continuation_token=None): return AsyncItemPaged(get_next, extract_data) @overload - async def create_generation_job( + async def update( self, - job: _models.DataGenerationJob, + name: str, *, - operation_id: Optional[str] = None, content_type: str = "application/json", + description: Optional[str] = None, + instructions: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. - - Creates a data generation job. + ) -> _models.SkillDetails: + """Updates an existing skill. - :param job: The job to create. Required. - :type job: ~azure.ai.projects.models.DataGenerationJob - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str + :param name: The unique name of the skill. Required. + :type name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_generation_job( - self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. - - Creates a data generation job. - - :param job: The job to create. Required. - :type job: JSON - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str + async def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Updates an existing skill. + + :param name: The unique name of the skill. Required. + :type name: str + :param body: Required. + :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - async def create_generation_job( - self, - job: IO[bytes], - *, - operation_id: Optional[str] = None, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. - - Creates a data generation job. + async def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Updates an existing skill. - :param job: The job to create. Required. - :type job: IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str + :param name: The unique name of the skill. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace_async - async def create_generation_job( + async def update( self, - job: Union[_models.DataGenerationJob, JSON, IO[bytes]], + name: str, + body: Union[JSON, IO[bytes]] = _Unset, *, - operation_id: Optional[str] = None, + description: Optional[str] = None, + instructions: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. + ) -> _models.SkillDetails: + """Updates an existing skill. - Creates a data generation job. + :param name: The unique name of the skill. Required. + :type name: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. - :param job: The job to create. Is one of the following types: DataGenerationJob, JSON, - IO[bytes] Required. - :type job: ~azure.ai.projects.models.DataGenerationJob or JSON or IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10822,17 +10735,20 @@ async def create_generation_job( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + if body is _Unset: + body = {"description": description, "instructions": instructions, "metadata": metadata} + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(job, (IOBase, bytes)): - _content = job + if isinstance(body, (IOBase, bytes)): + _content = body else: - _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_datasets_create_generation_job_request( - operation_id=operation_id, + _request = build_beta_skills_update_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10852,7 +10768,7 @@ async def create_generation_job( response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: await response.read() # Load the body in memory and close the socket @@ -10865,30 +10781,24 @@ async def create_generation_job( ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DataGenerationJob, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore @distributed_trace_async - async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: - """Cancels a data generation job. - - Cancels a data generation job by its ID. + async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: + """Deletes a skill. - :param job_id: The ID of the job to cancel. Required. - :type job_id: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :param name: The unique name of the skill. Required. + :type name: str + :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10902,10 +10812,10 @@ async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Dat _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) - _request = build_beta_datasets_cancel_generation_job_request( - job_id=job_id, + _request = build_beta_skills_delete_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -10939,63 +10849,9 @@ async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Dat if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DataGenerationJob, response.json()) + deserialized = _deserialize(_models.DeleteSkillResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - - @distributed_trace_async - async def delete_generation_job(self, job_id: str, **kwargs: Any) -> None: - """Deletes a data generation job. - - Deletes a data generation job by its ID. - - :param job_id: The ID of the job to delete. Required. - :type job_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) - - _request = build_beta_datasets_delete_generation_job_request( - job_id=job_id, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _stream = False - pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [204]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index 3c3e527771b4..56dea6851b0d 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py @@ -18,7 +18,6 @@ from ._patch_sessions_async import BetaAgentsOperations from ...operations._patch import _BETA_OPERATION_FEATURE_HEADERS, _OperationMethodHeaderProxy from ._operations import ( - BetaDatasetsOperations, BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, @@ -58,8 +57,6 @@ class BetaOperations(GeneratedBetaOperations): """:class:`~azure.ai.projects.aio.operations.BetaToolboxesOperations` operations""" skills: BetaSkillsOperations """:class:`~azure.ai.projects.aio.operations.BetaSkillsOperations` operations""" - datasets: BetaDatasetsOperations - """:class:`~azure.ai.projects.aio.operations.BetaDatasetsOperations` operations""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -81,7 +78,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: __all__: List[str] = [ "AgentsOperations", "BetaAgentsOperations", - "BetaDatasetsOperations", "BetaEvaluationTaxonomiesOperations", "BetaEvaluatorsOperations", "BetaInsightsOperations", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py index afefa8c51f7d..0eaa3938765d 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py @@ -21,12 +21,10 @@ AgentCardSkill, AgentClusterInsightRequest, AgentClusterInsightResult, - AgentDataGenerationJobSource, AgentDefinition, AgentDetails, AgentEndpointAuthorizationScheme, AgentEndpointConfig, - AgentEvaluatorGenerationJobSource, AgentIdentity, AgentObjectVersions, AgentSessionResource, @@ -88,6 +86,9 @@ CosmosDBIndex, CreateAgentVersionFromCodeContent, CreateAgentVersionFromCodeMetadata, + CreateAsyncResponse, + CreateEvalCompletionsRunDataSourceInputMessagesItemReference, + CreateEvalResponsesRunDataSourceInputMessagesTemplate, CronTrigger, CustomCredential, CustomGrammarFormatParam, @@ -95,19 +96,7 @@ CustomToolParam, CustomToolParamFormat, DailyRecurrenceSchedule, - DataGenerationJob, - DataGenerationJobInputs, - DataGenerationJobOptions, - DataGenerationJobOutput, - DataGenerationJobResult, - DataGenerationJobSource, - DataGenerationModelOptions, - DataGenerationTokenUsage, DatasetCredential, - DatasetDataGenerationJobOutput, - DatasetDataGenerationJobSource, - DatasetEvaluatorGenerationJobSource, - DatasetReference, DatasetVersion, DeleteAgentResponse, DeleteAgentVersionResponse, @@ -117,12 +106,24 @@ EmbeddingConfiguration, EntraAuthorizationScheme, EntraIDCredentials, + EvalGraderLabelModel, + EvalGraderPython, + EvalGraderScoreModel, + EvalGraderScoreModelSamplingParams, + EvalGraderStringCheck, + EvalGraderTextSimilarity, + EvalItem, + EvalItemContentItemObject, + EvalItemContentItemObjectInputTextContent, + EvalItemContentOutputText, + EvalItemInputImage, EvalResult, EvalRunResultCompareItem, EvalRunResultComparison, EvalRunResultSummary, EvaluationComparisonInsightRequest, EvaluationComparisonInsightResult, + EvaluationDatasetReference, EvaluationResultSample, EvaluationRule, EvaluationRuleAction, @@ -130,22 +131,20 @@ EvaluationRunClusterInsightRequest, EvaluationRunClusterInsightResult, EvaluationScheduleTask, + EvaluationSuiteRunRequest, + EvaluationSuiteRunResponse, + EvaluationSuiteRunResult, + EvaluationSuiteVersion, + EvaluationSuiteVersionInputMessagesTemplate1, EvaluationTarget, EvaluationTaxonomy, EvaluationTaxonomyInput, EvaluatorDefinition, - EvaluatorGenerationArtifacts, - EvaluatorGenerationInputs, - EvaluatorGenerationJob, - EvaluatorGenerationJobSource, - EvaluatorGenerationTokenUsage, EvaluatorMetric, EvaluatorVersion, FabricDataAgentToolParameters, FabricIQPreviewTool, FieldMapping, - FileDataGenerationJobOutput, - FileDataGenerationJobSource, FileDatasetVersion, FileSearchTool, FixedRatioVersionSelectionRule, @@ -166,6 +165,8 @@ Index, InlineSkillParam, InlineSkillSourceParam, + InputAudio, + InputAudioInputAudio, Insight, InsightCluster, InsightModelConfiguration, @@ -201,6 +202,8 @@ ModelCredentialRequest, ModelDeployment, ModelDeploymentSku, + ModelPendingUploadRequest, + ModelPendingUploadResponse, ModelSamplingParams, ModelSourceData, ModelVersion, @@ -222,8 +225,6 @@ PromptAgentDefinition, PromptAgentDefinitionTextOptions, PromptBasedEvaluatorDefinition, - PromptDataGenerationJobSource, - PromptEvaluatorGenerationJobSource, ProtocolVersionRecord, RaiConfig, RankingOptions, @@ -234,8 +235,6 @@ RedTeamTargetConfig, ResponseUsageInputTokensDetails, ResponseUsageOutputTokensDetails, - RubricBasedEvaluatorDefinition, - RubricCriterion, SASCredentials, Schedule, ScheduleRun, @@ -246,7 +245,6 @@ SessionLogEvent, SharepointGroundingToolParameters, SharepointPreviewTool, - SimpleQnADataGenerationJobOptions, SkillDetails, SkillReferenceParam, SpecificApplyPatchParam, @@ -259,6 +257,7 @@ TelemetryConfig, TelemetryEndpoint, TelemetryEndpointAuth, + TestingCriterionAzureAIEvaluator, TextResponseFormat, TextResponseFormatJsonObject, TextResponseFormatJsonSchema, @@ -277,14 +276,10 @@ ToolChoiceWebSearchPreview20250311, ToolDescription, ToolProjectConnection, - ToolUseFineTuningDataGenerationJobOptions, ToolboxObject, ToolboxPolicies, ToolboxSearchPreviewTool, ToolboxVersionObject, - TracesDataGenerationJobOptions, - TracesDataGenerationJobSource, - TracesEvaluatorGenerationJobSource, Trigger, UpdateModelVersionRequest, UpdateToolboxRequest, @@ -322,19 +317,17 @@ ContainerSkillType, CredentialType, CustomToolParamFormatType, - DataGenerationJobOutputType, - DataGenerationJobScenario, - DataGenerationJobSourceType, - DataGenerationJobType, DatasetType, DayOfWeek, DeploymentType, + EvalItemContentItemObjectType, + EvaluationLevel, EvaluationRuleActionType, EvaluationRuleEventType, + EvaluationSuiteSubtype, EvaluationTaxonomyInputType, EvaluatorCategory, EvaluatorDefinitionType, - EvaluatorGenerationJobSourceType, EvaluatorMetricDirection, EvaluatorMetricType, EvaluatorType, @@ -367,7 +360,6 @@ ScheduleTaskType, SearchContextSize, SessionLogEventType, - SimpleQnAFineTuningQuestionType, TelemetryDataKind, TelemetryEndpointAuthType, TelemetryEndpointKind, @@ -392,12 +384,10 @@ "AgentCardSkill", "AgentClusterInsightRequest", "AgentClusterInsightResult", - "AgentDataGenerationJobSource", "AgentDefinition", "AgentDetails", "AgentEndpointAuthorizationScheme", "AgentEndpointConfig", - "AgentEvaluatorGenerationJobSource", "AgentIdentity", "AgentObjectVersions", "AgentSessionResource", @@ -459,6 +449,9 @@ "CosmosDBIndex", "CreateAgentVersionFromCodeContent", "CreateAgentVersionFromCodeMetadata", + "CreateAsyncResponse", + "CreateEvalCompletionsRunDataSourceInputMessagesItemReference", + "CreateEvalResponsesRunDataSourceInputMessagesTemplate", "CronTrigger", "CustomCredential", "CustomGrammarFormatParam", @@ -466,19 +459,7 @@ "CustomToolParam", "CustomToolParamFormat", "DailyRecurrenceSchedule", - "DataGenerationJob", - "DataGenerationJobInputs", - "DataGenerationJobOptions", - "DataGenerationJobOutput", - "DataGenerationJobResult", - "DataGenerationJobSource", - "DataGenerationModelOptions", - "DataGenerationTokenUsage", "DatasetCredential", - "DatasetDataGenerationJobOutput", - "DatasetDataGenerationJobSource", - "DatasetEvaluatorGenerationJobSource", - "DatasetReference", "DatasetVersion", "DeleteAgentResponse", "DeleteAgentVersionResponse", @@ -488,12 +469,24 @@ "EmbeddingConfiguration", "EntraAuthorizationScheme", "EntraIDCredentials", + "EvalGraderLabelModel", + "EvalGraderPython", + "EvalGraderScoreModel", + "EvalGraderScoreModelSamplingParams", + "EvalGraderStringCheck", + "EvalGraderTextSimilarity", + "EvalItem", + "EvalItemContentItemObject", + "EvalItemContentItemObjectInputTextContent", + "EvalItemContentOutputText", + "EvalItemInputImage", "EvalResult", "EvalRunResultCompareItem", "EvalRunResultComparison", "EvalRunResultSummary", "EvaluationComparisonInsightRequest", "EvaluationComparisonInsightResult", + "EvaluationDatasetReference", "EvaluationResultSample", "EvaluationRule", "EvaluationRuleAction", @@ -501,22 +494,20 @@ "EvaluationRunClusterInsightRequest", "EvaluationRunClusterInsightResult", "EvaluationScheduleTask", + "EvaluationSuiteRunRequest", + "EvaluationSuiteRunResponse", + "EvaluationSuiteRunResult", + "EvaluationSuiteVersion", + "EvaluationSuiteVersionInputMessagesTemplate1", "EvaluationTarget", "EvaluationTaxonomy", "EvaluationTaxonomyInput", "EvaluatorDefinition", - "EvaluatorGenerationArtifacts", - "EvaluatorGenerationInputs", - "EvaluatorGenerationJob", - "EvaluatorGenerationJobSource", - "EvaluatorGenerationTokenUsage", "EvaluatorMetric", "EvaluatorVersion", "FabricDataAgentToolParameters", "FabricIQPreviewTool", "FieldMapping", - "FileDataGenerationJobOutput", - "FileDataGenerationJobSource", "FileDatasetVersion", "FileSearchTool", "FixedRatioVersionSelectionRule", @@ -537,6 +528,8 @@ "Index", "InlineSkillParam", "InlineSkillSourceParam", + "InputAudio", + "InputAudioInputAudio", "Insight", "InsightCluster", "InsightModelConfiguration", @@ -572,6 +565,8 @@ "ModelCredentialRequest", "ModelDeployment", "ModelDeploymentSku", + "ModelPendingUploadRequest", + "ModelPendingUploadResponse", "ModelSamplingParams", "ModelSourceData", "ModelVersion", @@ -593,8 +588,6 @@ "PromptAgentDefinition", "PromptAgentDefinitionTextOptions", "PromptBasedEvaluatorDefinition", - "PromptDataGenerationJobSource", - "PromptEvaluatorGenerationJobSource", "ProtocolVersionRecord", "RaiConfig", "RankingOptions", @@ -605,8 +598,6 @@ "RedTeamTargetConfig", "ResponseUsageInputTokensDetails", "ResponseUsageOutputTokensDetails", - "RubricBasedEvaluatorDefinition", - "RubricCriterion", "SASCredentials", "Schedule", "ScheduleRun", @@ -617,7 +608,6 @@ "SessionLogEvent", "SharepointGroundingToolParameters", "SharepointPreviewTool", - "SimpleQnADataGenerationJobOptions", "SkillDetails", "SkillReferenceParam", "SpecificApplyPatchParam", @@ -630,6 +620,7 @@ "TelemetryConfig", "TelemetryEndpoint", "TelemetryEndpointAuth", + "TestingCriterionAzureAIEvaluator", "TextResponseFormat", "TextResponseFormatJsonObject", "TextResponseFormatJsonSchema", @@ -648,14 +639,10 @@ "ToolChoiceWebSearchPreview20250311", "ToolDescription", "ToolProjectConnection", - "ToolUseFineTuningDataGenerationJobOptions", "ToolboxObject", "ToolboxPolicies", "ToolboxSearchPreviewTool", "ToolboxVersionObject", - "TracesDataGenerationJobOptions", - "TracesDataGenerationJobSource", - "TracesEvaluatorGenerationJobSource", "Trigger", "UpdateModelVersionRequest", "UpdateToolboxRequest", @@ -690,19 +677,17 @@ "ContainerSkillType", "CredentialType", "CustomToolParamFormatType", - "DataGenerationJobOutputType", - "DataGenerationJobScenario", - "DataGenerationJobSourceType", - "DataGenerationJobType", "DatasetType", "DayOfWeek", "DeploymentType", + "EvalItemContentItemObjectType", + "EvaluationLevel", "EvaluationRuleActionType", "EvaluationRuleEventType", + "EvaluationSuiteSubtype", "EvaluationTaxonomyInputType", "EvaluatorCategory", "EvaluatorDefinitionType", - "EvaluatorGenerationJobSourceType", "EvaluatorMetricDirection", "EvaluatorMetricType", "EvaluatorType", @@ -735,7 +720,6 @@ "ScheduleTaskType", "SearchContextSize", "SessionLogEventType", - "SimpleQnAFineTuningQuestionType", "TelemetryDataKind", "TelemetryEndpointAuthType", "TelemetryEndpointKind", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py index b65c38c1fa73..aab621a92104 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py @@ -29,8 +29,6 @@ class _AgentDefinitionOptInKeys(str, Enum, metaclass=CaseInsensitiveEnumMeta): class _FoundryFeaturesOptInKeys(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of _FoundryFeaturesOptInKeys.""" - SKILLS_V1_PREVIEW = "Skills=V1Preview" - """SKILLS_V1_PREVIEW.""" EVALUATIONS_V1_PREVIEW = "Evaluations=V1Preview" """EVALUATIONS_V1_PREVIEW.""" SCHEDULES_V1_PREVIEW = "Schedules=V1Preview" @@ -43,8 +41,12 @@ class _FoundryFeaturesOptInKeys(str, Enum, metaclass=CaseInsensitiveEnumMeta): """MEMORY_STORES_V1_PREVIEW.""" TOOLBOXES_V1_PREVIEW = "Toolboxes=V1Preview" """TOOLBOXES_V1_PREVIEW.""" + SKILLS_V1_PREVIEW = "Skills=V1Preview" + """SKILLS_V1_PREVIEW.""" DATA_GENERATION_JOBS_V1_PREVIEW = "DataGenerationJobs=V1Preview" """DATA_GENERATION_JOBS_V1_PREVIEW.""" + MODELS_V1_PREVIEW = "Models=V1Preview" + """MODELS_V1_PREVIEW.""" class AgentBlueprintReferenceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -74,6 +76,8 @@ class AgentEndpointProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """RESPONSES.""" A2A = "a2a" """A2A.""" + MCP = "mcp" + """MCP.""" INVOCATIONS = "invocations" """INVOCATIONS.""" @@ -111,6 +115,8 @@ class AgentProtocol(str, Enum, metaclass=CaseInsensitiveEnumMeta): """ACTIVITY_PROTOCOL.""" RESPONSES = "responses" """RESPONSES.""" + MCP = "mcp" + """MCP.""" INVOCATIONS = "invocations" """INVOCATIONS.""" @@ -344,52 +350,6 @@ class CustomToolParamFormatType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """GRAMMAR.""" -class DataGenerationJobOutputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The supported output file types for a data generation job.""" - - FILE = "file" - """The generated data is an Azure OpenAI File.""" - DATASET = "dataset" - """The generated data is a Dataset.""" - - -class DataGenerationJobScenario(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The supported scenarios for a data generation job.""" - - SUPERVISED_FINETUNING = "supervised_finetuning" - """Supervised Fine-tuning scenario.""" - REINFORCEMENT_FINETUNING = "reinforcement_finetuning" - """Reinforcement Fine-tuning scenario.""" - EVALUATION = "evaluation" - """Evaluation scenario.""" - - -class DataGenerationJobSourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The supported source types for data generation jobs.""" - - PROMPT = "prompt" - """Prompt source — inline text provided by the user.""" - AGENT = "agent" - """Agent source — references an agent.""" - TRACES = "traces" - """Traces source — conversation traces from Application Insights.""" - DATASET = "dataset" - """Dataset source — reference to a dataset.""" - FILE = "file" - """File source — Azure OpenAI file.""" - - -class DataGenerationJobType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The supported data generation job types.""" - - SIMPLE_QNA = "simple_qna" - """Simple question and answers between user and agent.""" - TRACES = "traces" - """Single turn query and response from agent traces.""" - TOOL_USE = "tool_use" - """Tool calling conversation between user and agent.""" - - class DatasetType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Enum to determine the type of data.""" @@ -425,6 +385,28 @@ class DeploymentType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Model deployment.""" +class EvalItemContentItemObjectType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Type of EvalItemContentItemObjectType.""" + + INPUT_TEXT = "input_text" + """INPUT_TEXT.""" + OUTPUT_TEXT = "output_text" + """OUTPUT_TEXT.""" + INPUT_IMAGE = "input_image" + """INPUT_IMAGE.""" + INPUT_AUDIO = "input_audio" + """INPUT_AUDIO.""" + + +class EvaluationLevel(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The level at which evaluation is performed.""" + + TURN = "turn" + """Evaluation is performed at the turn level.""" + CONVERSATION = "conversation" + """Evaluation is performed at the conversation level.""" + + class EvaluationRuleActionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of the evaluation action.""" @@ -443,6 +425,15 @@ class EvaluationRuleEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Manual trigger.""" +class EvaluationSuiteSubtype(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The subtype of an evaluation suite.""" + + DEFAULT = "default" + """Default suite type.""" + BENCHMARK = "benchmark" + """Benchmark suite.""" + + class EvaluationTaxonomyInputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of the evaluation taxonomy input.""" @@ -476,22 +467,6 @@ class EvaluatorDefinitionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Service-based evaluator.""" OPENAI_GRADERS = "openai_graders" """OpenAI graders.""" - RUBRICS = "rubrics" - """Rubric-based evaluator definition. Stores rubric criteria for both quality and safety - evaluators. Can be created via the generate API or manually via createVersion.""" - - -class EvaluatorGenerationJobSourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The supported source types for evaluator generation jobs.""" - - PROMPT = "prompt" - """Prompt source — inline text provided by the user.""" - AGENT = "agent" - """Agent source — references an agent to fetch instructions and metadata from.""" - TRACES = "traces" - """Traces source — conversation traces from Application Insights.""" - DATASET = "dataset" - """Dataset source — reference to a dataset.""" class EvaluatorMetricDirection(str, Enum, metaclass=CaseInsensitiveEnumMeta): @@ -761,6 +736,9 @@ class PendingUploadType(str, Enum, metaclass=CaseInsensitiveEnumMeta): NONE = "None" """No pending upload.""" + BLOB_REFERENCE = "BlobReference" + """Deprecated: the service never read this value and silently ignored it. Use + TemporaryBlobReference instead.""" TEMPORARY_BLOB_REFERENCE = "TemporaryBlobReference" """Temporary blob reference.""" @@ -863,15 +841,6 @@ class SessionLogEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """A log line from the agent session container.""" -class SimpleQnAFineTuningQuestionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The supported question types for SimpleQnA data generation jobs used for fine-tuning scenarios.""" - - SHORT_ANSWER = "short_answer" - """Short answer question type.""" - LONG_ANSWER = "long_answer" - """Long answer question type.""" - - class TelemetryDataKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The type of telemetry data to export.""" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py index ca04b06b7543..12a382abb18f 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py @@ -22,15 +22,12 @@ ContainerSkillType, CredentialType, CustomToolParamFormatType, - DataGenerationJobOutputType, - DataGenerationJobSourceType, - DataGenerationJobType, DatasetType, DeploymentType, + EvalItemContentItemObjectType, EvaluationRuleActionType, EvaluationTaxonomyInputType, EvaluatorDefinitionType, - EvaluatorGenerationJobSourceType, FunctionShellToolParamEnvironmentType, IndexType, InsightType, @@ -426,94 +423,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = InsightType.AGENT_CLUSTER_INSIGHT # type: ignore -class DataGenerationJobSource(_Model): - """The base source model for data generation jobs. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - AgentDataGenerationJobSource, DatasetDataGenerationJobSource, FileDataGenerationJobSource, - PromptDataGenerationJobSource, TracesDataGenerationJobSource - - :ivar type: The type of source. Required. Known values are: "prompt", "agent", "traces", - "dataset", and "file". - :vartype type: str or ~azure.ai.projects.models.DataGenerationJobSourceType - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - """ - - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of source. Required. Known values are: \"prompt\", \"agent\", \"traces\", \"dataset\", - and \"file\".""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of what this source represents — helps the pipeline interpret its content - (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" - - @overload - def __init__( - self, - *, - type: str, - description: Optional[str] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class AgentDataGenerationJobSource(DataGenerationJobSource, discriminator="agent"): - """Agent source for data generation jobs — references an agent to fetch instructions and metadata - from. - - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Agent. Required. Agent source — - references an agent. - :vartype type: str or ~azure.ai.projects.models.AGENT - :ivar agent_name: The agent name to fetch instructions from. Required. - :vartype agent_name: str - :ivar agent_version: The agent version. If not specified, the latest version is used. - :vartype agent_version: str - """ - - type: Literal[DataGenerationJobSourceType.AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Agent. Required. Agent source — references an agent.""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent name to fetch instructions from. Required.""" - agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent version. If not specified, the latest version is used.""" - - @overload - def __init__( - self, - *, - agent_name: str, - description: Optional[str] = None, - agent_version: Optional[str] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = DataGenerationJobSourceType.AGENT # type: ignore - - class AgentDefinition(_Model): """AgentDefinition. @@ -696,90 +605,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluatorGenerationJobSource(_Model): - """The base source model for evaluator generation jobs. Polymorphic over ``type``. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - AgentEvaluatorGenerationJobSource, DatasetEvaluatorGenerationJobSource, - PromptEvaluatorGenerationJobSource, TracesEvaluatorGenerationJobSource - - :ivar type: The type of source. Required. Known values are: "prompt", "agent", "traces", and - "dataset". - :vartype type: str or ~azure.ai.projects.models.EvaluatorGenerationJobSourceType - """ - - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of source. Required. Known values are: \"prompt\", \"agent\", \"traces\", and - \"dataset\".""" - - @overload - def __init__( - self, - *, - type: str, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class AgentEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="agent"): - """Agent source for evaluator generation jobs — references an agent to fetch instructions and - metadata from. - - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Agent. Required. Agent source — - references an agent to fetch instructions and metadata from. - :vartype type: str or ~azure.ai.projects.models.AGENT - :ivar agent_name: The agent name to fetch instructions from. Required. - :vartype agent_name: str - :ivar agent_version: The agent version. If not specified, the latest version is used. - :vartype agent_version: str - """ - - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of what this source represents — helps the pipeline interpret its content - (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" - type: Literal[EvaluatorGenerationJobSourceType.AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Agent. Required. Agent source — references an agent - to fetch instructions and metadata from.""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent name to fetch instructions from. Required.""" - agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent version. If not specified, the latest version is used.""" - - @overload - def __init__( - self, - *, - agent_name: str, - description: Optional[str] = None, - agent_version: Optional[str] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = EvaluatorGenerationJobSourceType.AGENT # type: ignore - - class BaseCredentials(_Model): """A base class for connection credentials. @@ -2846,10 +2671,10 @@ class EvaluatorDefinition(_Model): """Base evaluator configuration with discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - CodeBasedEvaluatorDefinition, PromptBasedEvaluatorDefinition, RubricBasedEvaluatorDefinition + CodeBasedEvaluatorDefinition, PromptBasedEvaluatorDefinition :ivar type: The type of evaluator definition. Required. Known values are: "prompt", "code", - "prompt_and_code", "service", "openai_graders", and "rubrics". + "prompt_and_code", "service", and "openai_graders". :vartype type: str or ~azure.ai.projects.models.EvaluatorDefinitionType :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. This includes parameters like type, properties, required. @@ -2864,7 +2689,7 @@ class EvaluatorDefinition(_Model): __mapping__: dict[str, _Model] = {} type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) """The type of evaluator definition. Required. Known values are: \"prompt\", \"code\", - \"prompt_and_code\", \"service\", \"openai_graders\", and \"rubrics\".""" + \"prompt_and_code\", \"service\", and \"openai_graders\".""" init_parameters: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The JSON schema (Draft 2020-12) for the evaluator's input parameters. This includes parameters like type, properties, required.""" @@ -3778,6 +3603,111 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class CreateAsyncResponse(_Model): + """CreateAsyncResponse. + + :ivar location: URL to poll for operation status. + :vartype location: str + :ivar operation_result: URL to the operation result, or null if the operation is still in + progress. + :vartype operation_result: str + """ + + location: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """URL to poll for operation status.""" + operation_result: Optional[str] = rest_field( + name="operationResult", visibility=["read", "create", "update", "delete", "query"] + ) + """URL to the operation result, or null if the operation is still in progress.""" + + @overload + def __init__( + self, + *, + location: Optional[str] = None, + operation_result: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class CreateEvalCompletionsRunDataSourceInputMessagesItemReference(_Model): # pylint: disable=name-too-long + """CreateEvalCompletionsRunDataSourceInputMessagesItemReference. + + :ivar type: Required. Default value is "item_reference". + :vartype type: str + :ivar item_reference: Required. + :vartype item_reference: str + """ + + type: Literal["item_reference"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"item_reference\".""" + item_reference: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + item_reference: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["item_reference"] = "item_reference" + + +class CreateEvalResponsesRunDataSourceInputMessagesTemplate(_Model): # pylint: disable=name-too-long + """CreateEvalResponsesRunDataSourceInputMessagesTemplate. + + :ivar type: Required. Default value is "template". + :vartype type: str + :ivar template: Required. + :vartype template: list[~azure.ai.projects.models.EvaluationSuiteVersionInputMessagesTemplate1 + or ~azure.ai.projects.models.EvalItem] + """ + + type: Literal["template"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Default value is \"template\".""" + template: list[Union["_models.EvaluationSuiteVersionInputMessagesTemplate1", "_models.EvalItem"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Required.""" + + @overload + def __init__( + self, + *, + template: list[Union["_models.EvaluationSuiteVersionInputMessagesTemplate1", "_models.EvalItem"]], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["template"] = "template" + + class Trigger(_Model): """Base model for Trigger of the schedule. @@ -4104,53 +4034,23 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = RecurrenceType.DAILY # type: ignore -class DataGenerationJob(_Model): - """Data Generation Job resource. +class DatasetCredential(_Model): + """Represents a reference to a blob for consumption. - :ivar id: Server-assigned unique identifier. Required. - :vartype id: str - :ivar inputs: Caller-supplied inputs. - :vartype inputs: ~azure.ai.projects.models.DataGenerationJobInputs - :ivar result: Result produced on success. - :vartype result: ~azure.ai.projects.models.DataGenerationJobResult - :ivar status: Current lifecycle status. Required. Known values are: "queued", "in_progress", - "succeeded", "failed", and "cancelled". - :vartype status: str or ~azure.ai.projects.models.JobStatus - :ivar error: Error details — populated only on failure. - :vartype error: ~azure.ai.projects.models.ApiError - :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds - since January 1, 1970). Required. - :vartype created_at: ~datetime.datetime - :ivar finished_at: The timestamp when the job was finished, represented in Unix time (seconds - since January 1, 1970). - :vartype finished_at: ~datetime.datetime + :ivar blob_reference: Credential info to access the storage account. Required. + :vartype blob_reference: ~azure.ai.projects.models.BlobReference """ - id: str = rest_field(visibility=["read"]) - """Server-assigned unique identifier. Required.""" - inputs: Optional["_models.DataGenerationJobInputs"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + blob_reference: "_models.BlobReference" = rest_field( + name="blobReference", visibility=["read", "create", "update", "delete", "query"] ) - """Caller-supplied inputs.""" - result: Optional["_models.DataGenerationJobResult"] = rest_field(visibility=["read"]) - """Result produced on success.""" - status: Union[str, "_models.JobStatus"] = rest_field(visibility=["read"]) - """Current lifecycle status. Required. Known values are: \"queued\", \"in_progress\", - \"succeeded\", \"failed\", and \"cancelled\".""" - error: Optional["_models.ApiError"] = rest_field(visibility=["read"]) - """Error details — populated only on failure.""" - created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") - """The timestamp when the job was created, represented in Unix time (seconds since January 1, - 1970). Required.""" - finished_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The timestamp when the job was finished, represented in Unix time (seconds since January 1, - 1970).""" + """Credential info to access the storage account. Required.""" @overload def __init__( self, *, - inputs: Optional["_models.DataGenerationJobInputs"] = None, + blob_reference: "_models.BlobReference", ) -> None: ... @overload @@ -4164,43 +4064,67 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DataGenerationJobInputs(_Model): - """Caller-supplied inputs for a data generation job. +class DatasetVersion(_Model): + """DatasetVersion Definition. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + FileDatasetVersion, FolderDatasetVersion - :ivar name: The display name of the data generation job. Required. + :ivar data_uri: URI of the data (`example `_). + Required. + :vartype data_uri: str + :ivar type: Dataset type. Required. Known values are: "uri_file" and "uri_folder". + :vartype type: str or ~azure.ai.projects.models.DatasetType + :ivar is_reference: Indicates if the dataset holds a reference to the storage, or the dataset + manages storage itself. If true, the underlying data will not be deleted when the dataset + version is deleted. + :vartype is_reference: bool + :ivar connection_name: The Azure Storage Account connection name. Required if + startPendingUploadVersion was not called before creating the Dataset. + :vartype connection_name: str + :ivar id: Asset ID, a unique identifier for the asset. + :vartype id: str + :ivar name: The name of the resource. Required. :vartype name: str - :ivar sources: The sources used for the data generation job. Required. - :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] - :ivar options: The options for the data generation job. Required. - :vartype options: ~azure.ai.projects.models.DataGenerationJobOptions - :ivar scenario: The scenario of the data generation job. Either for fine-tuning or evaluation. - Required. Known values are: "supervised_finetuning", "reinforcement_finetuning", and - "evaluation". - :vartype scenario: str or ~azure.ai.projects.models.DataGenerationJobScenario + :ivar version: The version of the resource. Required. + :vartype version: str + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The display name of the data generation job. Required.""" - sources: list["_models.DataGenerationJobSource"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The sources used for the data generation job. Required.""" - options: "_models.DataGenerationJobOptions" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The options for the data generation job. Required.""" - scenario: Union[str, "_models.DataGenerationJobScenario"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The scenario of the data generation job. Either for fine-tuning or evaluation. Required. Known - values are: \"supervised_finetuning\", \"reinforcement_finetuning\", and \"evaluation\".""" + __mapping__: dict[str, _Model] = {} + data_uri: str = rest_field(name="dataUri", visibility=["read", "create"]) + """URI of the data (`example `_). Required.""" + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Dataset type. Required. Known values are: \"uri_file\" and \"uri_folder\".""" + is_reference: Optional[bool] = rest_field(name="isReference", visibility=["read"]) + """Indicates if the dataset holds a reference to the storage, or the dataset manages storage + itself. If true, the underlying data will not be deleted when the dataset version is deleted.""" + connection_name: Optional[str] = rest_field(name="connectionName", visibility=["read", "create"]) + """The Azure Storage Account connection name. Required if startPendingUploadVersion was not called + before creating the Dataset.""" + id: Optional[str] = rest_field(visibility=["read"]) + """Asset ID, a unique identifier for the asset.""" + name: str = rest_field(visibility=["read"]) + """The name of the resource. Required.""" + version: str = rest_field(visibility=["read"]) + """The version of the resource. Required.""" + description: Optional[str] = rest_field(visibility=["create", "update"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) + """Tag dictionary. Tags can be added, removed, and updated.""" @overload def __init__( self, *, - name: str, - sources: list["_models.DataGenerationJobSource"], - options: "_models.DataGenerationJobOptions", - scenario: Union[str, "_models.DataGenerationJobScenario"], + data_uri: str, + type: str, + connection_name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -4214,47 +4138,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DataGenerationJobOptions(_Model): - """Options for managing data generation jobs. +class DeleteAgentResponse(_Model): + """A deleted agent Object. - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - SimpleQnADataGenerationJobOptions, ToolUseFineTuningDataGenerationJobOptions, - TracesDataGenerationJobOptions - - :ivar type: The data generation job type. Required. Known values are: "simple_qna", "traces", - and "tool_use". - :vartype type: str or ~azure.ai.projects.models.DataGenerationJobType - :ivar max_samples: Maximum number of samples to generate. Required. - :vartype max_samples: int - :ivar train_split: The proportion of the generated data to be used for training when the data - is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. - :vartype train_split: float - :ivar model_options: The LLM model options. - :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions + :ivar object: The object type. Always 'agent.deleted'. Required. AGENT_DELETED. + :vartype object: str or ~azure.ai.projects.models.AGENT_DELETED + :ivar name: The name of the agent. Required. + :vartype name: str + :ivar deleted: Whether the agent was successfully deleted. Required. + :vartype deleted: bool """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The data generation job type. Required. Known values are: \"simple_qna\", \"traces\", and - \"tool_use\".""" - max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of samples to generate. Required.""" - train_split: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The proportion of the generated data to be used for training when the data is used for - fine-tuning. The rest will be used for validation. Value should be between 0 and 1.""" - model_options: Optional["_models.DataGenerationModelOptions"] = rest_field( + object: Literal[AgentObjectType.AGENT_DELETED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The LLM model options.""" + """The object type. Always 'agent.deleted'. Required. AGENT_DELETED.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the agent. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the agent was successfully deleted. Required.""" @overload def __init__( self, *, - type: str, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, + object: Literal[AgentObjectType.AGENT_DELETED], + name: str, + deleted: bool, ) -> None: ... @overload @@ -4268,25 +4178,38 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DataGenerationJobOutput(_Model): - """Output information for a data generation job. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - DatasetDataGenerationJobOutput, FileDataGenerationJobOutput +class DeleteAgentVersionResponse(_Model): + """A deleted agent version Object. - :ivar type: The type of the output. Required. Known values are: "file" and "dataset". - :vartype type: str or ~azure.ai.projects.models.DataGenerationJobOutputType + :ivar object: The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED. + :vartype object: str or ~azure.ai.projects.models.AGENT_VERSION_DELETED + :ivar name: The name of the agent. Required. + :vartype name: str + :ivar version: The version identifier of the agent. Required. + :vartype version: str + :ivar deleted: Whether the agent was successfully deleted. Required. + :vartype deleted: bool """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of the output. Required. Known values are: \"file\" and \"dataset\".""" + object: Literal[AgentObjectType.AGENT_VERSION_DELETED] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the agent. Required.""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version identifier of the agent. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the agent was successfully deleted. Required.""" @overload def __init__( self, *, - type: str, + object: Literal[AgentObjectType.AGENT_VERSION_DELETED], + name: str, + version: str, + deleted: bool, ) -> None: ... @overload @@ -4300,36 +4223,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DataGenerationJobResult(_Model): - """Result produced by a successful data generation job. +class DeleteMemoryStoreResult(_Model): + """DeleteMemoryStoreResult. - :ivar outputs: The final job outputs: Azure OpenAI files for fine-tuning, or datasets for - evaluation. - :vartype outputs: list[~azure.ai.projects.models.DataGenerationJobOutput] - :ivar generated_samples: The number of samples actually generated. Required. - :vartype generated_samples: int - :ivar token_usage: The token usage information for the data generation job. - :vartype token_usage: ~azure.ai.projects.models.DataGenerationTokenUsage + :ivar object: The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED. + :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE_DELETED + :ivar name: The name of the memory store. Required. + :vartype name: str + :ivar deleted: Whether the memory store was successfully deleted. Required. + :vartype deleted: bool """ - outputs: Optional[list["_models.DataGenerationJobOutput"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The final job outputs: Azure OpenAI files for fine-tuning, or datasets for evaluation.""" - generated_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The number of samples actually generated. Required.""" - token_usage: Optional["_models.DataGenerationTokenUsage"] = rest_field( + object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The token usage information for the data generation job.""" + """The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the memory store. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the memory store was successfully deleted. Required.""" @overload def __init__( self, *, - generated_samples: int, - outputs: Optional[list["_models.DataGenerationJobOutput"]] = None, - token_usage: Optional["_models.DataGenerationTokenUsage"] = None, + object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED], + name: str, + deleted: bool, ) -> None: ... @overload @@ -4343,21 +4263,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DataGenerationModelOptions(_Model): - """LLM model options for data generation jobs. +class DeleteSkillResult(_Model): + """A deleted skill Object. - :ivar model: Base model name used to generate data. Required. - :vartype model: str + :ivar name: The unique name of the skill. Required. + :vartype name: str + :ivar deleted: Whether the skill was successfully deleted. Required. + :vartype deleted: bool """ - model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Base model name used to generate data. Required.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique name of the skill. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the skill was successfully deleted. Required.""" @overload def __init__( self, *, - model: str, + name: str, + deleted: bool, ) -> None: ... @overload @@ -4371,42 +4296,64 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DataGenerationTokenUsage(_Model): - """Token usage information for a data generation job. +class Deployment(_Model): + """Model Deployment Definition. - :ivar prompt_tokens: The number of prompt tokens used. Required. - :vartype prompt_tokens: int - :ivar completion_tokens: The number of completion tokens generated. Required. - :vartype completion_tokens: int - :ivar total_tokens: Total number of tokens used. Required. - :vartype total_tokens: int + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + ModelDeployment + + :ivar type: The type of the deployment. Required. "ModelDeployment" + :vartype type: str or ~azure.ai.projects.models.DeploymentType + :ivar name: Name of the deployment. Required. + :vartype name: str """ - prompt_tokens: int = rest_field(visibility=["read"]) - """The number of prompt tokens used. Required.""" - completion_tokens: int = rest_field(visibility=["read"]) - """The number of completion tokens generated. Required.""" - total_tokens: int = rest_field(visibility=["read"]) - """Total number of tokens used. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of the deployment. Required. \"ModelDeployment\"""" + name: str = rest_field(visibility=["read"]) + """Name of the deployment. Required.""" + @overload + def __init__( + self, + *, + type: str, + ) -> None: ... -class DatasetCredential(_Model): - """Represents a reference to a blob for consumption. + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ - :ivar blob_reference: Credential info to access the storage account. Required. - :vartype blob_reference: ~azure.ai.projects.models.BlobReference + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class EmbeddingConfiguration(_Model): + """Embedding configuration class. + + :ivar model_deployment_name: Deployment name of embedding model. It can point to a model + deployment either in the parent AIServices or a connection. Required. + :vartype model_deployment_name: str + :ivar embedding_field: Embedding field. Required. + :vartype embedding_field: str """ - blob_reference: "_models.BlobReference" = rest_field( - name="blobReference", visibility=["read", "create", "update", "delete", "query"] - ) - """Credential info to access the storage account. Required.""" + model_deployment_name: str = rest_field(name="modelDeploymentName", visibility=["create"]) + """Deployment name of embedding model. It can point to a model deployment either in the parent + AIServices or a connection. Required.""" + embedding_field: str = rest_field(name="embeddingField", visibility=["create"]) + """Embedding field. Required.""" @overload def __init__( self, *, - blob_reference: "_models.BlobReference", + model_deployment_name: str, + embedding_field: str, ) -> None: ... @overload @@ -4420,45 +4367,19 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatasetDataGenerationJobOutput(DataGenerationJobOutput, discriminator="dataset"): - """Dataset output for a data generation job. +class EntraAuthorizationScheme(AgentEndpointAuthorizationScheme, discriminator="Entra"): + """EntraAuthorizationScheme. - :ivar type: Dataset output. Required. The generated data is a Dataset. - :vartype type: str or ~azure.ai.projects.models.DATASET - :ivar id: The id of the output dataset created. - :vartype id: str - :ivar name: The name of the output dataset and can be optionally set during job creation time. - :vartype name: str - :ivar version: The version of the output dataset. - :vartype version: str - :ivar description: Description of the output dataset and can be optionally set during job - creation time. - :vartype description: str - :ivar tags: Tag dictionary of the output dataset and can be optionally set during job creation - time. - :vartype tags: dict[str, str] + :ivar type: Required. ENTRA. + :vartype type: str or ~azure.ai.projects.models.ENTRA """ - type: Literal[DataGenerationJobOutputType.DATASET] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Dataset output. Required. The generated data is a Dataset.""" - id: Optional[str] = rest_field(visibility=["read"]) - """The id of the output dataset created.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the output dataset and can be optionally set during job creation time.""" - version: Optional[str] = rest_field(visibility=["read"]) - """The version of the output dataset.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description of the output dataset and can be optionally set during job creation time.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Tag dictionary of the output dataset and can be optionally set during job creation time.""" + type: Literal[AgentEndpointAuthorizationSchemeType.ENTRA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. ENTRA.""" @overload def __init__( self, - *, - name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -4470,40 +4391,22 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobOutputType.DATASET # type: ignore + self.type = AgentEndpointAuthorizationSchemeType.ENTRA # type: ignore -class DatasetDataGenerationJobSource(DataGenerationJobSource, discriminator="dataset"): - """Dataset source for data generation jobs — reference to a dataset. +class EntraIDCredentials(BaseCredentials, discriminator="AAD"): + """Entra ID credential definition. - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Dataset. Required. Dataset source — - reference to a dataset. - :vartype type: str or ~azure.ai.projects.models.DATASET - :ivar name: The name of the dataset. Required. - :vartype name: str - :ivar version: The version of the dataset. If not specified, the latest version is used. - :vartype version: str + :ivar type: The credential type. Required. Entra ID credential (formerly known as AAD). + :vartype type: str or ~azure.ai.projects.models.ENTRA_ID """ - type: Literal[DataGenerationJobSourceType.DATASET] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Dataset. Required. Dataset source — reference to a - dataset.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the dataset. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version of the dataset. If not specified, the latest version is used.""" + type: Literal[CredentialType.ENTRA_ID] = rest_discriminator(name="type", visibility=["read"]) # type: ignore + """The credential type. Required. Entra ID credential (formerly known as AAD).""" @overload def __init__( self, - *, - name: str, - description: Optional[str] = None, - version: Optional[str] = None, ) -> None: ... @overload @@ -4515,43 +4418,50 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobSourceType.DATASET # type: ignore + self.type = CredentialType.ENTRA_ID # type: ignore -class DatasetEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="dataset"): - """Dataset source for evaluator generation jobs — reference to a dataset. +class EvalGraderLabelModel(_Model): + """LabelModelGrader. - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Dataset. Required. Dataset source — - reference to a dataset. - :vartype type: str or ~azure.ai.projects.models.DATASET - :ivar name: The name of the dataset. Required. + :ivar type: The object type, which is always ``label_model``. Required. Default value is + "label_model". + :vartype type: str + :ivar name: The name of the grader. Required. :vartype name: str - :ivar version: The version of the dataset. If not specified, the latest version is used. - :vartype version: str + :ivar model: The model to use for the evaluation. Must support structured outputs. Required. + :vartype model: str + :ivar input: Required. + :vartype input: list[~azure.ai.projects.models.EvalItem] + :ivar labels: The labels to assign to each item in the evaluation. Required. + :vartype labels: list[str] + :ivar passing_labels: The labels that indicate a passing result. Must be a subset of labels. + Required. + :vartype passing_labels: list[str] """ - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of what this source represents — helps the pipeline interpret its content - (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" - type: Literal[EvaluatorGenerationJobSourceType.DATASET] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Dataset. Required. Dataset source — reference to a - dataset.""" + type: Literal["label_model"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, which is always ``label_model``. Required. Default value is \"label_model\".""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the dataset. Required.""" - version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version of the dataset. If not specified, the latest version is used.""" + """The name of the grader. Required.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model to use for the evaluation. Must support structured outputs. Required.""" + input: list["_models.EvalItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + labels: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The labels to assign to each item in the evaluation. Required.""" + passing_labels: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The labels that indicate a passing result. Must be a subset of labels. Required.""" @overload def __init__( self, *, name: str, - description: Optional[str] = None, - version: Optional[str] = None, + model: str, + input: list["_models.EvalItem"], + labels: list[str], + passing_labels: list[str], ) -> None: ... @overload @@ -4563,29 +4473,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorGenerationJobSourceType.DATASET # type: ignore + self.type: Literal["label_model"] = "label_model" -class DatasetReference(_Model): - """Reference to a versioned Foundry Dataset. +class EvalGraderPython(_Model): + """PythonGrader. - :ivar name: Dataset name. Required. + :ivar type: The object type, which is always ``python``. Required. Default value is "python". + :vartype type: str + :ivar name: The name of the grader. Required. :vartype name: str - :ivar version: Dataset version. Required. - :vartype version: str + :ivar source: The source code of the python script. Required. + :vartype source: str + :ivar image_tag: The image tag to use for the python script. + :vartype image_tag: str + :ivar pass_threshold: The threshold for the score. + :vartype pass_threshold: int """ + type: Literal["python"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, which is always ``python``. Required. Default value is \"python\".""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Dataset name. Required.""" - version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Dataset version. Required.""" + """The name of the grader. Required.""" + source: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The source code of the python script. Required.""" + image_tag: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The image tag to use for the python script.""" + pass_threshold: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The threshold for the score.""" @overload def __init__( self, *, name: str, - version: str, + source: str, + image_tag: Optional[str] = None, + pass_threshold: Optional[int] = None, ) -> None: ... @overload @@ -4597,69 +4521,58 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["python"] = "python" -class DatasetVersion(_Model): - """DatasetVersion Definition. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - FileDatasetVersion, FolderDatasetVersion +class EvalGraderScoreModel(_Model): + """ScoreModelGrader. - :ivar data_uri: URI of the data (`example `_). - Required. - :vartype data_uri: str - :ivar type: Dataset type. Required. Known values are: "uri_file" and "uri_folder". - :vartype type: str or ~azure.ai.projects.models.DatasetType - :ivar is_reference: Indicates if the dataset holds a reference to the storage, or the dataset - manages storage itself. If true, the underlying data will not be deleted when the dataset - version is deleted. - :vartype is_reference: bool - :ivar connection_name: The Azure Storage Account connection name. Required if - startPendingUploadVersion was not called before creating the Dataset. - :vartype connection_name: str - :ivar id: Asset ID, a unique identifier for the asset. - :vartype id: str - :ivar name: The name of the resource. Required. + :ivar type: The object type, which is always ``score_model``. Required. Default value is + "score_model". + :vartype type: str + :ivar name: The name of the grader. Required. :vartype name: str - :ivar version: The version of the resource. Required. - :vartype version: str - :ivar description: The asset description text. - :vartype description: str - :ivar tags: Tag dictionary. Tags can be added, removed, and updated. - :vartype tags: dict[str, str] - """ - - __mapping__: dict[str, _Model] = {} - data_uri: str = rest_field(name="dataUri", visibility=["read", "create"]) - """URI of the data (`example `_). Required.""" - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Dataset type. Required. Known values are: \"uri_file\" and \"uri_folder\".""" - is_reference: Optional[bool] = rest_field(name="isReference", visibility=["read"]) - """Indicates if the dataset holds a reference to the storage, or the dataset manages storage - itself. If true, the underlying data will not be deleted when the dataset version is deleted.""" - connection_name: Optional[str] = rest_field(name="connectionName", visibility=["read", "create"]) - """The Azure Storage Account connection name. Required if startPendingUploadVersion was not called - before creating the Dataset.""" - id: Optional[str] = rest_field(visibility=["read"]) - """Asset ID, a unique identifier for the asset.""" - name: str = rest_field(visibility=["read"]) - """The name of the resource. Required.""" - version: str = rest_field(visibility=["read"]) - """The version of the resource. Required.""" - description: Optional[str] = rest_field(visibility=["create", "update"]) - """The asset description text.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) - """Tag dictionary. Tags can be added, removed, and updated.""" + :ivar model: The model to use for the evaluation. Required. + :vartype model: str + :ivar sampling_params: The sampling parameters for the model. + :vartype sampling_params: ~azure.ai.projects.models.EvalGraderScoreModelSamplingParams + :ivar input: The input messages evaluated by the grader. Supports text, output text, input + image, and input audio content blocks, and may include template strings. Required. + :vartype input: list[~azure.ai.projects.models.EvalItem] + :ivar range: The range of the score. Defaults to ``[0, 1]``. + :vartype range: list[int] + :ivar pass_threshold: The threshold for the score. + :vartype pass_threshold: int + """ + + type: Literal["score_model"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, which is always ``score_model``. Required. Default value is \"score_model\".""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the grader. Required.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model to use for the evaluation. Required.""" + sampling_params: Optional["_models.EvalGraderScoreModelSamplingParams"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The sampling parameters for the model.""" + input: list["_models.EvalItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The input messages evaluated by the grader. Supports text, output text, input image, and input + audio content blocks, and may include template strings. Required.""" + range: Optional[list[int]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The range of the score. Defaults to ``[0, 1]``.""" + pass_threshold: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The threshold for the score.""" @overload def __init__( self, *, - data_uri: str, - type: str, - connection_name: Optional[str] = None, - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, + name: str, + model: str, + input: list["_models.EvalItem"], + sampling_params: Optional["_models.EvalGraderScoreModelSamplingParams"] = None, + range: Optional[list[int]] = None, + pass_threshold: Optional[int] = None, ) -> None: ... @overload @@ -4671,35 +4584,44 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["score_model"] = "score_model" -class DeleteAgentResponse(_Model): - """A deleted agent Object. +class EvalGraderScoreModelSamplingParams(_Model): + """EvalGraderScoreModelSamplingParams. - :ivar object: The object type. Always 'agent.deleted'. Required. AGENT_DELETED. - :vartype object: str or ~azure.ai.projects.models.AGENT_DELETED - :ivar name: The name of the agent. Required. - :vartype name: str - :ivar deleted: Whether the agent was successfully deleted. Required. - :vartype deleted: bool + :ivar seed: + :vartype seed: int + :ivar top_p: + :vartype top_p: int + :ivar temperature: + :vartype temperature: int + :ivar max_completions_tokens: + :vartype max_completions_tokens: int + :ivar reasoning_effort: Is one of the following types: Literal["none"], Literal["minimal"], + Literal["low"], Literal["medium"], Literal["high"], Literal["xhigh"] + :vartype reasoning_effort: str or str or str or str or str or str """ - object: Literal[AgentObjectType.AGENT_DELETED] = rest_field( + seed: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + top_p: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + temperature: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + max_completions_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The object type. Always 'agent.deleted'. Required. AGENT_DELETED.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the agent. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the agent was successfully deleted. Required.""" + """Is one of the following types: Literal[\"none\"], Literal[\"minimal\"], Literal[\"low\"], + Literal[\"medium\"], Literal[\"high\"], Literal[\"xhigh\"]""" @overload def __init__( self, *, - object: Literal[AgentObjectType.AGENT_DELETED], - name: str, - deleted: bool, + seed: Optional[int] = None, + top_p: Optional[int] = None, + temperature: Optional[int] = None, + max_completions_tokens: Optional[int] = None, + reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] = None, ) -> None: ... @overload @@ -4713,38 +4635,47 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteAgentVersionResponse(_Model): - """A deleted agent version Object. +class EvalGraderStringCheck(_Model): + """StringCheckGrader. - :ivar object: The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED. - :vartype object: str or ~azure.ai.projects.models.AGENT_VERSION_DELETED - :ivar name: The name of the agent. Required. + :ivar type: The object type, which is always ``string_check``. Required. Default value is + "string_check". + :vartype type: str + :ivar name: The name of the grader. Required. :vartype name: str - :ivar version: The version identifier of the agent. Required. - :vartype version: str - :ivar deleted: Whether the agent was successfully deleted. Required. - :vartype deleted: bool - """ - - object: Literal[AgentObjectType.AGENT_VERSION_DELETED] = rest_field( + :ivar input: The input text. This may include template strings. Required. + :vartype input: str + :ivar reference: The reference text. This may include template strings. Required. + :vartype reference: str + :ivar operation: The string check operation to perform. One of ``eq``, ``ne``, ``like``, or + ``ilike``. Required. Is one of the following types: Literal["eq"], Literal["ne"], + Literal["like"], Literal["ilike"] + :vartype operation: str or str or str or str + """ + + type: Literal["string_check"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, which is always ``string_check``. Required. Default value is \"string_check\".""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the grader. Required.""" + input: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The input text. This may include template strings. Required.""" + reference: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The reference text. This may include template strings. Required.""" + operation: Literal["eq", "ne", "like", "ilike"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the agent. Required.""" - version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version identifier of the agent. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the agent was successfully deleted. Required.""" + """The string check operation to perform. One of ``eq``, ``ne``, ``like``, or ``ilike``. Required. + Is one of the following types: Literal[\"eq\"], Literal[\"ne\"], Literal[\"like\"], + Literal[\"ilike\"]""" @overload def __init__( self, *, - object: Literal[AgentObjectType.AGENT_VERSION_DELETED], name: str, - version: str, - deleted: bool, + input: str, + reference: str, + operation: Literal["eq", "ne", "like", "ilike"], ) -> None: ... @overload @@ -4756,35 +4687,83 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["string_check"] = "string_check" -class DeleteMemoryStoreResult(_Model): - """DeleteMemoryStoreResult. +class EvalGraderTextSimilarity(_Model): + """TextSimilarityGrader. - :ivar object: The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED. - :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE_DELETED - :ivar name: The name of the memory store. Required. + :ivar type: The type of grader. Required. Default value is "text_similarity". + :vartype type: str + :ivar name: The name of the grader. Required. :vartype name: str - :ivar deleted: Whether the memory store was successfully deleted. Required. - :vartype deleted: bool - """ - - object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED.""" + :ivar input: The text being graded. Required. + :vartype input: str + :ivar reference: The text being graded against. Required. + :vartype reference: str + :ivar evaluation_metric: The evaluation metric to use. One of ``cosine``, ``fuzzy_match``, + ``bleu``, ``gleu``, ``meteor``, ``rouge_1``, ``rouge_2``, ``rouge_3``, ``rouge_4``, + ``rouge_5``, or ``rouge_l``. Required. Is one of the following types: Literal["cosine"], + Literal["fuzzy_match"], Literal["bleu"], Literal["gleu"], Literal["meteor"], + Literal["rouge_1"], Literal["rouge_2"], Literal["rouge_3"], Literal["rouge_4"], + Literal["rouge_5"], Literal["rouge_l"] + :vartype evaluation_metric: str or str or str or str or str or str or str or str or str or str + or str + :ivar pass_threshold: The threshold for the score. Required. + :vartype pass_threshold: int + """ + + type: Literal["text_similarity"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The type of grader. Required. Default value is \"text_similarity\".""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the memory store. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the memory store was successfully deleted. Required.""" + """The name of the grader. Required.""" + input: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text being graded. Required.""" + reference: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text being graded against. Required.""" + evaluation_metric: Literal[ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l", + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The evaluation metric to use. One of ``cosine``, ``fuzzy_match``, ``bleu``, ``gleu``, + ``meteor``, ``rouge_1``, ``rouge_2``, ``rouge_3``, ``rouge_4``, ``rouge_5``, or ``rouge_l``. + Required. Is one of the following types: Literal[\"cosine\"], Literal[\"fuzzy_match\"], + Literal[\"bleu\"], Literal[\"gleu\"], Literal[\"meteor\"], Literal[\"rouge_1\"], + Literal[\"rouge_2\"], Literal[\"rouge_3\"], Literal[\"rouge_4\"], Literal[\"rouge_5\"], + Literal[\"rouge_l\"]""" + pass_threshold: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The threshold for the score. Required.""" @overload def __init__( self, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED], name: str, - deleted: bool, + input: str, + reference: str, + evaluation_metric: Literal[ + "cosine", + "fuzzy_match", + "bleu", + "gleu", + "meteor", + "rouge_1", + "rouge_2", + "rouge_3", + "rouge_4", + "rouge_5", + "rouge_l", + ], + pass_threshold: int, ) -> None: ... @overload @@ -4796,28 +4775,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type: Literal["text_similarity"] = "text_similarity" -class DeleteSkillResult(_Model): - """A deleted skill Object. +class EvalItem(_Model): + """Eval message object. - :ivar name: The unique name of the skill. Required. - :vartype name: str - :ivar deleted: Whether the skill was successfully deleted. Required. - :vartype deleted: bool + :ivar role: The role of the message input. One of ``user``, ``assistant``, ``system``, or + ``developer``. Required. Is one of the following types: Literal["user"], Literal["assistant"], + Literal["system"], Literal["developer"] + :vartype role: str or str or str or str + :ivar content: Required. Is either a "_types.EvalItemContentItem" type or a + ["_types.EvalItemContentItem"] type. + :vartype content: str or ~azure.ai.projects.models.EvalItemContentItemObject or list[str or + ~azure.ai.projects.models.EvalItemContentItemObject] + :ivar type: The type of the message input. Always ``message``. Default value is "message". + :vartype type: str """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique name of the skill. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the skill was successfully deleted. Required.""" + role: Literal["user", "assistant", "system", "developer"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The role of the message input. One of ``user``, ``assistant``, ``system``, or ``developer``. + Required. Is one of the following types: Literal[\"user\"], Literal[\"assistant\"], + Literal[\"system\"], Literal[\"developer\"]""" + content: "_types.EvalItemContent" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a \"_types.EvalItemContentItem\" type or a [\"_types.EvalItemContentItem\"] + type.""" + type: Optional[Literal["message"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The type of the message input. Always ``message``. Default value is \"message\".""" @overload def __init__( self, *, - name: str, - deleted: bool, + role: Literal["user", "assistant", "system", "developer"], + content: "_types.EvalItemContent", + type: Optional[Literal["message"]] = None, ) -> None: ... @overload @@ -4831,23 +4825,22 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Deployment(_Model): - """Model Deployment Definition. +class EvalItemContentItemObject(_Model): + """Eval content item. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ModelDeployment + InputAudio, EvalItemInputImage, EvalItemContentItemObjectInputTextContent, + EvalItemContentOutputText - :ivar type: The type of the deployment. Required. "ModelDeployment" - :vartype type: str or ~azure.ai.projects.models.DeploymentType - :ivar name: Name of the deployment. Required. - :vartype name: str + :ivar type: Required. Known values are: "input_text", "output_text", "input_image", and + "input_audio". + :vartype type: str or ~azure.ai.projects.models.EvalItemContentItemObjectType """ __mapping__: dict[str, _Model] = {} type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of the deployment. Required. \"ModelDeployment\"""" - name: str = rest_field(visibility=["read"]) - """Name of the deployment. Required.""" + """Required. Known values are: \"input_text\", \"output_text\", \"input_image\", and + \"input_audio\".""" @overload def __init__( @@ -4867,28 +4860,27 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EmbeddingConfiguration(_Model): - """Embedding configuration class. +class EvalItemContentItemObjectInputTextContent( + EvalItemContentItemObject, discriminator="input_text" +): # pylint: disable=name-too-long + """Input text. - :ivar model_deployment_name: Deployment name of embedding model. It can point to a model - deployment either in the parent AIServices or a connection. Required. - :vartype model_deployment_name: str - :ivar embedding_field: Embedding field. Required. - :vartype embedding_field: str + :ivar type: The type of the input item. Always ``input_text``. Required. INPUT_TEXT. + :vartype type: str or ~azure.ai.projects.models.INPUT_TEXT + :ivar text: The text input to the model. Required. + :vartype text: str """ - model_deployment_name: str = rest_field(name="modelDeploymentName", visibility=["create"]) - """Deployment name of embedding model. It can point to a model deployment either in the parent - AIServices or a connection. Required.""" - embedding_field: str = rest_field(name="embeddingField", visibility=["create"]) - """Embedding field. Required.""" + type: Literal[EvalItemContentItemObjectType.INPUT_TEXT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the input item. Always ``input_text``. Required. INPUT_TEXT.""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text input to the model. Required.""" @overload def __init__( self, *, - model_deployment_name: str, - embedding_field: str, + text: str, ) -> None: ... @overload @@ -4900,21 +4892,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = EvalItemContentItemObjectType.INPUT_TEXT # type: ignore -class EntraAuthorizationScheme(AgentEndpointAuthorizationScheme, discriminator="Entra"): - """EntraAuthorizationScheme. +class EvalItemContentOutputText(EvalItemContentItemObject, discriminator="output_text"): + """Output text. - :ivar type: Required. ENTRA. - :vartype type: str or ~azure.ai.projects.models.ENTRA + :ivar type: The type of the output text. Always ``output_text``. Required. OUTPUT_TEXT. + :vartype type: str or ~azure.ai.projects.models.OUTPUT_TEXT + :ivar text: The text output from the model. Required. + :vartype text: str """ - type: Literal[AgentEndpointAuthorizationSchemeType.ENTRA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. ENTRA.""" + type: Literal[EvalItemContentItemObjectType.OUTPUT_TEXT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the output text. Always ``output_text``. Required. OUTPUT_TEXT.""" + text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The text output from the model. Required.""" @overload def __init__( self, + *, + text: str, ) -> None: ... @overload @@ -4926,22 +4925,35 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = AgentEndpointAuthorizationSchemeType.ENTRA # type: ignore + self.type = EvalItemContentItemObjectType.OUTPUT_TEXT # type: ignore -class EntraIDCredentials(BaseCredentials, discriminator="AAD"): - """Entra ID credential definition. +class EvalItemInputImage(EvalItemContentItemObject, discriminator="input_image"): + """Input image. - :ivar type: The credential type. Required. Entra ID credential (formerly known as AAD). - :vartype type: str or ~azure.ai.projects.models.ENTRA_ID + :ivar type: The type of the image input. Always ``input_image``. Required. INPUT_IMAGE. + :vartype type: str or ~azure.ai.projects.models.INPUT_IMAGE + :ivar image_url: The URL of the image input. Required. + :vartype image_url: str + :ivar detail: The detail level of the image to be sent to the model. One of ``high``, ``low``, + or ``auto``. Defaults to ``auto``. + :vartype detail: str """ - type: Literal[CredentialType.ENTRA_ID] = rest_discriminator(name="type", visibility=["read"]) # type: ignore - """The credential type. Required. Entra ID credential (formerly known as AAD).""" + type: Literal[EvalItemContentItemObjectType.INPUT_IMAGE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the image input. Always ``input_image``. Required. INPUT_IMAGE.""" + image_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The URL of the image input. Required.""" + detail: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The detail level of the image to be sent to the model. One of ``high``, ``low``, or ``auto``. + Defaults to ``auto``.""" @overload def __init__( self, + *, + image_url: str, + detail: Optional[str] = None, ) -> None: ... @overload @@ -4953,7 +4965,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = CredentialType.ENTRA_ID # type: ignore + self.type = EvalItemContentItemObjectType.INPUT_IMAGE # type: ignore class EvalResult(_Model): @@ -5239,6 +5251,48 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = InsightType.EVALUATION_COMPARISON # type: ignore +class EvaluationDatasetReference(_Model): + """Reference to a dataset by name and version. + + :ivar name: Dataset name. Required. + :vartype name: str + :ivar version: Dataset version. If not provided, resolves to the latest version. + :vartype version: str + :ivar schema_file_name: Name of the schema file within the dataset's blob folder (e.g., + "a3f2b1c4_schema.json"). Optional — if not provided, schema is inferred at runtime from the + data. Only applicable for uri_folder datasets. + :vartype schema_file_name: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Dataset name. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Dataset version. If not provided, resolves to the latest version.""" + schema_file_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name of the schema file within the dataset's blob folder (e.g., \"a3f2b1c4_schema.json\"). + Optional — if not provided, schema is inferred at runtime from the data. Only applicable for + uri_folder datasets.""" + + @overload + def __init__( + self, + *, + name: str, + version: Optional[str] = None, + schema_file_name: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class InsightSample(_Model): """A sample from the analysis. @@ -5559,20 +5613,63 @@ class EvaluationScheduleTask(ScheduleTask, discriminator="Evaluation"): :vartype eval_run: any """ - type: Literal[ScheduleTaskType.EVALUATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Evaluation task.""" - eval_id: str = rest_field(name="evalId", visibility=["read", "create", "update", "delete", "query"]) - """Identifier of the evaluation group. Required.""" - eval_run: Any = rest_field(name="evalRun", visibility=["read", "create", "update", "delete", "query"]) - """The evaluation run payload. Required.""" + type: Literal[ScheduleTaskType.EVALUATION] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Evaluation task.""" + eval_id: str = rest_field(name="evalId", visibility=["read", "create", "update", "delete", "query"]) + """Identifier of the evaluation group. Required.""" + eval_run: Any = rest_field(name="evalRun", visibility=["read", "create", "update", "delete", "query"]) + """The evaluation run payload. Required.""" + + @overload + def __init__( + self, + *, + eval_id: str, + eval_run: Any, + configuration: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = ScheduleTaskType.EVALUATION # type: ignore + + +class EvaluationSuiteRunRequest(_Model): + """Request body for running an evaluation from a suite. + + :ivar evaluation_name: Name for the evaluation. Default: '{suiteName}-runs'. + :vartype evaluation_name: str + :ivar evaluation_suite_version: Evaluation suite version to run. Default: latest. + :vartype evaluation_suite_version: str + :ivar evaluation_level: Overrides the suite's default evaluation level. If omitted, uses the + level from the suite. Known values are: "turn" and "conversation". + :vartype evaluation_level: str or ~azure.ai.projects.models.EvaluationLevel + """ + + evaluation_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Name for the evaluation. Default: '{suiteName}-runs'.""" + evaluation_suite_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Evaluation suite version to run. Default: latest.""" + evaluation_level: Optional[Union[str, "_models.EvaluationLevel"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Overrides the suite's default evaluation level. If omitted, uses the level from the suite. + Known values are: \"turn\" and \"conversation\".""" @overload def __init__( self, *, - eval_id: str, - eval_run: Any, - configuration: Optional[dict[str, str]] = None, + evaluation_name: Optional[str] = None, + evaluation_suite_version: Optional[str] = None, + evaluation_level: Optional[Union[str, "_models.EvaluationLevel"]] = None, ) -> None: ... @overload @@ -5584,60 +5681,37 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = ScheduleTaskType.EVALUATION # type: ignore -class EvaluationTaxonomy(_Model): - """Evaluation Taxonomy Definition. +class EvaluationSuiteRunResponse(_Model): + """Response from running an evaluation suite. - :ivar id: Asset ID, a unique identifier for the asset. - :vartype id: str - :ivar name: The name of the resource. Required. - :vartype name: str - :ivar version: The version of the resource. Required. - :vartype version: str - :ivar description: The asset description text. - :vartype description: str - :ivar tags: Tag dictionary. Tags can be added, removed, and updated. - :vartype tags: dict[str, str] - :ivar taxonomy_input: Input configuration for the evaluation taxonomy. Required. - :vartype taxonomy_input: ~azure.ai.projects.models.EvaluationTaxonomyInput - :ivar taxonomy_categories: List of taxonomy categories. - :vartype taxonomy_categories: list[~azure.ai.projects.models.TaxonomyCategory] - :ivar properties: Additional properties for the evaluation taxonomy. - :vartype properties: dict[str, str] + :ivar evaluation_suite_name: The evaluation suite name used. Required. + :vartype evaluation_suite_name: str + :ivar evaluation_suite_version: The evaluation suite version resolved. Required. + :vartype evaluation_suite_version: str + :ivar results: The run results. Currently a single-element array; will support multiple runs in + the future. Required. + :vartype results: list[~azure.ai.projects.models.EvaluationSuiteRunResult] """ - id: Optional[str] = rest_field(visibility=["read"]) - """Asset ID, a unique identifier for the asset.""" - name: str = rest_field(visibility=["read"]) - """The name of the resource. Required.""" - version: str = rest_field(visibility=["read"]) - """The version of the resource. Required.""" - description: Optional[str] = rest_field(visibility=["create", "update"]) - """The asset description text.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) - """Tag dictionary. Tags can be added, removed, and updated.""" - taxonomy_input: "_models.EvaluationTaxonomyInput" = rest_field( - name="taxonomyInput", visibility=["read", "create", "update", "delete", "query"] - ) - """Input configuration for the evaluation taxonomy. Required.""" - taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = rest_field( - name="taxonomyCategories", visibility=["read", "create", "update", "delete", "query"] + evaluation_suite_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The evaluation suite name used. Required.""" + evaluation_suite_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The evaluation suite version resolved. Required.""" + results: list["_models.EvaluationSuiteRunResult"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """List of taxonomy categories.""" - properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Additional properties for the evaluation taxonomy.""" + """The run results. Currently a single-element array; will support multiple runs in the future. + Required.""" @overload def __init__( self, *, - taxonomy_input: "_models.EvaluationTaxonomyInput", - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, - taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = None, - properties: Optional[dict[str, str]] = None, + evaluation_suite_name: str, + evaluation_suite_version: str, + results: list["_models.EvaluationSuiteRunResult"], ) -> None: ... @overload @@ -5651,42 +5725,40 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluatorGenerationArtifacts(_Model): - """Service-managed provenance artifacts produced by an evaluator generation job. Present only on - EvaluatorVersion resources created via the generation pipeline. The combined-JSONL Foundry - Dataset is read-only and resolves to a versioned dataset in a service-reserved namespace. +class EvaluationSuiteRunResult(_Model): + """Result of a single evaluation run within a suite execution. - :ivar dataset: Reference to the single Foundry Dataset (one combined JSONL file, - version-aligned to ``EvaluatorVersion.version``) holding all artifacts produced by the - generation pipeline. Each row in the JSONL carries a ``kind`` field discriminating its content - (e.g. ``spec``, ``tools``, ``context``). Required. - :vartype dataset: ~azure.ai.projects.models.DatasetReference - :ivar kinds: The kinds of rows present in ``dataset``. Always contains ``"spec"`` (the - generated evaluation specification, a Markdown document describing what the evaluator - measures). May additionally contain ``"tools"`` (when the generation pipeline produced or - inferred OpenAI tool schemas) and/or ``"context"`` (when supplementary materials such as file - uploads or trace samples were used during generation). Required. - :vartype kinds: list[str] + :ivar eval_id: The evaluation ID created. Required. + :vartype eval_id: str + :ivar run_id: The eval run ID created. Required. + :vartype run_id: str + :ivar status: Status of the run. Required. Known values are: "queued", "in_progress", + "succeeded", "failed", and "cancelled". + :vartype status: str or ~azure.ai.projects.models.JobStatus + :ivar created_at: Timestamp when the run was created. Required. + :vartype created_at: ~datetime.datetime """ - dataset: "_models.DatasetReference" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Reference to the single Foundry Dataset (one combined JSONL file, version-aligned to - ``EvaluatorVersion.version``) holding all artifacts produced by the generation pipeline. Each - row in the JSONL carries a ``kind`` field discriminating its content (e.g. ``spec``, ``tools``, - ``context``). Required.""" - kinds: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The kinds of rows present in ``dataset``. Always contains ``\"spec\"`` (the generated - evaluation specification, a Markdown document describing what the evaluator measures). May - additionally contain ``\"tools\"`` (when the generation pipeline produced or inferred OpenAI - tool schemas) and/or ``\"context\"`` (when supplementary materials such as file uploads or - trace samples were used during generation). Required.""" + eval_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The evaluation ID created. Required.""" + run_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The eval run ID created. Required.""" + status: Union[str, "_models.JobStatus"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Status of the run. Required. Known values are: \"queued\", \"in_progress\", \"succeeded\", + \"failed\", and \"cancelled\".""" + created_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """Timestamp when the run was created. Required.""" @overload def __init__( self, *, - dataset: "_models.DatasetReference", - kinds: list[str], + eval_id: str, + run_id: str, + status: Union[str, "_models.JobStatus"], + created_at: datetime.datetime, ) -> None: ... @overload @@ -5700,61 +5772,135 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluatorGenerationInputs(_Model): - """Caller-supplied inputs for an evaluator generation job. +class EvaluationSuiteVersion(_Model): + """An evaluation suite bundles testing criteria — an optional dataset, one or more evaluator + configs with thresholds and init params — into a reusable, named artifact that can gate agent + changes across batch, scheduled, continuous, and CI/CD evals. - :ivar name: Display name for this generation job. Required. + :ivar display_name: Human-readable display name. Does not need to be unique. Shown in Foundry + portal list views and eval reports. + :vartype display_name: str + :ivar subtype: Subtype of the evaluation suite. Known values are: "default" and "benchmark". + :vartype subtype: str or ~azure.ai.projects.models.EvaluationSuiteSubtype + :ivar dataset: Dataset reference for evaluation. Optional — omit for evaluator-only suites + where data comes from live production traces or is provided at run time. The referenced dataset + must exist in the project's dataset registry. + :vartype dataset: ~azure.ai.projects.models.EvaluationDatasetReference + :ivar testing_criteria: Testing criteria — the evaluator configurations for this suite. + Supports all grader types: azure_ai_evaluator, string_check, label_model, score_model, + text_similarity, python, etc. At least one entry is required. Required. + :vartype testing_criteria: list[~azure.ai.projects.models.EvalGraderLabelModel or + ~azure.ai.projects.models.EvalGraderStringCheck or + ~azure.ai.projects.models.EvalGraderTextSimilarity or + ~azure.ai.projects.models.EvalGraderPython or ~azure.ai.projects.models.EvalGraderScoreModel or + ~azure.ai.projects.models.TestingCriterionAzureAIEvaluator] + :ivar target: Target for this evaluation suite. Uses the existing Target discriminated type + from eval runs. Supports azure_ai_agent, azure_ai_model, azure_ai_assistant. Optional — allows + suites to exist without a target. + :vartype target: ~azure.ai.projects.models.EvaluationTarget + :ivar input_messages: How to send dataset rows to the target (agent or model). Supports + template type (prompt with column placeholders) and item_reference type (column containing + pre-built messages). Is either a CreateEvalResponsesRunDataSourceInputMessagesTemplate type or + a CreateEvalCompletionsRunDataSourceInputMessagesItemReference type. + :vartype input_messages: + ~azure.ai.projects.models.CreateEvalResponsesRunDataSourceInputMessagesTemplate or + ~azure.ai.projects.models.CreateEvalCompletionsRunDataSourceInputMessagesItemReference + :ivar evaluation_level: Default evaluation level for this suite. Can be overridden at run time. + Known values are: "turn" and "conversation". + :vartype evaluation_level: str or ~azure.ai.projects.models.EvaluationLevel + :ivar name: The name of the resource. Required. :vartype name: str - :ivar sources: Source materials for generation — agent descriptions, prompts, traces, or - datasets. Each entry is an ``EvaluatorGenerationJobSource`` variant discriminated by ``type``. - Required. - :vartype sources: list[~azure.ai.projects.models.EvaluatorGenerationJobSource] - :ivar category: Category determines the rubric generation focus: 'quality' (default) produces - quality-focused rubric criteria, 'safety' produces policy-derived safety rubric criteria. Both - use the same rubric structure. Singular because quality and safety generation are mutually - exclusive pipelines — the output EvaluatorVersion.categories is an array (e.g., ['agents', - 'quality']). Known values are: "quality", "safety", and "agents". - :vartype category: str or ~azure.ai.projects.models.EvaluatorCategory - :ivar model: The LLM model to use for rubric generation (e.g., 'gpt-4o'). Required — users must - provide their own model rather than relying on service-owned capacity. Required. - :vartype model: str - :ivar evaluator_name: The evaluator name to create or update. If an evaluator with this name - already exists, the service retrieves the latest version's criteria as context for improvement. - Required. - :vartype evaluator_name: str + :ivar version: The version of the resource. Required. + :vartype version: str + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Display name for this generation job. Required.""" - sources: list["_models.EvaluatorGenerationJobSource"] = rest_field( + display_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Human-readable display name. Does not need to be unique. Shown in Foundry portal list views and + eval reports.""" + subtype: Optional[Union[str, "_models.EvaluationSuiteSubtype"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Source materials for generation — agent descriptions, prompts, traces, or datasets. Each entry - is an ``EvaluatorGenerationJobSource`` variant discriminated by ``type``. Required.""" - category: Optional[Union[str, "_models.EvaluatorCategory"]] = rest_field( + """Subtype of the evaluation suite. Known values are: \"default\" and \"benchmark\".""" + dataset: Optional["_models.EvaluationDatasetReference"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Category determines the rubric generation focus: 'quality' (default) produces quality-focused - rubric criteria, 'safety' produces policy-derived safety rubric criteria. Both use the same - rubric structure. Singular because quality and safety generation are mutually exclusive - pipelines — the output EvaluatorVersion.categories is an array (e.g., ['agents', 'quality']). - Known values are: \"quality\", \"safety\", and \"agents\".""" - model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The LLM model to use for rubric generation (e.g., 'gpt-4o'). Required — users must provide - their own model rather than relying on service-owned capacity. Required.""" - evaluator_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The evaluator name to create or update. If an evaluator with this name already exists, the - service retrieves the latest version's criteria as context for improvement. Required.""" + """Dataset reference for evaluation. Optional — omit for evaluator-only suites where data comes + from live production traces or is provided at run time. The referenced dataset must exist in + the project's dataset registry.""" + testing_criteria: list[ + Union[ + "_models.EvalGraderLabelModel", + "_models.EvalGraderStringCheck", + "_models.EvalGraderTextSimilarity", + "_models.EvalGraderPython", + "_models.EvalGraderScoreModel", + "_models.TestingCriterionAzureAIEvaluator", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Testing criteria — the evaluator configurations for this suite. Supports all grader types: + azure_ai_evaluator, string_check, label_model, score_model, text_similarity, python, etc. At + least one entry is required. Required.""" + target: Optional["_models.EvaluationTarget"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Target for this evaluation suite. Uses the existing Target discriminated type from eval runs. + Supports azure_ai_agent, azure_ai_model, azure_ai_assistant. Optional — allows suites to exist + without a target.""" + input_messages: Optional[ + Union[ + "_models.CreateEvalResponsesRunDataSourceInputMessagesTemplate", + "_models.CreateEvalCompletionsRunDataSourceInputMessagesItemReference", + ] + ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """How to send dataset rows to the target (agent or model). Supports template type (prompt with + column placeholders) and item_reference type (column containing pre-built messages). Is either + a CreateEvalResponsesRunDataSourceInputMessagesTemplate type or a + CreateEvalCompletionsRunDataSourceInputMessagesItemReference type.""" + evaluation_level: Optional[Union[str, "_models.EvaluationLevel"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Default evaluation level for this suite. Can be overridden at run time. Known values are: + \"turn\" and \"conversation\".""" + name: str = rest_field(visibility=["read"]) + """The name of the resource. Required.""" + version: str = rest_field(visibility=["read"]) + """The version of the resource. Required.""" + description: Optional[str] = rest_field(visibility=["create", "update"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) + """Tag dictionary. Tags can be added, removed, and updated.""" @overload def __init__( self, *, - name: str, - sources: list["_models.EvaluatorGenerationJobSource"], - model: str, - evaluator_name: str, - category: Optional[Union[str, "_models.EvaluatorCategory"]] = None, + testing_criteria: list[ + Union[ + "_models.EvalGraderLabelModel", + "_models.EvalGraderStringCheck", + "_models.EvalGraderTextSimilarity", + "_models.EvalGraderPython", + "_models.EvalGraderScoreModel", + "_models.TestingCriterionAzureAIEvaluator", + ] + ], + display_name: Optional[str] = None, + subtype: Optional[Union[str, "_models.EvaluationSuiteSubtype"]] = None, + dataset: Optional["_models.EvaluationDatasetReference"] = None, + target: Optional["_models.EvaluationTarget"] = None, + input_messages: Optional[ + Union[ + "_models.CreateEvalResponsesRunDataSourceInputMessagesTemplate", + "_models.CreateEvalCompletionsRunDataSourceInputMessagesItemReference", + ] + ] = None, + evaluation_level: Optional[Union[str, "_models.EvaluationLevel"]] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -5768,57 +5914,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluatorGenerationJob(_Model): - """Evaluator Generation Job resource — a long-running job that generates rubric-based evaluator - definitions from source materials. On success, the result is the persisted EvaluatorVersion. +class EvaluationSuiteVersionInputMessagesTemplate1(_Model): # pylint: disable=name-too-long + """EvaluationSuiteVersionInputMessagesTemplate1. - :ivar id: Server-assigned unique identifier. Required. - :vartype id: str - :ivar inputs: Caller-supplied inputs. - :vartype inputs: ~azure.ai.projects.models.EvaluatorGenerationInputs - :ivar result: Result produced on success. - :vartype result: ~azure.ai.projects.models.EvaluatorVersion - :ivar status: Current lifecycle status. Required. Known values are: "queued", "in_progress", - "succeeded", "failed", and "cancelled". - :vartype status: str or ~azure.ai.projects.models.JobStatus - :ivar error: Error details — populated only on failure. - :vartype error: ~azure.ai.projects.models.ApiError - :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds - since January 1, 1970). Required. - :vartype created_at: ~datetime.datetime - :ivar finished_at: The timestamp when the job finished, represented in Unix time (seconds since - January 1, 1970). - :vartype finished_at: ~datetime.datetime - :ivar usage: Token consumption summary. Populated when the job reaches a terminal state. - :vartype usage: ~azure.ai.projects.models.EvaluatorGenerationTokenUsage + :ivar role: Required. + :vartype role: str + :ivar content: Required. + :vartype content: str """ - id: str = rest_field(visibility=["read"]) - """Server-assigned unique identifier. Required.""" - inputs: Optional["_models.EvaluatorGenerationInputs"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Caller-supplied inputs.""" - result: Optional["_models.EvaluatorVersion"] = rest_field(visibility=["read"]) - """Result produced on success.""" - status: Union[str, "_models.JobStatus"] = rest_field(visibility=["read"]) - """Current lifecycle status. Required. Known values are: \"queued\", \"in_progress\", - \"succeeded\", \"failed\", and \"cancelled\".""" - error: Optional["_models.ApiError"] = rest_field(visibility=["read"]) - """Error details — populated only on failure.""" - created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") - """The timestamp when the job was created, represented in Unix time (seconds since January 1, - 1970). Required.""" - finished_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") - """The timestamp when the job finished, represented in Unix time (seconds since January 1, 1970).""" - usage: Optional["_models.EvaluatorGenerationTokenUsage"] = rest_field(visibility=["read"]) - """Token consumption summary. Populated when the job reaches a terminal state.""" + role: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + content: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" @overload def __init__( self, *, - inputs: Optional["_models.EvaluatorGenerationInputs"] = None, + role: str, + content: str, ) -> None: ... @overload @@ -5832,32 +5947,57 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluatorGenerationTokenUsage(_Model): - """Token consumption summary for an evaluator generation job. Populated when the job reaches a - terminal state. +class EvaluationTaxonomy(_Model): + """Evaluation Taxonomy Definition. - :ivar input_tokens: Number of input (prompt) tokens consumed. Required. - :vartype input_tokens: int - :ivar output_tokens: Number of output (completion) tokens generated. Required. - :vartype output_tokens: int - :ivar total_tokens: Total tokens consumed (input + output). Required. - :vartype total_tokens: int + :ivar id: Asset ID, a unique identifier for the asset. + :vartype id: str + :ivar name: The name of the resource. Required. + :vartype name: str + :ivar version: The version of the resource. Required. + :vartype version: str + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] + :ivar taxonomy_input: Input configuration for the evaluation taxonomy. Required. + :vartype taxonomy_input: ~azure.ai.projects.models.EvaluationTaxonomyInput + :ivar taxonomy_categories: List of taxonomy categories. + :vartype taxonomy_categories: list[~azure.ai.projects.models.TaxonomyCategory] + :ivar properties: Additional properties for the evaluation taxonomy. + :vartype properties: dict[str, str] """ - input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of input (prompt) tokens consumed. Required.""" - output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Number of output (completion) tokens generated. Required.""" - total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Total tokens consumed (input + output). Required.""" + id: Optional[str] = rest_field(visibility=["read"]) + """Asset ID, a unique identifier for the asset.""" + name: str = rest_field(visibility=["read"]) + """The name of the resource. Required.""" + version: str = rest_field(visibility=["read"]) + """The version of the resource. Required.""" + description: Optional[str] = rest_field(visibility=["create", "update"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) + """Tag dictionary. Tags can be added, removed, and updated.""" + taxonomy_input: "_models.EvaluationTaxonomyInput" = rest_field( + name="taxonomyInput", visibility=["read", "create", "update", "delete", "query"] + ) + """Input configuration for the evaluation taxonomy. Required.""" + taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = rest_field( + name="taxonomyCategories", visibility=["read", "create", "update", "delete", "query"] + ) + """List of taxonomy categories.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Additional properties for the evaluation taxonomy.""" @overload def __init__( self, *, - input_tokens: int, - output_tokens: int, - total_tokens: int, + taxonomy_input: "_models.EvaluationTaxonomyInput", + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = None, + properties: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -5945,10 +6085,6 @@ class EvaluatorVersion(_Model): :vartype categories: list[str or ~azure.ai.projects.models.EvaluatorCategory] :ivar definition: Definition of the evaluator. Required. :vartype definition: ~azure.ai.projects.models.EvaluatorDefinition - :ivar generation_artifacts: Provenance artifacts from the generation pipeline. Read-only; - present only on evaluator versions created via an EvaluatorGenerationJob. Each artifact - resolves to a versioned Foundry Dataset. - :vartype generation_artifacts: ~azure.ai.projects.models.EvaluatorGenerationArtifacts :ivar created_by: Creator of the evaluator. Required. :vartype created_by: str :ivar created_at: Creation date/time of the evaluator. Required. @@ -5980,10 +6116,6 @@ class EvaluatorVersion(_Model): """The categories of the evaluator. Required.""" definition: "_models.EvaluatorDefinition" = rest_field(visibility=["read", "create"]) """Definition of the evaluator. Required.""" - generation_artifacts: Optional["_models.EvaluatorGenerationArtifacts"] = rest_field(visibility=["read"]) - """Provenance artifacts from the generation pipeline. Read-only; present only on evaluator - versions created via an EvaluatorGenerationJob. Each artifact resolves to a versioned Foundry - Dataset.""" created_by: str = rest_field(visibility=["read"]) """Creator of the evaluator. Required.""" created_at: datetime.datetime = rest_field(visibility=["read"], format="rfc3339") @@ -6105,96 +6237,8 @@ def __init__( server_label: Optional[str] = None, server_url: Optional[str] = None, require_approval: Optional[Union["_models.MCPToolRequireApproval", str]] = None, - name: Optional[str] = None, - description: Optional[str] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = ToolType.FABRIC_IQ_PREVIEW # type: ignore - - -class FieldMapping(_Model): - """Field mapping configuration class. - - :ivar content_fields: List of fields with text content. Required. - :vartype content_fields: list[str] - :ivar filepath_field: Path of file to be used as a source of text content. - :vartype filepath_field: str - :ivar title_field: Field containing the title of the document. - :vartype title_field: str - :ivar url_field: Field containing the url of the document. - :vartype url_field: str - :ivar vector_fields: List of fields with vector content. - :vartype vector_fields: list[str] - :ivar metadata_fields: List of fields with metadata content. - :vartype metadata_fields: list[str] - """ - - content_fields: list[str] = rest_field(name="contentFields", visibility=["create"]) - """List of fields with text content. Required.""" - filepath_field: Optional[str] = rest_field(name="filepathField", visibility=["create"]) - """Path of file to be used as a source of text content.""" - title_field: Optional[str] = rest_field(name="titleField", visibility=["create"]) - """Field containing the title of the document.""" - url_field: Optional[str] = rest_field(name="urlField", visibility=["create"]) - """Field containing the url of the document.""" - vector_fields: Optional[list[str]] = rest_field(name="vectorFields", visibility=["create"]) - """List of fields with vector content.""" - metadata_fields: Optional[list[str]] = rest_field(name="metadataFields", visibility=["create"]) - """List of fields with metadata content.""" - - @overload - def __init__( - self, - *, - content_fields: list[str], - filepath_field: Optional[str] = None, - title_field: Optional[str] = None, - url_field: Optional[str] = None, - vector_fields: Optional[list[str]] = None, - metadata_fields: Optional[list[str]] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class FileDataGenerationJobOutput(DataGenerationJobOutput, discriminator="file"): - """Azure OpenAI file output for a data generation job. - - :ivar type: Azure OpenAI file output. Required. The generated data is an Azure OpenAI File. - :vartype type: str or ~azure.ai.projects.models.FILE - :ivar id: The id of the output Azure OpenAI file. Required. - :vartype id: str - :ivar filename: The filename of the output Azure OpenAI file. Required. - :vartype filename: str - """ - - type: Literal[DataGenerationJobOutputType.FILE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Azure OpenAI file output. Required. The generated data is an Azure OpenAI File.""" - id: str = rest_field(visibility=["read"]) - """The id of the output Azure OpenAI file. Required.""" - filename: str = rest_field(visibility=["read"]) - """The filename of the output Azure OpenAI file. Required.""" - - @overload - def __init__( - self, + name: Optional[str] = None, + description: Optional[str] = None, ) -> None: ... @overload @@ -6206,34 +6250,49 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobOutputType.FILE # type: ignore + self.type = ToolType.FABRIC_IQ_PREVIEW # type: ignore -class FileDataGenerationJobSource(DataGenerationJobSource, discriminator="file"): - """File source for data generation jobs — Azure OpenAI file input. +class FieldMapping(_Model): + """Field mapping configuration class. - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this job, which is File. Required. File source — Azure OpenAI - file. - :vartype type: str or ~azure.ai.projects.models.FILE - :ivar id: Input Azure Open AI file id used for data generation. Required. - :vartype id: str + :ivar content_fields: List of fields with text content. Required. + :vartype content_fields: list[str] + :ivar filepath_field: Path of file to be used as a source of text content. + :vartype filepath_field: str + :ivar title_field: Field containing the title of the document. + :vartype title_field: str + :ivar url_field: Field containing the url of the document. + :vartype url_field: str + :ivar vector_fields: List of fields with vector content. + :vartype vector_fields: list[str] + :ivar metadata_fields: List of fields with metadata content. + :vartype metadata_fields: list[str] """ - type: Literal[DataGenerationJobSourceType.FILE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this job, which is File. Required. File source — Azure OpenAI file.""" - id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Input Azure Open AI file id used for data generation. Required.""" + content_fields: list[str] = rest_field(name="contentFields", visibility=["create"]) + """List of fields with text content. Required.""" + filepath_field: Optional[str] = rest_field(name="filepathField", visibility=["create"]) + """Path of file to be used as a source of text content.""" + title_field: Optional[str] = rest_field(name="titleField", visibility=["create"]) + """Field containing the title of the document.""" + url_field: Optional[str] = rest_field(name="urlField", visibility=["create"]) + """Field containing the url of the document.""" + vector_fields: Optional[list[str]] = rest_field(name="vectorFields", visibility=["create"]) + """List of fields with vector content.""" + metadata_fields: Optional[list[str]] = rest_field(name="metadataFields", visibility=["create"]) + """List of fields with metadata content.""" @overload def __init__( self, *, - id: str, # pylint: disable=redefined-builtin - description: Optional[str] = None, + content_fields: list[str], + filepath_field: Optional[str] = None, + title_field: Optional[str] = None, + url_field: Optional[str] = None, + vector_fields: Optional[list[str]] = None, + metadata_fields: Optional[list[str]] = None, ) -> None: ... @overload @@ -6245,7 +6304,6 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobSourceType.FILE # type: ignore class FileDatasetVersion(DatasetVersion, discriminator="uri_file"): @@ -7216,6 +7274,72 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.media_type: Literal["application/zip"] = "application/zip" +class InputAudio(EvalItemContentItemObject, discriminator="input_audio"): + """Input audio. + + :ivar type: The type of the input item. Always ``input_audio``. Required. INPUT_AUDIO. + :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO + :ivar input_audio: Required. + :vartype input_audio: ~azure.ai.projects.models.InputAudioInputAudio + """ + + type: Literal[EvalItemContentItemObjectType.INPUT_AUDIO] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The type of the input item. Always ``input_audio``. Required. INPUT_AUDIO.""" + input_audio: "_models.InputAudioInputAudio" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + + @overload + def __init__( + self, + *, + input_audio: "_models.InputAudioInputAudio", + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = EvalItemContentItemObjectType.INPUT_AUDIO # type: ignore + + +class InputAudioInputAudio(_Model): + """InputAudioInputAudio. + + :ivar data: Required. + :vartype data: str + :ivar format: Required. Is either a Literal["mp3"] type or a Literal["wav"] type. + :vartype format: str or str + """ + + data: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required.""" + format: Literal["mp3", "wav"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Required. Is either a Literal[\"mp3\"] type or a Literal[\"wav\"] type.""" + + @overload + def __init__( + self, + *, + data: str, + format: Literal["mp3", "wav"], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class Insight(_Model): """The response body for cluster insights. @@ -8666,6 +8790,105 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class ModelPendingUploadRequest(_Model): + """Represents a request for a pending upload of a model version. + + :ivar pending_upload_id: If PendingUploadId is not provided, a random GUID will be used. + :vartype pending_upload_id: str + :ivar connection_name: Azure Storage Account connection name to use for generating temporary + SAS token. + :vartype connection_name: str + :ivar pending_upload_type: The type of pending upload. Only TemporaryBlobReference is supported + for models. Required. Temporary blob reference. + :vartype pending_upload_type: str or ~azure.ai.projects.models.TEMPORARY_BLOB_REFERENCE + """ + + pending_upload_id: Optional[str] = rest_field( + name="pendingUploadId", visibility=["read", "create", "update", "delete", "query"] + ) + """If PendingUploadId is not provided, a random GUID will be used.""" + connection_name: Optional[str] = rest_field( + name="connectionName", visibility=["read", "create", "update", "delete", "query"] + ) + """Azure Storage Account connection name to use for generating temporary SAS token.""" + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( + name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + ) + """The type of pending upload. Only TemporaryBlobReference is supported for models. Required. + Temporary blob reference.""" + + @overload + def __init__( + self, + *, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + pending_upload_id: Optional[str] = None, + connection_name: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class ModelPendingUploadResponse(_Model): + """Represents the response for a model pending upload request. + + :ivar blob_reference: Container-level read, write, list SAS. Required. + :vartype blob_reference: ~azure.ai.projects.models.BlobReference + :ivar pending_upload_id: ID for this upload request. Required. + :vartype pending_upload_id: str + :ivar version: Version of asset to be created if user did not specify version when initially + creating upload. + :vartype version: str + :ivar pending_upload_type: The type of pending upload. Only TemporaryBlobReference is supported + for models. Required. Temporary blob reference. + :vartype pending_upload_type: str or ~azure.ai.projects.models.TEMPORARY_BLOB_REFERENCE + """ + + blob_reference: "_models.BlobReference" = rest_field( + name="blobReference", visibility=["read", "create", "update", "delete", "query"] + ) + """Container-level read, write, list SAS. Required.""" + pending_upload_id: str = rest_field( + name="pendingUploadId", visibility=["read", "create", "update", "delete", "query"] + ) + """ID for this upload request. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Version of asset to be created if user did not specify version when initially creating upload.""" + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( + name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] + ) + """The type of pending upload. Only TemporaryBlobReference is supported for models. Required. + Temporary blob reference.""" + + @overload + def __init__( + self, + *, + blob_reference: "_models.BlobReference", + pending_upload_id: str, + pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + version: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class ModelSamplingParams(_Model): """Represents a set of parameters used to control the sampling behavior of a language model during text generation. @@ -9361,9 +9584,9 @@ class PendingUploadRequest(_Model): :ivar connection_name: Azure Storage Account connection name to use for generating temporary SAS token. :vartype connection_name: str - :ivar pending_upload_type: TemporaryBlobReference is the only supported type. Required. - Temporary blob reference. - :vartype pending_upload_type: str or ~azure.ai.projects.models.TEMPORARY_BLOB_REFERENCE + :ivar pending_upload_type: The type of pending upload. Required. Deprecated: the service never + read this value and silently ignored it. Use TemporaryBlobReference instead. + :vartype pending_upload_type: str or ~azure.ai.projects.models.BLOB_REFERENCE """ pending_upload_id: Optional[str] = rest_field( @@ -9374,16 +9597,17 @@ class PendingUploadRequest(_Model): name="connectionName", visibility=["read", "create", "update", "delete", "query"] ) """Azure Storage Account connection name to use for generating temporary SAS token.""" - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] = rest_field( name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] ) - """TemporaryBlobReference is the only supported type. Required. Temporary blob reference.""" + """The type of pending upload. Required. Deprecated: the service never read this value and + silently ignored it. Use TemporaryBlobReference instead.""" @overload def __init__( self, *, - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], pending_upload_id: Optional[str] = None, connection_name: Optional[str] = None, ) -> None: ... @@ -9409,9 +9633,9 @@ class PendingUploadResult(_Model): :ivar version: Version of asset to be created if user did not specify version when initially creating upload. :vartype version: str - :ivar pending_upload_type: TemporaryBlobReference is the only supported type. Required. - Temporary blob reference. - :vartype pending_upload_type: str or ~azure.ai.projects.models.TEMPORARY_BLOB_REFERENCE + :ivar pending_upload_type: The type of pending upload. Required. Deprecated: the service never + read this value and silently ignored it. Use TemporaryBlobReference instead. + :vartype pending_upload_type: str or ~azure.ai.projects.models.BLOB_REFERENCE """ blob_reference: "_models.BlobReference" = rest_field( @@ -9424,10 +9648,11 @@ class PendingUploadResult(_Model): """ID for this upload request. Required.""" version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """Version of asset to be created if user did not specify version when initially creating upload.""" - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE] = rest_field( + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE] = rest_field( name="pendingUploadType", visibility=["read", "create", "update", "delete", "query"] ) - """TemporaryBlobReference is the only supported type. Required. Temporary blob reference.""" + """The type of pending upload. Required. Deprecated: the service never read this value and + silently ignored it. Use TemporaryBlobReference instead.""" @overload def __init__( @@ -9435,7 +9660,7 @@ def __init__( *, blob_reference: "_models.BlobReference", pending_upload_id: str, - pending_upload_type: Literal[PendingUploadType.TEMPORARY_BLOB_REFERENCE], + pending_upload_type: Literal[PendingUploadType.BLOB_REFERENCE], version: Optional[str] = None, ) -> None: ... @@ -9557,105 +9782,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class PromptAgentDefinitionTextOptions(_Model): """Configuration options for a text response from the model. Can be plain text or structured JSON - data. - - :ivar format: - :vartype format: ~azure.ai.projects.models.TextResponseFormat - """ - - format: Optional["_models.TextResponseFormat"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - - @overload - def __init__( - self, - *, - format: Optional["_models.TextResponseFormat"] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class PromptBasedEvaluatorDefinition(EvaluatorDefinition, discriminator="prompt"): - """Prompt-based evaluator. - - :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. - This includes parameters like type, properties, required. - :vartype init_parameters: dict[str, any] - :ivar data_schema: The JSON schema (Draft 2020-12) for the evaluator's input data. This - includes parameters like type, properties, required. - :vartype data_schema: dict[str, any] - :ivar metrics: List of output metrics produced by this evaluator. - :vartype metrics: dict[str, ~azure.ai.projects.models.EvaluatorMetric] - :ivar type: Required. Prompt-based definition. - :vartype type: str or ~azure.ai.projects.models.PROMPT - :ivar prompt_text: The prompt text used for evaluation. Required. - :vartype prompt_text: str - """ - - type: Literal[EvaluatorDefinitionType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Prompt-based definition.""" - prompt_text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The prompt text used for evaluation. Required.""" - - @overload - def __init__( - self, - *, - prompt_text: str, - init_parameters: Optional[dict[str, Any]] = None, - data_schema: Optional[dict[str, Any]] = None, - metrics: Optional[dict[str, "_models.EvaluatorMetric"]] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = EvaluatorDefinitionType.PROMPT # type: ignore - - -class PromptDataGenerationJobSource(DataGenerationJobSource, discriminator="prompt"): - """Prompt source for data generation jobs — inline text provided by the user. - - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Prompt. Required. Prompt source — inline - text provided by the user. - :vartype type: str or ~azure.ai.projects.models.PROMPT - :ivar prompt: Inline prompt text (e.g., agent description, policy text, supplementary context). - Required. - :vartype prompt: str + data. + + :ivar format: + :vartype format: ~azure.ai.projects.models.TextResponseFormat """ - type: Literal[DataGenerationJobSourceType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Prompt. Required. Prompt source — inline text - provided by the user.""" - prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Inline prompt text (e.g., agent description, policy text, supplementary context). Required.""" + format: Optional["_models.TextResponseFormat"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) @overload def __init__( self, *, - prompt: str, - description: Optional[str] = None, + format: Optional["_models.TextResponseFormat"] = None, ) -> None: ... @overload @@ -9667,39 +9808,38 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = DataGenerationJobSourceType.PROMPT # type: ignore -class PromptEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="prompt"): - """Prompt source for evaluator generation jobs — inline text provided by the user. +class PromptBasedEvaluatorDefinition(EvaluatorDefinition, discriminator="prompt"): + """Prompt-based evaluator. - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Prompt. Required. Prompt source — inline - text provided by the user. + :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. + This includes parameters like type, properties, required. + :vartype init_parameters: dict[str, any] + :ivar data_schema: The JSON schema (Draft 2020-12) for the evaluator's input data. This + includes parameters like type, properties, required. + :vartype data_schema: dict[str, any] + :ivar metrics: List of output metrics produced by this evaluator. + :vartype metrics: dict[str, ~azure.ai.projects.models.EvaluatorMetric] + :ivar type: Required. Prompt-based definition. :vartype type: str or ~azure.ai.projects.models.PROMPT - :ivar prompt: Inline prompt text (e.g., agent description, policy text, supplementary context). - Required. - :vartype prompt: str + :ivar prompt_text: The prompt text used for evaluation. Required. + :vartype prompt_text: str """ - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of what this source represents — helps the pipeline interpret its content - (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" - type: Literal[EvaluatorGenerationJobSourceType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Prompt. Required. Prompt source — inline text - provided by the user.""" - prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Inline prompt text (e.g., agent description, policy text, supplementary context). Required.""" + type: Literal[EvaluatorDefinitionType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Prompt-based definition.""" + prompt_text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The prompt text used for evaluation. Required.""" @overload def __init__( self, *, - prompt: str, - description: Optional[str] = None, + prompt_text: str, + init_parameters: Optional[dict[str, Any]] = None, + data_schema: Optional[dict[str, Any]] = None, + metrics: Optional[dict[str, "_models.EvaluatorMetric"]] = None, ) -> None: ... @overload @@ -9711,14 +9851,14 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorGenerationJobSourceType.PROMPT # type: ignore + self.type = EvaluatorDefinitionType.PROMPT # type: ignore class ProtocolVersionRecord(_Model): """A record mapping for a single protocol and its version. :ivar protocol: The protocol type. Required. Known values are: "activity_protocol", - "responses", and "invocations". + "responses", "mcp", and "invocations". :vartype protocol: str or ~azure.ai.projects.models.AgentProtocol :ivar version: The version string for the protocol, e.g. 'v0.1.1'. Required. :vartype version: str @@ -9727,8 +9867,8 @@ class ProtocolVersionRecord(_Model): protocol: Union[str, "_models.AgentProtocol"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The protocol type. Required. Known values are: \"activity_protocol\", \"responses\", and - \"invocations\".""" + """The protocol type. Required. Known values are: \"activity_protocol\", \"responses\", \"mcp\", + and \"invocations\".""" version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The version string for the protocol, e.g. 'v0.1.1'. Required.""" @@ -10079,122 +10219,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RubricBasedEvaluatorDefinition(EvaluatorDefinition, discriminator="rubrics"): - """Rubric-based evaluator definition — stores rubric criteria produced by the generate API. Used - for both quality and safety evaluators. - - :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. - This includes parameters like type, properties, required. - :vartype init_parameters: dict[str, any] - :ivar data_schema: The JSON schema (Draft 2020-12) for the evaluator's input data. This - includes parameters like type, properties, required. - :vartype data_schema: dict[str, any] - :ivar metrics: List of output metrics produced by this evaluator. - :vartype metrics: dict[str, ~azure.ai.projects.models.EvaluatorMetric] - :ivar type: Required. Rubric-based evaluator definition. Stores rubric criteria for both - quality and safety evaluators. Can be created via the generate API or manually via - createVersion. - :vartype type: str or ~azure.ai.projects.models.RUBRICS - :ivar rubric_criteria: Rubric criteria — the scoring blueprint used by the LLM judge. Quality - evaluators include a non-editable residual criterion with rubric_id 'general_quality' - (always_applicable: true); safety evaluators include 'general_policy_compliance'. Both use the - same rubric structure. Required. - :vartype rubric_criteria: list[~azure.ai.projects.models.RubricCriterion] - """ - - type: Literal[EvaluatorDefinitionType.RUBRICS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Rubric-based evaluator definition. Stores rubric criteria for both quality and safety - evaluators. Can be created via the generate API or manually via createVersion.""" - rubric_criteria: list["_models.RubricCriterion"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Rubric criteria — the scoring blueprint used by the LLM judge. Quality evaluators include a - non-editable residual criterion with rubric_id 'general_quality' (always_applicable: true); - safety evaluators include 'general_policy_compliance'. Both use the same rubric structure. - Required.""" - - @overload - def __init__( - self, - *, - rubric_criteria: list["_models.RubricCriterion"], - init_parameters: Optional[dict[str, Any]] = None, - data_schema: Optional[dict[str, Any]] = None, - metrics: Optional[dict[str, "_models.EvaluatorMetric"]] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = EvaluatorDefinitionType.RUBRICS # type: ignore - - -class RubricCriterion(_Model): - """A single rubric criterion — one measurable quality dimension in an evaluator's scoring - blueprint. - - :ivar rubric_id: Stable identifier for this rubric criterion (snake_case, e.g., - ``correct_resolution``). Required. Provided by the user when manually creating a rubric - evaluator or during human-in-the-loop review of a generated catalog; the generation pipeline - produces an initial value the user can edit. Editable when saving new versions. Required. - :vartype rubric_id: str - :ivar description: What this criterion measures (e.g., 'Correctly identifies the user's - reservation intent and pursues the appropriate workflow'). Required. - :vartype description: str - :ivar weight: Relative weight of this criterion (1-10). The generation pipeline assigns exactly - one criterion weight 8-10; all others use 1-6. User edits are not constrained by this - heuristic. Required. - :vartype weight: int - :ivar always_applicable: When true, the LLM judge always scores this criterion regardless of - relevance (skips applicability assessment). The service-generated general quality/policy - criterion has this set to true and is non-editable. Users may set this on their own custom - criteria. - :vartype always_applicable: bool - """ - - rubric_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Stable identifier for this rubric criterion (snake_case, e.g., ``correct_resolution``). - Required. Provided by the user when manually creating a rubric evaluator or during - human-in-the-loop review of a generated catalog; the generation pipeline produces an initial - value the user can edit. Editable when saving new versions. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """What this criterion measures (e.g., 'Correctly identifies the user's reservation intent and - pursues the appropriate workflow'). Required.""" - weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Relative weight of this criterion (1-10). The generation pipeline assigns exactly one criterion - weight 8-10; all others use 1-6. User edits are not constrained by this heuristic. Required.""" - always_applicable: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """When true, the LLM judge always scores this criterion regardless of relevance (skips - applicability assessment). The service-generated general quality/policy criterion has this set - to true and is non-editable. Users may set this on their own custom criteria.""" - - @overload - def __init__( - self, - *, - rubric_id: str, - description: str, - weight: int, - always_applicable: Optional[bool] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - class SASCredentials(BaseCredentials, discriminator="SAS"): """Shared Access Signature (SAS) credential definition. @@ -10607,53 +10631,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolType.SHAREPOINT_GROUNDING_PREVIEW # type: ignore -class SimpleQnADataGenerationJobOptions(DataGenerationJobOptions, discriminator="simple_qna"): - """The options for a data generation job with SimpleQnA type. - - :ivar max_samples: Maximum number of samples to generate. Required. - :vartype max_samples: int - :ivar train_split: The proportion of the generated data to be used for training when the data - is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. - :vartype train_split: float - :ivar model_options: The LLM model options. - :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions - :ivar type: The data generation job type, which is SimpleQnA for this model. Required. Simple - question and answers between user and agent. - :vartype type: str or ~azure.ai.projects.models.SIMPLE_QNA - :ivar question_types: The question types to generate. Used only for fine-tuning scenarios. - :vartype question_types: list[str or ~azure.ai.projects.models.SimpleQnAFineTuningQuestionType] - """ - - type: Literal[DataGenerationJobType.SIMPLE_QNA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The data generation job type, which is SimpleQnA for this model. Required. Simple question and - answers between user and agent.""" - question_types: Optional[list[Union[str, "_models.SimpleQnAFineTuningQuestionType"]]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The question types to generate. Used only for fine-tuning scenarios.""" - - @overload - def __init__( - self, - *, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, - question_types: Optional[list[Union[str, "_models.SimpleQnAFineTuningQuestionType"]]] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = DataGenerationJobType.SIMPLE_QNA # type: ignore - - class SkillDetails(_Model): """A skill object. @@ -11123,6 +11100,62 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class TestingCriterionAzureAIEvaluator(_Model): + """AzureAIEvaluatorGrader. + + :ivar type: The object type, which is always ``azure_ai_evaluator``. Required. Default value is + "azure_ai_evaluator". + :vartype type: str + :ivar name: The name of the grader. Required. + :vartype name: str + :ivar evaluator_name: The name of the evaluator. Required. + :vartype evaluator_name: str + :ivar evaluator_version: The version of the evaluator. Latest version if not specified. + :vartype evaluator_version: str + :ivar initialization_parameters: The initialization parameters for the evaluation. Must support + structured outputs. + :vartype initialization_parameters: any + :ivar data_mapping: The model to use for the evaluation. Must support structured outputs. + :vartype data_mapping: dict[str, str] + """ + + type: Literal["azure_ai_evaluator"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The object type, which is always ``azure_ai_evaluator``. Required. Default value is + \"azure_ai_evaluator\".""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the grader. Required.""" + evaluator_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the evaluator. Required.""" + evaluator_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version of the evaluator. Latest version if not specified.""" + initialization_parameters: Optional[Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The initialization parameters for the evaluation. Must support structured outputs.""" + data_mapping: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The model to use for the evaluation. Must support structured outputs.""" + + @overload + def __init__( + self, + *, + name: str, + evaluator_name: str, + evaluator_version: Optional[str] = None, + initialization_parameters: Optional[Any] = None, + data_mapping: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type: Literal["azure_ai_evaluator"] = "azure_ai_evaluator" + + class TextResponseFormat(_Model): """An object specifying the format that the model must output. Configuring ``{ "type": "json_schema" }`` enables Structured Outputs, which ensures the model will match your supplied @@ -11850,237 +11883,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ToolUseFineTuningDataGenerationJobOptions( - DataGenerationJobOptions, discriminator="tool_use" -): # pylint: disable=name-too-long - """The options for a data generation job with ToolUse type. Used only for fine-tuning scenarios. - - :ivar max_samples: Maximum number of samples to generate. Required. - :vartype max_samples: int - :ivar train_split: The proportion of the generated data to be used for training when the data - is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. - :vartype train_split: float - :ivar model_options: The LLM model options. - :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions - :ivar type: The data generation job type, which is ToolUse for this model. Required. Tool - calling conversation between user and agent. - :vartype type: str or ~azure.ai.projects.models.TOOL_USE - """ - - type: Literal[DataGenerationJobType.TOOL_USE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The data generation job type, which is ToolUse for this model. Required. Tool calling - conversation between user and agent.""" - - @overload - def __init__( - self, - *, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = DataGenerationJobType.TOOL_USE # type: ignore - - -class TracesDataGenerationJobOptions(DataGenerationJobOptions, discriminator="traces"): - """The options for a data generation job with Traces type. - - :ivar max_samples: Maximum number of samples to generate. Required. - :vartype max_samples: int - :ivar train_split: The proportion of the generated data to be used for training when the data - is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. - :vartype train_split: float - :ivar model_options: The LLM model options. - :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions - :ivar type: The data generation job type, which is Traces for this model. Required. Single turn - query and response from agent traces. - :vartype type: str or ~azure.ai.projects.models.TRACES - """ - - type: Literal[DataGenerationJobType.TRACES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The data generation job type, which is Traces for this model. Required. Single turn query and - response from agent traces.""" - - @overload - def __init__( - self, - *, - max_samples: int, - train_split: Optional[float] = None, - model_options: Optional["_models.DataGenerationModelOptions"] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = DataGenerationJobType.TRACES # type: ignore - - -class TracesDataGenerationJobSource(DataGenerationJobSource, discriminator="traces"): - """Traces source for data generation jobs — conversation traces from Application Insights. - - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Traces. Required. Traces source — - conversation traces from Application Insights. - :vartype type: str or ~azure.ai.projects.models.TRACES - :ivar agent_id: The unique agent ID used to filter traces. Optional — when omitted, traces are - filtered by ``agent_name`` (and ``agent_version`` if specified). - :vartype agent_id: str - :ivar agent_name: The agent name to fetch traces for. Required. - :vartype agent_name: str - :ivar agent_version: The agent version. If not specified, traces for ALL versions of the agent - are included within the time window. - :vartype agent_version: str - :ivar start_time: Start of the time window (Unix timestamp in seconds) for fetching traces. - :vartype start_time: ~datetime.datetime - :ivar end_time: End of the time window (Unix timestamp in seconds). Defaults to current time. - :vartype end_time: ~datetime.datetime - :ivar max_traces: Maximum number of traces to retrieve. - :vartype max_traces: int - """ - - type: Literal[DataGenerationJobSourceType.TRACES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Traces. Required. Traces source — conversation traces - from Application Insights.""" - agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique agent ID used to filter traces. Optional — when omitted, traces are filtered by - ``agent_name`` (and ``agent_version`` if specified).""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent name to fetch traces for. Required.""" - agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent version. If not specified, traces for ALL versions of the agent are included within - the time window.""" - start_time: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """Start of the time window (Unix timestamp in seconds) for fetching traces.""" - end_time: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """End of the time window (Unix timestamp in seconds). Defaults to current time.""" - max_traces: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of traces to retrieve.""" - - @overload - def __init__( - self, - *, - agent_name: str, - description: Optional[str] = None, - agent_id: Optional[str] = None, - agent_version: Optional[str] = None, - start_time: Optional[datetime.datetime] = None, - end_time: Optional[datetime.datetime] = None, - max_traces: Optional[int] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = DataGenerationJobSourceType.TRACES # type: ignore - - -class TracesEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="traces"): - """Traces source for evaluator generation jobs — conversation traces from Application Insights. - - :ivar description: Optional description of what this source represents — helps the pipeline - interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core - capabilities'). - :vartype description: str - :ivar type: The source type for this source, which is Traces. Required. Traces source — - conversation traces from Application Insights. - :vartype type: str or ~azure.ai.projects.models.TRACES - :ivar agent_id: The unique agent ID used to filter traces. Optional — when omitted, traces are - filtered by ``agent_name`` (and ``agent_version`` if specified). - :vartype agent_id: str - :ivar agent_name: The agent name to fetch traces for. Required. - :vartype agent_name: str - :ivar agent_version: The agent version. If not specified, traces for ALL versions of the agent - are included within the time window. - :vartype agent_version: str - :ivar start_time: Start of the time window (Unix timestamp in seconds) for fetching traces. - :vartype start_time: ~datetime.datetime - :ivar end_time: End of the time window (Unix timestamp in seconds). Defaults to current time. - :vartype end_time: ~datetime.datetime - :ivar max_traces: Maximum number of traces to retrieve. - :vartype max_traces: int - """ - - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Optional description of what this source represents — helps the pipeline interpret its content - (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" - type: Literal[EvaluatorGenerationJobSourceType.TRACES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The source type for this source, which is Traces. Required. Traces source — conversation traces - from Application Insights.""" - agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique agent ID used to filter traces. Optional — when omitted, traces are filtered by - ``agent_name`` (and ``agent_version`` if specified).""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent name to fetch traces for. Required.""" - agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent version. If not specified, traces for ALL versions of the agent are included within - the time window.""" - start_time: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """Start of the time window (Unix timestamp in seconds) for fetching traces.""" - end_time: Optional[datetime.datetime] = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """End of the time window (Unix timestamp in seconds). Defaults to current time.""" - max_traces: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of traces to retrieve.""" - - @overload - def __init__( - self, - *, - agent_name: str, - description: Optional[str] = None, - agent_id: Optional[str] = None, - agent_version: Optional[str] = None, - start_time: Optional[datetime.datetime] = None, - end_time: Optional[datetime.datetime] = None, - max_traces: Optional[int] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = EvaluatorGenerationJobSourceType.TRACES # type: ignore - - class UpdateModelVersionRequest(_Model): """Request body for updating a model version. Only description and tags can be modified. diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py index 03b2e81ab05d..305dbad771f8 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_patch.py @@ -44,11 +44,11 @@ "evaluators": _FoundryFeaturesOptInKeys.EVALUATIONS_V1_PREVIEW.value, "insights": _FoundryFeaturesOptInKeys.INSIGHTS_V1_PREVIEW.value, "memory_stores": _FoundryFeaturesOptInKeys.MEMORY_STORES_V1_PREVIEW.value, + "models": _FoundryFeaturesOptInKeys.MODELS_V1_PREVIEW.value, "red_teams": _FoundryFeaturesOptInKeys.RED_TEAMS_V1_PREVIEW.value, "schedules": _FoundryFeaturesOptInKeys.SCHEDULES_V1_PREVIEW.value, "toolboxes": _FoundryFeaturesOptInKeys.TOOLBOXES_V1_PREVIEW.value, "skills": _FoundryFeaturesOptInKeys.SKILLS_V1_PREVIEW.value, - "datasets": _FoundryFeaturesOptInKeys.DATA_GENERATION_JOBS_V1_PREVIEW.value, "agents": ",".join( [ _AgentDefinitionOptInKeys.HOSTED_AGENTS_V1_PREVIEW.value, diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py index 1a1c0ffec86c..546fdb068dcc 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py @@ -19,6 +19,7 @@ from ._operations import DatasetsOperations # type: ignore from ._operations import DeploymentsOperations # type: ignore from ._operations import IndexesOperations # type: ignore +from ._operations import EvaluationSuitesOperations # type: ignore from ._patch import __all__ as _patch_all from ._patch import * @@ -32,6 +33,7 @@ "DatasetsOperations", "DeploymentsOperations", "IndexesOperations", + "EvaluationSuitesOperations", ] __all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index 78aa8bbfb245..b0b0bc260e45 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -798,6 +798,189 @@ def build_indexes_create_or_update_request(name: str, version: str, **kwargs: An return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) +def build_evaluation_suites_list_versions_request( # pylint: disable=name-too-long + name: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/evaluation_suites/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_evaluation_suites_list_latest_request( # pylint: disable=name-too-long + *, agent_name: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/evaluation_suites" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + if agent_name is not None: + _params["agent_name"] = _SERIALIZER.query("agent_name", agent_name, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_evaluation_suites_get_version_request( # pylint: disable=name-too-long + name: str, version: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/evaluation_suites/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_evaluation_suites_delete_version_request( # pylint: disable=name-too-long + name: str, version: str, **kwargs: Any +) -> HttpRequest: + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + # Construct URL + _url = "/evaluation_suites/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + + +def build_evaluation_suites_create_or_update_version_request( # pylint: disable=name-too-long + name: str, version: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/evaluation_suites/{name}/versions/{version}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + "version": _SERIALIZER.url("version", version, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_evaluation_suites_create_evaluation_suite_version_request( # pylint: disable=name-too-long + name: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/evaluation_suites/{name}/versions" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_evaluation_suites_run_request(name: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/evaluation_suites/{name}:run" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + def build_beta_agents_update_agent_from_code_request( # pylint: disable=name-too-long agent_name: str, *, code_zip_sha256: str, **kwargs: Any ) -> HttpRequest: @@ -1481,9 +1664,7 @@ def build_beta_evaluators_update_version_request( # pylint: disable=name-too-lo return HttpRequest(method="PATCH", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_create_generation_job_request( # pylint: disable=name-too-long - *, operation_id: Optional[str] = None, **kwargs: Any -) -> HttpRequest: +def build_beta_insights_generate_request(**kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1492,14 +1673,18 @@ def build_beta_evaluators_create_generation_job_request( # pylint: disable=name accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluator_generation_jobs" + _url = "/insights" # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers - if operation_id is not None: - _headers["Operation-Id"] = _SERIALIZER.header("operation_id", operation_id, "str") + if "Repeatability-Request-ID" not in _headers: + _headers["Repeatability-Request-ID"] = str(uuid.uuid4()) + if "Repeatability-First-Sent" not in _headers: + _headers["Repeatability-First-Sent"] = _SERIALIZER.serialize_data( + datetime.datetime.now(datetime.timezone.utc), "rfc-1123" + ) if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") @@ -1507,8 +1692,8 @@ def build_beta_evaluators_create_generation_job_request( # pylint: disable=name return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_get_generation_job_request( # pylint: disable=name-too-long - job_id: str, **kwargs: Any +def build_beta_insights_get_request( + insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -1517,14 +1702,16 @@ def build_beta_evaluators_get_generation_job_request( # pylint: disable=name-to accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluator_generation_jobs/{jobId}" + _url = "/insights/{id}" path_format_arguments = { - "jobId": _SERIALIZER.url("job_id", job_id, "str"), + "id": _SERIALIZER.url("insight_id", insight_id, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters + if include_coordinates is not None: + _params["includeCoordinates"] = _SERIALIZER.query("include_coordinates", include_coordinates, "bool") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers @@ -1533,13 +1720,13 @@ def build_beta_evaluators_get_generation_job_request( # pylint: disable=name-to return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_list_generation_jobs_request( # pylint: disable=name-too-long +def build_beta_insights_list_request( *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - after: Optional[str] = None, - before: Optional[str] = None, - category: Optional[Union[str, _models.EvaluatorCategory]] = None, + type: Optional[Union[str, _models.InsightType]] = None, + eval_id: Optional[str] = None, + run_id: Optional[str] = None, + agent_name: Optional[str] = None, + include_coordinates: Optional[bool] = None, **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) @@ -1549,19 +1736,19 @@ def build_beta_evaluators_list_generation_jobs_request( # pylint: disable=name- accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluator_generation_jobs" + _url = "/insights" # Construct parameters - if limit is not None: - _params["limit"] = _SERIALIZER.query("limit", limit, "int") - if order is not None: - _params["order"] = _SERIALIZER.query("order", order, "str") - if after is not None: - _params["after"] = _SERIALIZER.query("after", after, "str") - if before is not None: - _params["before"] = _SERIALIZER.query("before", before, "str") - if category is not None: - _params["category"] = _SERIALIZER.query("category", category, "str") + if type is not None: + _params["type"] = _SERIALIZER.query("type", type, "str") + if eval_id is not None: + _params["evalId"] = _SERIALIZER.query("eval_id", eval_id, "str") + if run_id is not None: + _params["runId"] = _SERIALIZER.query("run_id", run_id, "str") + if agent_name is not None: + _params["agentName"] = _SERIALIZER.query("agent_name", agent_name, "str") + if include_coordinates is not None: + _params["includeCoordinates"] = _SERIALIZER.query("include_coordinates", include_coordinates, "bool") _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers @@ -1570,42 +1757,40 @@ def build_beta_evaluators_list_generation_jobs_request( # pylint: disable=name- return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_cancel_generation_job_request( # pylint: disable=name-too-long - job_id: str, **kwargs: Any -) -> HttpRequest: +def build_beta_memory_stores_create_request(**kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/evaluator_generation_jobs/{jobId}:cancel" - path_format_arguments = { - "jobId": _SERIALIZER.url("job_id", job_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore + _url = "/memory_stores" # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_evaluators_delete_generation_job_request( # pylint: disable=name-too-long - job_id: str, **kwargs: Any -) -> HttpRequest: +def build_beta_memory_stores_update_request(name: str, **kwargs: Any) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + # Construct URL - _url = "/evaluator_generation_jobs/{jobId}" + _url = "/memory_stores/{name}" path_format_arguments = { - "jobId": _SERIALIZER.url("job_id", job_id, "str"), + "name": _SERIALIZER.url("name", name, "str"), } _url: str = _url.format(**path_format_arguments) # type: ignore @@ -1613,173 +1798,36 @@ def build_beta_evaluators_delete_generation_job_request( # pylint: disable=name # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + # Construct headers + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_insights_generate_request(**kwargs: Any) -> HttpRequest: + +def build_beta_memory_stores_get_request(name: str, **kwargs: Any) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) accept = _headers.pop("Accept", "application/json") # Construct URL - _url = "/insights" + _url = "/memory_stores/{name}" + path_format_arguments = { + "name": _SERIALIZER.url("name", name, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore # Construct parameters _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") # Construct headers - if "Repeatability-Request-ID" not in _headers: - _headers["Repeatability-Request-ID"] = str(uuid.uuid4()) - if "Repeatability-First-Sent" not in _headers: - _headers["Repeatability-First-Sent"] = _SERIALIZER.serialize_data( - datetime.datetime.now(datetime.timezone.utc), "rfc-1123" - ) - if content_type is not None: - _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_insights_get_request( - insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/insights/{id}" - path_format_arguments = { - "id": _SERIALIZER.url("insight_id", insight_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore - - # Construct parameters - if include_coordinates is not None: - _params["includeCoordinates"] = _SERIALIZER.query("include_coordinates", include_coordinates, "bool") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_insights_list_request( - *, - type: Optional[Union[str, _models.InsightType]] = None, - eval_id: Optional[str] = None, - run_id: Optional[str] = None, - agent_name: Optional[str] = None, - include_coordinates: Optional[bool] = None, - **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/insights" - - # Construct parameters - if type is not None: - _params["type"] = _SERIALIZER.query("type", type, "str") - if eval_id is not None: - _params["evalId"] = _SERIALIZER.query("eval_id", eval_id, "str") - if run_id is not None: - _params["runId"] = _SERIALIZER.query("run_id", run_id, "str") - if agent_name is not None: - _params["agentName"] = _SERIALIZER.query("agent_name", agent_name, "str") - if include_coordinates is not None: - _params["includeCoordinates"] = _SERIALIZER.query("include_coordinates", include_coordinates, "bool") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_memory_stores_create_request(**kwargs: Any) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/memory_stores" - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - if content_type is not None: - _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_memory_stores_update_request(name: str, **kwargs: Any) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/memory_stores/{name}" - path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - if content_type is not None: - _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_memory_stores_get_request(name: str, **kwargs: Any) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/memory_stores/{name}" - path_format_arguments = { - "name": _SERIALIZER.url("name", name, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) def build_beta_memory_stores_list_request( @@ -2048,6 +2096,8 @@ def build_beta_models_create_async_request(name: str, version: str, **kwargs: An content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + # Construct URL _url = "/models/{name}/versions/{version}/createAsync" path_format_arguments = { @@ -2063,6 +2113,7 @@ def build_beta_models_create_async_request(name: str, version: str, **kwargs: An # Construct headers if content_type is not None: _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) @@ -2739,144 +2790,6 @@ def build_beta_skills_delete_request(name: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) -def build_beta_datasets_get_generation_job_request( # pylint: disable=name-too-long - job_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/data_generation_jobs/{jobId}" - path_format_arguments = { - "jobId": _SERIALIZER.url("job_id", job_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_datasets_list_generation_jobs_request( # pylint: disable=name-too-long - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - after: Optional[str] = None, - before: Optional[str] = None, - scenario: Optional[Union[str, _models.DataGenerationJobScenario]] = None, - type: Optional[List[Union[str, _models.DataGenerationJobType]]] = None, - **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/data_generation_jobs" - - # Construct parameters - if limit is not None: - _params["limit"] = _SERIALIZER.query("limit", limit, "int") - if order is not None: - _params["order"] = _SERIALIZER.query("order", order, "str") - if after is not None: - _params["after"] = _SERIALIZER.query("after", after, "str") - if before is not None: - _params["before"] = _SERIALIZER.query("before", before, "str") - if scenario is not None: - _params["scenario"] = _SERIALIZER.query("scenario", scenario, "str") - if type is not None: - _params["type"] = _SERIALIZER.query("type", type, "[str]", div=",") - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_datasets_create_generation_job_request( # pylint: disable=name-too-long - *, operation_id: Optional[str] = None, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/data_generation_jobs" - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - if operation_id is not None: - _headers["Operation-Id"] = _SERIALIZER.header("operation_id", operation_id, "str") - if content_type is not None: - _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_datasets_cancel_generation_job_request( # pylint: disable=name-too-long - job_id: str, **kwargs: Any -) -> HttpRequest: - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - accept = _headers.pop("Accept", "application/json") - - # Construct URL - _url = "/data_generation_jobs/{jobId}:cancel" - path_format_arguments = { - "jobId": _SERIALIZER.url("job_id", job_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - # Construct headers - _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") - - return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) - - -def build_beta_datasets_delete_generation_job_request( # pylint: disable=name-too-long - job_id: str, **kwargs: Any -) -> HttpRequest: - _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) - - api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) - # Construct URL - _url = "/data_generation_jobs/{jobId}" - path_format_arguments = { - "jobId": _SERIALIZER.url("job_id", job_id, "str"), - } - - _url: str = _url.format(**path_format_arguments) # type: ignore - - # Construct parameters - _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") - - return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) - - class BetaOperations: # pylint: disable=too-many-instance-attributes """ .. warning:: @@ -2906,7 +2819,6 @@ def __init__(self, *args, **kwargs) -> None: self.schedules = BetaSchedulesOperations(self._client, self._config, self._serialize, self._deserialize) self.toolboxes = BetaToolboxesOperations(self._client, self._config, self._serialize, self._deserialize) self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) - self.datasets = BetaDatasetsOperations(self._client, self._config, self._serialize, self._deserialize) class AgentsOperations: @@ -5741,14 +5653,14 @@ def create_or_update( return deserialized # type: ignore -class BetaAgentsOperations: +class EvaluationSuitesOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`agents` attribute. + :attr:`evaluation_suites` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -5758,91 +5670,202 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - def update_agent_from_code( - self, - agent_name: str, - content: _models.CreateAgentVersionFromCodeContent, - *, - code_zip_sha256: str, - **kwargs: Any - ) -> _models.AgentDetails: - """Updates a code-based agent by uploading new code and creating a new version. If the code and - definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing - version. The request body is multipart/form-data with a JSON metadata part and a binary code - part (part order is irrelevant). Maximum upload size is 250 MB. - - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + @distributed_trace + def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.EvaluationSuiteVersion"]: + """List all versions of the given EvaluationSuiteVersion. - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :param name: The name of the resource. Required. + :type name: str + :return: An iterator like instance of EvaluationSuiteVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluationSuiteVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @overload - def update_agent_from_code( - self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any - ) -> _models.AgentDetails: - """Updates a code-based agent by uploading new code and creating a new version. If the code and - definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing - version. The request body is multipart/form-data with a JSON metadata part and a binary code - part (part order is irrelevant). Maximum upload size is 250 MB. + cls: ClsType[List[_models.EvaluationSuiteVersion]] = kwargs.pop("cls", None) - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + def prepare_request(next_link=None): + if not next_link: + + _request = build_evaluation_suites_list_versions_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluationSuiteVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def list_latest( + self, *, agent_name: Optional[str] = None, **kwargs: Any + ) -> ItemPaged["_models.EvaluationSuiteVersion"]: + """List the latest version of each EvaluationSuiteVersion. + + :keyword agent_name: Filter by associated Foundry agent name (from target). Default value is + None. + :paramtype agent_name: str + :return: An iterator like instance of EvaluationSuiteVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluationSuiteVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @distributed_trace - def update_agent_from_code( - self, - agent_name: str, - content: Union[_models.CreateAgentVersionFromCodeContent, JSON], - *, - code_zip_sha256: str, - **kwargs: Any - ) -> _models.AgentDetails: - """Updates a code-based agent by uploading new code and creating a new version. If the code and - definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing - version. The request body is multipart/form-data with a JSON metadata part and a binary code - part (part order is irrelevant). Maximum upload size is 250 MB. + cls: ClsType[List[_models.EvaluationSuiteVersion]] = kwargs.pop("cls", None) - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + def prepare_request(next_link=None): + if not next_link: + + _request = build_evaluation_suites_list_latest_request( + agent_name=agent_name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluationSuiteVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def get_version(self, name: str, version: str, **kwargs: Any) -> _models.EvaluationSuiteVersion: + """Get the specific version of the EvaluationSuiteVersion. The service returns 404 Not Found error + if the EvaluationSuiteVersion does not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to retrieve. Required. + :type version: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -5856,18 +5879,12 @@ def update_agent_from_code( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) - - _body = content.as_dict() if isinstance(content, _Model) else content - _file_fields: list[str] = ["code"] - _data_fields: list[str] = ["metadata"] - _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + cls: ClsType[_models.EvaluationSuiteVersion] = kwargs.pop("cls", None) - _request = build_beta_agents_update_agent_from_code_request( - agent_name=agent_name, - code_zip_sha256=code_zip_sha256, + _request = build_evaluation_suites_get_version_request( + name=name, + version=version, api_version=self._config.api_version, - files=_files, headers=_headers, params=_params, ) @@ -5891,106 +5908,175 @@ def update_agent_from_code( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentDetails, response.json()) + deserialized = _deserialize(_models.EvaluationSuiteVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace + def delete_version( # pylint: disable=inconsistent-return-statements + self, name: str, version: str, **kwargs: Any + ) -> None: + """Delete the specific version of the EvaluationSuiteVersion. The service returns 204 No Content + if the EvaluationSuiteVersion was deleted successfully or if the EvaluationSuiteVersion does + not exist. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluationSuiteVersion to delete. Required. + :type version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_evaluation_suites_delete_version_request( + name=name, + version=version, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + @overload - def patch_agent_details( + def create_or_update_version( self, - agent_name: str, + name: str, + version: str, + evaluation_suite_version: _models.EvaluationSuiteVersion, *, content_type: str = "application/merge-patch+json", - agent_endpoint: Optional[_models.AgentEndpointConfig] = None, - agent_card: Optional[_models.AgentCard] = None, **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. - :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig - :keyword agent_card: Optional agent card for the agent. Default value is None. - :paramtype agent_card: ~azure.ai.projects.models.AgentCard - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def patch_agent_details( - self, agent_name: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + def create_or_update_version( + self, + name: str, + version: str, + evaluation_suite_version: JSON, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :param body: Required. - :type body: JSON + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Required. + :type evaluation_suite_version: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def patch_agent_details( - self, agent_name: str, body: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + def create_or_update_version( + self, + name: str, + version: str, + evaluation_suite_version: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :param body: Required. - :type body: IO[bytes] + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Required. + :type evaluation_suite_version: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def patch_agent_details( + def create_or_update_version( self, - agent_name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - agent_endpoint: Optional[_models.AgentEndpointConfig] = None, - agent_card: Optional[_models.AgentCard] = None, + name: str, + version: str, + evaluation_suite_version: Union[_models.EvaluationSuiteVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.AgentDetails: - """Updates an agent endpoint. + ) -> _models.EvaluationSuiteVersion: + """Create a new or update an existing EvaluationSuiteVersion with the given version id. - :param agent_name: The name of the agent to retrieve. Required. - :type agent_name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. - :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig - :keyword agent_card: Optional agent card for the agent. Default value is None. - :paramtype agent_card: ~azure.ai.projects.models.AgentCard - :return: AgentDetails. The AgentDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentDetails + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluationSuiteVersion to create or update. + Required. + :type version: str + :param evaluation_suite_version: The EvaluationSuiteVersion to create or update. Is one of the + following types: EvaluationSuiteVersion, JSON, IO[bytes] Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion or JSON or + IO[bytes] + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6005,20 +6091,18 @@ def patch_agent_details( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationSuiteVersion] = kwargs.pop("cls", None) - if body is _Unset: - body = {"agent_card": agent_card, "agent_endpoint": agent_endpoint} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/merge-patch+json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(evaluation_suite_version, (IOBase, bytes)): + _content = evaluation_suite_version else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(evaluation_suite_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_patch_agent_details_request( - agent_name=agent_name, + _request = build_evaluation_suites_create_or_update_version_request( + name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -6038,23 +6122,19 @@ def patch_agent_details( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [200, 201]: if _stream: try: response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentDetails, response.json()) + deserialized = _deserialize(_models.EvaluationSuiteVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6062,81 +6142,78 @@ def patch_agent_details( return deserialized # type: ignore @overload - def create_agent_version_from_code( + def create_evaluation_suite_version( self, - agent_name: str, - content: _models.CreateAgentVersionFromCodeContent, + name: str, + evaluation_suite_version: _models.EvaluationSuiteVersion, *, - code_zip_sha256: str, + content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentVersionDetails: - """create_agent_version_from_code. - - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_agent_version_from_code( - self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any - ) -> _models.AgentVersionDetails: - """create_agent_version_from_code. + def create_evaluation_suite_version( + self, name: str, evaluation_suite_version: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Required. + :type evaluation_suite_version: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Required. - :type content: JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + @overload + def create_evaluation_suite_version( + self, name: str, evaluation_suite_version: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Required. + :type evaluation_suite_version: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_agent_version_from_code( - self, - agent_name: str, - content: Union[_models.CreateAgentVersionFromCodeContent, JSON], - *, - code_zip_sha256: str, - **kwargs: Any - ) -> _models.AgentVersionDetails: - """create_agent_version_from_code. - - :param agent_name: The unique name that identifies the agent. Name can be used to - retrieve/update/delete the agent. + def create_evaluation_suite_version( + self, name: str, evaluation_suite_version: Union[_models.EvaluationSuiteVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationSuiteVersion: + """Create a new EvaluationSuiteVersion with auto incremented version id. - * Must start and end with alphanumeric characters, - * Can contain hyphens in the middle - * Must not exceed 63 characters. Required. - :type agent_name: str - :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. - :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON - :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change - detection (dedup) and integrity verification. Required. - :paramtype code_zip_sha256: str - :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentVersionDetails + :param name: The name of the evaluation suite. Required. + :type name: str + :param evaluation_suite_version: The evaluation suite version to create. Is one of the + following types: EvaluationSuiteVersion, JSON, IO[bytes] Required. + :type evaluation_suite_version: ~azure.ai.projects.models.EvaluationSuiteVersion or JSON or + IO[bytes] + :return: EvaluationSuiteVersion. The EvaluationSuiteVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6147,21 +6224,24 @@ def create_agent_version_from_code( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.AgentVersionDetails] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluationSuiteVersion] = kwargs.pop("cls", None) - _body = content.as_dict() if isinstance(content, _Model) else content - _file_fields: list[str] = ["code"] - _data_fields: list[str] = ["metadata"] - _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + content_type = content_type or "application/json" + _content = None + if isinstance(evaluation_suite_version, (IOBase, bytes)): + _content = evaluation_suite_version + else: + _content = json.dumps(evaluation_suite_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_create_agent_version_from_code_request( - agent_name=agent_name, - code_zip_sha256=code_zip_sha256, + _request = build_evaluation_suites_create_evaluation_suite_version_request( + name=name, + content_type=content_type, api_version=self._config.api_version, - files=_files, + content=_content, headers=_headers, params=_params, ) @@ -6178,7 +6258,7 @@ def create_agent_version_from_code( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -6194,25 +6274,89 @@ def create_agent_version_from_code( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentVersionDetails, response.json()) + deserialized = _deserialize(_models.EvaluationSuiteVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + def run( + self, + name: str, + body: _models.EvaluationSuiteRunRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Required. + :type body: ~azure.ai.projects.models.EvaluationSuiteRunRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def run( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def run( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. + + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace - def download_agent_version_code(self, agent_name: str, agent_version: str, **kwargs: Any) -> Iterator[bytes]: - """Download the code zip for a specific version of a code-based hosted agent. Returns the - previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches - the ``content_hash`` on the agent version's ``code_configuration``. + def run( + self, name: str, body: Union[_models.EvaluationSuiteRunRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationSuiteRunResponse: + """Run an evaluation using the suite's testing criteria and dataset. - :param agent_name: The name of the agent. Required. - :type agent_name: str - :param agent_version: The version of the agent whose code zip should be downloaded. Required. - :type agent_version: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param name: The name of the evaluation suite. Required. + :type name: str + :param body: The run request parameters. Is one of the following types: + EvaluationSuiteRunRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.EvaluationSuiteRunRequest or JSON or IO[bytes] + :return: EvaluationSuiteRunResponse. The EvaluationSuiteRunResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationSuiteRunResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6223,15 +6367,24 @@ def download_agent_version_code(self, agent_name: str, agent_version: str, **kwa } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluationSuiteRunResponse] = kwargs.pop("cls", None) - _request = build_beta_agents_download_agent_version_code_request( - agent_name=agent_name, - agent_version=agent_version, + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_evaluation_suites_run_request( + name=name, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -6241,14 +6394,14 @@ def download_agent_version_code(self, agent_name: str, agent_version: str, **kwa _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -6261,27 +6414,119 @@ def download_agent_version_code(self, agent_name: str, agent_version: str, **kwa ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.EvaluationSuiteRunResponse, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaAgentsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`agents` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @overload + def update_agent_from_code( + self, + agent_name: str, + content: _models.CreateAgentVersionFromCodeContent, + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentDetails: + """Updates a code-based agent by uploading new code and creating a new version. If the code and + definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing + version. The request body is multipart/form-data with a JSON metadata part and a binary code + part (part order is irrelevant). Maximum upload size is 250 MB. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update_agent_from_code( + self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any + ) -> _models.AgentDetails: + """Updates a code-based agent by uploading new code and creating a new version. If the code and + definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing + version. The request body is multipart/form-data with a JSON metadata part and a binary code + part (part order is irrelevant). Maximum upload size is 250 MB. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace - def download_agent_code(self, agent_name: str, **kwargs: Any) -> Iterator[bytes]: - """Download the code zip for the latest version of a code-based hosted agent. Returns the - previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches - the ``content_hash`` on the latest version's ``code_configuration``. + def update_agent_from_code( + self, + agent_name: str, + content: Union[_models.CreateAgentVersionFromCodeContent, JSON], + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentDetails: + """Updates a code-based agent by uploading new code and creating a new version. If the code and + definition are unchanged (matched by x-ms-code-zip-sha256 header), returns the existing + version. The request body is multipart/form-data with a JSON metadata part and a binary code + part (part order is irrelevant). Maximum upload size is 250 MB. - :param agent_name: The name of the agent whose latest-version code zip should be downloaded. - Required. + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. :type agent_name: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6295,11 +6540,18 @@ def download_agent_code(self, agent_name: str, **kwargs: Any) -> Iterator[bytes] _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) - _request = build_beta_agents_download_agent_code_request( + _body = content.as_dict() if isinstance(content, _Model) else content + _file_fields: list[str] = ["code"] + _data_fields: list[str] = ["metadata"] + _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + + _request = build_beta_agents_update_agent_from_code_request( agent_name=agent_name, + code_zip_sha256=code_zip_sha256, api_version=self._config.api_version, + files=_files, headers=_headers, params=_params, ) @@ -6309,7 +6561,7 @@ def download_agent_code(self, agent_name: str, **kwargs: Any) -> Iterator[bytes] _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -6329,110 +6581,100 @@ def download_agent_code(self, agent_name: str, **kwargs: Any) -> Iterator[bytes] ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.AgentDetails, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore @overload - def create_session( + def patch_agent_details( self, agent_name: str, *, - version_indicator: _models.VersionIndicator, - content_type: str = "application/json", - agent_session_id: Optional[str] = None, + content_type: str = "application/merge-patch+json", + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, + agent_card: Optional[_models.AgentCard] = None, **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str - :keyword version_indicator: Determines which agent version backs the session. Required. - :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique - within the agent endpoint. Auto-generated if omitted. Default value is None. - :paramtype agent_session_id: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. + :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig + :keyword agent_card: Optional agent card for the agent. Default value is None. + :paramtype agent_card: ~azure.ai.projects.models.AgentCard + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_session( - self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + def patch_agent_details( + self, agent_name: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_session( - self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + def patch_agent_details( + self, agent_name: str, body: IO[bytes], *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". + Default value is "application/merge-patch+json". :paramtype content_type: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_session( + def patch_agent_details( self, agent_name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - version_indicator: _models.VersionIndicator = _Unset, - agent_session_id: Optional[str] = None, + agent_endpoint: Optional[_models.AgentEndpointConfig] = None, + agent_card: Optional[_models.AgentCard] = None, **kwargs: Any - ) -> _models.AgentSessionResource: - """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version - from ``version_indicator`` and enforces session ownership using the provided isolation key for - session-mutating operations. + ) -> _models.AgentDetails: + """Updates an agent endpoint. - :param agent_name: The name of the agent to create a session for. Required. + :param agent_name: The name of the agent to retrieve. Required. :type agent_name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword version_indicator: Determines which agent version backs the session. Required. - :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator - :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique - within the agent endpoint. Auto-generated if omitted. Default value is None. - :paramtype agent_session_id: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :keyword agent_endpoint: The endpoint configuration for the agent. Default value is None. + :paramtype agent_endpoint: ~azure.ai.projects.models.AgentEndpointConfig + :keyword agent_card: Optional agent card for the agent. Default value is None. + :paramtype agent_card: ~azure.ai.projects.models.AgentCard + :return: AgentDetails. The AgentDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6447,21 +6689,19 @@ def create_session( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentDetails] = kwargs.pop("cls", None) if body is _Unset: - if version_indicator is _Unset: - raise TypeError("missing required argument: version_indicator") - body = {"agent_session_id": agent_session_id, "version_indicator": version_indicator} + body = {"agent_card": agent_card, "agent_endpoint": agent_endpoint} body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" + content_type = content_type or "application/merge-patch+json" _content = None if isinstance(body, (IOBase, bytes)): _content = body else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_create_session_request( + _request = build_beta_agents_patch_agent_details_request( agent_name=agent_name, content_type=content_type, api_version=self._config.api_version, @@ -6482,7 +6722,7 @@ def create_session( response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -6498,23 +6738,89 @@ def create_session( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentSessionResource, response.json()) + deserialized = _deserialize(_models.AgentDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + def create_agent_version_from_code( + self, + agent_name: str, + content: _models.CreateAgentVersionFromCodeContent, + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_agent_version_from_code. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_agent_version_from_code( + self, agent_name: str, content: JSON, *, code_zip_sha256: str, **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_agent_version_from_code. + + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. + :type agent_name: str + :param content: Required. + :type content: JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace - def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _models.AgentSessionResource: - """Retrieves a session by ID. + def create_agent_version_from_code( + self, + agent_name: str, + content: Union[_models.CreateAgentVersionFromCodeContent, JSON], + *, + code_zip_sha256: str, + **kwargs: Any + ) -> _models.AgentVersionDetails: + """create_agent_version_from_code. - :param agent_name: The name of the agent. Required. + :param agent_name: The unique name that identifies the agent. Name can be used to + retrieve/update/delete the agent. + + * Must start and end with alphanumeric characters, + * Can contain hyphens in the middle + * Must not exceed 63 characters. Required. :type agent_name: str - :param session_id: The session identifier. Required. - :type session_id: str - :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.AgentSessionResource + :param content: Is either a CreateAgentVersionFromCodeContent type or a JSON type. Required. + :type content: ~azure.ai.projects.models.CreateAgentVersionFromCodeContent or JSON + :keyword code_zip_sha256: SHA-256 hex digest of the uploaded code zip. Used for change + detection (dedup) and integrity verification. Required. + :paramtype code_zip_sha256: str + :return: AgentVersionDetails. The AgentVersionDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentVersionDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6528,12 +6834,18 @@ def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _model _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentVersionDetails] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_request( + _body = content.as_dict() if isinstance(content, _Model) else content + _file_fields: list[str] = ["code"] + _data_fields: list[str] = ["metadata"] + _files = prepare_multipart_form_data(_body, _file_fields, _data_fields) + + _request = build_beta_agents_create_agent_version_from_code_request( agent_name=agent_name, - session_id=session_id, + code_zip_sha256=code_zip_sha256, api_version=self._config.api_version, + files=_files, headers=_headers, params=_params, ) @@ -6566,7 +6878,7 @@ def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _model if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.AgentSessionResource, response.json()) + deserialized = _deserialize(_models.AgentVersionDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6574,18 +6886,17 @@ def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _model return deserialized # type: ignore @distributed_trace - def delete_session( # pylint: disable=inconsistent-return-statements - self, agent_name: str, session_id: str, **kwargs: Any - ) -> None: - """Deletes a session synchronously. Returns 204 No Content when the session is deleted or does not - exist. + def download_agent_version_code(self, agent_name: str, agent_version: str, **kwargs: Any) -> Iterator[bytes]: + """Download the code zip for a specific version of a code-based hosted agent. Returns the + previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches + the ``content_hash`` on the agent version's ``code_configuration``. :param agent_name: The name of the agent. Required. :type agent_name: str - :param session_id: The session identifier. Required. - :type session_id: str - :return: None - :rtype: None + :param agent_version: The version of the agent whose code zip should be downloaded. Required. + :type agent_version: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6599,11 +6910,11 @@ def delete_session( # pylint: disable=inconsistent-return-statements _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_agents_delete_session_request( + _request = build_beta_agents_download_agent_version_code_request( agent_name=agent_name, - session_id=session_id, + agent_version=agent_version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -6613,14 +6924,20 @@ def delete_session( # pylint: disable=inconsistent-return-statements } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -6628,46 +6945,29 @@ def delete_session( # pylint: disable=inconsistent-return-statements ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @distributed_trace - def list_sessions( - self, - agent_name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.AgentSessionResource"]: - """Returns a list of sessions for the specified agent. + def download_agent_code(self, agent_name: str, **kwargs: Any) -> Iterator[bytes]: + """Download the code zip for the latest version of a code-based hosted agent. Returns the + previously-uploaded zip (``application/zip``). The SHA-256 digest of the returned bytes matches + the ``content_hash`` on the latest version's ``code_configuration``. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the agent whose latest-version code zip should be downloaded. + Required. :type agent_name: str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of AgentSessionResource - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.AgentSessionResource] + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.AgentSessionResource]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -6676,113 +6976,13 @@ def list_sessions( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - _request = build_beta_agents_list_sessions_request( - agent_name=agent_name, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.AgentSessionResource], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) - - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return ItemPaged(get_next, extract_data) - - @distributed_trace - def get_session_log_stream( - self, agent_name: str, agent_version: str, session_id: str, **kwargs: Any - ) -> _models.SessionLogEvent: - """Streams console logs (stdout / stderr) for a specific hosted agent session - as a Server-Sent Events (SSE) stream. - - Each SSE frame contains: - - * `event`: always `"log"` - * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) - - Example SSE frames: - - .. code-block:: - - event: log - data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} - - event: log - data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} - - event: log - data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} - - event: log - data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} - - The stream remains open until the client disconnects or the server - terminates the connection. Clients should handle reconnection as needed. - - :param agent_name: The name of the hosted agent. Required. - :type agent_name: str - :param agent_version: The version of the agent. Required. - :type agent_version: str - :param session_id: The session ID (maps to an ADC sandbox). Required. - :type session_id: str - :return: SessionLogEvent. The SessionLogEvent is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionLogEvent - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.SessionLogEvent] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_log_stream_request( + _request = build_beta_agents_download_agent_code_request( agent_name=agent_name, - agent_version=agent_version, - session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -6793,7 +6993,7 @@ def get_session_log_stream( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = True + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -6816,34 +7016,107 @@ def get_session_log_stream( response_headers = {} response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SessionLogEvent, response.text()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore + @overload + def create_session( + self, + agent_name: str, + *, + version_indicator: _models.VersionIndicator, + content_type: str = "application/json", + agent_session_id: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. + + :param agent_name: The name of the agent to create a session for. Required. + :type agent_name: str + :keyword version_indicator: Determines which agent version backs the session. Required. + :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique + within the agent endpoint. Auto-generated if omitted. Default value is None. + :paramtype agent_session_id: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_session( + self, agent_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. + + :param agent_name: The name of the agent to create a session for. Required. + :type agent_name: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_session( + self, agent_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. + + :param agent_name: The name of the agent to create a session for. Required. + :type agent_name: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace - def _upload_session_file( - self, agent_name: str, agent_session_id: str, content: bytes, *, path: str, **kwargs: Any - ) -> _models.SessionFileWriteResult: - """Upload a file to the session sandbox via binary stream. Maximum file size is 50 MB. Uploads - exceeding this limit return 413 Payload Too Large. + def create_session( + self, + agent_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + version_indicator: _models.VersionIndicator = _Unset, + agent_session_id: Optional[str] = None, + **kwargs: Any + ) -> _models.AgentSessionResource: + """Creates a new session for an agent endpoint. The endpoint resolves the backing agent version + from ``version_indicator`` and enforces session ownership using the provided isolation key for + session-mutating operations. - :param agent_name: The name of the agent. Required. + :param agent_name: The name of the agent to create a session for. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :param content: Required. - :type content: bytes - :keyword path: The destination file path within the sandbox, relative to the session home - directory. Required. - :paramtype path: str - :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SessionFileWriteResult + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword version_indicator: Determines which agent version backs the session. Required. + :paramtype version_indicator: ~azure.ai.projects.models.VersionIndicator + :keyword agent_session_id: Optional caller-provided session ID. If specified, it must be unique + within the agent endpoint. Auto-generated if omitted. Default value is None. + :paramtype agent_session_id: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6857,15 +7130,23 @@ def _upload_session_file( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) - cls: ClsType[_models.SessionFileWriteResult] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) - _content = content + if body is _Unset: + if version_indicator is _Unset: + raise TypeError("missing required argument: version_indicator") + body = {"agent_session_id": agent_session_id, "version_indicator": version_indicator} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_agents_upload_session_file_request( + _request = build_beta_agents_create_session_request( agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -6901,7 +7182,7 @@ def _upload_session_file( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SessionFileWriteResult, response.json()) + deserialized = _deserialize(_models.AgentSessionResource, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -6909,20 +7190,15 @@ def _upload_session_file( return deserialized # type: ignore @distributed_trace - def download_session_file( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any - ) -> Iterator[bytes]: - """Download a file from the session sandbox as a binary stream. + def get_session(self, agent_name: str, session_id: str, **kwargs: Any) -> _models.AgentSessionResource: + """Retrieves a session by ID. :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :keyword path: The file path to download from the sandbox, relative to the session home - directory. Required. - :paramtype path: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param session_id: The session identifier. Required. + :type session_id: str + :return: AgentSessionResource. The AgentSessionResource is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.AgentSessionResource :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -6936,12 +7212,11 @@ def download_session_file( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[_models.AgentSessionResource] = kwargs.pop("cls", None) - _request = build_beta_agents_download_session_file_request( + _request = build_beta_agents_get_session_request( agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, + session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -6952,7 +7227,7 @@ def download_session_file( _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -6972,29 +7247,29 @@ def download_session_file( ) raise HttpResponseError(response=response, model=error) - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - - if cls: + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.AgentSessionResource, response.json()) + + if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore @distributed_trace - def get_session_files( - self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any - ) -> _models.SessionDirectoryListResult: - """List files and directories at a given path in the session sandbox. Returns only the immediate - children of the specified directory (non-recursive). + def delete_session( # pylint: disable=inconsistent-return-statements + self, agent_name: str, session_id: str, **kwargs: Any + ) -> None: + """Deletes a session synchronously. Returns 204 No Content when the session is deleted or does not + exist. :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :keyword path: The directory path to list, relative to the session home directory. Required. - :paramtype path: str - :return: SessionDirectoryListResult. The SessionDirectoryListResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.SessionDirectoryListResult + :param session_id: The session identifier. Required. + :type session_id: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7008,12 +7283,11 @@ def get_session_files( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SessionDirectoryListResult] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_agents_get_session_files_request( + _request = build_beta_agents_delete_session_request( agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, + session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7023,20 +7297,14 @@ def get_session_files( } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -7044,37 +7312,46 @@ def get_session_files( ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SessionDirectoryListResult, response.json()) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def delete_session_file( # pylint: disable=inconsistent-return-statements - self, agent_name: str, agent_session_id: str, *, path: str, recursive: Optional[bool] = None, **kwargs: Any - ) -> None: - """Delete a file or directory from the session sandbox. If ``recursive`` is false (default) and - the target is a non-empty directory, the API returns 409 Conflict. + def list_sessions( + self, + agent_name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.AgentSessionResource"]: + """Returns a list of sessions for the specified agent. :param agent_name: The name of the agent. Required. :type agent_name: str - :param agent_session_id: The session ID. Required. - :type agent_session_id: str - :keyword path: The file or directory path to delete, relative to the session home directory. - Required. - :paramtype path: str - :keyword recursive: Whether to recursively delete directory contents. Defaults to false. + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. Default value is None. - :paramtype recursive: bool - :return: None - :rtype: None + :paramtype before: str + :return: An iterator like instance of AgentSessionResource + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.AgentSessionResource] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.AgentSessionResource]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -7083,69 +7360,94 @@ def delete_session_file( # pylint: disable=inconsistent-return-statements } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) + def prepare_request(_continuation_token=None): - _request = build_beta_agents_delete_session_file_request( - agent_name=agent_name, - agent_session_id=agent_session_id, - path=path, - recursive=recursive, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _request = build_beta_agents_list_sessions_request( + agent_name=agent_name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.AgentSessionResource], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) - response = pipeline_response.http_response + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [204]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) + response = pipeline_response.http_response - if cls: - return cls(pipeline_response, None, {}) # type: ignore + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + return pipeline_response -class BetaEvaluationTaxonomiesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + return ItemPaged(get_next, extract_data) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`evaluation_taxonomies` attribute. - """ + @distributed_trace + def get_session_log_stream( + self, agent_name: str, agent_version: str, session_id: str, **kwargs: Any + ) -> _models.SessionLogEvent: + """Streams console logs (stdout / stderr) for a specific hosted agent session + as a Server-Sent Events (SSE) stream. - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + Each SSE frame contains: - @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: - """Get an evaluation run by name. + * `event`: always `"log"` + * `data`: a plain-text log line (currently JSON-formatted, but the schema is not contractual and may include additional keys or change format over time; clients should treat it as an opaque string) - :param name: The name of the resource. Required. - :type name: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + Example SSE frames: + + .. code-block:: + + event: log + data: {"timestamp":"2026-03-10T09:33:17.121Z","stream":"stdout","message":"Starting FoundryCBAgent server on port 8088"} + + event: log + data: {"timestamp":"2026-03-10T09:33:17.130Z","stream":"stderr","message":"INFO: Application startup complete."} + + event: log + data: {"timestamp":"2026-03-10T09:34:52.714Z","stream":"status","message":"Successfully connected to container"} + + event: log + data: {"timestamp":"2026-03-10T09:35:52.714Z","stream":"status","message":"No logs since last 60 seconds"} + + The stream remains open until the client disconnects or the server + terminates the connection. Clients should handle reconnection as needed. + + :param agent_name: The name of the hosted agent. Required. + :type agent_name: str + :param agent_version: The version of the agent. Required. + :type agent_version: str + :param session_id: The session ID (maps to an ADC sandbox). Required. + :type session_id: str + :return: SessionLogEvent. The SessionLogEvent is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SessionLogEvent :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7159,10 +7461,12 @@ def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) + cls: ClsType[_models.SessionLogEvent] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_get_request( - name=name, + _request = build_beta_agents_get_session_log_stream_request( + agent_name=agent_name, + agent_version=agent_version, + session_id=session_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7173,7 +7477,7 @@ def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = True pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -7187,37 +7491,45 @@ def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) + deserialized = _deserialize(_models.SessionLogEvent, response.text()) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore @distributed_trace - def list( - self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.EvaluationTaxonomy"]: - """List evaluation taxonomies. + def _upload_session_file( + self, agent_name: str, agent_session_id: str, content: bytes, *, path: str, **kwargs: Any + ) -> _models.SessionFileWriteResult: + """Upload a file to the session sandbox via binary stream. Maximum file size is 50 MB. Uploads + exceeding this limit return 413 Payload Too Large. - :keyword input_name: Filter by the evaluation input name. Default value is None. - :paramtype input_name: str - :keyword input_type: Filter by taxonomy input type. Default value is None. - :paramtype input_type: str - :return: An iterator like instance of EvaluationTaxonomy - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluationTaxonomy] + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :param content: Required. + :type content: bytes + :keyword path: The destination file path within the sandbox, relative to the session home + directory. Required. + :paramtype path: str + :return: SessionFileWriteResult. The SessionFileWriteResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SessionFileWriteResult :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.EvaluationTaxonomy]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -7226,83 +7538,75 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - _request = build_beta_evaluation_taxonomies_list_request( - input_name=input_name, - input_type=input_type, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) + cls: ClsType[_models.SessionFileWriteResult] = kwargs.pop("cls", None) - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _content = content - return _request + _request = build_beta_agents_upload_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.EvaluationTaxonomy], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - def get_next(next_link=None): - _request = prepare_request(next_link) + response = pipeline_response.http_response - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs + if response.status_code not in [201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, ) - response = pipeline_response.http_response + raise HttpResponseError(response=response, model=error) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SessionFileWriteResult, response.json()) - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - return ItemPaged(get_next, extract_data) + return deserialized # type: ignore @distributed_trace - def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete an evaluation taxonomy by name. + def download_session_file( + self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + ) -> Iterator[bytes]: + """Download a file from the session sandbox as a binary stream. - :param name: The name of the resource. Required. - :type name: str - :return: None - :rtype: None + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :keyword path: The file path to download from the sandbox, relative to the session home + directory. Required. + :paramtype path: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7316,10 +7620,12 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_evaluation_taxonomies_delete_request( - name=name, + _request = build_beta_agents_download_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7329,87 +7635,50 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore - - @overload - def create( - self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. - - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create( - self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + deserialized = response.iter_bytes() if _decompress else response.iter_raw() - @overload - def create( - self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + return deserialized # type: ignore @distributed_trace - def create( - self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Create an evaluation taxonomy. + def get_session_files( + self, agent_name: str, agent_session_id: str, *, path: str, **kwargs: Any + ) -> _models.SessionDirectoryListResult: + """List files and directories at a given path in the session sandbox. Returns only the immediate + children of the specified directory (non-recursive). - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, - JSON, IO[bytes] Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :keyword path: The directory path to list, relative to the session home directory. Required. + :paramtype path: str + :return: SessionDirectoryListResult. The SessionDirectoryListResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.SessionDirectoryListResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7420,24 +7689,16 @@ def create( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) + cls: ClsType[_models.SessionDirectoryListResult] = kwargs.pop("cls", None) - content_type = content_type or "application/json" - _content = None - if isinstance(taxonomy, (IOBase, bytes)): - _content = taxonomy - else: - _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_evaluation_taxonomies_create_request( - name=name, - content_type=content_type, + _request = build_beta_agents_get_session_files_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -7454,90 +7715,119 @@ def create( response = pipeline_response.http_response - if response.status_code not in [200, 201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) + deserialized = _deserialize(_models.SessionDirectoryListResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def update( - self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + @distributed_trace + def delete_session_file( # pylint: disable=inconsistent-return-statements + self, agent_name: str, agent_session_id: str, *, path: str, recursive: Optional[bool] = None, **kwargs: Any + ) -> None: + """Delete a file or directory from the session sandbox. If ``recursive`` is false (default) and + the target is a non-empty directory, the API returns 409 Conflict. - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy + :param agent_name: The name of the agent. Required. + :type agent_name: str + :param agent_session_id: The session ID. Required. + :type agent_session_id: str + :keyword path: The file or directory path to delete, relative to the session home directory. + Required. + :paramtype path: str + :keyword recursive: Whether to recursively delete directory contents. Defaults to false. + Default value is None. + :paramtype recursive: bool + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - @overload - def update( - self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + cls: ClsType[None] = kwargs.pop("cls", None) - @overload - def update( - self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + _request = build_beta_agents_delete_session_file_request( + agent_name=agent_name, + agent_session_id=agent_session_id, + path=path, + recursive=recursive, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore - :param name: The name of the evaluation taxonomy. Required. - :type name: str - :param taxonomy: The evaluation taxonomy. Required. - :type taxonomy: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluationTaxonomy - :raises ~azure.core.exceptions.HttpResponseError: - """ + +class BetaEvaluationTaxonomiesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`evaluation_taxonomies` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def update( - self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluationTaxonomy: - """Update an evaluation taxonomy. + def get(self, name: str, **kwargs: Any) -> _models.EvaluationTaxonomy: + """Get an evaluation run by name. - :param name: The name of the evaluation taxonomy. Required. + :param name: The name of the resource. Required. :type name: str - :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, - JSON, IO[bytes] Required. - :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: @@ -7550,24 +7840,14 @@ def update( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) - content_type = content_type or "application/json" - _content = None - if isinstance(taxonomy, (IOBase, bytes)): - _content = taxonomy - else: - _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_evaluation_taxonomies_update_request( + _request = build_beta_evaluation_taxonomies_get_request( name=name, - content_type=content_type, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -7603,52 +7883,24 @@ def update( return deserialized # type: ignore - -class BetaEvaluatorsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`evaluators` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace - def list_versions( - self, - name: str, - *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, - **kwargs: Any - ) -> ItemPaged["_models.EvaluatorVersion"]: - """List all versions of the given evaluator. + def list( + self, *, input_name: Optional[str] = None, input_type: Optional[str] = None, **kwargs: Any + ) -> ItemPaged["_models.EvaluationTaxonomy"]: + """List evaluation taxonomies. - :param name: The name of the resource. Required. - :type name: str - :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one - of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default - value is None. - :paramtype type: str or str or str or str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. Default value is None. - :paramtype limit: int - :return: An iterator like instance of EvaluatorVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluatorVersion] + :keyword input_name: Filter by the evaluation input name. Default value is None. + :paramtype input_name: str + :keyword input_type: Filter by taxonomy input type. Default value is None. + :paramtype input_type: str + :return: An iterator like instance of EvaluationTaxonomy + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluationTaxonomy] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.EvaluationTaxonomy]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -7661,10 +7913,9 @@ def list_versions( def prepare_request(next_link=None): if not next_link: - _request = build_beta_evaluators_list_versions_request( - name=name, - type=type, - limit=limit, + _request = build_beta_evaluation_taxonomies_list_request( + input_name=input_name, + input_type=input_type, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7704,7 +7955,7 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.EvaluatorVersion], + List[_models.EvaluationTaxonomy], deserialized.get("value", []), ) if cls: @@ -7729,186 +7980,13 @@ def get_next(next_link=None): return ItemPaged(get_next, extract_data) @distributed_trace - def list( - self, - *, - type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, - limit: Optional[int] = None, - **kwargs: Any - ) -> ItemPaged["_models.EvaluatorVersion"]: - """List the latest version of each evaluator. + def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete an evaluation taxonomy by name. - :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one - of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default - value is None. - :paramtype type: str or str or str or str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the default is 20. Default value is None. - :paramtype limit: int - :return: An iterator like instance of EvaluatorVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluatorVersion] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_evaluators_list_request( - type=type, - limit=limit, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.EvaluatorVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) - - def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - return pipeline_response - - return ItemPaged(get_next, extract_data) - - @distributed_trace - def get_version(self, name: str, version: str, **kwargs: Any) -> _models.EvaluatorVersion: - """Get the specific version of the EvaluatorVersion. The service returns 404 Not Found error if - the EvaluatorVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the EvaluatorVersion to retrieve. Required. - :type version: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) - - _request = build_beta_evaluators_get_version_request( - name=name, - version=version, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def delete_version( # pylint: disable=inconsistent-return-statements - self, name: str, version: str, **kwargs: Any - ) -> None: - """Delete the specific version of the EvaluatorVersion. The service returns 204 No Content if the - EvaluatorVersion was deleted successfully or if the EvaluatorVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The version of the EvaluatorVersion to delete. Required. - :type version: str - :return: None - :rtype: None + :param name: The name of the resource. Required. + :type name: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -7924,9 +8002,8 @@ def delete_version( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_evaluators_delete_version_request( + _request = build_beta_evaluation_taxonomies_delete_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -7951,77 +8028,72 @@ def delete_version( # pylint: disable=inconsistent-return-statements return cls(pipeline_response, None, {}) # type: ignore @overload - def create_version( - self, - name: str, - evaluator_version: _models.EvaluatorVersion, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + def create( + self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_version( - self, name: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + def create( + self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: JSON + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_version( - self, name: str, evaluator_version: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + def create( + self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Required. - :type evaluator_version: IO[bytes] + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_version( - self, name: str, evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.EvaluatorVersion: - """Create a new EvaluatorVersion with auto incremented version id. + def create( + self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Create an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param evaluator_version: Is one of the following types: EvaluatorVersion, JSON, IO[bytes] - Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, + JSON, IO[bytes] Required. + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8036,16 +8108,16 @@ def create_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(evaluator_version, (IOBase, bytes)): - _content = evaluator_version + if isinstance(taxonomy, (IOBase, bytes)): + _content = taxonomy else: - _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluators_create_version_request( + _request = build_beta_evaluation_taxonomies_create_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -8066,7 +8138,7 @@ def create_version( response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200, 201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -8078,7 +8150,7 @@ def create_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -8086,96 +8158,72 @@ def create_version( return deserialized # type: ignore @overload - def update_version( - self, - name: str, - version: str, - evaluator_version: _models.EvaluatorVersion, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + def update( + self, name: str, taxonomy: _models.EvaluationTaxonomy, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update_version( - self, name: str, version: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + def update( + self, name: str, taxonomy: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Required. - :type evaluator_version: JSON + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update_version( - self, - name: str, - version: str, - evaluator_version: IO[bytes], - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + def update( + self, name: str, taxonomy: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Required. - :type evaluator_version: IO[bytes] + :param taxonomy: The evaluation taxonomy. Required. + :type taxonomy: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update_version( - self, - name: str, - version: str, - evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], - **kwargs: Any - ) -> _models.EvaluatorVersion: - """Update an existing EvaluatorVersion with the given version id. + def update( + self, name: str, taxonomy: Union[_models.EvaluationTaxonomy, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluationTaxonomy: + """Update an evaluation taxonomy. - :param name: The name of the resource. Required. + :param name: The name of the evaluation taxonomy. Required. :type name: str - :param version: The version of the EvaluatorVersion to update. Required. - :type version: str - :param evaluator_version: Evaluator resource. Is one of the following types: EvaluatorVersion, + :param taxonomy: The evaluation taxonomy. Is one of the following types: EvaluationTaxonomy, JSON, IO[bytes] Required. - :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] - :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorVersion + :type taxonomy: ~azure.ai.projects.models.EvaluationTaxonomy or JSON or IO[bytes] + :return: EvaluationTaxonomy. The EvaluationTaxonomy is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluationTaxonomy :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8190,18 +8238,17 @@ def update_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluationTaxonomy] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(evaluator_version, (IOBase, bytes)): - _content = evaluator_version + if isinstance(taxonomy, (IOBase, bytes)): + _content = taxonomy else: - _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(taxonomy, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_evaluators_update_version_request( + _request = build_beta_evaluation_taxonomies_update_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8233,112 +8280,60 @@ def update_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluatorVersion, response.json()) + deserialized = _deserialize(_models.EvaluationTaxonomy, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def create_generation_job( - self, - job: _models.EvaluatorGenerationJob, - *, - operation_id: Optional[str] = None, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. +class BetaEvaluatorsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - :param job: The job to create. Required. - :type job: ~azure.ai.projects.models.EvaluatorGenerationJob - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`evaluators` attribute. + """ - @overload - def create_generation_job( - self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. - - :param job: The job to create. Required. - :type job: JSON - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - def create_generation_job( + @distributed_trace + def list_versions( self, - job: IO[bytes], + name: str, *, - operation_id: Optional[str] = None, - content_type: str = "application/json", + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, + limit: Optional[int] = None, **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. + ) -> ItemPaged["_models.EvaluatorVersion"]: + """List all versions of the given evaluator. - :param job: The job to create. Required. - :type job: IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob + :param name: The name of the resource. Required. + :type name: str + :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one + of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default + value is None. + :paramtype type: str or str or str or str + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the default is 20. Default value is None. + :paramtype limit: int + :return: An iterator like instance of EvaluatorVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluatorVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @distributed_trace - def create_generation_job( - self, - job: Union[_models.EvaluatorGenerationJob, JSON, IO[bytes]], - *, - operation_id: Optional[str] = None, - **kwargs: Any - ) -> _models.EvaluatorGenerationJob: - """Creates an evaluator generation job. - - Creates an evaluator generation job. The service generates rubric-based evaluator definitions - from the provided source materials asynchronously. + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) - :param job: The job to create. Is one of the following types: EvaluatorGenerationJob, JSON, - IO[bytes] Required. - :type job: ~azure.ai.projects.models.EvaluatorGenerationJob or JSON or IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -8347,176 +8342,101 @@ def create_generation_job( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(job, (IOBase, bytes)): - _content = job - else: - _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + def prepare_request(next_link=None): + if not next_link: - _request = build_beta_evaluators_create_generation_job_request( - operation_id=operation_id, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _request = build_beta_evaluators_list_versions_request( + name=name, + type=type, + limit=limit, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - response = pipeline_response.http_response + return _request - if response.status_code not in [201]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.EvaluatorVersion], + deserialized.get("value", []), ) - raise HttpResponseError(response=response, model=error) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) - response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) - - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: - """Get info about an evaluator generation job. - - Gets the details of an evaluator generation job by its ID. - - :param job_id: The ID of the job. Required. - :type job_id: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) - - _request = build_beta_evaluators_get_generation_job_request( - job_id=job_id, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response + def get_next(next_link=None): + _request = prepare_request(next_link) - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + response = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return pipeline_response - return deserialized # type: ignore + return ItemPaged(get_next, extract_data) @distributed_trace - def list_generation_jobs( + def list( self, *, + type: Optional[Union[Literal["builtin"], Literal["custom"], Literal["all"], str]] = None, limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - category: Optional[Union[str, _models.EvaluatorCategory]] = None, **kwargs: Any - ) -> ItemPaged["_models.EvaluatorGenerationJob"]: - """Returns a list of evaluator generation jobs. - - Returns a list of evaluator generation jobs. + ) -> ItemPaged["_models.EvaluatorVersion"]: + """List the latest version of each evaluator. + :keyword type: Filter evaluators by type. Possible values: 'all', 'custom', 'builtin'. Is one + of the following types: Literal["builtin"], Literal["custom"], Literal["all"], str Default + value is None. + :paramtype type: str or str or str or str :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. + 100, and the default is 20. Default value is None. :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :keyword category: Filter evaluator generation jobs by category. Known values are: "quality", - "safety", and "agents". Default value is None. - :paramtype category: str or ~azure.ai.projects.models.EvaluatorCategory - :return: An iterator like instance of EvaluatorGenerationJob - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluatorGenerationJob] + :return: An iterator like instance of EvaluatorVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.EvaluatorVersion] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.EvaluatorGenerationJob]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.EvaluatorVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -8526,36 +8446,60 @@ def list_generation_jobs( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_evaluators_list_request( + type=type, + limit=limit, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_evaluators_list_generation_jobs_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - category=category, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.EvaluatorGenerationJob], - deserialized.get("data", []), + List[_models.EvaluatorVersion], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) + return deserialized.get("nextLink") or None, iter(list_of_elem) - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access @@ -8565,26 +8509,23 @@ def get_next(_continuation_token=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) return pipeline_response return ItemPaged(get_next, extract_data) @distributed_trace - def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.EvaluatorGenerationJob: - """Cancels an evaluator generation job. - - Cancels an evaluator generation job by its ID. + def get_version(self, name: str, version: str, **kwargs: Any) -> _models.EvaluatorVersion: + """Get the specific version of the EvaluatorVersion. The service returns 404 Not Found error if + the EvaluatorVersion does not exist. - :param job_id: The ID of the job to cancel. Required. - :type job_id: str - :return: EvaluatorGenerationJob. The EvaluatorGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.EvaluatorGenerationJob + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the EvaluatorVersion to retrieve. Required. + :type version: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8598,10 +8539,11 @@ def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Evaluator _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.EvaluatorGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) - _request = build_beta_evaluators_cancel_generation_job_request( - job_id=job_id, + _request = build_beta_evaluators_get_version_request( + name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -8626,16 +8568,12 @@ def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Evaluator except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.EvaluatorGenerationJob, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -8643,14 +8581,16 @@ def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.Evaluator return deserialized # type: ignore @distributed_trace - def delete_generation_job( # pylint: disable=inconsistent-return-statements - self, job_id: str, **kwargs: Any + def delete_version( # pylint: disable=inconsistent-return-statements + self, name: str, version: str, **kwargs: Any ) -> None: - """Deletes an evaluator generation job by its ID. Deletes the job record only; the generated - evaluator (if any) is preserved. + """Delete the specific version of the EvaluatorVersion. The service returns 204 No Content if the + EvaluatorVersion was deleted successfully or if the EvaluatorVersion does not exist. - :param job_id: The ID of the job to delete. Required. - :type job_id: str + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to delete. Required. + :type version: str :return: None :rtype: None :raises ~azure.core.exceptions.HttpResponseError: @@ -8668,8 +8608,9 @@ def delete_generation_job( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_evaluators_delete_generation_job_request( - job_id=job_id, + _request = build_beta_evaluators_delete_version_request( + name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -8688,89 +8629,83 @@ def delete_generation_job( # pylint: disable=inconsistent-return-statements if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if cls: return cls(pipeline_response, None, {}) # type: ignore - -class BetaInsightsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`insights` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - def generate( - self, insight: _models.Insight, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Insight: - """Generate Insights. + def create_version( + self, + name: str, + evaluator_version: _models.EvaluatorVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: ~azure.ai.projects.models.Insight + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def generate(self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.Insight: - """Generate Insights. + def create_version( + self, name: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: JSON + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Required. + :type evaluator_version: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def generate(self, insight: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.Insight: - """Generate Insights. + def create_version( + self, name: str, evaluator_version: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Required. - :type insight: IO[bytes] + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Required. + :type evaluator_version: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: - """Generate Insights. + def create_version( + self, name: str, evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.EvaluatorVersion: + """Create a new EvaluatorVersion with auto incremented version id. - :param insight: Complete evaluation configuration including data source, evaluators, and result - settings. Is one of the following types: Insight, JSON, IO[bytes] Required. - :type insight: ~azure.ai.projects.models.Insight or JSON or IO[bytes] - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :param name: The name of the resource. Required. + :type name: str + :param evaluator_version: Is one of the following types: EvaluatorVersion, JSON, IO[bytes] + Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8785,16 +8720,17 @@ def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: A _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.Insight] = kwargs.pop("cls", None) + cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(insight, (IOBase, bytes)): - _content = insight + if isinstance(evaluator_version, (IOBase, bytes)): + _content = evaluator_version else: - _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_insights_generate_request( + _request = build_beta_evaluators_create_version_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -8821,33 +8757,109 @@ def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: A except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Insight, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + def update_version( + self, + name: str, + version: str, + evaluator_version: _models.EvaluatorVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update_version( + self, name: str, version: str, evaluator_version: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Required. + :type evaluator_version: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update_version( + self, + name: str, + version: str, + evaluator_version: IO[bytes], + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Required. + :type evaluator_version: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + @distributed_trace - def get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any) -> _models.Insight: - """Get a specific insight by Id. + def update_version( + self, + name: str, + version: str, + evaluator_version: Union[_models.EvaluatorVersion, JSON, IO[bytes]], + **kwargs: Any + ) -> _models.EvaluatorVersion: + """Update an existing EvaluatorVersion with the given version id. - :param insight_id: The unique identifier for the insights report. Required. - :type insight_id: str - :keyword include_coordinates: Whether to include coordinates for visualization in the response. - Defaults to false. Default value is None. - :paramtype include_coordinates: bool - :return: Insight. The Insight is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Insight + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the EvaluatorVersion to update. Required. + :type version: str + :param evaluator_version: Evaluator resource. Is one of the following types: EvaluatorVersion, + JSON, IO[bytes] Required. + :type evaluator_version: ~azure.ai.projects.models.EvaluatorVersion or JSON or IO[bytes] + :return: EvaluatorVersion. The EvaluatorVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.EvaluatorVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -8858,15 +8870,25 @@ def get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, ** } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Insight] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.EvaluatorVersion] = kwargs.pop("cls", None) - _request = build_beta_insights_get_request( - insight_id=insight_id, - include_coordinates=include_coordinates, + content_type = content_type or "application/json" + _content = None + if isinstance(evaluator_version, (IOBase, bytes)): + _content = evaluator_version + else: + _content = json.dumps(evaluator_version, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_evaluators_update_version_request( + name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -8890,246 +8912,92 @@ def get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, ** except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Insight, response.json()) + deserialized = _deserialize(_models.EvaluatorVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( - self, - *, - type: Optional[Union[str, _models.InsightType]] = None, - eval_id: Optional[str] = None, - run_id: Optional[str] = None, - agent_name: Optional[str] = None, - include_coordinates: Optional[bool] = None, - **kwargs: Any - ) -> ItemPaged["_models.Insight"]: - """List all insights in reverse chronological order (newest first). - :keyword type: Filter by the type of analysis. Known values are: "EvaluationRunClusterInsight", - "AgentClusterInsight", and "EvaluationComparison". Default value is None. - :paramtype type: str or ~azure.ai.projects.models.InsightType - :keyword eval_id: Filter by the evaluation ID. Default value is None. - :paramtype eval_id: str - :keyword run_id: Filter by the evaluation run ID. Default value is None. - :paramtype run_id: str - :keyword agent_name: Filter by the agent name. Default value is None. - :paramtype agent_name: str - :keyword include_coordinates: Whether to include coordinates for visualization in the response. - Defaults to false. Default value is None. - :paramtype include_coordinates: bool - :return: An iterator like instance of Insight - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Insight] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} +class BetaInsightsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`insights` attribute. + """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - def prepare_request(next_link=None): - if not next_link: + @overload + def generate( + self, insight: _models.Insight, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Insight: + """Generate Insights. - _request = build_beta_insights_list_request( - type=type, - eval_id=eval_id, - run_id=run_id, - agent_name=agent_name, - include_coordinates=include_coordinates, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Insight], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) - - def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return ItemPaged(get_next, extract_data) - - -class BetaMemoryStoresOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`memory_stores` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - - @overload - def create( - self, - *, - name: str, - definition: _models.MemoryStoreDefinition, - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. - - :keyword name: The name of the memory store. Required. - :paramtype name: str - :keyword definition: The memory store definition. Required. - :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Required. + :type insight: ~azure.ai.projects.models.Insight :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create( - self, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + def generate(self, insight: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.Insight: + """Generate Insights. - :param body: Required. - :type body: JSON + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Required. + :type insight: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create( - self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + def generate(self, insight: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.Insight: + """Generate Insights. - :param body: Required. - :type body: IO[bytes] + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Required. + :type insight: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create( - self, - body: Union[JSON, IO[bytes]] = _Unset, - *, - name: str = _Unset, - definition: _models.MemoryStoreDefinition = _Unset, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Create a memory store. + def generate(self, insight: Union[_models.Insight, JSON, IO[bytes]], **kwargs: Any) -> _models.Insight: + """Generate Insights. - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword name: The name of the memory store. Required. - :paramtype name: str - :keyword definition: The memory store definition. Required. - :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :param insight: Complete evaluation configuration including data source, evaluators, and result + settings. Is one of the following types: Insight, JSON, IO[bytes] Required. + :type insight: ~azure.ai.projects.models.Insight or JSON or IO[bytes] + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9144,23 +9012,16 @@ def create( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.Insight] = kwargs.pop("cls", None) - if body is _Unset: - if name is _Unset: - raise TypeError("missing required argument: name") - if definition is _Unset: - raise TypeError("missing required argument: definition") - body = {"definition": definition, "description": description, "metadata": metadata, "name": name} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(insight, (IOBase, bytes)): + _content = insight else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(insight, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_create_request( + _request = build_beta_insights_generate_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -9180,7 +9041,7 @@ def create( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -9196,194 +9057,42 @@ def create( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def update( - self, - name: str, - *, - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + @distributed_trace + def get(self, insight_id: str, *, include_coordinates: Optional[bool] = None, **kwargs: Any) -> _models.Insight: + """Get a specific insight by Id. - :param name: The name of the memory store to update. Required. - :type name: str - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :param insight_id: The unique identifier for the insights report. Required. + :type insight_id: str + :keyword include_coordinates: Whether to include coordinates for visualization in the response. + Defaults to false. Default value is None. + :paramtype include_coordinates: bool + :return: Insight. The Insight is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Insight :raises ~azure.core.exceptions.HttpResponseError: """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - @overload - def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ + cls: ClsType[_models.Insight] = kwargs.pop("cls", None) - @overload - def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. - - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @distributed_trace - def update( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.MemoryStoreDetails: - """Update a memory store. - - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword description: A human-readable description of the memory store. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default - value is None. - :paramtype metadata: dict[str, str] - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - - if body is _Unset: - body = {"description": description, "metadata": metadata} - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_update_request( - name=name, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: - """Retrieve a memory store. - - :param name: The name of the memory store to retrieve. Required. - :type name: str - :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - - _request = build_beta_memory_stores_get_request( - name=name, + _request = build_beta_insights_get_request( + insight_id=insight_id, + include_coordinates=include_coordinates, api_version=self._config.api_version, headers=_headers, params=_params, @@ -9417,7 +9126,7 @@ def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) + deserialized = _deserialize(_models.Insight, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -9428,35 +9137,35 @@ def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: def list( self, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + type: Optional[Union[str, _models.InsightType]] = None, + eval_id: Optional[str] = None, + run_id: Optional[str] = None, + agent_name: Optional[str] = None, + include_coordinates: Optional[bool] = None, **kwargs: Any - ) -> ItemPaged["_models.MemoryStoreDetails"]: - """List all memory stores. + ) -> ItemPaged["_models.Insight"]: + """List all insights in reverse chronological order (newest first). - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of MemoryStoreDetails - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.MemoryStoreDetails] + :keyword type: Filter by the type of analysis. Known values are: "EvaluationRunClusterInsight", + "AgentClusterInsight", and "EvaluationComparison". Default value is None. + :paramtype type: str or ~azure.ai.projects.models.InsightType + :keyword eval_id: Filter by the evaluation ID. Default value is None. + :paramtype eval_id: str + :keyword run_id: Filter by the evaluation run ID. Default value is None. + :paramtype run_id: str + :keyword agent_name: Filter by the agent name. Default value is None. + :paramtype agent_name: str + :keyword include_coordinates: Whether to include coordinates for visualization in the response. + Defaults to false. Default value is None. + :paramtype include_coordinates: bool + :return: An iterator like instance of Insight + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Insight] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.MemoryStoreDetails]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Insight]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -9466,35 +9175,63 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_insights_list_request( + type=type, + eval_id=eval_id, + run_id=run_id, + agent_name=agent_name, + include_coordinates=include_coordinates, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_memory_stores_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.MemoryStoreDetails], - deserialized.get("data", []), + List[_models.Insight], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) + return deserialized.get("nextLink") or None, iter(list_of_elem) - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access @@ -9514,477 +9251,112 @@ def get_next(_continuation_token=None): return ItemPaged(get_next, extract_data) - @distributed_trace - def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: - """Delete a memory store. - :param name: The name of the memory store to delete. Required. - :type name: str - :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.DeleteMemoryStoreResult] = kwargs.pop("cls", None) - - _request = build_beta_memory_stores_delete_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DeleteMemoryStoreResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @overload - def _search_memories( - self, - name: str, - *, - scope: str, - content_type: str = "application/json", - items: Optional[List[dict[str, Any]]] = None, - previous_search_id: Optional[str] = None, - options: Optional[_models.MemorySearchOptions] = None, - **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... - @overload - def _search_memories( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... - @overload - def _search_memories( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreSearchResult: ... - - @distributed_trace - def _search_memories( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_search_id: Optional[str] = None, - options: Optional[_models.MemorySearchOptions] = None, - **kwargs: Any - ) -> _models.MemoryStoreSearchResult: - """Search for relevant memories from a memory store based on conversation context. - - :param name: The name of the memory store to search. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. - Required. - :paramtype scope: str - :keyword items: Items for which to search for relevant memories. Default value is None. - :paramtype items: list[dict[str, any]] - :keyword previous_search_id: The unique ID of the previous search request, enabling incremental - memory search from where the last operation left off. Default value is None. - :paramtype previous_search_id: str - :keyword options: Memory search options. Default value is None. - :paramtype options: ~azure.ai.projects.models.MemorySearchOptions - :return: MemoryStoreSearchResult. The MemoryStoreSearchResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreSearchResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreSearchResult] = kwargs.pop("cls", None) - - if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = { - "items": items, - "options": options, - "previous_search_id": previous_search_id, - "scope": scope, - } - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_search_memories_request( - name=name, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.MemoryStoreSearchResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - def _update_memories_initial( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_update_id: Optional[str] = None, - update_delay: Optional[int] = None, - **kwargs: Any - ) -> Iterator[bytes]: - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - - if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = { - "items": items, - "previous_update_id": previous_update_id, - "scope": scope, - "update_delay": update_delay, - } - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - - _request = build_beta_memory_stores_update_memories_request( - name=name, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = True - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [202]: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @overload - def _begin_update_memories( - self, - name: str, - *, - scope: str, - content_type: str = "application/json", - items: Optional[List[dict[str, Any]]] = None, - previous_update_id: Optional[str] = None, - update_delay: Optional[int] = None, - **kwargs: Any - ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: ... - @overload - def _begin_update_memories( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: ... - @overload - def _begin_update_memories( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: ... - - @distributed_trace - def _begin_update_memories( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - scope: str = _Unset, - items: Optional[List[dict[str, Any]]] = None, - previous_update_id: Optional[str] = None, - update_delay: Optional[int] = None, - **kwargs: Any - ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: - """Update memory store with conversation memories. - - :param name: The name of the memory store to update. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. - Required. - :paramtype scope: str - :keyword items: Conversation items to be stored in memory. Default value is None. - :paramtype items: list[dict[str, any]] - :keyword previous_update_id: The unique ID of the previous update request, enabling incremental - memory updates from where the last operation left off. Default value is None. - :paramtype previous_update_id: str - :keyword update_delay: Timeout period before processing the memory update in seconds. - If a new update request is received during this period, it will cancel the current request and - reset the timeout. - Set to 0 to immediately trigger the update without delay. - Defaults to 300 (5 minutes). Default value is None. - :paramtype update_delay: int - :return: An instance of LROPoller that returns MemoryStoreUpdateCompletedResult. The - MemoryStoreUpdateCompletedResult is compatible with MutableMapping - :rtype: - ~azure.core.polling.LROPoller[~azure.ai.projects.models.MemoryStoreUpdateCompletedResult] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreUpdateCompletedResult] = kwargs.pop("cls", None) - polling: Union[bool, PollingMethod] = kwargs.pop("polling", True) - lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) - cont_token: Optional[str] = kwargs.pop("continuation_token", None) - if cont_token is None: - raw_result = self._update_memories_initial( - name=name, - body=body, - scope=scope, - items=items, - previous_update_id=previous_update_id, - update_delay=update_delay, - content_type=content_type, - cls=lambda x, y, z: x, - headers=_headers, - params=_params, - **kwargs - ) - raw_result.http_response.read() # type: ignore - kwargs.pop("error_map", None) - - def get_long_running_output(pipeline_response): - response_headers = {} - response = pipeline_response.http_response - response_headers["Operation-Location"] = self._deserialize( - "str", response.headers.get("Operation-Location") - ) - - deserialized = _deserialize(_models.MemoryStoreUpdateCompletedResult, response.json().get("result", {})) - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - return deserialized +class BetaMemoryStoresOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`memory_stores` attribute. + """ - if polling is True: - polling_method: PollingMethod = cast( - PollingMethod, LROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) - ) - elif polling is False: - polling_method = cast(PollingMethod, NoPolling()) - else: - polling_method = polling - if cont_token: - return LROPoller[_models.MemoryStoreUpdateCompletedResult].from_continuation_token( - polling_method=polling_method, - continuation_token=cont_token, - client=self._client, - deserialization_callback=get_long_running_output, - ) - return LROPoller[_models.MemoryStoreUpdateCompletedResult]( - self._client, raw_result, get_long_running_output, polling_method # type: ignore - ) + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @overload - def delete_scope( - self, name: str, *, scope: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + def create( + self, + *, + name: str, + definition: _models.MemoryStoreDefinition, + content_type: str = "application/json", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str - :keyword scope: The namespace that logically groups and isolates memories to delete, such as a - user ID. Required. - :paramtype scope: str + :keyword name: The name of the memory store. Required. + :paramtype name: str + :keyword definition: The memory store definition. Required. + :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def delete_scope( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + def create( + self, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def delete_scope( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + def create( + self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def delete_scope( - self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, scope: str = _Unset, **kwargs: Any - ) -> _models.MemoryStoreDeleteScopeResult: - """Delete all memories associated with a specific scope from a memory store. + def create( + self, + body: Union[JSON, IO[bytes]] = _Unset, + *, + name: str = _Unset, + definition: _models.MemoryStoreDefinition = _Unset, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Create a memory store. - :param name: The name of the memory store. Required. - :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword scope: The namespace that logically groups and isolates memories to delete, such as a - user ID. Required. - :paramtype scope: str - :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult + :keyword name: The name of the memory store. Required. + :paramtype name: str + :keyword definition: The memory store definition. Required. + :paramtype definition: ~azure.ai.projects.models.MemoryStoreDefinition + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -9999,12 +9371,14 @@ def delete_scope( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.MemoryStoreDeleteScopeResult] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) if body is _Unset: - if scope is _Unset: - raise TypeError("missing required argument: scope") - body = {"scope": scope} + if name is _Unset: + raise TypeError("missing required argument: name") + if definition is _Unset: + raise TypeError("missing required argument: definition") + body = {"definition": definition, "description": description, "metadata": metadata, "name": name} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -10013,8 +9387,7 @@ def delete_scope( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_memory_stores_delete_scope_request( - name=name, + _request = build_beta_memory_stores_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10050,135 +9423,101 @@ def delete_scope( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.MemoryStoreDeleteScopeResult, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @overload + def update( + self, + name: str, + *, + content_type: str = "application/json", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. -class BetaModelsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`models` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - - @distributed_trace - def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: - """List all versions of the given ModelVersion. - - :param name: The name of the resource. Required. + :param name: The name of the memory store to update. Required. :type name: str - :return: An iterator like instance of ModelVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_models_list_versions_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ModelVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) - - def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - return pipeline_response + @overload + def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. - return ItemPaged(get_next, extract_data) + :param name: The name of the memory store to update. Required. + :type name: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ - @distributed_trace - def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: - """List the latest version of each ModelVersion. + @overload + def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. - :return: An iterator like instance of ModelVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] + :param name: The name of the memory store to update. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + @distributed_trace + def update( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.MemoryStoreDetails: + """Update a memory store. + :param name: The name of the memory store to update. Required. + :type name: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword description: A human-readable description of the memory store. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the memory store. Default + value is None. + :paramtype metadata: dict[str, str] + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -10187,84 +9526,74 @@ def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - _request = build_beta_models_list_request( - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + if body is _Unset: + body = {"description": description, "metadata": metadata} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - return _request + _request = build_beta_memory_stores_update_request( + name=name, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ModelVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - def get_next(next_link=None): - _request = prepare_request(next_link) + response = pipeline_response.http_response - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, ) - response = pipeline_response.http_response + raise HttpResponseError(response=response, model=error) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - return ItemPaged(get_next, extract_data) + return deserialized # type: ignore @distributed_trace - def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: - """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the - ModelVersion does not exist. + def get(self, name: str, **kwargs: Any) -> _models.MemoryStoreDetails: + """Retrieve a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store to retrieve. Required. :type name: str - :param version: The specific version id of the ModelVersion to retrieve. Required. - :type version: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :return: MemoryStoreDetails. The MemoryStoreDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10278,11 +9607,10 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreDetails] = kwargs.pop("cls", None) - _request = build_beta_models_get_request( + _request = build_beta_memory_stores_get_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -10307,29 +9635,120 @@ def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ModelVersion, response.json()) + deserialized = _deserialize(_models.MemoryStoreDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.MemoryStoreDetails"]: + """List all memory stores. + + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of MemoryStoreDetails + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.MemoryStoreDetails] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.MemoryStoreDetails]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_memory_stores_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.MemoryStoreDetails], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return pipeline_response - return deserialized # type: ignore + return ItemPaged(get_next, extract_data) @distributed_trace - def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete the specific version of the ModelVersion. The service returns 204 No Content if the - ModelVersion was deleted successfully or if the ModelVersion does not exist. + def delete(self, name: str, **kwargs: Any) -> _models.DeleteMemoryStoreResult: + """Delete a memory store. - :param name: The name of the resource. Required. + :param name: The name of the memory store to delete. Required. :type name: str - :param version: The version of the ModelVersion to delete. Required. - :type version: str - :return: None - :rtype: None + :return: DeleteMemoryStoreResult. The DeleteMemoryStoreResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteMemoryStoreResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10343,11 +9762,10 @@ def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: dis _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.DeleteMemoryStoreResult] = kwargs.pop("cls", None) - _request = build_beta_models_delete_request( + _request = build_beta_memory_stores_delete_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -10357,111 +9775,88 @@ def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: dis } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DeleteMemoryStoreResult, response.json()) if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @overload - def update( + def _search_memories( self, name: str, - version: str, - body: _models.UpdateModelVersionRequest, *, - content_type: str = "application/merge-patch+json", + scope: str, + content_type: str = "application/json", + items: Optional[List[dict[str, Any]]] = None, + previous_search_id: Optional[str] = None, + options: Optional[_models.MemorySearchOptions] = None, **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: ~azure.ai.projects.models.UpdateModelVersionRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/merge-patch+json". - :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - + ) -> _models.MemoryStoreSearchResult: ... @overload - def update( - self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/merge-patch+json". - :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - + def _search_memories( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreSearchResult: ... @overload - def update( + def _search_memories( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreSearchResult: ... + + @distributed_trace + def _search_memories( self, name: str, - version: str, - body: IO[bytes], + body: Union[JSON, IO[bytes]] = _Unset, *, - content_type: str = "application/merge-patch+json", + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_search_id: Optional[str] = None, + options: Optional[_models.MemorySearchOptions] = None, **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/merge-patch+json". - :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @distributed_trace - def update( - self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. + ) -> _models.MemoryStoreSearchResult: + """Search for relevant memories from a memory store based on conversation context. - :param name: The name of the resource. Required. + :param name: The name of the memory store to search. Required. :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: - UpdateModelVersionRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :paramtype scope: str + :keyword items: Items for which to search for relevant memories. Default value is None. + :paramtype items: list[dict[str, any]] + :keyword previous_search_id: The unique ID of the previous search request, enabling incremental + memory search from where the last operation left off. Default value is None. + :paramtype previous_search_id: str + :keyword options: Memory search options. Default value is None. + :paramtype options: ~azure.ai.projects.models.MemorySearchOptions + :return: MemoryStoreSearchResult. The MemoryStoreSearchResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreSearchResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10476,18 +9871,27 @@ def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreSearchResult] = kwargs.pop("cls", None) - content_type = content_type or "application/merge-patch+json" + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = { + "items": items, + "options": options, + "previous_search_id": previous_search_id, + "scope": scope, + } + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): _content = body else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_update_request( + _request = build_beta_memory_stores_search_memories_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10499,120 +9903,48 @@ def update( } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200, 201]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.ModelVersion, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @overload - def create_async( - self, - name: str, - version: str, - body: _models.ModelVersion, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: ~azure.ai.projects.models.ModelVersion - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_async( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_async( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ + response = pipeline_response.http_response - @distributed_trace - def create_async( # pylint: disable=inconsistent-return-statements - self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any - ) -> None: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Is one of the following types: ModelVersion, JSON, - IO[bytes] Required. - :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.MemoryStoreSearchResult, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + def _update_memories_initial( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, + **kwargs: Any + ) -> Iterator[bytes]: error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -10625,8 +9957,18 @@ def create_async( # pylint: disable=inconsistent-return-statements _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = { + "items": items, + "previous_update_id": previous_update_id, + "scope": scope, + "update_delay": update_delay, + } + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -10634,9 +9976,8 @@ def create_async( # pylint: disable=inconsistent-return-statements else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_create_async_request( + _request = build_beta_memory_stores_update_memories_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10648,7 +9989,8 @@ def create_async( # pylint: disable=inconsistent-return-statements } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = True pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -10656,239 +9998,220 @@ def create_async( # pylint: disable=inconsistent-return-statements response = pipeline_response.http_response if response.status_code not in [202]: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: - return cls(pipeline_response, None, response_headers) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore @overload - def pending_upload( + def _begin_update_memories( self, name: str, - version: str, - body: _models.PendingUploadRequest, *, + scope: str, content_type: str = "application/json", + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: ~azure.ai.projects.models.PendingUploadRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - + ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: ... @overload - def pending_upload( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult - :raises ~azure.core.exceptions.HttpResponseError: - """ - + def _begin_update_memories( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: ... @overload - def pending_upload( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult - :raises ~azure.core.exceptions.HttpResponseError: - """ + def _begin_update_memories( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: ... @distributed_trace - def pending_upload( - self, name: str, version: str, body: Union[_models.PendingUploadRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.PendingUploadResult: - """Start or retrieve a pending upload for a model version. + def _begin_update_memories( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + scope: str = _Unset, + items: Optional[List[dict[str, Any]]] = None, + previous_update_id: Optional[str] = None, + update_delay: Optional[int] = None, + **kwargs: Any + ) -> LROPoller[_models.MemoryStoreUpdateCompletedResult]: + """Update memory store with conversation memories. - :param name: Name of the model. Required. + :param name: The name of the memory store to update. Required. :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Is one of the following types: PendingUploadRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.PendingUploadRequest or JSON or IO[bytes] - :return: PendingUploadResult. The PendingUploadResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.PendingUploadResult + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword scope: The namespace that logically groups and isolates memories, such as a user ID. + Required. + :paramtype scope: str + :keyword items: Conversation items to be stored in memory. Default value is None. + :paramtype items: list[dict[str, any]] + :keyword previous_update_id: The unique ID of the previous update request, enabling incremental + memory updates from where the last operation left off. Default value is None. + :paramtype previous_update_id: str + :keyword update_delay: Timeout period before processing the memory update in seconds. + If a new update request is received during this period, it will cancel the current request and + reset the timeout. + Set to 0 to immediately trigger the update without delay. + Defaults to 300 (5 minutes). Default value is None. + :paramtype update_delay: int + :return: An instance of LROPoller that returns MemoryStoreUpdateCompletedResult. The + MemoryStoreUpdateCompletedResult is compatible with MutableMapping + :rtype: + ~azure.core.polling.LROPoller[~azure.ai.projects.models.MemoryStoreUpdateCompletedResult] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.PendingUploadResult] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreUpdateCompletedResult] = kwargs.pop("cls", None) + polling: Union[bool, PollingMethod] = kwargs.pop("polling", True) + lro_delay = kwargs.pop("polling_interval", self._config.polling_interval) + cont_token: Optional[str] = kwargs.pop("continuation_token", None) + if cont_token is None: + raw_result = self._update_memories_initial( + name=name, + body=body, + scope=scope, + items=items, + previous_update_id=previous_update_id, + update_delay=update_delay, + content_type=content_type, + cls=lambda x, y, z: x, + headers=_headers, + params=_params, + **kwargs + ) + raw_result.http_response.read() # type: ignore + kwargs.pop("error_map", None) - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + def get_long_running_output(pipeline_response): + response_headers = {} + response = pipeline_response.http_response + response_headers["Operation-Location"] = self._deserialize( + "str", response.headers.get("Operation-Location") + ) + + deserialized = _deserialize(_models.MemoryStoreUpdateCompletedResult, response.json().get("result", {})) + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized - _request = build_beta_models_pending_upload_request( - name=name, - version=version, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) path_format_arguments = { "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if polling is True: + polling_method: PollingMethod = cast( + PollingMethod, LROBasePolling(lro_delay, path_format_arguments=path_format_arguments, **kwargs) + ) + elif polling is False: + polling_method = cast(PollingMethod, NoPolling()) else: - deserialized = _deserialize(_models.PendingUploadResult, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + polling_method = polling + if cont_token: + return LROPoller[_models.MemoryStoreUpdateCompletedResult].from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output, + ) + return LROPoller[_models.MemoryStoreUpdateCompletedResult]( + self._client, raw_result, get_long_running_output, polling_method # type: ignore + ) @overload - def get_credentials( - self, - name: str, - version: str, - body: _models.ModelCredentialRequest, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + def delete_scope( + self, name: str, *, scope: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: ~azure.ai.projects.models.ModelCredentialRequest + :keyword scope: The namespace that logically groups and isolates memories to delete, such as a + user ID. Required. + :paramtype scope: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def get_credentials( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + def delete_scope( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def get_credentials( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + def delete_scope( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def get_credentials( - self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + def delete_scope( + self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, scope: str = _Unset, **kwargs: Any + ) -> _models.MemoryStoreDeleteScopeResult: + """Delete all memories associated with a specific scope from a memory store. - :param name: Name of the model. Required. + :param name: The name of the memory store. Required. :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword scope: The namespace that logically groups and isolates memories to delete, such as a + user ID. Required. + :paramtype scope: str + :return: MemoryStoreDeleteScopeResult. The MemoryStoreDeleteScopeResult is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.MemoryStoreDeleteScopeResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -10903,8 +10226,13 @@ def get_credentials( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) + cls: ClsType[_models.MemoryStoreDeleteScopeResult] = kwargs.pop("cls", None) + if body is _Unset: + if scope is _Unset: + raise TypeError("missing required argument: scope") + body = {"scope": scope} + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -10912,9 +10240,8 @@ def get_credentials( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_get_credentials_request( + _request = build_beta_memory_stores_delete_scope_request( name=name, - version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -10941,12 +10268,16 @@ def get_credentials( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DatasetCredential, response.json()) + deserialized = _deserialize(_models.MemoryStoreDeleteScopeResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -10954,14 +10285,14 @@ def get_credentials( return deserialized # type: ignore -class BetaRedTeamsOperations: +class BetaModelsOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`red_teams` attribute. + :attr:`models` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -10972,15 +10303,20 @@ def __init__(self, *args, **kwargs) -> None: self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.RedTeam: - """Get a redteam by name. + def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: + """List all versions of the given ModelVersion. - :param name: Identifier of the red team run. Required. + :param name: The name of the resource. Required. :type name: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -10989,61 +10325,86 @@ def get(self, name: str, **kwargs: Any) -> _models.RedTeam: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + def prepare_request(next_link=None): + if not next_link: - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + _request = build_beta_models_list_versions_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_red_teams_get_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + return _request - response = pipeline_response.http_response + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ModelVersion], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + def get_next(next_link=None): + _request = prepare_request(next_link) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.RedTeam, response.json()) + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - return deserialized # type: ignore + return pipeline_response + + return ItemPaged(get_next, extract_data) @distributed_trace - def list(self, **kwargs: Any) -> ItemPaged["_models.RedTeam"]: - """List a redteam by name. + def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: + """List the latest version of each ModelVersion. - :return: An iterator like instance of RedTeam - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RedTeam] + :return: An iterator like instance of ModelVersion + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -11056,7 +10417,7 @@ def list(self, **kwargs: Any) -> ItemPaged["_models.RedTeam"]: def prepare_request(next_link=None): if not next_link: - _request = build_beta_red_teams_list_request( + _request = build_beta_models_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -11096,7 +10457,7 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.RedTeam], + List[_models.ModelVersion], deserialized.get("value", []), ) if cls: @@ -11120,59 +10481,17 @@ def get_next(next_link=None): return ItemPaged(get_next, extract_data) - @overload - def create( - self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: ~azure.ai.projects.models.RedTeam - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create(self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. - - :param red_team: Redteam to be run. Required. - :type red_team: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace - def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: + """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the + ModelVersion does not exist. - :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] - Required. - :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the ModelVersion to retrieve. Required. + :type version: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11183,23 +10502,15 @@ def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: An } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(red_team, (IOBase, bytes)): - _content = red_team - else: - _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) - _request = build_beta_red_teams_create_request( - content_type=content_type, + _request = build_beta_models_get_request( + name=name, + version=version, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -11216,55 +10527,168 @@ def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: An response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RedTeam, response.json()) + deserialized = _deserialize(_models.ModelVersion, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace + def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete the specific version of the ModelVersion. The service returns 200 OK if the ModelVersion + was deleted successfully or if the ModelVersion does not exist. -class BetaSchedulesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + :param name: The name of the resource. Required. + :type name: str + :param version: The version of the ModelVersion to delete. Required. + :type version: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`schedules` attribute. - """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_models_delete_request( + name=name, + version=version, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @overload + def update( + self, + name: str, + version: str, + body: _models.UpdateModelVersionRequest, + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update( + self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def update( + self, + name: str, + version: str, + body: IO[bytes], + *, + content_type: str = "application/merge-patch+json", + **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. + + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/merge-patch+json". + :paramtype content_type: str + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def delete(self, schedule_id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete a schedule. + def update( + self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ModelVersion: + """Update an existing ModelVersion with the given version id. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: None - :rtype: None + :param name: The name of the resource. Required. + :type name: str + :param version: The specific version id of the UpdateModelVersionRequest to create or update. + Required. + :type version: str + :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: + UpdateModelVersionRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] + :return: ModelVersion. The ModelVersion is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ModelVersion :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11275,14 +10699,25 @@ def delete(self, schedule_id: str, **kwargs: Any) -> None: # pylint: disable=in } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) - _request = build_beta_schedules_delete_request( - schedule_id=schedule_id, + content_type = content_type or "application/merge-patch+json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_update_request( + name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -11291,28 +10726,118 @@ def delete(self, schedule_id: str, **kwargs: Any) -> None: # pylint: disable=in } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200, 201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelVersion, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @overload + def create_async( + self, + name: str, + version: str, + body: _models.ModelVersion, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: ~azure.ai.projects.models.ModelVersion + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_async( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_async( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ @distributed_trace - def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: - """Get a schedule by id. + def create_async( + self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any + ) -> _models.CreateAsyncResponse: + """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with + a Location header for polling. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Model version to create. Is one of the following types: ModelVersion, JSON, + IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] + :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.CreateAsyncResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11323,14 +10848,25 @@ def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.CreateAsyncResponse] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_request( - schedule_id=schedule_id, + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_models_create_async_request( + name=name, + version=version, + content_type=content_type, api_version=self._config.api_version, + content=_content, headers=_headers, params=_params, ) @@ -11347,7 +10883,7 @@ def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [202]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -11356,40 +10892,106 @@ def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) + response_headers = {} + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Schedule, response.json()) + deserialized = _deserialize(_models.CreateAsyncResponse, response.json()) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore - @distributed_trace - def list( + @overload + def pending_upload( self, + name: str, + version: str, + body: _models.ModelPendingUploadRequest, *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, + content_type: str = "application/json", **kwargs: Any - ) -> ItemPaged["_models.Schedule"]: - """List all schedules. + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. - :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". - Default value is None. - :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of Schedule - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Schedule] + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.ModelPendingUploadRequest + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.Schedule]] = kwargs.pop("cls", None) + @overload + def pending_upload( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def pending_upload( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. + + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def pending_upload( + self, name: str, version: str, body: Union[_models.ModelPendingUploadRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.ModelPendingUploadResponse: + """Start or retrieve a pending upload for a model version. + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: ModelPendingUploadRequest, JSON, IO[bytes] + Required. + :type body: ~azure.ai.projects.models.ModelPendingUploadRequest or JSON or IO[bytes] + :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with + MutableMapping + :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -11398,142 +11000,140 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - _request = build_beta_schedules_list_request( - type=type, - enabled=enabled, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.ModelPendingUploadResponse] = kwargs.pop("cls", None) - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - return _request + _request = build_beta_models_pending_upload_request( + name=name, + version=version, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Schedule], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - def get_next(next_link=None): - _request = prepare_request(next_link) + response = pipeline_response.http_response - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ModelPendingUploadResponse, response.json()) - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - return ItemPaged(get_next, extract_data) + return deserialized # type: ignore @overload - def create_or_update( - self, schedule_id: str, schedule: _models.Schedule, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + def get_credentials( + self, + name: str, + version: str, + body: _models.ModelCredentialRequest, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: ~azure.ai.projects.models.Schedule + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_or_update( - self, schedule_id: str, schedule: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + def get_credentials( + self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: JSON + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_or_update( - self, schedule_id: str, schedule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + def get_credentials( + self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: IO[bytes] + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Required. + :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_or_update( - self, schedule_id: str, schedule: Union[_models.Schedule, JSON, IO[bytes]], **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + def get_credentials( + self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any + ) -> _models.DatasetCredential: + """Get credentials for a model version asset. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Is one of the following types: Schedule, JSON, - IO[bytes] Required. - :type schedule: ~azure.ai.projects.models.Schedule or JSON or IO[bytes] - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: Name of the model. Required. + :type name: str + :param version: Version of the model. Required. + :type version: str + :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. + :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] + :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DatasetCredential :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11548,17 +11148,18 @@ def create_or_update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) content_type = content_type or "application/json" _content = None - if isinstance(schedule, (IOBase, bytes)): - _content = schedule + if isinstance(body, (IOBase, bytes)): + _content = body else: - _content = json.dumps(schedule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_schedules_create_or_update_request( - schedule_id=schedule_id, + _request = build_beta_models_get_credentials_request( + name=name, + version=version, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -11578,7 +11179,7 @@ def create_or_update( response = pipeline_response.http_response - if response.status_code not in [200, 201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -11590,23 +11191,39 @@ def create_or_update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Schedule, response.json()) + deserialized = _deserialize(_models.DatasetCredential, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaRedTeamsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`red_teams` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @distributed_trace - def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: - """Get a schedule run by id. + def get(self, name: str, **kwargs: Any) -> _models.RedTeam: + """Get a redteam by name. - :param schedule_id: The unique identifier of the schedule. Required. - :type schedule_id: str - :param run_id: The unique identifier of the schedule run. Required. - :type run_id: str - :return: ScheduleRun. The ScheduleRun is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ScheduleRun + :param name: Identifier of the red team run. Required. + :type name: str + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11620,11 +11237,10 @@ def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.Sched _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ScheduleRun] = kwargs.pop("cls", None) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_run_request( - schedule_id=schedule_id, - run_id=run_id, + _request = build_beta_red_teams_get_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -11649,48 +11265,30 @@ def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.Sched except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ScheduleRun, response.json()) + deserialized = _deserialize(_models.RedTeam, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore - return deserialized # type: ignore - - @distributed_trace - def list_runs( - self, - schedule_id: str, - *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, - **kwargs: Any - ) -> ItemPaged["_models.ScheduleRun"]: - """List all schedule runs. - - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". - Default value is None. - :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of ScheduleRun - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ScheduleRun] + return deserialized # type: ignore + + @distributed_trace + def list(self, **kwargs: Any) -> ItemPaged["_models.RedTeam"]: + """List a redteam by name. + + :return: An iterator like instance of RedTeam + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RedTeam] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ScheduleRun]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -11703,10 +11301,7 @@ def list_runs( def prepare_request(next_link=None): if not next_link: - _request = build_beta_schedules_list_runs_request( - schedule_id=schedule_id, - type=type, - enabled=enabled, + _request = build_beta_red_teams_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -11746,7 +11341,7 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.ScheduleRun], + List[_models.RedTeam], deserialized.get("value", []), ) if cls: @@ -11770,126 +11365,59 @@ def get_next(next_link=None): return ItemPaged(get_next, extract_data) - -class BetaToolboxesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`toolboxes` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - def create_version( - self, - name: str, - *, - tools: List[_models.Tool], - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - policies: Optional[_models.ToolboxPolicies] = None, - **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + def create( + self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. - :type name: str - :keyword tools: The list of tools to include in this version. Required. - :paramtype tools: list[~azure.ai.projects.models.Tool] + :param red_team: Redteam to be run. Required. + :type red_team: ~azure.ai.projects.models.RedTeam :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the toolbox. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is - None. - :paramtype metadata: dict[str, str] - :keyword policies: Policy configuration for this toolbox version. Default value is None. - :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_version( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. - :type name: str - :param body: Required. - :type body: JSON + :param red_team: Redteam to be run. Required. + :type red_team: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_version( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + def create(self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. - :type name: str - :param body: Required. - :type body: IO[bytes] + :param red_team: Redteam to be run. Required. + :type red_team: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_version( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - tools: List[_models.Tool] = _Unset, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - policies: Optional[_models.ToolboxPolicies] = None, - **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword tools: The list of tools to include in this version. Required. - :paramtype tools: list[~azure.ai.projects.models.Tool] - :keyword description: A human-readable description of the toolbox. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is - None. - :paramtype metadata: dict[str, str] - :keyword policies: Policy configuration for this toolbox version. Default value is None. - :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11904,22 +11432,16 @@ def create_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - if body is _Unset: - if tools is _Unset: - raise TypeError("missing required argument: tools") - body = {"description": description, "metadata": metadata, "policies": policies, "tools": tools} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(red_team, (IOBase, bytes)): + _content = red_team else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_toolboxes_create_version_request( - name=name, + _request = build_beta_red_teams_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -11939,7 +11461,7 @@ def create_version( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -11955,21 +11477,39 @@ def create_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) + deserialized = _deserialize(_models.RedTeam, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaSchedulesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`schedules` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: - """Retrieve a toolbox. + def delete(self, schedule_id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete a schedule. - :param name: The name of the toolbox to retrieve. Required. - :type name: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -11983,10 +11523,58 @@ def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_request( - name=name, + _request = build_beta_schedules_delete_request( + schedule_id=schedule_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace + def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: + """Get a schedule by id. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + + _request = build_beta_schedules_get_request( + schedule_id=schedule_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -12011,16 +11599,12 @@ def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) + deserialized = _deserialize(_models.Schedule, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -12031,35 +11615,25 @@ def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: def list( self, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, **kwargs: Any - ) -> ItemPaged["_models.ToolboxObject"]: - """List all toolboxes. + ) -> ItemPaged["_models.Schedule"]: + """List all schedules. - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. + :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". Default value is None. - :paramtype before: str - :return: An iterator like instance of ToolboxObject - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxObject] + :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of Schedule + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Schedule] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ToolboxObject]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Schedule]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -12069,35 +11643,60 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_schedules_list_request( + type=type, + enabled=enabled, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_toolboxes_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.ToolboxObject], - deserialized.get("data", []), + List[_models.Schedule], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) + return deserialized.get("nextLink") or None, iter(list_of_elem) - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access @@ -12107,53 +11706,81 @@ def get_next(_continuation_token=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) return pipeline_response return ItemPaged(get_next, extract_data) - @distributed_trace - def list_versions( - self, - name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.ToolboxVersionObject"]: - """List all versions of a toolbox. + @overload + def create_or_update( + self, schedule_id: str, schedule: _models.Schedule, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. - :param name: The name of the toolbox to list versions for. Required. - :type name: str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of ToolboxVersionObject - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxVersionObject] + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: ~azure.ai.projects.models.Schedule + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ToolboxVersionObject]] = kwargs.pop("cls", None) + @overload + def create_or_update( + self, schedule_id: str, schedule: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, schedule_id: str, schedule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_or_update( + self, schedule_id: str, schedule: Union[_models.Schedule, JSON, IO[bytes]], **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Is one of the following types: Schedule, JSON, + IO[bytes] Required. + :type schedule: ~azure.ai.projects.models.Schedule or JSON or IO[bytes] + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -12162,65 +11789,69 @@ def list_versions( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} - _request = build_beta_toolboxes_list_versions_request( - name=name, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ToolboxVersionObject], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) + content_type = content_type or "application/json" + _content = None + if isinstance(schedule, (IOBase, bytes)): + _content = schedule + else: + _content = json.dumps(schedule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + _request = build_beta_schedules_create_or_update_request( + schedule_id=schedule_id, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + response = pipeline_response.http_response - return pipeline_response + if response.status_code not in [200, 201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - return ItemPaged(get_next, extract_data) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.Schedule, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace - def get_version(self, name: str, version: str, **kwargs: Any) -> _models.ToolboxVersionObject: - """Retrieve a specific version of a toolbox. + def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: + """Get a schedule run by id. - :param name: The name of the toolbox. Required. - :type name: str - :param version: The version identifier to retrieve. Required. - :type version: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :param schedule_id: The unique identifier of the schedule. Required. + :type schedule_id: str + :param run_id: The unique identifier of the schedule run. Required. + :type run_id: str + :return: ScheduleRun. The ScheduleRun is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ScheduleRun :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12234,11 +11865,11 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.Toolbox _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) + cls: ClsType[_models.ScheduleRun] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_version_request( - name=name, - version=version, + _request = build_beta_schedules_get_run_request( + schedule_id=schedule_id, + run_id=run_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -12272,83 +11903,238 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.Toolbox if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) + deserialized = _deserialize(_models.ScheduleRun, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + @distributed_trace + def list_runs( + self, + schedule_id: str, + *, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, + **kwargs: Any + ) -> ItemPaged["_models.ScheduleRun"]: + """List all schedule runs. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". + Default value is None. + :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of ScheduleRun + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ScheduleRun] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ScheduleRun]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(next_link=None): + if not next_link: + + _request = build_beta_schedules_list_runs_request( + schedule_id=schedule_id, + type=type, + enabled=enabled, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ScheduleRun], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + +class BetaToolboxesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`toolboxes` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @overload - def update( - self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + def create_version( + self, + name: str, + *, + tools: List[_models.Tool], + content_type: str = "application/json", + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + policies: Optional[_models.ToolboxPolicies] = None, + **kwargs: Any + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str - :keyword default_version: The version identifier that the toolbox should point to. When set, - the toolbox's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str + :keyword tools: The list of tools to include in this version. Required. + :paramtype tools: list[~azure.ai.projects.models.Tool] :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :keyword description: A human-readable description of the toolbox. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is + None. + :paramtype metadata: dict[str, str] + :keyword policies: Policy configuration for this toolbox version. Default value is None. + :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( + def create_version( self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( + def create_version( self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update( - self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, default_version: str = _Unset, **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + def create_version( + self, + name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + tools: List[_models.Tool] = _Unset, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + policies: Optional[_models.ToolboxPolicies] = None, + **kwargs: Any + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param name: The name of the toolbox to update. Required. + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword default_version: The version identifier that the toolbox should point to. When set, - the toolbox's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :keyword tools: The list of tools to include in this version. Required. + :paramtype tools: list[~azure.ai.projects.models.Tool] + :keyword description: A human-readable description of the toolbox. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is + None. + :paramtype metadata: dict[str, str] + :keyword policies: Policy configuration for this toolbox version. Default value is None. + :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12363,12 +12149,12 @@ def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) if body is _Unset: - if default_version is _Unset: - raise TypeError("missing required argument: default_version") - body = {"default_version": default_version} + if tools is _Unset: + raise TypeError("missing required argument: tools") + body = {"description": description, "metadata": metadata, "policies": policies, "tools": tools} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -12377,7 +12163,7 @@ def update( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_toolboxes_update_request( + _request = build_beta_toolboxes_create_version_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -12414,7 +12200,7 @@ def update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) + deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -12422,13 +12208,13 @@ def update( return deserialized # type: ignore @distributed_trace - def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete a toolbox and all its versions. + def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: + """Retrieve a toolbox. - :param name: The name of the toolbox to delete. Required. + :param name: The name of the toolbox to retrieve. Required. :type name: str - :return: None - :rtype: None + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12442,9 +12228,9 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_delete_request( + _request = build_beta_toolboxes_get_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -12455,14 +12241,20 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -12470,21 +12262,210 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ToolboxObject, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace - def delete_version( # pylint: disable=inconsistent-return-statements - self, name: str, version: str, **kwargs: Any - ) -> None: - """Delete a specific version of a toolbox. + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.ToolboxObject"]: + """List all toolboxes. + + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of ToolboxObject + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxObject] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ToolboxObject]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_toolboxes_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ToolboxObject], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def list_versions( + self, + name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.ToolboxVersionObject"]: + """List all versions of a toolbox. + + :param name: The name of the toolbox to list versions for. Required. + :type name: str + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of ToolboxVersionObject + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxVersionObject] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.ToolboxVersionObject]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_toolboxes_list_versions_request( + name=name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ToolboxVersionObject], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @distributed_trace + def get_version(self, name: str, version: str, **kwargs: Any) -> _models.ToolboxVersionObject: + """Retrieve a specific version of a toolbox. :param name: The name of the toolbox. Required. :type name: str - :param version: The version identifier to delete. Required. + :param version: The version identifier to retrieve. Required. :type version: str - :return: None - :rtype: None + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12498,9 +12479,9 @@ def delete_version( # pylint: disable=inconsistent-return-statements _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_delete_version_request( + _request = build_beta_toolboxes_get_version_request( name=name, version=version, api_version=self._config.api_version, @@ -12512,14 +12493,20 @@ def delete_version( # pylint: disable=inconsistent-return-statements } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -12527,121 +12514,86 @@ def delete_version( # pylint: disable=inconsistent-return-statements ) raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, None, {}) # type: ignore - - -class BetaSkillsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`skills` attribute. - """ + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + return deserialized # type: ignore @overload - def create( - self, - *, - name: str, - content_type: str = "application/json", - description: Optional[str] = None, - instructions: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.SkillDetails: - """Creates a skill. + def update( + self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. - :keyword name: The unique name of the skill. Required. - :paramtype name: str + :param name: The name of the toolbox to update. Required. + :type name: str + :keyword default_version: The version identifier that the toolbox should point to. When set, + the toolbox's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: - """Creates a skill. + def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. + :param name: The name of the toolbox to update. Required. + :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create(self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: - """Creates a skill. + def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. + :param name: The name of the toolbox to update. Required. + :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create( - self, - body: Union[JSON, IO[bytes]] = _Unset, - *, - name: str = _Unset, - description: Optional[str] = None, - instructions: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - **kwargs: Any - ) -> _models.SkillDetails: - """Creates a skill. + def update( + self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, default_version: str = _Unset, **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. + :param name: The name of the toolbox to update. Required. + :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword name: The unique name of the skill. Required. - :paramtype name: str - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :keyword default_version: The version identifier that the toolbox should point to. When set, + the toolbox's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: str + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12656,12 +12608,12 @@ def create( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) if body is _Unset: - if name is _Unset: - raise TypeError("missing required argument: name") - body = {"description": description, "instructions": instructions, "metadata": metadata, "name": name} + if default_version is _Unset: + raise TypeError("missing required argument: default_version") + body = {"default_version": default_version} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -12670,76 +12622,8 @@ def create( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_skills_create_request( - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [201]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SkillDetails, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: - """Creates a skill from a zip package. - - :param content: The zip package used to create the skill. Required. - :type content: bytes - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/zip")) - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - - _content = content - - _request = build_beta_skills_create_from_package_request( + _request = build_beta_toolboxes_update_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -12759,7 +12643,7 @@ def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDet response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -12775,7 +12659,7 @@ def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDet if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + deserialized = _deserialize(_models.ToolboxObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -12783,13 +12667,13 @@ def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDet return deserialized # type: ignore @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: - """Retrieves a skill. + def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete a toolbox and all its versions. - :param name: The unique name of the skill. Required. + :param name: The name of the toolbox to delete. Required. :type name: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12803,9 +12687,9 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_skills_get_request( + _request = build_beta_toolboxes_delete_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -12816,45 +12700,36 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + ) + raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: - """Downloads a skill package. + def delete_version( # pylint: disable=inconsistent-return-statements + self, name: str, version: str, **kwargs: Any + ) -> None: + """Delete a specific version of a toolbox. - :param name: The unique name of the skill. Required. + :param name: The name of the toolbox. Required. :type name: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + :param version: The version identifier to delete. Required. + :type version: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -12868,10 +12743,11 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_skills_download_request( + _request = build_beta_toolboxes_delete_version_request( name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -12881,20 +12757,14 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -12902,121 +12772,42 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def list( - self, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.SkillDetails"]: - """Returns the list of all skills. - - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of SkillDetails - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillDetails] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(_continuation_token=None): - - _request = build_beta_skills_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.SkillDetails], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) - - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + return cls(pipeline_response, None, {}) # type: ignore - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) +class BetaSkillsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. - return pipeline_response + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`skills` attribute. + """ - return ItemPaged(get_next, extract_data) + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @overload - def update( + def create( self, - name: str, *, + name: str, content_type: str = "application/json", description: Optional[str] = None, instructions: Optional[str] = None, metadata: Optional[dict[str, str]] = None, **kwargs: Any ) -> _models.SkillDetails: - """Updates an existing skill. + """Creates a skill. - :param name: The unique name of the skill. Required. - :type name: str + :keyword name: The unique name of the skill. Required. + :paramtype name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str @@ -13038,13 +12829,9 @@ def update( """ @overload - def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Updates an existing skill. + def create(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: + """Creates a skill. - :param name: The unique name of the skill. Required. - :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. @@ -13056,13 +12843,9 @@ def update( """ @overload - def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Updates an existing skill. + def create(self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: + """Creates a skill. - :param name: The unique name of the skill. Required. - :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. @@ -13074,34 +12857,113 @@ def update( """ @distributed_trace - def update( + def create( self, - name: str, body: Union[JSON, IO[bytes]] = _Unset, *, + name: str = _Unset, description: Optional[str] = None, instructions: Optional[str] = None, metadata: Optional[dict[str, str]] = None, **kwargs: Any ) -> _models.SkillDetails: - """Updates an existing skill. + """Creates a skill. + + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword name: The unique name of the skill. Required. + :paramtype name: str + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + + if body is _Unset: + if name is _Unset: + raise TypeError("missing required argument: name") + body = {"description": description, "instructions": instructions, "metadata": metadata, "name": name} + body = {k: v for k, v in body.items() if v is not None} + content_type = content_type or "application/json" + _content = None + if isinstance(body, (IOBase, bytes)): + _content = body + else: + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_skills_create_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) - :param name: The unique name of the skill. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] + return deserialized # type: ignore + + @distributed_trace + def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: + """Creates a skill from a zip package. + + :param content: The zip package used to create the skill. Required. + :type content: bytes :return: SkillDetails. The SkillDetails is compatible with MutableMapping :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: @@ -13117,21 +12979,12 @@ def update( _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/zip")) cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - if body is _Unset: - body = {"description": description, "instructions": instructions, "metadata": metadata} - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = content - _request = build_beta_skills_update_request( - name=name, + _request = build_beta_skills_create_from_package_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -13151,7 +13004,7 @@ def update( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -13175,13 +13028,13 @@ def update( return deserialized # type: ignore @distributed_trace - def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: - """Deletes a skill. + def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: + """Retrieves a skill. :param name: The unique name of the skill. Required. :type name: str - :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillResult + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13195,9 +13048,9 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - _request = build_beta_skills_delete_request( + _request = build_beta_skills_get_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -13232,41 +13085,21 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteSkillResult, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - -class BetaDatasetsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`datasets` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace - def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: - """Get info about a data generation job. - - Gets the details of a data generation job by its ID. + def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: + """Downloads a skill package. - :param job_id: The ID of the job. Required. - :type job_id: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :param name: The unique name of the skill. Required. + :type name: str + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13280,10 +13113,10 @@ def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerati _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_datasets_get_generation_job_request( - job_id=job_id, + _request = build_beta_skills_download_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -13294,7 +13127,7 @@ def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerati _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -13315,12 +13148,9 @@ def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerati raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.DataGenerationJob, response.json()) + deserialized = response.iter_bytes() if _decompress else response.iter_raw() if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -13328,19 +13158,15 @@ def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerati return deserialized # type: ignore @distributed_trace - def list_generation_jobs( + def list( self, *, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, - scenario: Optional[Union[str, _models.DataGenerationJobScenario]] = None, - type: Optional[List[Union[str, _models.DataGenerationJobType]]] = None, **kwargs: Any - ) -> ItemPaged["_models.DataGenerationJob"]: - """Returns a list of data generation jobs. - - Returns a list of data generation jobs. + ) -> ItemPaged["_models.SkillDetails"]: + """Returns the list of all skills. :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the @@ -13356,19 +13182,14 @@ def list_generation_jobs( subsequent call can include before=obj_foo in order to fetch the previous page of the list. Default value is None. :paramtype before: str - :keyword scenario: Filter data generation jobs by their scenario. Known values are: - "supervised_finetuning", "reinforcement_finetuning", and "evaluation". Default value is None. - :paramtype scenario: str or ~azure.ai.projects.models.DataGenerationJobScenario - :keyword type: Filter data generation jobs by their type. Default value is None. - :paramtype type: list[str or ~azure.ai.projects.models.DataGenerationJobType] - :return: An iterator like instance of DataGenerationJob - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.DataGenerationJob] + :return: An iterator like instance of SkillDetails + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillDetails] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.DataGenerationJob]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -13380,13 +13201,11 @@ def list_generation_jobs( def prepare_request(_continuation_token=None): - _request = build_beta_datasets_list_generation_jobs_request( + _request = build_beta_skills_list_request( limit=limit, order=order, after=_continuation_token, before=before, - scenario=scenario, - type=type, api_version=self._config.api_version, headers=_headers, params=_params, @@ -13400,7 +13219,7 @@ def prepare_request(_continuation_token=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.DataGenerationJob], + List[_models.SkillDetails], deserialized.get("data", []), ) if cls: @@ -13429,98 +13248,107 @@ def get_next(_continuation_token=None): return ItemPaged(get_next, extract_data) @overload - def create_generation_job( + def update( self, - job: _models.DataGenerationJob, + name: str, *, - operation_id: Optional[str] = None, content_type: str = "application/json", + description: Optional[str] = None, + instructions: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. - - Creates a data generation job. + ) -> _models.SkillDetails: + """Updates an existing skill. - :param job: The job to create. Required. - :type job: ~azure.ai.projects.models.DataGenerationJob - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str + :param name: The unique name of the skill. Required. + :type name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_generation_job( - self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. - - Creates a data generation job. - - :param job: The job to create. Required. - :type job: JSON - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str + def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Updates an existing skill. + + :param name: The unique name of the skill. Required. + :type name: str + :param body: Required. + :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_generation_job( - self, - job: IO[bytes], - *, - operation_id: Optional[str] = None, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. - - Creates a data generation job. + def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Updates an existing skill. - :param job: The job to create. Required. - :type job: IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str + :param name: The unique name of the skill. Required. + :type name: str + :param body: Required. + :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_generation_job( + def update( self, - job: Union[_models.DataGenerationJob, JSON, IO[bytes]], + name: str, + body: Union[JSON, IO[bytes]] = _Unset, *, - operation_id: Optional[str] = None, + description: Optional[str] = None, + instructions: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.DataGenerationJob: - """Creates a data generation job. + ) -> _models.SkillDetails: + """Updates an existing skill. - Creates a data generation job. + :param name: The unique name of the skill. Required. + :type name: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. - :param job: The job to create. Is one of the following types: DataGenerationJob, JSON, - IO[bytes] Required. - :type job: ~azure.ai.projects.models.DataGenerationJob or JSON or IO[bytes] - :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the - server creates the job unconditionally. Default value is None. - :paramtype operation_id: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13535,17 +13363,20 @@ def create_generation_job( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + if body is _Unset: + body = {"description": description, "instructions": instructions, "metadata": metadata} + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(job, (IOBase, bytes)): - _content = job + if isinstance(body, (IOBase, bytes)): + _content = body else: - _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_datasets_create_generation_job_request( - operation_id=operation_id, + _request = build_beta_skills_update_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -13565,7 +13396,7 @@ def create_generation_job( response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -13578,30 +13409,24 @@ def create_generation_job( ) raise HttpResponseError(response=response, model=error) - response_headers = {} - response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) - if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DataGenerationJob, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore @distributed_trace - def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: - """Cancels a data generation job. - - Cancels a data generation job by its ID. + def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: + """Deletes a skill. - :param job_id: The ID of the job to cancel. Required. - :type job_id: str - :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DataGenerationJob + :param name: The unique name of the skill. Required. + :type name: str + :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13615,10 +13440,10 @@ def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGener _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) - _request = build_beta_datasets_cancel_generation_job_request( - job_id=job_id, + _request = build_beta_skills_delete_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -13652,65 +13477,9 @@ def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGener if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DataGenerationJob, response.json()) + deserialized = _deserialize(_models.DeleteSkillResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - - @distributed_trace - def delete_generation_job( # pylint: disable=inconsistent-return-statements - self, job_id: str, **kwargs: Any - ) -> None: - """Deletes a data generation job. - - Deletes a data generation job by its ID. - - :param job_id: The ID of the job to delete. Required. - :type job_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) - - _request = build_beta_datasets_delete_generation_job_request( - job_id=job_id, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [204]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index c280d73d0b6f..c4b774f0e679 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -21,7 +21,6 @@ from ._patch_models import BetaModelsOperations from ._patch_sessions import BetaAgentsOperations from ._operations import ( - BetaDatasetsOperations, BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, @@ -116,8 +115,6 @@ class BetaOperations(GeneratedBetaOperations): """:class:`~azure.ai.projects.operations.BetaToolboxesOperations` operations""" skills: BetaSkillsOperations """:class:`~azure.ai.projects.operations.BetaSkillsOperations` operations""" - datasets: BetaDatasetsOperations - """:class:`~azure.ai.projects.operations.BetaDatasetsOperations` operations""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -141,7 +138,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: __all__: List[str] = [ "AgentsOperations", "BetaAgentsOperations", - "BetaDatasetsOperations", "BetaEvaluationTaxonomiesOperations", "BetaEvaluatorsOperations", "BetaInsightsOperations", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py index 3afcca8655c7..5d8971693fe5 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -21,9 +21,9 @@ from ._operations import BetaModelsOperations as BetaModelsOperationsGenerated from ..models._models import ( + ModelPendingUploadRequest, + ModelPendingUploadResponse, ModelVersion, - PendingUploadRequest, - PendingUploadResult, PendingUploadType, ) @@ -42,13 +42,13 @@ class BetaModelsOperations(BetaModelsOperationsGenerated): @staticmethod def _extract_pending_upload_targets( - response: Union[PendingUploadResult, dict], + response: Union[ModelPendingUploadResponse, dict], ) -> "tuple[str, str, Optional[str]]": """Return ``(sas_uri, container_blob_uri, pending_upload_id)`` from a pending-upload response. The service currently returns the raw datastore-style payload (``blobReferenceForConsumption`` / ``temporaryDataReferenceId``) for some - Foundry deployments rather than the SDK-modeled ``PendingUploadResult`` + Foundry deployments rather than the SDK-modeled ``ModelPendingUploadResponse`` shape (``blobReference`` / ``pendingUploadId``). Tolerate both wire shapes so callers don't have to. """ @@ -242,7 +242,7 @@ def models_create( pending = self.pending_upload( name=name, version=version, - body=PendingUploadRequest( + body=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), **kwargs, diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py index 10925bc65a87..c66e0eb740f0 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py @@ -57,8 +57,8 @@ from azure.ai.projects.models import ( FoundryModelWeightType, ModelCredentialRequest, + ModelPendingUploadRequest, ModelVersion, - PendingUploadRequest, PendingUploadType, UpdateModelVersionRequest, ) @@ -89,7 +89,7 @@ async def main() -> None: pending = await project_client.beta.models.pending_upload( name=model_name, version=model_version, - body=PendingUploadRequest( + body=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), ) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py index 9bc181654810..ba65999cbfcc 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py @@ -55,8 +55,8 @@ from azure.ai.projects import AIProjectClient from azure.ai.projects.models import ( FoundryModelWeightType, + ModelPendingUploadRequest, ModelVersion, - PendingUploadRequest, PendingUploadType, ) @@ -83,7 +83,7 @@ pending = project_client.beta.models.pending_upload( name=model_name, version=model_version, - body=PendingUploadRequest( + body=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), ) diff --git a/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py b/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py index c0c242ee5723..7bcccc408878 100644 --- a/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py +++ b/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py @@ -39,11 +39,11 @@ "evaluators": "Evaluations=V1Preview", "insights": "Insights=V1Preview", "memory_stores": "MemoryStores=V1Preview", + "models": "Models=V1Preview", "red_teams": "RedTeams=V1Preview", "schedules": "Schedules=V1Preview", "toolboxes": "Toolboxes=V1Preview", "skills": "Skills=V1Preview", - "datasets": "DataGenerationJobs=V1Preview", "agents": "HostedAgents=V1Preview,AgentEndpoints=V1Preview,CodeAgents=V1Preview", } diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models.py b/sdk/ai/azure-ai-projects/tests/models/test_models.py index cc7c1e402e6c..e87d196c311a 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models.py @@ -117,7 +117,7 @@ def test_models_models_create(self, **kwargs): @recorded_by_proxy def test_models_pending_upload(self, **kwargs): """Lower-level: ``pending_upload`` returns a usable SAS URI.""" - from azure.ai.projects.models import PendingUploadRequest, PendingUploadType + from azure.ai.projects.models import ModelPendingUploadRequest, PendingUploadType model_name = self.test_models_params["model_name_2"] model_version = self.test_models_params["model_version"] @@ -129,7 +129,7 @@ def test_models_pending_upload(self, **kwargs): pending = project_client.beta.models.pending_upload( name=model_name, version=model_version, - body=PendingUploadRequest( + body=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), ) diff --git a/sdk/ai/azure-ai-projects/tsp-location.yaml b/sdk/ai/azure-ai-projects/tsp-location.yaml index f7ab1acc313e..944a6eb18e08 100644 --- a/sdk/ai/azure-ai-projects/tsp-location.yaml +++ b/sdk/ai/azure-ai-projects/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/ai-foundry/data-plane/Foundry -commit: 8dba3c8402a82cf0c2bf8a905b0e932bec57727a +commit: 6e498c0f7af2a0f23e97240d9f08e0487f475134 repo: Azure/azure-rest-api-specs additionalDirectories: From f5274d08d00615a991919d1ba4e5e89ab789f250 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Thu, 14 May 2026 16:14:09 +0530 Subject: [PATCH 06/14] reverting pyproject.toml --- sdk/ai/azure-ai-projects/pyproject.toml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sdk/ai/azure-ai-projects/pyproject.toml b/sdk/ai/azure-ai-projects/pyproject.toml index fe16fe054548..26eac48e1123 100644 --- a/sdk/ai/azure-ai-projects/pyproject.toml +++ b/sdk/ai/azure-ai-projects/pyproject.toml @@ -14,10 +14,10 @@ name = "azure-ai-projects" authors = [ { name = "Microsoft Corporation", email = "azpysdkhelp@microsoft.com" }, ] -description = "Microsoft Corporation Azure Ai Projects Client Library for Python" +description = "Microsoft Corporation Azure AI Projects Client Library for Python" license = "MIT" classifiers = [ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] requires-python = ">=3.9" keywords = ["azure", "azure sdk"] @@ -43,7 +44,7 @@ dynamic = [ ] [project.urls] -repository = "https://github.com/Azure/azure-sdk-for-python" +repository = "https://aka.ms/azsdk/azure-ai-projects-v2/python/code" [tool.setuptools.dynamic] version = {attr = "azure.ai.projects._version.VERSION"} @@ -51,13 +52,13 @@ readme = {file = ["README.md", "CHANGELOG.md"], content-type = "text/markdown"} [tool.setuptools.packages.find] exclude = [ - "tests*", + "azure.ai", + "azure", + "doc*", + "generated_samples*", "generated_tests*", "samples*", - "generated_samples*", - "doc*", - "azure", - "azure.ai", + "tests*", ] [tool.setuptools.package-data] @@ -68,3 +69,4 @@ verifytypes = false [tool.azure-sdk-conda] in_bundle = false + From b9f1fc26579529823ea6d1e7d27e3bc9c2198170 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Thu, 21 May 2026 19:11:16 +0530 Subject: [PATCH 07/14] pulling base branch of foundry sdk release for build --- .../azure/ai/projects/_client.py | 6 - .../azure/ai/projects/_types.py | 2 - .../azure/ai/projects/aio/_client.py | 6 - .../ai/projects/aio/operations/__init__.py | 2 - .../ai/projects/aio/operations/_operations.py | 493 ++- .../azure/ai/projects/models/__init__.py | 52 +- .../azure/ai/projects/models/_enums.py | 64 +- .../azure/ai/projects/models/_models.py | 2269 ++++++---- .../azure/ai/projects/operations/__init__.py | 2 - .../ai/projects/operations/_operations.py | 3793 ++++++++--------- 10 files changed, 3748 insertions(+), 2941 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py index c20cfd7223c6..318f549168a8 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_client.py @@ -23,7 +23,6 @@ DatasetsOperations, DeploymentsOperations, EvaluationRulesOperations, - EvaluationSuitesOperations, IndexesOperations, ) @@ -48,8 +47,6 @@ class AIProjectClient: # pylint: disable=too-many-instance-attributes :vartype deployments: azure.ai.projects.operations.DeploymentsOperations :ivar indexes: IndexesOperations operations :vartype indexes: azure.ai.projects.operations.IndexesOperations - :ivar evaluation_suites: EvaluationSuitesOperations operations - :vartype evaluation_suites: azure.ai.projects.operations.EvaluationSuitesOperations :param endpoint: Foundry Project endpoint in the form "https://{ai-services-account-name}.services.ai.azure.com/api/projects/{project-name}". If you only have one Project in your Foundry Hub, or to target the default Project in your Hub, use @@ -105,9 +102,6 @@ def __init__( self.datasets = DatasetsOperations(self._client, self._config, self._serialize, self._deserialize) self.deployments = DeploymentsOperations(self._client, self._config, self._serialize, self._deserialize) self.indexes = IndexesOperations(self._client, self._config, self._serialize, self._deserialize) - self.evaluation_suites = EvaluationSuitesOperations( - self._client, self._config, self._serialize, self._deserialize - ) def send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: Any) -> HttpResponse: """Runs the network request through the client's chained policies. diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py b/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py index 4cad4f8c3efe..5e23b3911701 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/_types.py @@ -11,5 +11,3 @@ if TYPE_CHECKING: from . import models as _models Filters = Union["_models.ComparisonFilter", "_models.CompoundFilter"] -EvalItemContentItem = Union[str, "_models.EvalItemContentItemObject"] -EvalItemContent = Union["_types.EvalItemContentItem", list["_types.EvalItemContentItem"]] diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py index 19c25c051357..e92b1057b268 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_client.py @@ -23,7 +23,6 @@ DatasetsOperations, DeploymentsOperations, EvaluationRulesOperations, - EvaluationSuitesOperations, IndexesOperations, ) @@ -48,8 +47,6 @@ class AIProjectClient: # pylint: disable=too-many-instance-attributes :vartype deployments: azure.ai.projects.aio.operations.DeploymentsOperations :ivar indexes: IndexesOperations operations :vartype indexes: azure.ai.projects.aio.operations.IndexesOperations - :ivar evaluation_suites: EvaluationSuitesOperations operations - :vartype evaluation_suites: azure.ai.projects.aio.operations.EvaluationSuitesOperations :param endpoint: Foundry Project endpoint in the form "https://{ai-services-account-name}.services.ai.azure.com/api/projects/{project-name}". If you only have one Project in your Foundry Hub, or to target the default Project in your Hub, use @@ -105,9 +102,6 @@ def __init__( self.datasets = DatasetsOperations(self._client, self._config, self._serialize, self._deserialize) self.deployments = DeploymentsOperations(self._client, self._config, self._serialize, self._deserialize) self.indexes = IndexesOperations(self._client, self._config, self._serialize, self._deserialize) - self.evaluation_suites = EvaluationSuitesOperations( - self._client, self._config, self._serialize, self._deserialize - ) def send_request( self, request: HttpRequest, *, stream: bool = False, **kwargs: Any diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py index 546fdb068dcc..1a1c0ffec86c 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/__init__.py @@ -19,7 +19,6 @@ from ._operations import DatasetsOperations # type: ignore from ._operations import DeploymentsOperations # type: ignore from ._operations import IndexesOperations # type: ignore -from ._operations import EvaluationSuitesOperations # type: ignore from ._patch import __all__ as _patch_all from ._patch import * @@ -33,7 +32,6 @@ "DatasetsOperations", "DeploymentsOperations", "IndexesOperations", - "EvaluationSuitesOperations", ] __all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index 59a0946fa044..5e6c7cc31436 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -66,16 +66,25 @@ build_beta_agents_list_sessions_request, build_beta_agents_patch_agent_details_request, build_beta_agents_upload_session_file_request, + build_beta_datasets_cancel_generation_job_request, + build_beta_datasets_create_generation_job_request, + build_beta_datasets_delete_generation_job_request, + build_beta_datasets_get_generation_job_request, + build_beta_datasets_list_generation_jobs_request, build_beta_evaluation_taxonomies_create_request, build_beta_evaluation_taxonomies_delete_request, build_beta_evaluation_taxonomies_get_request, build_beta_evaluation_taxonomies_list_request, build_beta_evaluation_taxonomies_update_request, + build_beta_evaluators_cancel_generation_job_request, + build_beta_evaluators_create_generation_job_request, build_beta_evaluators_create_version_request, + build_beta_evaluators_delete_generation_job_request, build_beta_evaluators_delete_version_request, build_beta_evaluators_get_credentials_request, build_beta_evaluators_get_generation_job_request, build_beta_evaluators_get_version_request, + build_beta_evaluators_list_generation_jobs_request, build_beta_evaluators_list_request, build_beta_evaluators_list_versions_request, build_beta_evaluators_pending_upload_request, @@ -152,13 +161,6 @@ build_evaluation_rules_delete_request, build_evaluation_rules_get_request, build_evaluation_rules_list_request, - build_evaluation_suites_create_evaluation_suite_version_request, - build_evaluation_suites_create_or_update_version_request, - build_evaluation_suites_delete_version_request, - build_evaluation_suites_get_version_request, - build_evaluation_suites_list_latest_request, - build_evaluation_suites_list_versions_request, - build_evaluation_suites_run_request, build_indexes_create_or_update_request, build_indexes_delete_request, build_indexes_get_request, @@ -204,6 +206,7 @@ def __init__(self, *args, **kwargs) -> None: self.schedules = BetaSchedulesOperations(self._client, self._config, self._serialize, self._deserialize) self.toolboxes = BetaToolboxesOperations(self._client, self._config, self._serialize, self._deserialize) self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) + self.datasets = BetaDatasetsOperations(self._client, self._config, self._serialize, self._deserialize) class AgentsOperations: @@ -3063,7 +3066,7 @@ class BetaAgentsOperations: # pylint: disable=too-many-public-methods Instead, you should access the following operations through :class:`~azure.ai.projects.aio.AIProjectClient`'s - :attr:`evaluation_suites` attribute. + :attr:`agents` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -13043,3 +13046,477 @@ async def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + + +class BetaDatasetsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`datasets` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: + """Get info about a data generation job. + + Gets the details of a data generation job by its ID. + + :param job_id: The ID of the job. Required. + :type job_id: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + + _request = build_beta_datasets_get_generation_job_request( + job_id=job_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DataGenerationJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_generation_jobs( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + scenario: Optional[Union[str, _models.DataGenerationJobScenario]] = None, + type: Optional[List[Union[str, _models.DataGenerationJobType]]] = None, + **kwargs: Any + ) -> AsyncItemPaged["_models.DataGenerationJob"]: + """Returns a list of data generation jobs. + + Returns a list of data generation jobs. + + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :keyword scenario: Filter data generation jobs by their scenario. Known values are: + "supervised_finetuning", "reinforcement_finetuning", and "evaluation". Default value is None. + :paramtype scenario: str or ~azure.ai.projects.models.DataGenerationJobScenario + :keyword type: Filter data generation jobs by their type. Default value is None. + :paramtype type: list[str or ~azure.ai.projects.models.DataGenerationJobType] + :return: An iterator like instance of DataGenerationJob + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.projects.models.DataGenerationJob] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.DataGenerationJob]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_datasets_list_generation_jobs_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + scenario=scenario, + type=type, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + async def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.DataGenerationJob], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, AsyncList(list_of_elem) + + async def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return AsyncItemPaged(get_next, extract_data) + + @overload + async def create_generation_job( + self, + job: _models.DataGenerationJob, + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DataGenerationJob: + """Creates a data generation job. + + Creates a data generation job. + + :param job: The job to create. Required. + :type job: ~azure.ai.projects.models.DataGenerationJob + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_generation_job( + self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any + ) -> _models.DataGenerationJob: + """Creates a data generation job. + + Creates a data generation job. + + :param job: The job to create. Required. + :type job: JSON + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_generation_job( + self, + job: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DataGenerationJob: + """Creates a data generation job. + + Creates a data generation job. + + :param job: The job to create. Required. + :type job: IO[bytes] + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_generation_job( + self, + job: Union[_models.DataGenerationJob, JSON, IO[bytes]], + *, + operation_id: Optional[str] = None, + **kwargs: Any + ) -> _models.DataGenerationJob: + """Creates a data generation job. + + Creates a data generation job. + + :param job: The job to create. Is one of the following types: DataGenerationJob, JSON, + IO[bytes] Required. + :type job: ~azure.ai.projects.models.DataGenerationJob or JSON or IO[bytes] + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(job, (IOBase, bytes)): + _content = job + else: + _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_datasets_create_generation_job_request( + operation_id=operation_id, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DataGenerationJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: + """Cancels a data generation job. + + Cancels a data generation job by its ID. + + :param job_id: The ID of the job to cancel. Required. + :type job_id: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) + + _request = build_beta_datasets_cancel_generation_job_request( + job_id=job_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + if _stream: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DataGenerationJob, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def delete_generation_job(self, job_id: str, **kwargs: Any) -> None: + """Deletes a data generation job. + + Deletes a data generation job by its ID. + + :param job_id: The ID of the job to delete. Required. + :type job_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_datasets_delete_generation_job_request( + job_id=job_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py index 75a96137818b..1b8c85aace5a 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/__init__.py @@ -21,10 +21,12 @@ AgentCardSkill, AgentClusterInsightRequest, AgentClusterInsightResult, + AgentDataGenerationJobSource, AgentDefinition, AgentDetails, AgentEndpointAuthorizationScheme, AgentEndpointConfig, + AgentEvaluatorGenerationJobSource, AgentIdentity, AgentObjectVersions, AgentSessionResource, @@ -146,12 +148,19 @@ EvaluationTaxonomyInput, EvaluatorCredentialRequest, EvaluatorDefinition, + EvaluatorGenerationArtifacts, + EvaluatorGenerationInputs, + EvaluatorGenerationJob, + EvaluatorGenerationJobSource, + EvaluatorGenerationTokenUsage, EvaluatorMetric, EvaluatorVersion, ExternalAgentDefinition, FabricDataAgentToolParameters, FabricIQPreviewTool, FieldMapping, + FileDataGenerationJobOutput, + FileDataGenerationJobSource, FileDatasetVersion, FileSearchTool, FixedRatioVersionSelectionRule, @@ -174,8 +183,6 @@ Index, InlineSkillParam, InlineSkillSourceParam, - InputAudio, - InputAudioInputAudio, Insight, InsightCluster, InsightModelConfiguration, @@ -249,6 +256,8 @@ PromptAgentDefinition, PromptAgentDefinitionTextOptions, PromptBasedEvaluatorDefinition, + PromptDataGenerationJobSource, + PromptEvaluatorGenerationJobSource, ProtocolVersionRecord, RaiConfig, RankingOptions, @@ -277,6 +286,7 @@ SessionLogEvent, SharepointGroundingToolParameters, SharepointPreviewTool, + SimpleQnADataGenerationJobOptions, SkillDetails, SkillReferenceParam, SpecificApplyPatchParam, @@ -289,7 +299,6 @@ TelemetryConfig, TelemetryEndpoint, TelemetryEndpointAuth, - TestingCriterionAzureAIEvaluator, TextResponseFormat, TextResponseFormatJsonObject, TextResponseFormatJsonSchema, @@ -310,10 +319,14 @@ ToolConfig, ToolDescription, ToolProjectConnection, + ToolUseFineTuningDataGenerationJobOptions, ToolboxObject, ToolboxPolicies, ToolboxSearchPreviewTool, ToolboxVersionObject, + TracesDataGenerationJobOptions, + TracesDataGenerationJobSource, + TracesEvaluatorGenerationJobSource, Trigger, UpdateModelVersionRequest, UpdateToolboxRequest, @@ -351,16 +364,20 @@ ContainerSkillType, CredentialType, CustomToolParamFormatType, + DataGenerationJobOutputType, + DataGenerationJobScenario, + DataGenerationJobSourceType, + DataGenerationJobType, DatasetType, DayOfWeek, DeploymentType, EvalRunOutputItemResultStatus, EvaluationRuleActionType, EvaluationRuleEventType, - EvaluationSuiteSubtype, EvaluationTaxonomyInputType, EvaluatorCategory, EvaluatorDefinitionType, + EvaluatorGenerationJobSourceType, EvaluatorMetricDirection, EvaluatorMetricType, EvaluatorType, @@ -401,6 +418,7 @@ ScheduleTaskType, SearchContextSize, SessionLogEventType, + SimpleQnAFineTuningQuestionType, TelemetryDataKind, TelemetryEndpointAuthType, TelemetryEndpointKind, @@ -425,10 +443,12 @@ "AgentCardSkill", "AgentClusterInsightRequest", "AgentClusterInsightResult", + "AgentDataGenerationJobSource", "AgentDefinition", "AgentDetails", "AgentEndpointAuthorizationScheme", "AgentEndpointConfig", + "AgentEvaluatorGenerationJobSource", "AgentIdentity", "AgentObjectVersions", "AgentSessionResource", @@ -550,12 +570,19 @@ "EvaluationTaxonomyInput", "EvaluatorCredentialRequest", "EvaluatorDefinition", + "EvaluatorGenerationArtifacts", + "EvaluatorGenerationInputs", + "EvaluatorGenerationJob", + "EvaluatorGenerationJobSource", + "EvaluatorGenerationTokenUsage", "EvaluatorMetric", "EvaluatorVersion", "ExternalAgentDefinition", "FabricDataAgentToolParameters", "FabricIQPreviewTool", "FieldMapping", + "FileDataGenerationJobOutput", + "FileDataGenerationJobSource", "FileDatasetVersion", "FileSearchTool", "FixedRatioVersionSelectionRule", @@ -578,8 +605,6 @@ "Index", "InlineSkillParam", "InlineSkillSourceParam", - "InputAudio", - "InputAudioInputAudio", "Insight", "InsightCluster", "InsightModelConfiguration", @@ -653,6 +678,8 @@ "PromptAgentDefinition", "PromptAgentDefinitionTextOptions", "PromptBasedEvaluatorDefinition", + "PromptDataGenerationJobSource", + "PromptEvaluatorGenerationJobSource", "ProtocolVersionRecord", "RaiConfig", "RankingOptions", @@ -681,6 +708,7 @@ "SessionLogEvent", "SharepointGroundingToolParameters", "SharepointPreviewTool", + "SimpleQnADataGenerationJobOptions", "SkillDetails", "SkillReferenceParam", "SpecificApplyPatchParam", @@ -693,7 +721,6 @@ "TelemetryConfig", "TelemetryEndpoint", "TelemetryEndpointAuth", - "TestingCriterionAzureAIEvaluator", "TextResponseFormat", "TextResponseFormatJsonObject", "TextResponseFormatJsonSchema", @@ -714,10 +741,14 @@ "ToolConfig", "ToolDescription", "ToolProjectConnection", + "ToolUseFineTuningDataGenerationJobOptions", "ToolboxObject", "ToolboxPolicies", "ToolboxSearchPreviewTool", "ToolboxVersionObject", + "TracesDataGenerationJobOptions", + "TracesDataGenerationJobSource", + "TracesEvaluatorGenerationJobSource", "Trigger", "UpdateModelVersionRequest", "UpdateToolboxRequest", @@ -752,16 +783,20 @@ "ContainerSkillType", "CredentialType", "CustomToolParamFormatType", + "DataGenerationJobOutputType", + "DataGenerationJobScenario", + "DataGenerationJobSourceType", + "DataGenerationJobType", "DatasetType", "DayOfWeek", "DeploymentType", "EvalRunOutputItemResultStatus", "EvaluationRuleActionType", "EvaluationRuleEventType", - "EvaluationSuiteSubtype", "EvaluationTaxonomyInputType", "EvaluatorCategory", "EvaluatorDefinitionType", + "EvaluatorGenerationJobSourceType", "EvaluatorMetricDirection", "EvaluatorMetricType", "EvaluatorType", @@ -802,6 +837,7 @@ "ScheduleTaskType", "SearchContextSize", "SessionLogEventType", + "SimpleQnAFineTuningQuestionType", "TelemetryDataKind", "TelemetryEndpointAuthType", "TelemetryEndpointKind", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py index 06e6ed3cca75..f728019a7cb4 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_enums.py @@ -354,6 +354,52 @@ class CustomToolParamFormatType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """GRAMMAR.""" +class DataGenerationJobOutputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The supported output file types for a data generation job.""" + + FILE = "file" + """The generated data is an Azure OpenAI File.""" + DATASET = "dataset" + """The generated data is a Dataset.""" + + +class DataGenerationJobScenario(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The supported scenarios for a data generation job.""" + + SUPERVISED_FINETUNING = "supervised_finetuning" + """Supervised Fine-tuning scenario.""" + REINFORCEMENT_FINETUNING = "reinforcement_finetuning" + """Reinforcement Fine-tuning scenario.""" + EVALUATION = "evaluation" + """Evaluation scenario.""" + + +class DataGenerationJobSourceType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The supported source types for data generation jobs.""" + + PROMPT = "prompt" + """Prompt source — inline text provided by the user.""" + AGENT = "agent" + """Agent source — references an agent.""" + TRACES = "traces" + """Traces source — conversation traces from Application Insights.""" + DATASET = "dataset" + """Dataset source — reference to a dataset.""" + FILE = "file" + """File source — Azure OpenAI file.""" + + +class DataGenerationJobType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The supported data generation job types.""" + + SIMPLE_QNA = "simple_qna" + """Simple question and answers between user and agent.""" + TRACES = "traces" + """Single turn query and response from agent traces.""" + TOOL_USE = "tool_use" + """Tool calling conversation between user and agent.""" + + class DatasetType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Enum to determine the type of data.""" @@ -418,15 +464,6 @@ class EvaluationRuleEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Manual trigger.""" -class EvaluationSuiteSubtype(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """The subtype of an evaluation suite.""" - - DEFAULT = "default" - """Default suite type.""" - BENCHMARK = "benchmark" - """Benchmark suite.""" - - class EvaluationTaxonomyInputType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """Type of the evaluation taxonomy input.""" @@ -938,6 +975,15 @@ class SessionLogEventType(str, Enum, metaclass=CaseInsensitiveEnumMeta): """A log line from the agent session container.""" +class SimpleQnAFineTuningQuestionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The supported question types for SimpleQnA data generation jobs used for fine-tuning scenarios.""" + + SHORT_ANSWER = "short_answer" + """Short answer question type.""" + LONG_ANSWER = "long_answer" + """Long answer question type.""" + + class TelemetryDataKind(str, Enum, metaclass=CaseInsensitiveEnumMeta): """The type of telemetry data to export.""" diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py index f95fc1bf1a94..b73ace6881df 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/models/_models.py @@ -22,12 +22,15 @@ ContainerSkillType, CredentialType, CustomToolParamFormatType, + DataGenerationJobOutputType, + DataGenerationJobSourceType, + DataGenerationJobType, DatasetType, DeploymentType, - EvalItemContentItemObjectType, EvaluationRuleActionType, EvaluationTaxonomyInputType, EvaluatorDefinitionType, + EvaluatorGenerationJobSourceType, FunctionShellToolParamEnvironmentType, IndexType, InsightType, @@ -438,6 +441,94 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = InsightType.AGENT_CLUSTER_INSIGHT # type: ignore +class DataGenerationJobSource(_Model): + """The base source model for data generation jobs. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + AgentDataGenerationJobSource, DatasetDataGenerationJobSource, FileDataGenerationJobSource, + PromptDataGenerationJobSource, TracesDataGenerationJobSource + + :ivar type: The type of source. Required. Known values are: "prompt", "agent", "traces", + "dataset", and "file". + :vartype type: str or ~azure.ai.projects.models.DataGenerationJobSourceType + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of source. Required. Known values are: \"prompt\", \"agent\", \"traces\", \"dataset\", + and \"file\".""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional description of what this source represents — helps the pipeline interpret its content + (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" + + @overload + def __init__( + self, + *, + type: str, + description: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class AgentDataGenerationJobSource(DataGenerationJobSource, discriminator="agent"): + """Agent source for data generation jobs — references an agent to fetch instructions and metadata + from. + + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this source, which is Agent. Required. Agent source — + references an agent. + :vartype type: str or ~azure.ai.projects.models.AGENT + :ivar agent_name: The agent name to fetch instructions from. Required. + :vartype agent_name: str + :ivar agent_version: The agent version. If not specified, the latest version is used. + :vartype agent_version: str + """ + + type: Literal[DataGenerationJobSourceType.AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this source, which is Agent. Required. Agent source — references an agent.""" + agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent name to fetch instructions from. Required.""" + agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent version. If not specified, the latest version is used.""" + + @overload + def __init__( + self, + *, + agent_name: str, + description: Optional[str] = None, + agent_version: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobSourceType.AGENT # type: ignore + + class AgentDefinition(_Model): """AgentDefinition. @@ -620,6 +711,90 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class EvaluatorGenerationJobSource(_Model): + """The base source model for evaluator generation jobs. Polymorphic over ``type``. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + AgentEvaluatorGenerationJobSource, DatasetEvaluatorGenerationJobSource, + PromptEvaluatorGenerationJobSource, TracesEvaluatorGenerationJobSource + + :ivar type: The type of source. Required. Known values are: "prompt", "agent", "traces", and + "dataset". + :vartype type: str or ~azure.ai.projects.models.EvaluatorGenerationJobSourceType + """ + + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of source. Required. Known values are: \"prompt\", \"agent\", \"traces\", and + \"dataset\".""" + + @overload + def __init__( + self, + *, + type: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class AgentEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="agent"): + """Agent source for evaluator generation jobs — references an agent to fetch instructions and + metadata from. + + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this source, which is Agent. Required. Agent source — + references an agent to fetch instructions and metadata from. + :vartype type: str or ~azure.ai.projects.models.AGENT + :ivar agent_name: The agent name to fetch instructions from. Required. + :vartype agent_name: str + :ivar agent_version: The agent version. If not specified, the latest version is used. + :vartype agent_version: str + """ + + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional description of what this source represents — helps the pipeline interpret its content + (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" + type: Literal[EvaluatorGenerationJobSourceType.AGENT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this source, which is Agent. Required. Agent source — references an agent + to fetch instructions and metadata from.""" + agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent name to fetch instructions from. Required.""" + agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent version. If not specified, the latest version is used.""" + + @overload + def __init__( + self, + *, + agent_name: str, + description: Optional[str] = None, + agent_version: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = EvaluatorGenerationJobSourceType.AGENT # type: ignore + + class BaseCredentials(_Model): """A base class for connection credentials. @@ -2883,10 +3058,10 @@ class EvaluatorDefinition(_Model): """Base evaluator configuration with discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - CodeBasedEvaluatorDefinition, PromptBasedEvaluatorDefinition + CodeBasedEvaluatorDefinition, PromptBasedEvaluatorDefinition, RubricBasedEvaluatorDefinition :ivar type: The type of evaluator definition. Required. Known values are: "prompt", "code", - "prompt_and_code", "service", "openai_graders", and "rubrics". + "prompt_and_code", "service", "openai_graders", and "rubric". :vartype type: str or ~azure.ai.projects.models.EvaluatorDefinitionType :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. This includes parameters like type, properties, required. @@ -2901,7 +3076,7 @@ class EvaluatorDefinition(_Model): __mapping__: dict[str, _Model] = {} type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) """The type of evaluator definition. Required. Known values are: \"prompt\", \"code\", - \"prompt_and_code\", \"service\", \"openai_graders\", and \"rubrics\".""" + \"prompt_and_code\", \"service\", \"openai_graders\", and \"rubric\".""" init_parameters: Optional[dict[str, Any]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The JSON schema (Draft 2020-12) for the evaluator's input parameters. This includes parameters like type, properties, required.""" @@ -3826,6 +4001,42 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class CreateAsyncResponse(_Model): + """CreateAsyncResponse. + + :ivar location: URL to poll for operation status. + :vartype location: str + :ivar operation_result: URL to the operation result, or null if the operation is still in + progress. + :vartype operation_result: str + """ + + location: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """URL to poll for operation status.""" + operation_result: Optional[str] = rest_field( + name="operationResult", visibility=["read", "create", "update", "delete", "query"] + ) + """URL to the operation result, or null if the operation is still in progress.""" + + @overload + def __init__( + self, + *, + location: Optional[str] = None, + operation_result: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class Trigger(_Model): """Base model for Trigger of the schedule. @@ -4152,23 +4363,53 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = RecurrenceType.DAILY # type: ignore -class DatasetCredential(_Model): - """Represents a reference to a blob for consumption. +class DataGenerationJob(_Model): + """Data Generation Job resource. - :ivar blob_reference: Credential info to access the storage account. Required. - :vartype blob_reference: ~azure.ai.projects.models.BlobReference + :ivar id: Server-assigned unique identifier. Required. + :vartype id: str + :ivar inputs: Caller-supplied inputs. + :vartype inputs: ~azure.ai.projects.models.DataGenerationJobInputs + :ivar result: Result produced on success. + :vartype result: ~azure.ai.projects.models.DataGenerationJobResult + :ivar status: Current lifecycle status. Required. Known values are: "queued", "in_progress", + "succeeded", "failed", and "cancelled". + :vartype status: str or ~azure.ai.projects.models.JobStatus + :ivar error: Error details — populated only on failure. + :vartype error: ~azure.ai.projects.models.ApiError + :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds + since January 1, 1970). Required. + :vartype created_at: ~datetime.datetime + :ivar finished_at: The timestamp when the job was finished, represented in Unix time (seconds + since January 1, 1970). + :vartype finished_at: ~datetime.datetime """ - blob_reference: "_models.BlobReference" = rest_field( - name="blobReference", visibility=["read", "create", "update", "delete", "query"] + id: str = rest_field(visibility=["read"]) + """Server-assigned unique identifier. Required.""" + inputs: Optional["_models.DataGenerationJobInputs"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] ) - """Credential info to access the storage account. Required.""" + """Caller-supplied inputs.""" + result: Optional["_models.DataGenerationJobResult"] = rest_field(visibility=["read"]) + """Result produced on success.""" + status: Union[str, "_models.JobStatus"] = rest_field(visibility=["read"]) + """Current lifecycle status. Required. Known values are: \"queued\", \"in_progress\", + \"succeeded\", \"failed\", and \"cancelled\".""" + error: Optional["_models.ApiError"] = rest_field(visibility=["read"]) + """Error details — populated only on failure.""" + created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """The timestamp when the job was created, represented in Unix time (seconds since January 1, + 1970). Required.""" + finished_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The timestamp when the job was finished, represented in Unix time (seconds since January 1, + 1970).""" @overload def __init__( self, *, - blob_reference: "_models.BlobReference", + inputs: Optional["_models.DataGenerationJobInputs"] = None, ) -> None: ... @overload @@ -4182,27 +4423,10 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatasetVersion(_Model): - """DatasetVersion Definition. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - FileDatasetVersion, FolderDatasetVersion +class DataGenerationJobInputs(_Model): + """Caller-supplied inputs for a data generation job. - :ivar data_uri: URI of the data (`example `_). - Required. - :vartype data_uri: str - :ivar type: Dataset type. Required. Known values are: "uri_file" and "uri_folder". - :vartype type: str or ~azure.ai.projects.models.DatasetType - :ivar is_reference: Indicates if the dataset holds a reference to the storage, or the dataset - manages storage itself. If true, the underlying data will not be deleted when the dataset - version is deleted. - :vartype is_reference: bool - :ivar connection_name: The Azure Storage Account connection name. Required if - startPendingUploadVersion was not called before creating the Dataset. - :vartype connection_name: str - :ivar id: Asset ID, a unique identifier for the asset. - :vartype id: str - :ivar name: The name of the resource. Required. + :ivar name: The display name of the data generation job. Required. :vartype name: str :ivar sources: The sources used for the data generation job. Required. :vartype sources: list[~azure.ai.projects.models.DataGenerationJobSource] @@ -4212,6 +4436,10 @@ class DatasetVersion(_Model): Required. Known values are: "supervised_finetuning", "reinforcement_finetuning", and "evaluation". :vartype scenario: str or ~azure.ai.projects.models.DataGenerationJobScenario + :ivar output_options: Optional caller-supplied metadata for the job's output. See individual + fields for whether they apply to file outputs (fine-tuning scenarios), dataset outputs + (evaluation scenario), or both. + :vartype output_options: ~azure.ai.projects.models.DataGenerationJobOutputOptions """ name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -4227,6 +4455,11 @@ class DatasetVersion(_Model): ) """The scenario of the data generation job. Either for fine-tuning or evaluation. Required. Known values are: \"supervised_finetuning\", \"reinforcement_finetuning\", and \"evaluation\".""" + output_options: Optional["_models.DataGenerationJobOutputOptions"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Optional caller-supplied metadata for the job's output. See individual fields for whether they + apply to file outputs (fine-tuning scenarios), dataset outputs (evaluation scenario), or both.""" @overload def __init__( @@ -4236,6 +4469,7 @@ def __init__( sources: list["_models.DataGenerationJobSource"], options: "_models.DataGenerationJobOptions", scenario: Union[str, "_models.DataGenerationJobScenario"], + output_options: Optional["_models.DataGenerationJobOutputOptions"] = None, ) -> None: ... @overload @@ -4249,33 +4483,47 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteAgentResponse(_Model): - """A deleted agent Object. +class DataGenerationJobOptions(_Model): + """Options for managing data generation jobs. - :ivar object: The object type. Always 'agent.deleted'. Required. AGENT_DELETED. - :vartype object: str or ~azure.ai.projects.models.AGENT_DELETED - :ivar name: The name of the agent. Required. - :vartype name: str - :ivar deleted: Whether the agent was successfully deleted. Required. - :vartype deleted: bool + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + SimpleQnADataGenerationJobOptions, ToolUseFineTuningDataGenerationJobOptions, + TracesDataGenerationJobOptions + + :ivar type: The data generation job type. Required. Known values are: "simple_qna", "traces", + and "tool_use". + :vartype type: str or ~azure.ai.projects.models.DataGenerationJobType + :ivar max_samples: Maximum number of samples to generate. Required. + :vartype max_samples: int + :ivar train_split: The proportion of the generated data to be used for training when the data + is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. + :vartype train_split: float + :ivar model_options: The LLM model options. + :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions """ - object: Literal[AgentObjectType.AGENT_DELETED] = rest_field( + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The data generation job type. Required. Known values are: \"simple_qna\", \"traces\", and + \"tool_use\".""" + max_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Maximum number of samples to generate. Required.""" + train_split: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The proportion of the generated data to be used for training when the data is used for + fine-tuning. The rest will be used for validation. Value should be between 0 and 1.""" + model_options: Optional["_models.DataGenerationModelOptions"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The object type. Always 'agent.deleted'. Required. AGENT_DELETED.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the agent. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the agent was successfully deleted. Required.""" + """The LLM model options.""" @overload def __init__( self, *, - object: Literal[AgentObjectType.AGENT_DELETED], - name: str, - deleted: bool, + type: str, + max_samples: int, + train_split: Optional[float] = None, + model_options: Optional["_models.DataGenerationModelOptions"] = None, ) -> None: ... @overload @@ -4289,38 +4537,25 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteAgentVersionResponse(_Model): - """A deleted agent version Object. +class DataGenerationJobOutput(_Model): + """Output information for a data generation job. - :ivar object: The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED. - :vartype object: str or ~azure.ai.projects.models.AGENT_VERSION_DELETED - :ivar name: The name of the agent. Required. - :vartype name: str - :ivar version: The version identifier of the agent. Required. - :vartype version: str - :ivar deleted: Whether the agent was successfully deleted. Required. - :vartype deleted: bool + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + DatasetDataGenerationJobOutput, FileDataGenerationJobOutput + + :ivar type: The type of the output. Required. Known values are: "file" and "dataset". + :vartype type: str or ~azure.ai.projects.models.DataGenerationJobOutputType """ - object: Literal[AgentObjectType.AGENT_VERSION_DELETED] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the agent. Required.""" - version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version identifier of the agent. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the agent was successfully deleted. Required.""" + __mapping__: dict[str, _Model] = {} + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """The type of the output. Required. Known values are: \"file\" and \"dataset\".""" @overload def __init__( self, *, - object: Literal[AgentObjectType.AGENT_VERSION_DELETED], - name: str, - version: str, - deleted: bool, + type: str, ) -> None: ... @overload @@ -4378,33 +4613,36 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteMemoryStoreResult(_Model): - """DeleteMemoryStoreResult. +class DataGenerationJobResult(_Model): + """Result produced by a successful data generation job. - :ivar object: The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED. - :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE_DELETED - :ivar name: The name of the memory store. Required. - :vartype name: str - :ivar deleted: Whether the memory store was successfully deleted. Required. - :vartype deleted: bool + :ivar outputs: The final job outputs: Azure OpenAI files for fine-tuning, or datasets for + evaluation. + :vartype outputs: list[~azure.ai.projects.models.DataGenerationJobOutput] + :ivar generated_samples: The number of samples actually generated. Required. + :vartype generated_samples: int + :ivar token_usage: The token usage information for the data generation job. + :vartype token_usage: ~azure.ai.projects.models.DataGenerationTokenUsage """ - object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED] = rest_field( + outputs: Optional[list["_models.DataGenerationJobOutput"]] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED.""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the memory store. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the memory store was successfully deleted. Required.""" + """The final job outputs: Azure OpenAI files for fine-tuning, or datasets for evaluation.""" + generated_samples: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The number of samples actually generated. Required.""" + token_usage: Optional["_models.DataGenerationTokenUsage"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The token usage information for the data generation job.""" @overload def __init__( self, *, - object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED], - name: str, - deleted: bool, + generated_samples: int, + outputs: Optional[list["_models.DataGenerationJobOutput"]] = None, + token_usage: Optional["_models.DataGenerationTokenUsage"] = None, ) -> None: ... @overload @@ -4418,26 +4656,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DeleteSkillResult(_Model): - """A deleted skill Object. +class DataGenerationModelOptions(_Model): + """LLM model options for data generation jobs. - :ivar name: The unique name of the skill. Required. - :vartype name: str - :ivar deleted: Whether the skill was successfully deleted. Required. - :vartype deleted: bool + :ivar model: Base model name used to generate data. Required. + :vartype model: str """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique name of the skill. Required.""" - deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Whether the skill was successfully deleted. Required.""" + model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Base model name used to generate data. Required.""" @overload def __init__( self, *, - name: str, - deleted: bool, + model: str, ) -> None: ... @overload @@ -4451,64 +4684,42 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Deployment(_Model): - """Model Deployment Definition. - - You probably want to use the sub-classes and not this class directly. Known sub-classes are: - ModelDeployment +class DataGenerationTokenUsage(_Model): + """Token usage information for a data generation job. - :ivar type: The type of the deployment. Required. "ModelDeployment" - :vartype type: str or ~azure.ai.projects.models.DeploymentType - :ivar name: Name of the deployment. Required. - :vartype name: str + :ivar prompt_tokens: The number of prompt tokens used. Required. + :vartype prompt_tokens: int + :ivar completion_tokens: The number of completion tokens generated. Required. + :vartype completion_tokens: int + :ivar total_tokens: Total number of tokens used. Required. + :vartype total_tokens: int """ - __mapping__: dict[str, _Model] = {} - type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """The type of the deployment. Required. \"ModelDeployment\"""" - name: str = rest_field(visibility=["read"]) - """Name of the deployment. Required.""" + prompt_tokens: int = rest_field(visibility=["read"]) + """The number of prompt tokens used. Required.""" + completion_tokens: int = rest_field(visibility=["read"]) + """The number of completion tokens generated. Required.""" + total_tokens: int = rest_field(visibility=["read"]) + """Total number of tokens used. Required.""" - @overload - def __init__( - self, - *, - type: str, - ) -> None: ... - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class EmbeddingConfiguration(_Model): - """Embedding configuration class. +class DatasetCredential(_Model): + """Represents a reference to a blob for consumption. - :ivar model_deployment_name: Deployment name of embedding model. It can point to a model - deployment either in the parent AIServices or a connection. Required. - :vartype model_deployment_name: str - :ivar embedding_field: Embedding field. Required. - :vartype embedding_field: str + :ivar blob_reference: Credential info to access the storage account. Required. + :vartype blob_reference: ~azure.ai.projects.models.BlobReference """ - model_deployment_name: str = rest_field(name="modelDeploymentName", visibility=["create"]) - """Deployment name of embedding model. It can point to a model deployment either in the parent - AIServices or a connection. Required.""" - embedding_field: str = rest_field(name="embeddingField", visibility=["create"]) - """Embedding field. Required.""" + blob_reference: "_models.BlobReference" = rest_field( + name="blobReference", visibility=["read", "create", "update", "delete", "query"] + ) + """Credential info to access the storage account. Required.""" @overload def __init__( self, *, - model_deployment_name: str, - embedding_field: str, + blob_reference: "_models.BlobReference", ) -> None: ... @overload @@ -4522,22 +4733,20 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EntraAuthorizationScheme(AgentEndpointAuthorizationScheme, discriminator="Entra"): - """EntraAuthorizationScheme. +class DatasetDataGenerationJobOutput(DataGenerationJobOutput, discriminator="dataset"): + """Dataset output for a data generation job. :ivar type: Dataset output. Required. The generated data is a Dataset. :vartype type: str or ~azure.ai.projects.models.DATASET :ivar id: The id of the output dataset created. :vartype id: str - :ivar name: The name of the output dataset and can be optionally set during job creation time. + :ivar name: The name of the output dataset. :vartype name: str :ivar version: The version of the output dataset. :vartype version: str - :ivar description: Description of the output dataset and can be optionally set during job - creation time. + :ivar description: Description of the output dataset. :vartype description: str - :ivar tags: Tag dictionary of the output dataset and can be optionally set during job creation - time. + :ivar tags: Tag dictionary of the output dataset. :vartype tags: dict[str, str] """ @@ -4545,14 +4754,14 @@ class EntraAuthorizationScheme(AgentEndpointAuthorizationScheme, discriminator=" """Dataset output. Required. The generated data is a Dataset.""" id: Optional[str] = rest_field(visibility=["read"]) """The id of the output dataset created.""" - name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the output dataset and can be optionally set during job creation time.""" + name: Optional[str] = rest_field(visibility=["read"]) + """The name of the output dataset.""" version: Optional[str] = rest_field(visibility=["read"]) """The version of the output dataset.""" - description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Description of the output dataset and can be optionally set during job creation time.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Tag dictionary of the output dataset and can be optionally set during job creation time.""" + description: Optional[str] = rest_field(visibility=["read"]) + """Description of the output dataset.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["read"]) + """Tag dictionary of the output dataset.""" @overload def __init__( @@ -4568,22 +4777,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = AgentEndpointAuthorizationSchemeType.ENTRA # type: ignore + self.type = DataGenerationJobOutputType.DATASET # type: ignore -class EntraIDCredentials(BaseCredentials, discriminator="AAD"): - """Entra ID credential definition. +class DatasetDataGenerationJobSource(DataGenerationJobSource, discriminator="dataset"): + """Dataset source for data generation jobs — reference to a dataset. - :ivar type: The credential type. Required. Entra ID credential (formerly known as AAD). - :vartype type: str or ~azure.ai.projects.models.ENTRA_ID + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this source, which is Dataset. Required. Dataset source — + reference to a dataset. + :vartype type: str or ~azure.ai.projects.models.DATASET + :ivar name: The name of the dataset. Required. + :vartype name: str + :ivar version: The version of the dataset. If not specified, the latest version is used. + :vartype version: str """ - type: Literal[CredentialType.ENTRA_ID] = rest_discriminator(name="type", visibility=["read"]) # type: ignore - """The credential type. Required. Entra ID credential (formerly known as AAD).""" + type: Literal[DataGenerationJobSourceType.DATASET] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this source, which is Dataset. Required. Dataset source — reference to a + dataset.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the dataset. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version of the dataset. If not specified, the latest version is used.""" @overload def __init__( self, + *, + name: str, + description: Optional[str] = None, + version: Optional[str] = None, ) -> None: ... @overload @@ -4595,50 +4822,43 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = CredentialType.ENTRA_ID # type: ignore + self.type = DataGenerationJobSourceType.DATASET # type: ignore -class EvalGraderLabelModel(_Model): - """LabelModelGrader. +class DatasetEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="dataset"): + """Dataset source for evaluator generation jobs — reference to a dataset. - :ivar type: The object type, which is always ``label_model``. Required. Default value is - "label_model". - :vartype type: str - :ivar name: The name of the grader. Required. + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this source, which is Dataset. Required. Dataset source — + reference to a dataset. + :vartype type: str or ~azure.ai.projects.models.DATASET + :ivar name: The name of the dataset. Required. :vartype name: str - :ivar model: The model to use for the evaluation. Must support structured outputs. Required. - :vartype model: str - :ivar input: Required. - :vartype input: list[~azure.ai.projects.models.EvalItem] - :ivar labels: The labels to assign to each item in the evaluation. Required. - :vartype labels: list[str] - :ivar passing_labels: The labels that indicate a passing result. Must be a subset of labels. - Required. - :vartype passing_labels: list[str] + :ivar version: The version of the dataset. If not specified, the latest version is used. + :vartype version: str """ - type: Literal["label_model"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The object type, which is always ``label_model``. Required. Default value is \"label_model\".""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional description of what this source represents — helps the pipeline interpret its content + (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" + type: Literal[EvaluatorGenerationJobSourceType.DATASET] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this source, which is Dataset. Required. Dataset source — reference to a + dataset.""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the grader. Required.""" - model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The model to use for the evaluation. Must support structured outputs. Required.""" - input: list["_models.EvalItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - labels: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The labels to assign to each item in the evaluation. Required.""" - passing_labels: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The labels that indicate a passing result. Must be a subset of labels. Required.""" + """The name of the dataset. Required.""" + version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version of the dataset. If not specified, the latest version is used.""" @overload def __init__( self, *, name: str, - model: str, - input: list["_models.EvalItem"], - labels: list[str], - passing_labels: list[str], + description: Optional[str] = None, + version: Optional[str] = None, ) -> None: ... @overload @@ -4650,7 +4870,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["label_model"] = "label_model" + self.type = EvaluatorGenerationJobSourceType.DATASET # type: ignore class DatasetItem(_Model): @@ -4749,40 +4969,26 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalGraderPython(_Model): - """PythonGrader. +class DatasetReference(_Model): + """Reference to a versioned Foundry Dataset. - :ivar type: The object type, which is always ``python``. Required. Default value is "python". - :vartype type: str - :ivar name: The name of the grader. Required. + :ivar name: Dataset name. Required. :vartype name: str - :ivar source: The source code of the python script. Required. - :vartype source: str - :ivar image_tag: The image tag to use for the python script. - :vartype image_tag: str - :ivar pass_threshold: The threshold for the score. - :vartype pass_threshold: int + :ivar version: Dataset version. Required. + :vartype version: str """ - type: Literal["python"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The object type, which is always ``python``. Required. Default value is \"python\".""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the grader. Required.""" - source: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The source code of the python script. Required.""" - image_tag: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The image tag to use for the python script.""" - pass_threshold: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The threshold for the score.""" + """Dataset name. Required.""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Dataset version. Required.""" @overload def __init__( self, *, name: str, - source: str, - image_tag: Optional[str] = None, - pass_threshold: Optional[int] = None, + version: str, ) -> None: ... @overload @@ -4794,58 +5000,109 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["python"] = "python" -class EvalGraderScoreModel(_Model): - """ScoreModelGrader. +class DatasetVersion(_Model): + """DatasetVersion Definition. + + You probably want to use the sub-classes and not this class directly. Known sub-classes are: + FileDatasetVersion, FolderDatasetVersion - :ivar type: The object type, which is always ``score_model``. Required. Default value is - "score_model". - :vartype type: str - :ivar name: The name of the grader. Required. + :ivar data_uri: URI of the data (`example `_). + Required. + :vartype data_uri: str + :ivar type: Dataset type. Required. Known values are: "uri_file" and "uri_folder". + :vartype type: str or ~azure.ai.projects.models.DatasetType + :ivar is_reference: Indicates if the dataset holds a reference to the storage, or the dataset + manages storage itself. If true, the underlying data will not be deleted when the dataset + version is deleted. + :vartype is_reference: bool + :ivar connection_name: The Azure Storage Account connection name. Required if + startPendingUploadVersion was not called before creating the Dataset. + :vartype connection_name: str + :ivar id: Asset ID, a unique identifier for the asset. + :vartype id: str + :ivar name: The name of the resource. Required. :vartype name: str - :ivar model: The model to use for the evaluation. Required. - :vartype model: str - :ivar sampling_params: The sampling parameters for the model. - :vartype sampling_params: ~azure.ai.projects.models.EvalGraderScoreModelSamplingParams - :ivar input: The input messages evaluated by the grader. Supports text, output text, input - image, and input audio content blocks, and may include template strings. Required. - :vartype input: list[~azure.ai.projects.models.EvalItem] - :ivar range: The range of the score. Defaults to ``[0, 1]``. - :vartype range: list[int] - :ivar pass_threshold: The threshold for the score. - :vartype pass_threshold: int - """ - - type: Literal["score_model"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The object type, which is always ``score_model``. Required. Default value is \"score_model\".""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the grader. Required.""" - model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The model to use for the evaluation. Required.""" - sampling_params: Optional["_models.EvalGraderScoreModelSamplingParams"] = rest_field( + :ivar version: The version of the resource. Required. + :vartype version: str + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] + """ + + __mapping__: dict[str, _Model] = {} + data_uri: str = rest_field(name="dataUri", visibility=["read", "create"]) + """URI of the data (`example `_). Required.""" + type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) + """Dataset type. Required. Known values are: \"uri_file\" and \"uri_folder\".""" + is_reference: Optional[bool] = rest_field(name="isReference", visibility=["read"]) + """Indicates if the dataset holds a reference to the storage, or the dataset manages storage + itself. If true, the underlying data will not be deleted when the dataset version is deleted.""" + connection_name: Optional[str] = rest_field(name="connectionName", visibility=["read", "create"]) + """The Azure Storage Account connection name. Required if startPendingUploadVersion was not called + before creating the Dataset.""" + id: Optional[str] = rest_field(visibility=["read"]) + """Asset ID, a unique identifier for the asset.""" + name: str = rest_field(visibility=["read"]) + """The name of the resource. Required.""" + version: str = rest_field(visibility=["read"]) + """The version of the resource. Required.""" + description: Optional[str] = rest_field(visibility=["create", "update"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) + """Tag dictionary. Tags can be added, removed, and updated.""" + + @overload + def __init__( + self, + *, + data_uri: str, + type: str, + connection_name: Optional[str] = None, + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class DeleteAgentResponse(_Model): + """A deleted agent Object. + + :ivar object: The object type. Always 'agent.deleted'. Required. AGENT_DELETED. + :vartype object: str or ~azure.ai.projects.models.AGENT_DELETED + :ivar name: The name of the agent. Required. + :vartype name: str + :ivar deleted: Whether the agent was successfully deleted. Required. + :vartype deleted: bool + """ + + object: Literal[AgentObjectType.AGENT_DELETED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The sampling parameters for the model.""" - input: list["_models.EvalItem"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The input messages evaluated by the grader. Supports text, output text, input image, and input - audio content blocks, and may include template strings. Required.""" - range: Optional[list[int]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The range of the score. Defaults to ``[0, 1]``.""" - pass_threshold: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The threshold for the score.""" + """The object type. Always 'agent.deleted'. Required. AGENT_DELETED.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the agent. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the agent was successfully deleted. Required.""" @overload def __init__( self, *, + object: Literal[AgentObjectType.AGENT_DELETED], name: str, - model: str, - input: list["_models.EvalItem"], - sampling_params: Optional["_models.EvalGraderScoreModelSamplingParams"] = None, - range: Optional[list[int]] = None, - pass_threshold: Optional[int] = None, + deleted: bool, ) -> None: ... @overload @@ -4857,44 +5114,40 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["score_model"] = "score_model" -class EvalGraderScoreModelSamplingParams(_Model): - """EvalGraderScoreModelSamplingParams. +class DeleteAgentVersionResponse(_Model): + """A deleted agent version Object. - :ivar seed: - :vartype seed: int - :ivar top_p: - :vartype top_p: int - :ivar temperature: - :vartype temperature: int - :ivar max_completions_tokens: - :vartype max_completions_tokens: int - :ivar reasoning_effort: Is one of the following types: Literal["none"], Literal["minimal"], - Literal["low"], Literal["medium"], Literal["high"], Literal["xhigh"] - :vartype reasoning_effort: str or str or str or str or str or str + :ivar object: The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED. + :vartype object: str or ~azure.ai.projects.models.AGENT_VERSION_DELETED + :ivar name: The name of the agent. Required. + :vartype name: str + :ivar version: The version identifier of the agent. Required. + :vartype version: str + :ivar deleted: Whether the agent was successfully deleted. Required. + :vartype deleted: bool """ - seed: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - top_p: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - temperature: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - max_completions_tokens: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] = rest_field( + object: Literal[AgentObjectType.AGENT_VERSION_DELETED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Is one of the following types: Literal[\"none\"], Literal[\"minimal\"], Literal[\"low\"], - Literal[\"medium\"], Literal[\"high\"], Literal[\"xhigh\"]""" + """The object type. Always 'agent.version.deleted'. Required. AGENT_VERSION_DELETED.""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The name of the agent. Required.""" + version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The version identifier of the agent. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the agent was successfully deleted. Required.""" @overload def __init__( self, *, - seed: Optional[int] = None, - top_p: Optional[int] = None, - temperature: Optional[int] = None, - max_completions_tokens: Optional[int] = None, - reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] = None, + object: Literal[AgentObjectType.AGENT_VERSION_DELETED], + name: str, + version: str, + deleted: bool, ) -> None: ... @overload @@ -4908,47 +5161,33 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalGraderStringCheck(_Model): - """StringCheckGrader. +class DeleteMemoryResponse(_Model): + """Response for deleting a memory item from a memory store. - :ivar type: The object type, which is always ``string_check``. Required. Default value is - "string_check". - :vartype type: str - :ivar name: The name of the grader. Required. - :vartype name: str - :ivar input: The input text. This may include template strings. Required. - :vartype input: str - :ivar reference: The reference text. This may include template strings. Required. - :vartype reference: str - :ivar operation: The string check operation to perform. One of ``eq``, ``ne``, ``like``, or - ``ilike``. Required. Is one of the following types: Literal["eq"], Literal["ne"], - Literal["like"], Literal["ilike"] - :vartype operation: str or str or str or str + :ivar object: The object type. Always 'memory_store.item.deleted'. Required. MEMORY_DELETED. + :vartype object: str or ~azure.ai.projects.models.MEMORY_DELETED + :ivar memory_id: The unique ID of the deleted memory item. Required. + :vartype memory_id: str + :ivar deleted: Whether the memory item was successfully deleted. Required. + :vartype deleted: bool """ - type: Literal["string_check"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The object type, which is always ``string_check``. Required. Default value is \"string_check\".""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the grader. Required.""" - input: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The input text. This may include template strings. Required.""" - reference: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The reference text. This may include template strings. Required.""" - operation: Literal["eq", "ne", "like", "ilike"] = rest_field( + object: Literal[MemoryStoreObjectType.MEMORY_DELETED] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """The string check operation to perform. One of ``eq``, ``ne``, ``like``, or ``ilike``. Required. - Is one of the following types: Literal[\"eq\"], Literal[\"ne\"], Literal[\"like\"], - Literal[\"ilike\"]""" + """The object type. Always 'memory_store.item.deleted'. Required. MEMORY_DELETED.""" + memory_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique ID of the deleted memory item. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the memory item was successfully deleted. Required.""" @overload def __init__( self, *, - name: str, - input: str, - reference: str, - operation: Literal["eq", "ne", "like", "ilike"], + object: Literal[MemoryStoreObjectType.MEMORY_DELETED], + memory_id: str, + deleted: bool, ) -> None: ... @overload @@ -4965,77 +5204,30 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class DeleteMemoryStoreResult(_Model): """DeleteMemoryStoreResult. - :ivar type: The type of grader. Required. Default value is "text_similarity". - :vartype type: str - :ivar name: The name of the grader. Required. + :ivar object: The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED. + :vartype object: str or ~azure.ai.projects.models.MEMORY_STORE_DELETED + :ivar name: The name of the memory store. Required. :vartype name: str - :ivar input: The text being graded. Required. - :vartype input: str - :ivar reference: The text being graded against. Required. - :vartype reference: str - :ivar evaluation_metric: The evaluation metric to use. One of ``cosine``, ``fuzzy_match``, - ``bleu``, ``gleu``, ``meteor``, ``rouge_1``, ``rouge_2``, ``rouge_3``, ``rouge_4``, - ``rouge_5``, or ``rouge_l``. Required. Is one of the following types: Literal["cosine"], - Literal["fuzzy_match"], Literal["bleu"], Literal["gleu"], Literal["meteor"], - Literal["rouge_1"], Literal["rouge_2"], Literal["rouge_3"], Literal["rouge_4"], - Literal["rouge_5"], Literal["rouge_l"] - :vartype evaluation_metric: str or str or str or str or str or str or str or str or str or str - or str - :ivar pass_threshold: The threshold for the score. Required. - :vartype pass_threshold: int - """ - - type: Literal["text_similarity"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The type of grader. Required. Default value is \"text_similarity\".""" + :ivar deleted: Whether the memory store was successfully deleted. Required. + :vartype deleted: bool + """ + + object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The object type. Always 'memory_store.deleted'. Required. MEMORY_STORE_DELETED.""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the grader. Required.""" - input: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The text being graded. Required.""" - reference: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The text being graded against. Required.""" - evaluation_metric: Literal[ - "cosine", - "fuzzy_match", - "bleu", - "gleu", - "meteor", - "rouge_1", - "rouge_2", - "rouge_3", - "rouge_4", - "rouge_5", - "rouge_l", - ] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The evaluation metric to use. One of ``cosine``, ``fuzzy_match``, ``bleu``, ``gleu``, - ``meteor``, ``rouge_1``, ``rouge_2``, ``rouge_3``, ``rouge_4``, ``rouge_5``, or ``rouge_l``. - Required. Is one of the following types: Literal[\"cosine\"], Literal[\"fuzzy_match\"], - Literal[\"bleu\"], Literal[\"gleu\"], Literal[\"meteor\"], Literal[\"rouge_1\"], - Literal[\"rouge_2\"], Literal[\"rouge_3\"], Literal[\"rouge_4\"], Literal[\"rouge_5\"], - Literal[\"rouge_l\"]""" - pass_threshold: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The threshold for the score. Required.""" + """The name of the memory store. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the memory store was successfully deleted. Required.""" @overload def __init__( self, *, + object: Literal[MemoryStoreObjectType.MEMORY_STORE_DELETED], name: str, - input: str, - reference: str, - evaluation_metric: Literal[ - "cosine", - "fuzzy_match", - "bleu", - "gleu", - "meteor", - "rouge_1", - "rouge_2", - "rouge_3", - "rouge_4", - "rouge_5", - "rouge_l", - ], - pass_threshold: int, + deleted: bool, ) -> None: ... @overload @@ -5047,43 +5239,28 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type: Literal["text_similarity"] = "text_similarity" -class EvalItem(_Model): - """Eval message object. +class DeleteSkillResult(_Model): + """A deleted skill Object. - :ivar role: The role of the message input. One of ``user``, ``assistant``, ``system``, or - ``developer``. Required. Is one of the following types: Literal["user"], Literal["assistant"], - Literal["system"], Literal["developer"] - :vartype role: str or str or str or str - :ivar content: Required. Is either a "_types.EvalItemContentItem" type or a - ["_types.EvalItemContentItem"] type. - :vartype content: str or ~azure.ai.projects.models.EvalItemContentItemObject or list[str or - ~azure.ai.projects.models.EvalItemContentItemObject] - :ivar type: The type of the message input. Always ``message``. Default value is "message". - :vartype type: str + :ivar name: The unique name of the skill. Required. + :vartype name: str + :ivar deleted: Whether the skill was successfully deleted. Required. + :vartype deleted: bool """ - role: Literal["user", "assistant", "system", "developer"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """The role of the message input. One of ``user``, ``assistant``, ``system``, or ``developer``. - Required. Is one of the following types: Literal[\"user\"], Literal[\"assistant\"], - Literal[\"system\"], Literal[\"developer\"]""" - content: "_types.EvalItemContent" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required. Is either a \"_types.EvalItemContentItem\" type or a [\"_types.EvalItemContentItem\"] - type.""" - type: Optional[Literal["message"]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The type of the message input. Always ``message``. Default value is \"message\".""" + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The unique name of the skill. Required.""" + deleted: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the skill was successfully deleted. Required.""" @overload def __init__( self, *, - role: Literal["user", "assistant", "system", "developer"], - content: "_types.EvalItemContent", - type: Optional[Literal["message"]] = None, + name: str, + deleted: bool, ) -> None: ... @overload @@ -5097,22 +5274,23 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalItemContentItemObject(_Model): - """Eval content item. +class Deployment(_Model): + """Model Deployment Definition. You probably want to use the sub-classes and not this class directly. Known sub-classes are: - InputAudio, EvalItemInputImage, EvalItemContentItemObjectInputTextContent, - EvalItemContentOutputText + ModelDeployment - :ivar type: Required. Known values are: "input_text", "output_text", "input_image", and - "input_audio". - :vartype type: str or ~azure.ai.projects.models.EvalItemContentItemObjectType + :ivar type: The type of the deployment. Required. "ModelDeployment" + :vartype type: str or ~azure.ai.projects.models.DeploymentType + :ivar name: Name of the deployment. Required. + :vartype name: str """ __mapping__: dict[str, _Model] = {} type: str = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) - """Required. Known values are: \"input_text\", \"output_text\", \"input_image\", and - \"input_audio\".""" + """The type of the deployment. Required. \"ModelDeployment\"""" + name: str = rest_field(visibility=["read"]) + """Name of the deployment. Required.""" @overload def __init__( @@ -5230,27 +5408,28 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvalItemContentItemObjectInputTextContent( - EvalItemContentItemObject, discriminator="input_text" -): # pylint: disable=name-too-long - """Input text. +class EmbeddingConfiguration(_Model): + """Embedding configuration class. - :ivar type: The type of the input item. Always ``input_text``. Required. INPUT_TEXT. - :vartype type: str or ~azure.ai.projects.models.INPUT_TEXT - :ivar text: The text input to the model. Required. - :vartype text: str + :ivar model_deployment_name: Deployment name of embedding model. It can point to a model + deployment either in the parent AIServices or a connection. Required. + :vartype model_deployment_name: str + :ivar embedding_field: Embedding field. Required. + :vartype embedding_field: str """ - type: Literal[EvalItemContentItemObjectType.INPUT_TEXT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the input item. Always ``input_text``. Required. INPUT_TEXT.""" - text: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The text input to the model. Required.""" + model_deployment_name: str = rest_field(name="modelDeploymentName", visibility=["create"]) + """Deployment name of embedding model. It can point to a model deployment either in the parent + AIServices or a connection. Required.""" + embedding_field: str = rest_field(name="embeddingField", visibility=["create"]) + """Embedding field. Required.""" @overload def __init__( self, *, - text: str, + model_deployment_name: str, + embedding_field: str, ) -> None: ... @overload @@ -5262,22 +5441,31 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvalItemContentItemObjectType.INPUT_TEXT # type: ignore -class EvalItemContentOutputText(EvalItemContentItemObject, discriminator="output_text"): - """Output text. +class EntraAuthorizationScheme(AgentEndpointAuthorizationScheme, discriminator="Entra"): + """EntraAuthorizationScheme. :ivar type: Required. ENTRA. :vartype type: str or ~azure.ai.projects.models.ENTRA + :ivar isolation_key_source: The source from which the per-user isolation key is derived for + requests authorized via this scheme. Defaults to Entra-based isolation when omitted. + :vartype isolation_key_source: ~azure.ai.projects.models.IsolationKeySource """ type: Literal[AgentEndpointAuthorizationSchemeType.ENTRA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. ENTRA.""" + isolation_key_source: Optional["_models.IsolationKeySource"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The source from which the per-user isolation key is derived for requests authorized via this + scheme. Defaults to Entra-based isolation when omitted.""" @overload def __init__( self, + *, + isolation_key_source: Optional["_models.IsolationKeySource"] = None, ) -> None: ... @overload @@ -5289,35 +5477,22 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvalItemContentItemObjectType.OUTPUT_TEXT # type: ignore + self.type = AgentEndpointAuthorizationSchemeType.ENTRA # type: ignore -class EvalItemInputImage(EvalItemContentItemObject, discriminator="input_image"): - """Input image. +class EntraIDCredentials(BaseCredentials, discriminator="AAD"): + """Entra ID credential definition. - :ivar type: The type of the image input. Always ``input_image``. Required. INPUT_IMAGE. - :vartype type: str or ~azure.ai.projects.models.INPUT_IMAGE - :ivar image_url: The URL of the image input. Required. - :vartype image_url: str - :ivar detail: The detail level of the image to be sent to the model. One of ``high``, ``low``, - or ``auto``. Defaults to ``auto``. - :vartype detail: str + :ivar type: The credential type. Required. Entra ID credential (formerly known as AAD). + :vartype type: str or ~azure.ai.projects.models.ENTRA_ID """ - type: Literal[EvalItemContentItemObjectType.INPUT_IMAGE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the image input. Always ``input_image``. Required. INPUT_IMAGE.""" - image_url: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The URL of the image input. Required.""" - detail: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The detail level of the image to be sent to the model. One of ``high``, ``low``, or ``auto``. - Defaults to ``auto``.""" + type: Literal[CredentialType.ENTRA_ID] = rest_discriminator(name="type", visibility=["read"]) # type: ignore + """The credential type. Required. Entra ID credential (formerly known as AAD).""" @overload def __init__( self, - *, - image_url: str, - detail: Optional[str] = None, ) -> None: ... @overload @@ -5329,7 +5504,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvalItemContentItemObjectType.INPUT_IMAGE # type: ignore + self.type = CredentialType.ENTRA_ID # type: ignore class IsolationKeySource(_Model): @@ -5761,6 +5936,39 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = InsightType.EVALUATION_COMPARISON # type: ignore +class EvaluationCriterion(_Model): + """LLM-as-judge evaluation criterion applied to a single task. + + :ivar name: Criterion name (referenced in evaluation result rows). Required. + :vartype name: str + :ivar instruction: Natural-language instruction passed to the judge LLM. Required. + :vartype instruction: str + """ + + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Criterion name (referenced in evaluation result rows). Required.""" + instruction: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Natural-language instruction passed to the judge LLM. Required.""" + + @overload + def __init__( + self, + *, + name: str, + instruction: str, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + class InsightSample(_Model): """A sample from the analysis. @@ -6109,77 +6317,57 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ScheduleTaskType.EVALUATION # type: ignore -class EvaluationSuiteRunRequest(_Model): - """Request body for running an evaluation from a suite. +class EvaluationTaxonomy(_Model): + """Evaluation Taxonomy Definition. - :ivar evaluation_name: Name for the evaluation. Default: '{suiteName}-runs'. - :vartype evaluation_name: str - :ivar evaluation_suite_version: Evaluation suite version to run. Default: latest. - :vartype evaluation_suite_version: str - :ivar evaluation_level: Overrides the suite's default evaluation level. If omitted, uses the - level from the suite. Known values are: "turn" and "conversation". - :vartype evaluation_level: str or ~azure.ai.projects.models.EvaluationLevel + :ivar id: Asset ID, a unique identifier for the asset. + :vartype id: str + :ivar name: The name of the resource. Required. + :vartype name: str + :ivar version: The version of the resource. Required. + :vartype version: str + :ivar description: The asset description text. + :vartype description: str + :ivar tags: Tag dictionary. Tags can be added, removed, and updated. + :vartype tags: dict[str, str] + :ivar taxonomy_input: Input configuration for the evaluation taxonomy. Required. + :vartype taxonomy_input: ~azure.ai.projects.models.EvaluationTaxonomyInput + :ivar taxonomy_categories: List of taxonomy categories. + :vartype taxonomy_categories: list[~azure.ai.projects.models.TaxonomyCategory] + :ivar properties: Additional properties for the evaluation taxonomy. + :vartype properties: dict[str, str] """ - evaluation_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Name for the evaluation. Default: '{suiteName}-runs'.""" - evaluation_suite_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Evaluation suite version to run. Default: latest.""" - evaluation_level: Optional[Union[str, "_models.EvaluationLevel"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + id: Optional[str] = rest_field(visibility=["read"]) + """Asset ID, a unique identifier for the asset.""" + name: str = rest_field(visibility=["read"]) + """The name of the resource. Required.""" + version: str = rest_field(visibility=["read"]) + """The version of the resource. Required.""" + description: Optional[str] = rest_field(visibility=["create", "update"]) + """The asset description text.""" + tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) + """Tag dictionary. Tags can be added, removed, and updated.""" + taxonomy_input: "_models.EvaluationTaxonomyInput" = rest_field( + name="taxonomyInput", visibility=["read", "create", "update", "delete", "query"] ) - """Overrides the suite's default evaluation level. If omitted, uses the level from the suite. - Known values are: \"turn\" and \"conversation\".""" - - @overload - def __init__( - self, - *, - evaluation_name: Optional[str] = None, - evaluation_suite_version: Optional[str] = None, - evaluation_level: Optional[Union[str, "_models.EvaluationLevel"]] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - -class EvaluationSuiteRunResponse(_Model): - """Response from running an evaluation suite. - - :ivar evaluation_suite_name: The evaluation suite name used. Required. - :vartype evaluation_suite_name: str - :ivar evaluation_suite_version: The evaluation suite version resolved. Required. - :vartype evaluation_suite_version: str - :ivar results: The run results. Currently a single-element array; will support multiple runs in - the future. Required. - :vartype results: list[~azure.ai.projects.models.EvaluationSuiteRunResult] - """ - - evaluation_suite_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The evaluation suite name used. Required.""" - evaluation_suite_version: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The evaluation suite version resolved. Required.""" - results: list["_models.EvaluationSuiteRunResult"] = rest_field( - visibility=["read", "create", "update", "delete", "query"] + """Input configuration for the evaluation taxonomy. Required.""" + taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = rest_field( + name="taxonomyCategories", visibility=["read", "create", "update", "delete", "query"] ) - """The run results. Currently a single-element array; will support multiple runs in the future. - Required.""" + """List of taxonomy categories.""" + properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Additional properties for the evaluation taxonomy.""" @overload def __init__( self, *, - evaluation_suite_name: str, - evaluation_suite_version: str, - results: list["_models.EvaluationSuiteRunResult"], + taxonomy_input: "_models.EvaluationTaxonomyInput", + description: Optional[str] = None, + tags: Optional[dict[str, str]] = None, + taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = None, + properties: Optional[dict[str, str]] = None, ) -> None: ... @overload @@ -6223,40 +6411,42 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationSuiteRunResult(_Model): - """Result of a single evaluation run within a suite execution. +class EvaluatorGenerationArtifacts(_Model): + """Service-managed provenance artifacts produced by an evaluator generation job. Present only on + EvaluatorVersion resources created via the generation pipeline. The combined-JSONL Foundry + Dataset is read-only and resolves to a versioned dataset in a service-reserved namespace. - :ivar eval_id: The evaluation ID created. Required. - :vartype eval_id: str - :ivar run_id: The eval run ID created. Required. - :vartype run_id: str - :ivar status: Status of the run. Required. Known values are: "queued", "in_progress", - "succeeded", "failed", and "cancelled". - :vartype status: str or ~azure.ai.projects.models.JobStatus - :ivar created_at: Timestamp when the run was created. Required. - :vartype created_at: ~datetime.datetime + :ivar dataset: Reference to the single Foundry Dataset (one combined JSONL file, + version-aligned to ``EvaluatorVersion.version``) holding all artifacts produced by the + generation pipeline. Each row in the JSONL carries a ``kind`` field discriminating its content + (e.g. ``spec``, ``tools``, ``context``). Required. + :vartype dataset: ~azure.ai.projects.models.DatasetReference + :ivar kinds: The kinds of rows present in ``dataset``. Always contains ``"spec"`` (the + generated evaluation specification, a Markdown document describing what the evaluator + measures). May additionally contain ``"tools"`` (when the generation pipeline produced or + inferred OpenAI tool schemas) and/or ``"context"`` (when supplementary materials such as file + uploads or trace samples were used during generation). Required. + :vartype kinds: list[str] """ - eval_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The evaluation ID created. Required.""" - run_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The eval run ID created. Required.""" - status: Union[str, "_models.JobStatus"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Status of the run. Required. Known values are: \"queued\", \"in_progress\", \"succeeded\", - \"failed\", and \"cancelled\".""" - created_at: datetime.datetime = rest_field( - visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" - ) - """Timestamp when the run was created. Required.""" + dataset: "_models.DatasetReference" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Reference to the single Foundry Dataset (one combined JSONL file, version-aligned to + ``EvaluatorVersion.version``) holding all artifacts produced by the generation pipeline. Each + row in the JSONL carries a ``kind`` field discriminating its content (e.g. ``spec``, ``tools``, + ``context``). Required.""" + kinds: list[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The kinds of rows present in ``dataset``. Always contains ``\"spec\"`` (the generated + evaluation specification, a Markdown document describing what the evaluator measures). May + additionally contain ``\"tools\"`` (when the generation pipeline produced or inferred OpenAI + tool schemas) and/or ``\"context\"`` (when supplementary materials such as file uploads or + trace samples were used during generation). Required.""" @overload def __init__( self, *, - eval_id: str, - run_id: str, - status: Union[str, "_models.JobStatus"], - created_at: datetime.datetime, + dataset: "_models.DatasetReference", + kinds: list[str], ) -> None: ... @overload @@ -6273,58 +6463,73 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: class EvaluatorGenerationInputs(_Model): """Caller-supplied inputs for an evaluator generation job. - :ivar name: Display name for this generation job. Required. - :vartype name: str :ivar sources: Source materials for generation — agent descriptions, prompts, traces, or datasets. Each entry is an ``EvaluatorGenerationJobSource`` variant discriminated by ``type``. Required. :vartype sources: list[~azure.ai.projects.models.EvaluatorGenerationJobSource] - :ivar category: Category determines the rubric generation focus: 'quality' (default) produces - quality-focused rubric criteria, 'safety' produces policy-derived safety rubric criteria. Both - use the same rubric structure. Singular because quality and safety generation are mutually - exclusive pipelines — the output EvaluatorVersion.categories is an array (e.g., ['agents', - 'quality']). Known values are: "quality", "safety", and "agents". - :vartype category: str or ~azure.ai.projects.models.EvaluatorCategory :ivar model: The LLM model to use for rubric generation (e.g., 'gpt-4o'). Required — users must provide their own model rather than relying on service-owned capacity. Required. :vartype model: str - :ivar evaluator_name: The evaluator name to create or update. If an evaluator with this name - already exists, the service retrieves the latest version's criteria as context for improvement. - Required. + :ivar evaluator_name: The evaluator name (immutable identifier). 1-256 characters; allowed + characters are ASCII letters, digits, underscore (``_``), period (``.``), tilde (``~``), and + hyphen (``-``). The prefix ``builtin.`` is reserved for system-managed evaluators and is + rejected by the service. If an evaluator with this name already exists in the project (and is + rubric-subtype), the service creates a new version under the same name and uses the prior + version's ``dimensions`` as context for incremental improvement (foundation of the post-//build + adaptive loop). Old versions remain queryable via ``get_version(name, version)``. If the + existing evaluator is not a rubric-subtype evaluator (built-in, prompt-based, code-based), the + request is rejected with ``400 Bad Request``. Required. :vartype evaluator_name: str + :ivar evaluator_display_name: Optional human-friendly display name for the resulting evaluator. + Surfaced as ``EvaluatorVersion.display_name`` on the persisted evaluator. When omitted, the + service uses ``evaluator_name`` as the display name. The ``evaluator_`` prefix disambiguates + this from the immutable ``evaluator_name`` identifier. + :vartype evaluator_display_name: str + :ivar evaluator_description: Optional human-friendly description for the resulting evaluator. + Surfaced as ``EvaluatorVersion.description`` on the persisted evaluator. Typically collected + from the UI alongside ``evaluator_display_name``. The ``evaluator_`` prefix disambiguates this + from any other description fields on related models. + :vartype evaluator_description: str """ - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Display name for this generation job. Required.""" sources: list["_models.EvaluatorGenerationJobSource"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) """Source materials for generation — agent descriptions, prompts, traces, or datasets. Each entry is an ``EvaluatorGenerationJobSource`` variant discriminated by ``type``. Required.""" - category: Optional[Union[str, "_models.EvaluatorCategory"]] = rest_field( - visibility=["read", "create", "update", "delete", "query"] - ) - """Category determines the rubric generation focus: 'quality' (default) produces quality-focused - rubric criteria, 'safety' produces policy-derived safety rubric criteria. Both use the same - rubric structure. Singular because quality and safety generation are mutually exclusive - pipelines — the output EvaluatorVersion.categories is an array (e.g., ['agents', 'quality']). - Known values are: \"quality\", \"safety\", and \"agents\".""" model: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The LLM model to use for rubric generation (e.g., 'gpt-4o'). Required — users must provide their own model rather than relying on service-owned capacity. Required.""" evaluator_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The evaluator name to create or update. If an evaluator with this name already exists, the - service retrieves the latest version's criteria as context for improvement. Required.""" + """The evaluator name (immutable identifier). 1-256 characters; allowed characters are ASCII + letters, digits, underscore (``_``), period (``.``), tilde (``~``), and hyphen (``-``). The + prefix ``builtin.`` is reserved for system-managed evaluators and is rejected by the service. + If an evaluator with this name already exists in the project (and is rubric-subtype), the + service creates a new version under the same name and uses the prior version's ``dimensions`` + as context for incremental improvement (foundation of the post-//build adaptive loop). Old + versions remain queryable via ``get_version(name, version)``. If the existing evaluator is not + a rubric-subtype evaluator (built-in, prompt-based, code-based), the request is rejected with + ``400 Bad Request``. Required.""" + evaluator_display_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional human-friendly display name for the resulting evaluator. Surfaced as + ``EvaluatorVersion.display_name`` on the persisted evaluator. When omitted, the service uses + ``evaluator_name`` as the display name. The ``evaluator_`` prefix disambiguates this from the + immutable ``evaluator_name`` identifier.""" + evaluator_description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional human-friendly description for the resulting evaluator. Surfaced as + ``EvaluatorVersion.description`` on the persisted evaluator. Typically collected from the UI + alongside ``evaluator_display_name``. The ``evaluator_`` prefix disambiguates this from any + other description fields on related models.""" @overload def __init__( self, *, - name: str, sources: list["_models.EvaluatorGenerationJobSource"], model: str, evaluator_name: str, - category: Optional[Union[str, "_models.EvaluatorCategory"]] = None, + evaluator_display_name: Optional[str] = None, + evaluator_description: Optional[str] = None, ) -> None: ... @overload @@ -6338,26 +6543,57 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationSuiteVersionInputMessagesTemplate1(_Model): # pylint: disable=name-too-long - """EvaluationSuiteVersionInputMessagesTemplate1. +class EvaluatorGenerationJob(_Model): + """Evaluator Generation Job resource — a long-running job that generates rubric-based evaluator + definitions from source materials. On success, the result is the persisted EvaluatorVersion. - :ivar role: Required. - :vartype role: str - :ivar content: Required. - :vartype content: str + :ivar id: Server-assigned unique identifier. Required. + :vartype id: str + :ivar inputs: Caller-supplied inputs. + :vartype inputs: ~azure.ai.projects.models.EvaluatorGenerationInputs + :ivar result: Result produced on success. + :vartype result: ~azure.ai.projects.models.EvaluatorVersion + :ivar status: Current lifecycle status. Required. Known values are: "queued", "in_progress", + "succeeded", "failed", and "cancelled". + :vartype status: str or ~azure.ai.projects.models.JobStatus + :ivar error: Error details — populated only on failure. + :vartype error: ~azure.ai.projects.models.ApiError + :ivar created_at: The timestamp when the job was created, represented in Unix time (seconds + since January 1, 1970). Required. + :vartype created_at: ~datetime.datetime + :ivar finished_at: The timestamp when the job finished, represented in Unix time (seconds since + January 1, 1970). + :vartype finished_at: ~datetime.datetime + :ivar usage: Token consumption summary. Populated when the job reaches a terminal state. + :vartype usage: ~azure.ai.projects.models.EvaluatorGenerationTokenUsage """ - role: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - content: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" + id: str = rest_field(visibility=["read"]) + """Server-assigned unique identifier. Required.""" + inputs: Optional["_models.EvaluatorGenerationInputs"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Caller-supplied inputs.""" + result: Optional["_models.EvaluatorVersion"] = rest_field(visibility=["read"]) + """Result produced on success.""" + status: Union[str, "_models.JobStatus"] = rest_field(visibility=["read"]) + """Current lifecycle status. Required. Known values are: \"queued\", \"in_progress\", + \"succeeded\", \"failed\", and \"cancelled\".""" + error: Optional["_models.ApiError"] = rest_field(visibility=["read"]) + """Error details — populated only on failure.""" + created_at: datetime.datetime = rest_field(visibility=["read"], format="unix-timestamp") + """The timestamp when the job was created, represented in Unix time (seconds since January 1, + 1970). Required.""" + finished_at: Optional[datetime.datetime] = rest_field(visibility=["read"], format="unix-timestamp") + """The timestamp when the job finished, represented in Unix time (seconds since January 1, 1970).""" + usage: Optional["_models.EvaluatorGenerationTokenUsage"] = rest_field(visibility=["read"]) + """Token consumption summary. Populated when the job reaches a terminal state.""" @overload def __init__( self, *, - role: str, - content: str, + inputs: Optional["_models.EvaluatorGenerationInputs"] = None, ) -> None: ... @overload @@ -6371,57 +6607,32 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EvaluationTaxonomy(_Model): - """Evaluation Taxonomy Definition. +class EvaluatorGenerationTokenUsage(_Model): + """Token consumption summary for an evaluator generation job. Populated when the job reaches a + terminal state. - :ivar id: Asset ID, a unique identifier for the asset. - :vartype id: str - :ivar name: The name of the resource. Required. - :vartype name: str - :ivar version: The version of the resource. Required. - :vartype version: str - :ivar description: The asset description text. - :vartype description: str - :ivar tags: Tag dictionary. Tags can be added, removed, and updated. - :vartype tags: dict[str, str] - :ivar taxonomy_input: Input configuration for the evaluation taxonomy. Required. - :vartype taxonomy_input: ~azure.ai.projects.models.EvaluationTaxonomyInput - :ivar taxonomy_categories: List of taxonomy categories. - :vartype taxonomy_categories: list[~azure.ai.projects.models.TaxonomyCategory] - :ivar properties: Additional properties for the evaluation taxonomy. - :vartype properties: dict[str, str] + :ivar input_tokens: Number of input (prompt) tokens consumed. Required. + :vartype input_tokens: int + :ivar output_tokens: Number of output (completion) tokens generated. Required. + :vartype output_tokens: int + :ivar total_tokens: Total tokens consumed (input + output). Required. + :vartype total_tokens: int """ - id: Optional[str] = rest_field(visibility=["read"]) - """Asset ID, a unique identifier for the asset.""" - name: str = rest_field(visibility=["read"]) - """The name of the resource. Required.""" - version: str = rest_field(visibility=["read"]) - """The version of the resource. Required.""" - description: Optional[str] = rest_field(visibility=["create", "update"]) - """The asset description text.""" - tags: Optional[dict[str, str]] = rest_field(visibility=["create", "update"]) - """Tag dictionary. Tags can be added, removed, and updated.""" - taxonomy_input: "_models.EvaluationTaxonomyInput" = rest_field( - name="taxonomyInput", visibility=["read", "create", "update", "delete", "query"] - ) - """Input configuration for the evaluation taxonomy. Required.""" - taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = rest_field( - name="taxonomyCategories", visibility=["read", "create", "update", "delete", "query"] - ) - """List of taxonomy categories.""" - properties: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Additional properties for the evaluation taxonomy.""" + input_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of input (prompt) tokens consumed. Required.""" + output_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Number of output (completion) tokens generated. Required.""" + total_tokens: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Total tokens consumed (input + output). Required.""" @overload def __init__( self, *, - taxonomy_input: "_models.EvaluationTaxonomyInput", - description: Optional[str] = None, - tags: Optional[dict[str, str]] = None, - taxonomy_categories: Optional[list["_models.TaxonomyCategory"]] = None, - properties: Optional[dict[str, str]] = None, + input_tokens: int, + output_tokens: int, + total_tokens: int, ) -> None: ... @overload @@ -6509,6 +6720,10 @@ class EvaluatorVersion(_Model): :vartype categories: list[str or ~azure.ai.projects.models.EvaluatorCategory] :ivar definition: Definition of the evaluator. Required. :vartype definition: ~azure.ai.projects.models.EvaluatorDefinition + :ivar generation_artifacts: Provenance artifacts from the generation pipeline. Read-only; + present only on evaluator versions created via an EvaluatorGenerationJob. Each artifact + resolves to a versioned Foundry Dataset. + :vartype generation_artifacts: ~azure.ai.projects.models.EvaluatorGenerationArtifacts :ivar created_by: Creator of the evaluator. Required. :vartype created_by: str :ivar created_at: Creation date/time of the evaluator. Required. @@ -6540,6 +6755,10 @@ class EvaluatorVersion(_Model): """The categories of the evaluator. Required.""" definition: "_models.EvaluatorDefinition" = rest_field(visibility=["read", "create"]) """Definition of the evaluator. Required.""" + generation_artifacts: Optional["_models.EvaluatorGenerationArtifacts"] = rest_field(visibility=["read"]) + """Provenance artifacts from the generation pipeline. Read-only; present only on evaluator + versions created via an EvaluatorGenerationJob. Each artifact resolves to a versioned Foundry + Dataset.""" created_by: str = rest_field(visibility=["read"]) """Creator of the evaluator. Required.""" created_at: datetime.datetime = rest_field(visibility=["read"], format="rfc3339") @@ -6789,6 +7008,80 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) +class FileDataGenerationJobOutput(DataGenerationJobOutput, discriminator="file"): + """Azure OpenAI file output for a data generation job. + + :ivar type: Azure OpenAI file output. Required. The generated data is an Azure OpenAI File. + :vartype type: str or ~azure.ai.projects.models.FILE + :ivar id: The id of the output Azure OpenAI file. Required. + :vartype id: str + :ivar filename: The filename of the output Azure OpenAI file. Required. + :vartype filename: str + """ + + type: Literal[DataGenerationJobOutputType.FILE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Azure OpenAI file output. Required. The generated data is an Azure OpenAI File.""" + id: str = rest_field(visibility=["read"]) + """The id of the output Azure OpenAI file. Required.""" + filename: str = rest_field(visibility=["read"]) + """The filename of the output Azure OpenAI file. Required.""" + + @overload + def __init__( + self, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobOutputType.FILE # type: ignore + + +class FileDataGenerationJobSource(DataGenerationJobSource, discriminator="file"): + """File source for data generation jobs — Azure OpenAI file input. + + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this job, which is File. Required. File source — Azure OpenAI + file. + :vartype type: str or ~azure.ai.projects.models.FILE + :ivar id: Input Azure Open AI file id used for data generation. Required. + :vartype id: str + """ + + type: Literal[DataGenerationJobSourceType.FILE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this job, which is File. Required. File source — Azure OpenAI file.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Input Azure Open AI file id used for data generation. Required.""" + + @overload + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + description: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobSourceType.FILE # type: ignore + + class FileDatasetVersion(DatasetVersion, discriminator="uri_file"): """FileDatasetVersion Definition. @@ -7899,72 +8192,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.media_type: Literal["application/zip"] = "application/zip" -class InputAudio(EvalItemContentItemObject, discriminator="input_audio"): - """Input audio. - - :ivar type: The type of the input item. Always ``input_audio``. Required. INPUT_AUDIO. - :vartype type: str or ~azure.ai.projects.models.INPUT_AUDIO - :ivar input_audio: Required. - :vartype input_audio: ~azure.ai.projects.models.InputAudioInputAudio - """ - - type: Literal[EvalItemContentItemObjectType.INPUT_AUDIO] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """The type of the input item. Always ``input_audio``. Required. INPUT_AUDIO.""" - input_audio: "_models.InputAudioInputAudio" = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - - @overload - def __init__( - self, - *, - input_audio: "_models.InputAudioInputAudio", - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type = EvalItemContentItemObjectType.INPUT_AUDIO # type: ignore - - -class InputAudioInputAudio(_Model): - """InputAudioInputAudio. - - :ivar data: Required. - :vartype data: str - :ivar format: Required. Is either a Literal["mp3"] type or a Literal["wav"] type. - :vartype format: str or str - """ - - data: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required.""" - format: Literal["mp3", "wav"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Required. Is either a Literal[\"mp3\"] type or a Literal[\"wav\"] type.""" - - @overload - def __init__( - self, - *, - data: str, - format: Literal["mp3", "wav"], - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - - class Insight(_Model): """The response body for cluster insights. @@ -11473,7 +11700,92 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorDefinitionType.PROMPT # type: ignore + self.type = EvaluatorDefinitionType.PROMPT # type: ignore + + +class PromptDataGenerationJobSource(DataGenerationJobSource, discriminator="prompt"): + """Prompt source for data generation jobs — inline text provided by the user. + + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this source, which is Prompt. Required. Prompt source — inline + text provided by the user. + :vartype type: str or ~azure.ai.projects.models.PROMPT + :ivar prompt: Inline prompt text (e.g., agent description, policy text, supplementary context). + Required. + :vartype prompt: str + """ + + type: Literal[DataGenerationJobSourceType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this source, which is Prompt. Required. Prompt source — inline text + provided by the user.""" + prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Inline prompt text (e.g., agent description, policy text, supplementary context). Required.""" + + @overload + def __init__( + self, + *, + prompt: str, + description: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobSourceType.PROMPT # type: ignore + + +class PromptEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discriminator="prompt"): + """Prompt source for evaluator generation jobs — inline text provided by the user. + + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). + :vartype description: str + :ivar type: The source type for this source, which is Prompt. Required. Prompt source — inline + text provided by the user. + :vartype type: str or ~azure.ai.projects.models.PROMPT + :ivar prompt: Inline prompt text (e.g., agent description, policy text, supplementary context). + Required. + :vartype prompt: str + """ + + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Optional description of what this source represents — helps the pipeline interpret its content + (e.g., 'Company refund policy document' or 'Describes the agent's core capabilities').""" + type: Literal[EvaluatorGenerationJobSourceType.PROMPT] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The source type for this source, which is Prompt. Required. Prompt source — inline text + provided by the user.""" + prompt: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Inline prompt text (e.g., agent description, policy text, supplementary context). Required.""" + + @overload + def __init__( + self, + *, + prompt: str, + description: Optional[str] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = EvaluatorGenerationJobSourceType.PROMPT # type: ignore class ProtocolVersionRecord(_Model): @@ -11841,48 +12153,57 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RubricBasedEvaluatorDefinition(EvaluatorDefinition, discriminator="rubrics"): - """Rubric-based evaluator definition — stores rubric criteria produced by the generate API. Used - for both quality and safety evaluators. +class Routine(_Model): + """A routine definition returned by the service. - :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. - This includes parameters like type, properties, required. - :vartype init_parameters: dict[str, any] - :ivar data_schema: The JSON schema (Draft 2020-12) for the evaluator's input data. This - includes parameters like type, properties, required. - :vartype data_schema: dict[str, any] - :ivar metrics: List of output metrics produced by this evaluator. - :vartype metrics: dict[str, ~azure.ai.projects.models.EvaluatorMetric] - :ivar type: Required. Rubric-based evaluator definition. Stores rubric criteria for both - quality and safety evaluators. Can be created via the generate API or manually via - createVersion. - :vartype type: str or ~azure.ai.projects.models.RUBRICS - :ivar rubric_criteria: Rubric criteria — the scoring blueprint used by the LLM judge. Quality - evaluators include a non-editable residual criterion with rubric_id 'general_quality' - (always_applicable: true); safety evaluators include 'general_policy_compliance'. Both use the - same rubric structure. Required. - :vartype rubric_criteria: list[~azure.ai.projects.models.RubricCriterion] + :ivar name: The routine name. Required. + :vartype name: str + :ivar description: A human-readable description of the routine. + :vartype description: str + :ivar enabled: Whether the routine is enabled. Required. + :vartype enabled: bool + :ivar triggers: The triggers configured for the routine. Required. + :vartype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] + :ivar action: The action executed when the routine fires. Required. + :vartype action: ~azure.ai.projects.models.RoutineAction + :ivar created_at: The time when the routine was created. + :vartype created_at: ~datetime.datetime + :ivar updated_at: The time when the routine was last updated. + :vartype updated_at: ~datetime.datetime """ - type: Literal[EvaluatorDefinitionType.RUBRICS] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore - """Required. Rubric-based evaluator definition. Stores rubric criteria for both quality and safety - evaluators. Can be created via the generate API or manually via createVersion.""" - rubric_criteria: list["_models.RubricCriterion"] = rest_field( + name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The routine name. Required.""" + description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """A human-readable description of the routine.""" + enabled: bool = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Whether the routine is enabled. Required.""" + triggers: dict[str, "_models.RoutineTrigger"] = rest_field( visibility=["read", "create", "update", "delete", "query"] ) - """Rubric criteria — the scoring blueprint used by the LLM judge. Quality evaluators include a - non-editable residual criterion with rubric_id 'general_quality' (always_applicable: true); - safety evaluators include 'general_policy_compliance'. Both use the same rubric structure. - Required.""" + """The triggers configured for the routine. Required.""" + action: "_models.RoutineAction" = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The action executed when the routine fires. Required.""" + created_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The time when the routine was created.""" + updated_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The time when the routine was last updated.""" @overload def __init__( self, *, - rubric_criteria: list["_models.RubricCriterion"], - init_parameters: Optional[dict[str, Any]] = None, - data_schema: Optional[dict[str, Any]] = None, - metrics: Optional[dict[str, "_models.EvaluatorMetric"]] = None, + name: str, + enabled: bool, + triggers: dict[str, "_models.RoutineTrigger"], + action: "_models.RoutineAction", + description: Optional[str] = None, + created_at: Optional[datetime.datetime] = None, + updated_at: Optional[datetime.datetime] = None, ) -> None: ... @overload @@ -11894,56 +12215,227 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) - self.type = EvaluatorDefinitionType.RUBRICS # type: ignore -class RubricCriterion(_Model): - """A single rubric criterion — one measurable quality dimension in an evaluator's scoring - blueprint. +class RoutineRun(_Model): + """A single routine run returned from the run history API. - :ivar rubric_id: Stable identifier for this rubric criterion (snake_case, e.g., - ``correct_resolution``). Required. Provided by the user when manually creating a rubric - evaluator or during human-in-the-loop review of a generated catalog; the generation pipeline - produces an initial value the user can edit. Editable when saving new versions. Required. - :vartype rubric_id: str - :ivar description: What this criterion measures (e.g., 'Correctly identifies the user's - reservation intent and pursues the appropriate workflow'). Required. - :vartype description: str - :ivar weight: Relative weight of this criterion (1-10). The generation pipeline assigns exactly - one criterion weight 8-10; all others use 1-6. User edits are not constrained by this - heuristic. Required. - :vartype weight: int - :ivar always_applicable: When true, the LLM judge always scores this criterion regardless of - relevance (skips applicability assessment). The service-generated general quality/policy - criterion has this set to true and is non-editable. Users may set this on their own custom - criteria. - :vartype always_applicable: bool + :ivar id: The MLflow run identifier for the routine attempt. Required. + :vartype id: str + :ivar status: The underlying MLflow run status. Required. + :vartype status: str + :ivar phase: The AgentExtensions lifecycle phase for the routine attempt. Known values are: + "queued", "dispatching", "completed", and "failed". + :vartype phase: str or ~azure.ai.projects.models.RoutineRunPhase + :ivar trigger_type: The trigger type that produced the routine attempt. Required. Known values + are: "github_issue_opened", "schedule", and "timer". + :vartype trigger_type: str or ~azure.ai.projects.models.RoutineTriggerType + :ivar attempt_source: The source path that created the routine attempt. Known values are: + "event_fire", "manual_dispatch", "queued_dispatch", "schedule_delivery", and "timer_delivery". + :vartype attempt_source: str or ~azure.ai.projects.models.RoutineAttemptSource + :ivar action_type: The action type dispatched for the routine attempt. Known values are: + "invoke_agent_responses_api" and "invoke_agent_invocations_api". + :vartype action_type: str or ~azure.ai.projects.models.RoutineActionType + :ivar triggered_at: The logical trigger time recorded for the routine attempt. + :vartype triggered_at: ~datetime.datetime + :ivar started_at: The time when the underlying run started. Required. + :vartype started_at: ~datetime.datetime + :ivar ended_at: The time when the underlying run reached a terminal state. + :vartype ended_at: ~datetime.datetime + :ivar dispatch_id: The dispatch identifier associated with the routine attempt. + :vartype dispatch_id: str + :ivar action_correlation_id: The downstream action correlation identifier, when available. + :vartype action_correlation_id: str + :ivar response_id: The downstream response or invocation identifier, when available. + :vartype response_id: str + :ivar task_id: The workspace task identifier linked to the routine attempt, when available. + :vartype task_id: str + :ivar error_type: The fully qualified error type captured for a failed attempt, when available. + :vartype error_type: str + :ivar error_message: The truncated failure message captured for a failed attempt, when + available. + :vartype error_message: str + :ivar diagnostics: Diagnostic data captured for the routine attempt. + :vartype diagnostics: ~azure.ai.projects.models.RoutineRunDiagnostics """ - rubric_id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Stable identifier for this rubric criterion (snake_case, e.g., ``correct_resolution``). - Required. Provided by the user when manually creating a rubric evaluator or during - human-in-the-loop review of a generated catalog; the generation pipeline produces an initial - value the user can edit. Editable when saving new versions. Required.""" - description: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """What this criterion measures (e.g., 'Correctly identifies the user's reservation intent and - pursues the appropriate workflow'). Required.""" - weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Relative weight of this criterion (1-10). The generation pipeline assigns exactly one criterion - weight 8-10; all others use 1-6. User edits are not constrained by this heuristic. Required.""" - always_applicable: Optional[bool] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """When true, the LLM judge always scores this criterion regardless of relevance (skips - applicability assessment). The service-generated general quality/policy criterion has this set - to true and is non-editable. Users may set this on their own custom criteria.""" + id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The MLflow run identifier for the routine attempt. Required.""" + status: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The underlying MLflow run status. Required.""" + phase: Optional[Union[str, "_models.RoutineRunPhase"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The AgentExtensions lifecycle phase for the routine attempt. Known values are: \"queued\", + \"dispatching\", \"completed\", and \"failed\".""" + trigger_type: Union[str, "_models.RoutineTriggerType"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The trigger type that produced the routine attempt. Required. Known values are: + \"github_issue_opened\", \"schedule\", and \"timer\".""" + attempt_source: Optional[Union[str, "_models.RoutineAttemptSource"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The source path that created the routine attempt. Known values are: \"event_fire\", + \"manual_dispatch\", \"queued_dispatch\", \"schedule_delivery\", and \"timer_delivery\".""" + action_type: Optional[Union[str, "_models.RoutineActionType"]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The action type dispatched for the routine attempt. Known values are: + \"invoke_agent_responses_api\" and \"invoke_agent_invocations_api\".""" + triggered_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The logical trigger time recorded for the routine attempt.""" + started_at: datetime.datetime = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The time when the underlying run started. Required.""" + ended_at: Optional[datetime.datetime] = rest_field( + visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" + ) + """The time when the underlying run reached a terminal state.""" + dispatch_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The dispatch identifier associated with the routine attempt.""" + action_correlation_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The downstream action correlation identifier, when available.""" + response_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The downstream response or invocation identifier, when available.""" + task_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The workspace task identifier linked to the routine attempt, when available.""" + error_type: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The fully qualified error type captured for a failed attempt, when available.""" + error_message: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The truncated failure message captured for a failed attempt, when available.""" + diagnostics: Optional["_models.RoutineRunDiagnostics"] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """Diagnostic data captured for the routine attempt.""" @overload def __init__( self, *, - rubric_id: str, - description: str, - weight: int, - always_applicable: Optional[bool] = None, + id: str, # pylint: disable=redefined-builtin + status: str, + trigger_type: Union[str, "_models.RoutineTriggerType"], + started_at: datetime.datetime, + phase: Optional[Union[str, "_models.RoutineRunPhase"]] = None, + attempt_source: Optional[Union[str, "_models.RoutineAttemptSource"]] = None, + action_type: Optional[Union[str, "_models.RoutineActionType"]] = None, + triggered_at: Optional[datetime.datetime] = None, + ended_at: Optional[datetime.datetime] = None, + dispatch_id: Optional[str] = None, + action_correlation_id: Optional[str] = None, + response_id: Optional[str] = None, + task_id: Optional[str] = None, + error_type: Optional[str] = None, + error_message: Optional[str] = None, + diagnostics: Optional["_models.RoutineRunDiagnostics"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class RoutineRunDiagnostics(_Model): + """Generic diagnostics captured on a routine run. + + :ivar parameters: MLflow parameters recorded on the run, keyed by parameter name. Required. + :vartype parameters: dict[str, str] + :ivar tags: MLflow tags recorded on the run, keyed by tag name. Required. + :vartype tags: dict[str, str] + :ivar metrics: Latest MLflow metric values recorded on the run, keyed by metric name. Required. + :vartype metrics: dict[str, float] + """ + + parameters: dict[str, str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """MLflow parameters recorded on the run, keyed by parameter name. Required.""" + tags: dict[str, str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """MLflow tags recorded on the run, keyed by tag name. Required.""" + metrics: dict[str, float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Latest MLflow metric values recorded on the run, keyed by metric name. Required.""" + + @overload + def __init__( + self, + *, + parameters: dict[str, str], + tags: dict[str, str], + metrics: dict[str, float], + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + +class RubricBasedEvaluatorDefinition(EvaluatorDefinition, discriminator="rubric"): + """Rubric-based evaluator definition — stores dimensions produced by the generate API. Used for + both quality and safety evaluators. + + :ivar init_parameters: The JSON schema (Draft 2020-12) for the evaluator's input parameters. + This includes parameters like type, properties, required. + :vartype init_parameters: dict[str, any] + :ivar data_schema: The JSON schema (Draft 2020-12) for the evaluator's input data. This + includes parameters like type, properties, required. + :vartype data_schema: dict[str, any] + :ivar metrics: List of output metrics produced by this evaluator. + :vartype metrics: dict[str, ~azure.ai.projects.models.EvaluatorMetric] + :ivar type: Required. Rubric-based evaluator definition. Stores dimensions (the scoring + blueprint) for both quality and safety evaluators. Can be created via the generate API or + manually via createVersion. + :vartype type: str or ~azure.ai.projects.models.RUBRIC + :ivar dimensions: The set of dimensions — the scoring blueprint used by the LLM judge. Quality + evaluators include a non-editable residual dimension with id 'general_quality' + (always_applicable: true); safety evaluators include 'general_policy_compliance'. Both use the + same Dimension structure. Required. + :vartype dimensions: list[~azure.ai.projects.models.Dimension] + :ivar pass_threshold: Pass/fail threshold for the aggregate rubric score, on the same + normalized 0.0-1.0 scale as the emitted ``score``. When the runtime weighted average meets or + exceeds this value, the result is ``pass``. Defaults to 0.5 (equivalent to a raw 1-5 weighted + average of 3.0). The 'any dimension scored 1 → fail' rule still applies regardless of this + threshold. + :vartype pass_threshold: float + """ + + type: Literal[EvaluatorDefinitionType.RUBRIC] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """Required. Rubric-based evaluator definition. Stores dimensions (the scoring blueprint) for both + quality and safety evaluators. Can be created via the generate API or manually via + createVersion.""" + dimensions: list["_models.Dimension"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The set of dimensions — the scoring blueprint used by the LLM judge. Quality evaluators include + a non-editable residual dimension with id 'general_quality' (always_applicable: true); safety + evaluators include 'general_policy_compliance'. Both use the same Dimension structure. + Required.""" + pass_threshold: Optional[float] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """Pass/fail threshold for the aggregate rubric score, on the same normalized 0.0-1.0 scale as the + emitted ``score``. When the runtime weighted average meets or exceeds this value, the result is + ``pass``. Defaults to 0.5 (equivalent to a raw 1-5 weighted average of 3.0). The 'any dimension + scored 1 → fail' rule still applies regardless of this threshold.""" + + @overload + def __init__( + self, + *, + dimensions: list["_models.Dimension"], + init_parameters: Optional[dict[str, Any]] = None, + data_schema: Optional[dict[str, Any]] = None, + metrics: Optional[dict[str, "_models.EvaluatorMetric"]] = None, + pass_threshold: Optional[float] = None, ) -> None: ... @overload @@ -11955,6 +12447,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = EvaluatorDefinitionType.RUBRIC # type: ignore class SASCredentials(BaseCredentials, discriminator="SAS"): @@ -12420,6 +12913,53 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.type = ToolType.SHAREPOINT_GROUNDING_PREVIEW # type: ignore +class SimpleQnADataGenerationJobOptions(DataGenerationJobOptions, discriminator="simple_qna"): + """The options for a data generation job with SimpleQnA type. + + :ivar max_samples: Maximum number of samples to generate. Required. + :vartype max_samples: int + :ivar train_split: The proportion of the generated data to be used for training when the data + is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. + :vartype train_split: float + :ivar model_options: The LLM model options. + :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions + :ivar type: The data generation job type, which is SimpleQnA for this model. Required. Simple + question and answers between user and agent. + :vartype type: str or ~azure.ai.projects.models.SIMPLE_QNA + :ivar question_types: The question types to generate. Used only for fine-tuning scenarios. + :vartype question_types: list[str or ~azure.ai.projects.models.SimpleQnAFineTuningQuestionType] + """ + + type: Literal[DataGenerationJobType.SIMPLE_QNA] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The data generation job type, which is SimpleQnA for this model. Required. Simple question and + answers between user and agent.""" + question_types: Optional[list[Union[str, "_models.SimpleQnAFineTuningQuestionType"]]] = rest_field( + visibility=["read", "create", "update", "delete", "query"] + ) + """The question types to generate. Used only for fine-tuning scenarios.""" + + @overload + def __init__( + self, + *, + max_samples: int, + train_split: Optional[float] = None, + model_options: Optional["_models.DataGenerationModelOptions"] = None, + question_types: Optional[list[Union[str, "_models.SimpleQnAFineTuningQuestionType"]]] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobType.SIMPLE_QNA # type: ignore + + class SkillDetails(_Model): """A skill object. @@ -12889,62 +13429,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TestingCriterionAzureAIEvaluator(_Model): - """AzureAIEvaluatorGrader. - - :ivar type: The object type, which is always ``azure_ai_evaluator``. Required. Default value is - "azure_ai_evaluator". - :vartype type: str - :ivar name: The name of the grader. Required. - :vartype name: str - :ivar evaluator_name: The name of the evaluator. Required. - :vartype evaluator_name: str - :ivar evaluator_version: The version of the evaluator. Latest version if not specified. - :vartype evaluator_version: str - :ivar initialization_parameters: The initialization parameters for the evaluation. Must support - structured outputs. - :vartype initialization_parameters: any - :ivar data_mapping: The model to use for the evaluation. Must support structured outputs. - :vartype data_mapping: dict[str, str] - """ - - type: Literal["azure_ai_evaluator"] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The object type, which is always ``azure_ai_evaluator``. Required. Default value is - \"azure_ai_evaluator\".""" - name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the grader. Required.""" - evaluator_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The name of the evaluator. Required.""" - evaluator_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The version of the evaluator. Latest version if not specified.""" - initialization_parameters: Optional[Any] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The initialization parameters for the evaluation. Must support structured outputs.""" - data_mapping: Optional[dict[str, str]] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The model to use for the evaluation. Must support structured outputs.""" - - @overload - def __init__( - self, - *, - name: str, - evaluator_name: str, - evaluator_version: Optional[str] = None, - initialization_parameters: Optional[Any] = None, - data_mapping: Optional[dict[str, str]] = None, - ) -> None: ... - - @overload - def __init__(self, mapping: Mapping[str, Any]) -> None: - """ - :param mapping: raw JSON to initialize the model. - :type mapping: Mapping[str, Any] - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.type: Literal["azure_ai_evaluator"] = "azure_ai_evaluator" - - class TextResponseFormat(_Model): """An object specifying the format that the model must output. Configuring ``{ "type": "json_schema" }`` enables Structured Outputs, which ensures the model will match your supplied @@ -13764,63 +14248,145 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UpdateModelVersionRequest(_Model): - """Request body for updating a model version. Only description and tags can be modified. +class ToolUseFineTuningDataGenerationJobOptions( + DataGenerationJobOptions, discriminator="tool_use" +): # pylint: disable=name-too-long + """The options for a data generation job with ToolUse type. Used only for fine-tuning scenarios. - :ivar description: The asset description text. + :ivar max_samples: Maximum number of samples to generate. Required. + :vartype max_samples: int + :ivar train_split: The proportion of the generated data to be used for training when the data + is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. + :vartype train_split: float + :ivar model_options: The LLM model options. + :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions + :ivar type: The data generation job type, which is ToolUse for this model. Required. Tool + calling conversation between user and agent. + :vartype type: str or ~azure.ai.projects.models.TOOL_USE + """ + + type: Literal[DataGenerationJobType.TOOL_USE] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The data generation job type, which is ToolUse for this model. Required. Tool calling + conversation between user and agent.""" + + @overload + def __init__( + self, + *, + max_samples: int, + train_split: Optional[float] = None, + model_options: Optional["_models.DataGenerationModelOptions"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobType.TOOL_USE # type: ignore + + +class TracesDataGenerationJobOptions(DataGenerationJobOptions, discriminator="traces"): + """The options for a data generation job with Traces type. + + :ivar max_samples: Maximum number of samples to generate. Required. + :vartype max_samples: int + :ivar train_split: The proportion of the generated data to be used for training when the data + is used for fine-tuning. The rest will be used for validation. Value should be between 0 and 1. + :vartype train_split: float + :ivar model_options: The LLM model options. + :vartype model_options: ~azure.ai.projects.models.DataGenerationModelOptions + :ivar type: The data generation job type, which is Traces for this model. Required. Single turn + query and response from agent traces. + :vartype type: str or ~azure.ai.projects.models.TRACES + """ + + type: Literal[DataGenerationJobType.TRACES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore + """The data generation job type, which is Traces for this model. Required. Single turn query and + response from agent traces.""" + + @overload + def __init__( + self, + *, + max_samples: int, + train_split: Optional[float] = None, + model_options: Optional["_models.DataGenerationModelOptions"] = None, + ) -> None: ... + + @overload + def __init__(self, mapping: Mapping[str, Any]) -> None: + """ + :param mapping: raw JSON to initialize the model. + :type mapping: Mapping[str, Any] + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.type = DataGenerationJobType.TRACES # type: ignore + + +class TracesDataGenerationJobSource(DataGenerationJobSource, discriminator="traces"): + """Traces source for data generation jobs — conversation traces from Application Insights. + + :ivar description: Optional description of what this source represents — helps the pipeline + interpret its content (e.g., 'Company refund policy document' or 'Describes the agent's core + capabilities'). :vartype description: str :ivar type: The source type for this source, which is Traces. Required. Traces source — conversation traces from Application Insights. :vartype type: str or ~azure.ai.projects.models.TRACES - :ivar agent_id: The unique agent ID used to filter traces. Optional — when omitted, traces are - filtered by ``agent_name`` (and ``agent_version`` if specified). + :ivar agent_id: The unique agent ID used to filter traces. Provide either ``agent_id`` or + ``agent_name`` — at least one is required. :vartype agent_id: str - :ivar agent_name: The agent name to fetch traces for. Required. + :ivar agent_name: The agent name to fetch traces for. Provide either ``agent_id`` or + ``agent_name`` — at least one is required. :vartype agent_name: str :ivar agent_version: The agent version. If not specified, traces for ALL versions of the agent are included within the time window. :vartype agent_version: str :ivar start_time: Start of the time window (Unix timestamp in seconds) for fetching traces. + Required. :vartype start_time: ~datetime.datetime :ivar end_time: End of the time window (Unix timestamp in seconds). Defaults to current time. :vartype end_time: ~datetime.datetime - :ivar max_traces: Maximum number of traces to retrieve. - :vartype max_traces: int """ type: Literal[DataGenerationJobSourceType.TRACES] = rest_discriminator(name="type", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """The source type for this source, which is Traces. Required. Traces source — conversation traces from Application Insights.""" agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique agent ID used to filter traces. Optional — when omitted, traces are filtered by - ``agent_name`` (and ``agent_version`` if specified).""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent name to fetch traces for. Required.""" + """The unique agent ID used to filter traces. Provide either ``agent_id`` or ``agent_name`` — at + least one is required.""" + agent_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent name to fetch traces for. Provide either ``agent_id`` or ``agent_name`` — at least + one is required.""" agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The agent version. If not specified, traces for ALL versions of the agent are included within the time window.""" - start_time: Optional[datetime.datetime] = rest_field( + start_time: datetime.datetime = rest_field( visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" ) - """Start of the time window (Unix timestamp in seconds) for fetching traces.""" + """Start of the time window (Unix timestamp in seconds) for fetching traces. Required.""" end_time: Optional[datetime.datetime] = rest_field( visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" ) """End of the time window (Unix timestamp in seconds). Defaults to current time.""" - max_traces: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of traces to retrieve.""" @overload def __init__( self, *, - agent_name: str, + start_time: datetime.datetime, description: Optional[str] = None, agent_id: Optional[str] = None, + agent_name: Optional[str] = None, agent_version: Optional[str] = None, - start_time: Optional[datetime.datetime] = None, end_time: Optional[datetime.datetime] = None, - max_traces: Optional[int] = None, ) -> None: ... @overload @@ -13845,20 +14411,20 @@ class TracesEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discrimin :ivar type: The source type for this source, which is Traces. Required. Traces source — conversation traces from Application Insights. :vartype type: str or ~azure.ai.projects.models.TRACES - :ivar agent_id: The unique agent ID used to filter traces. Optional — when omitted, traces are - filtered by ``agent_name`` (and ``agent_version`` if specified). + :ivar agent_id: The unique agent ID used to filter traces. Provide either ``agent_id`` or + ``agent_name`` — at least one is required. :vartype agent_id: str - :ivar agent_name: The agent name to fetch traces for. Required. + :ivar agent_name: The agent name to fetch traces for. Provide either ``agent_id`` or + ``agent_name`` — at least one is required. :vartype agent_name: str :ivar agent_version: The agent version. If not specified, traces for ALL versions of the agent are included within the time window. :vartype agent_version: str :ivar start_time: Start of the time window (Unix timestamp in seconds) for fetching traces. + Required. :vartype start_time: ~datetime.datetime :ivar end_time: End of the time window (Unix timestamp in seconds). Defaults to current time. :vartype end_time: ~datetime.datetime - :ivar max_traces: Maximum number of traces to retrieve. - :vartype max_traces: int """ description: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -13868,35 +14434,33 @@ class TracesEvaluatorGenerationJobSource(EvaluatorGenerationJobSource, discrimin """The source type for this source, which is Traces. Required. Traces source — conversation traces from Application Insights.""" agent_id: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The unique agent ID used to filter traces. Optional — when omitted, traces are filtered by - ``agent_name`` (and ``agent_version`` if specified).""" - agent_name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """The agent name to fetch traces for. Required.""" + """The unique agent ID used to filter traces. Provide either ``agent_id`` or ``agent_name`` — at + least one is required.""" + agent_name: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) + """The agent name to fetch traces for. Provide either ``agent_id`` or ``agent_name`` — at least + one is required.""" agent_version: Optional[str] = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The agent version. If not specified, traces for ALL versions of the agent are included within the time window.""" - start_time: Optional[datetime.datetime] = rest_field( + start_time: datetime.datetime = rest_field( visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" ) - """Start of the time window (Unix timestamp in seconds) for fetching traces.""" + """Start of the time window (Unix timestamp in seconds) for fetching traces. Required.""" end_time: Optional[datetime.datetime] = rest_field( visibility=["read", "create", "update", "delete", "query"], format="unix-timestamp" ) """End of the time window (Unix timestamp in seconds). Defaults to current time.""" - max_traces: Optional[int] = rest_field(visibility=["read", "create", "update", "delete", "query"]) - """Maximum number of traces to retrieve.""" @overload def __init__( self, *, - agent_name: str, + start_time: datetime.datetime, description: Optional[str] = None, agent_id: Optional[str] = None, + agent_name: Optional[str] = None, agent_version: Optional[str] = None, - start_time: Optional[datetime.datetime] = None, end_time: Optional[datetime.datetime] = None, - max_traces: Optional[int] = None, ) -> None: ... @overload @@ -13908,6 +14472,7 @@ def __init__(self, mapping: Mapping[str, Any]) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) + self.type = EvaluatorGenerationJobSourceType.TRACES # type: ignore class UpdateModelVersionRequest(_Model): diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py index 546fdb068dcc..1a1c0ffec86c 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/__init__.py @@ -19,7 +19,6 @@ from ._operations import DatasetsOperations # type: ignore from ._operations import DeploymentsOperations # type: ignore from ._operations import IndexesOperations # type: ignore -from ._operations import EvaluationSuitesOperations # type: ignore from ._patch import __all__ as _patch_all from ._patch import * @@ -33,7 +32,6 @@ "DatasetsOperations", "DeploymentsOperations", "IndexesOperations", - "EvaluationSuitesOperations", ] __all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore _patch_sdk() diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py index afcf58d48674..7a758cf07acd 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_operations.py @@ -3431,6 +3431,144 @@ def build_beta_skills_delete_request(name: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) +def build_beta_datasets_get_generation_job_request( # pylint: disable=name-too-long + job_id: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/data_generation_jobs/{jobId}" + path_format_arguments = { + "jobId": _SERIALIZER.url("job_id", job_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_datasets_list_generation_jobs_request( # pylint: disable=name-too-long + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + after: Optional[str] = None, + before: Optional[str] = None, + scenario: Optional[Union[str, _models.DataGenerationJobScenario]] = None, + type: Optional[List[Union[str, _models.DataGenerationJobType]]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/data_generation_jobs" + + # Construct parameters + if limit is not None: + _params["limit"] = _SERIALIZER.query("limit", limit, "int") + if order is not None: + _params["order"] = _SERIALIZER.query("order", order, "str") + if after is not None: + _params["after"] = _SERIALIZER.query("after", after, "str") + if before is not None: + _params["before"] = _SERIALIZER.query("before", before, "str") + if scenario is not None: + _params["scenario"] = _SERIALIZER.query("scenario", scenario, "str") + if type is not None: + _params["type"] = _SERIALIZER.query("type", type, "[str]", div=",") + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_datasets_create_generation_job_request( # pylint: disable=name-too-long + *, operation_id: Optional[str] = None, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/data_generation_jobs" + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + if operation_id is not None: + _headers["Operation-Id"] = _SERIALIZER.header("operation_id", operation_id, "str") + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_datasets_cancel_generation_job_request( # pylint: disable=name-too-long + job_id: str, **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = "/data_generation_jobs/{jobId}:cancel" + path_format_arguments = { + "jobId": _SERIALIZER.url("job_id", job_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + # Construct headers + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_beta_datasets_delete_generation_job_request( # pylint: disable=name-too-long + job_id: str, **kwargs: Any +) -> HttpRequest: + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + api_version: str = kwargs.pop("api_version", _params.pop("api-version", "v1")) + # Construct URL + _url = "/data_generation_jobs/{jobId}" + path_format_arguments = { + "jobId": _SERIALIZER.url("job_id", job_id, "str"), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, **kwargs) + + class BetaOperations: # pylint: disable=too-many-instance-attributes """ .. warning:: @@ -3461,6 +3599,7 @@ def __init__(self, *args, **kwargs) -> None: self.schedules = BetaSchedulesOperations(self._client, self._config, self._serialize, self._deserialize) self.toolboxes = BetaToolboxesOperations(self._client, self._config, self._serialize, self._deserialize) self.skills = BetaSkillsOperations(self._client, self._config, self._serialize, self._deserialize) + self.datasets = BetaDatasetsOperations(self._client, self._config, self._serialize, self._deserialize) class AgentsOperations: @@ -13232,14 +13371,14 @@ def get_credentials( return deserialized # type: ignore -class BetaModelsOperations: +class BetaRedTeamsOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`models` attribute. + :attr:`red_teams` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -13250,20 +13389,15 @@ def __init__(self, *args, **kwargs) -> None: self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @distributed_trace - def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: - """List all versions of the given ModelVersion. + def get(self, name: str, **kwargs: Any) -> _models.RedTeam: + """Get a redteam by name. - :param name: The name of the resource. Required. + :param name: Identifier of the red team run. Required. :type name: str - :return: An iterator like instance of ModelVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) - error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -13272,86 +13406,61 @@ def list_versions(self, name: str, **kwargs: Any) -> ItemPaged["_models.ModelVer } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_models_list_versions_request( - name=name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - return _request + _request = build_beta_red_teams_get_request( + name=name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ModelVersion], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) - def get_next(next_link=None): - _request = prepare_request(next_link) + response = pipeline_response.http_response - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.RedTeam, response.json()) - return pipeline_response + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore - return ItemPaged(get_next, extract_data) + return deserialized # type: ignore @distributed_trace - def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: - """List the latest version of each ModelVersion. + def list(self, **kwargs: Any) -> ItemPaged["_models.RedTeam"]: + """List a redteam by name. - :return: An iterator like instance of ModelVersion - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ModelVersion] + :return: An iterator like instance of RedTeam + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RedTeam] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.ModelVersion]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -13364,7 +13473,7 @@ def list(self, **kwargs: Any) -> ItemPaged["_models.ModelVersion"]: def prepare_request(next_link=None): if not next_link: - _request = build_beta_models_list_request( + _request = build_beta_red_teams_list_request( api_version=self._config.api_version, headers=_headers, params=_params, @@ -13404,7 +13513,7 @@ def prepare_request(next_link=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.ModelVersion], + List[_models.RedTeam], deserialized.get("value", []), ) if cls: @@ -13428,214 +13537,59 @@ def get_next(next_link=None): return ItemPaged(get_next, extract_data) - @distributed_trace - def get(self, name: str, version: str, **kwargs: Any) -> _models.ModelVersion: - """Get the specific version of the ModelVersion. The service returns 404 Not Found error if the - ModelVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the ModelVersion to retrieve. Required. - :type version: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) - - _request = build_beta_models_get_request( - name=name, - version=version, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.ModelVersion, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def delete(self, name: str, version: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete the specific version of the ModelVersion. The service returns 200 OK if the ModelVersion - was deleted successfully or if the ModelVersion does not exist. - - :param name: The name of the resource. Required. - :type name: str - :param version: The version of the ModelVersion to delete. Required. - :type version: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) - - _request = build_beta_models_delete_request( - name=name, - version=version, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore - @overload - def update( - self, - name: str, - version: str, - body: _models.UpdateModelVersionRequest, - *, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. + def create( + self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: ~azure.ai.projects.models.UpdateModelVersionRequest + :param red_team: Redteam to be run. Required. + :type red_team: ~azure.ai.projects.models.RedTeam :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/merge-patch+json". + Default value is "application/json". :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, version: str, body: JSON, *, content_type: str = "application/merge-patch+json", **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. + def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: JSON + :param red_team: Redteam to be run. Required. + :type red_team: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/merge-patch+json". + Default value is "application/json". :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, - name: str, - version: str, - body: IO[bytes], - *, - content_type: str = "application/merge-patch+json", - **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. + def create(self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. - Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Required. - :type body: IO[bytes] + :param red_team: Redteam to be run. Required. + :type red_team: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/merge-patch+json". + Default value is "application/json". :paramtype content_type: str - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update( - self, name: str, version: str, body: Union[_models.UpdateModelVersionRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.ModelVersion: - """Update an existing ModelVersion with the given version id. + def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: + """Creates a redteam run. - :param name: The name of the resource. Required. - :type name: str - :param version: The specific version id of the UpdateModelVersionRequest to create or update. + :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] Required. - :type version: str - :param body: The UpdateModelVersionRequest to create or update. Is one of the following types: - UpdateModelVersionRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.UpdateModelVersionRequest or JSON or IO[bytes] - :return: ModelVersion. The ModelVersion is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ModelVersion + :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] + :return: RedTeam. The RedTeam is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.RedTeam :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13650,18 +13604,16 @@ def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ModelVersion] = kwargs.pop("cls", None) + cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) - content_type = content_type or "application/merge-patch+json" + content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(red_team, (IOBase, bytes)): + _content = red_team else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_update_request( - name=name, - version=version, + _request = build_beta_red_teams_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -13681,110 +13633,145 @@ def update( response = pipeline_response.http_response - if response.status_code not in [200, 201]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ModelVersion, response.json()) + deserialized = _deserialize(_models.RedTeam, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaRoutinesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`routines` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @overload - def create_async( + def create_or_update( self, - name: str, - version: str, - body: _models.ModelVersion, + routine_name: str, *, + triggers: dict[str, _models.RoutineTrigger], + action: _models.RoutineAction, content_type: str = "application/json", + description: Optional[str] = None, + enabled: Optional[bool] = None, **kwargs: Any - ) -> _models.CreateAsyncResponse: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + ) -> _models.Routine: + """Create or update a routine. - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. - :type body: ~azure.ai.projects.models.ModelVersion + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :keyword triggers: The triggers configured for the routine. In v1, exactly one trigger entry is + supported. Required. + :paramtype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] + :keyword action: The action executed when the routine fires. Required. + :paramtype action: ~azure.ai.projects.models.RoutineAction :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :keyword description: A human-readable description of the routine. Default value is None. + :paramtype description: str + :keyword enabled: Whether the routine is enabled. Default value is None. + :paramtype enabled: bool + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_async( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.CreateAsyncResponse: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + def create_or_update( + self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Routine: + """Create or update a routine. - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_async( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.CreateAsyncResponse: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + def create_or_update( + self, routine_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Routine: + """Create or update a routine. - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Required. + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_async( - self, name: str, version: str, body: Union[_models.ModelVersion, JSON, IO[bytes]], **kwargs: Any - ) -> _models.CreateAsyncResponse: - """Creates a model version asynchronously with blob content validation. Returns 202 Accepted with - a Location header for polling. + def create_or_update( + self, + routine_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + triggers: dict[str, _models.RoutineTrigger] = _Unset, + action: _models.RoutineAction = _Unset, + description: Optional[str] = None, + enabled: Optional[bool] = None, + **kwargs: Any + ) -> _models.Routine: + """Create or update a routine. - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Model version to create. Is one of the following types: ModelVersion, JSON, - IO[bytes] Required. - :type body: ~azure.ai.projects.models.ModelVersion or JSON or IO[bytes] - :return: CreateAsyncResponse. The CreateAsyncResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.CreateAsyncResponse + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword triggers: The triggers configured for the routine. In v1, exactly one trigger entry is + supported. Required. + :paramtype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] + :keyword action: The action executed when the routine fires. Required. + :paramtype action: ~azure.ai.projects.models.RoutineAction + :keyword description: A human-readable description of the routine. Default value is None. + :paramtype description: str + :keyword enabled: Whether the routine is enabled. Default value is None. + :paramtype enabled: bool + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13799,8 +13786,15 @@ def create_async( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.CreateAsyncResponse] = kwargs.pop("cls", None) + cls: ClsType[_models.Routine] = kwargs.pop("cls", None) + if body is _Unset: + if triggers is _Unset: + raise TypeError("missing required argument: triggers") + if action is _Unset: + raise TypeError("missing required argument: action") + body = {"action": action, "description": description, "enabled": enabled, "triggers": triggers} + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None if isinstance(body, (IOBase, bytes)): @@ -13808,9 +13802,8 @@ def create_async( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_models_create_async_request( - name=name, - version=version, + _request = build_beta_routines_create_or_update_request( + routine_name=routine_name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -13830,113 +13823,37 @@ def create_async( response = pipeline_response.http_response - if response.status_code not in [202]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - response_headers = {} - response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.CreateAsyncResponse, response.json()) + deserialized = _deserialize(_models.Routine, response.json()) if cls: - return cls(pipeline_response, deserialized, response_headers) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def pending_upload( - self, - name: str, - version: str, - body: _models.ModelPendingUploadRequest, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.ModelPendingUploadResponse: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: ~azure.ai.projects.models.ModelPendingUploadRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def pending_upload( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ModelPendingUploadResponse: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def pending_upload( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ModelPendingUploadResponse: - """Start or retrieve a pending upload for a model version. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace - def pending_upload( - self, name: str, version: str, body: Union[_models.ModelPendingUploadRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.ModelPendingUploadResponse: - """Start or retrieve a pending upload for a model version. + def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Retrieve a routine. - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Is one of the following types: ModelPendingUploadRequest, JSON, IO[bytes] - Required. - :type body: ~azure.ai.projects.models.ModelPendingUploadRequest or JSON or IO[bytes] - :return: ModelPendingUploadResponse. The ModelPendingUploadResponse is compatible with - MutableMapping - :rtype: ~azure.ai.projects.models.ModelPendingUploadResponse + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -13947,25 +13864,14 @@ def pending_upload( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ModelPendingUploadResponse] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.Routine] = kwargs.pop("cls", None) - _request = build_beta_models_pending_upload_request( - name=name, - version=version, - content_type=content_type, + _request = build_beta_routines_get_request( + routine_name=routine_name, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -13989,98 +13895,30 @@ def pending_upload( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ModelPendingUploadResponse, response.json()) + deserialized = _deserialize(_models.Routine, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @overload - def get_credentials( - self, - name: str, - version: str, - body: _models.ModelCredentialRequest, - *, - content_type: str = "application/json", - **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: ~azure.ai.projects.models.ModelCredentialRequest - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def get_credentials( - self, name: str, version: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def get_credentials( - self, name: str, version: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. - - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace - def get_credentials( - self, name: str, version: str, body: Union[_models.ModelCredentialRequest, JSON, IO[bytes]], **kwargs: Any - ) -> _models.DatasetCredential: - """Get credentials for a model version asset. + def enable(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Enable a routine. - :param name: Name of the model. Required. - :type name: str - :param version: Version of the model. Required. - :type version: str - :param body: Is one of the following types: ModelCredentialRequest, JSON, IO[bytes] Required. - :type body: ~azure.ai.projects.models.ModelCredentialRequest or JSON or IO[bytes] - :return: DatasetCredential. The DatasetCredential is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DatasetCredential + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -14091,25 +13929,14 @@ def get_credentials( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.DatasetCredential] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[_models.Routine] = kwargs.pop("cls", None) - _request = build_beta_models_get_credentials_request( - name=name, - version=version, - content_type=content_type, + _request = build_beta_routines_enable_request( + routine_name=routine_name, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -14133,44 +13960,30 @@ def get_credentials( except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DatasetCredential, response.json()) + deserialized = _deserialize(_models.Routine, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - -class BetaRedTeamsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`red_teams` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.RedTeam: - """Get a redteam by name. + def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: + """Disable a routine. - :param name: Identifier of the red team run. Required. - :type name: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :return: Routine. The Routine is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Routine :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -14184,10 +13997,10 @@ def get(self, name: str, **kwargs: Any) -> _models.RedTeam: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + cls: ClsType[_models.Routine] = kwargs.pop("cls", None) - _request = build_beta_red_teams_get_request( - name=name, + _request = build_beta_routines_disable_request( + routine_name=routine_name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -14212,12 +14025,16 @@ def get(self, name: str, **kwargs: Any) -> _models.RedTeam: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RedTeam, response.json()) + deserialized = _deserialize(_models.Routine, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -14225,17 +14042,38 @@ def get(self, name: str, **kwargs: Any) -> _models.RedTeam: return deserialized # type: ignore @distributed_trace - def list(self, **kwargs: Any) -> ItemPaged["_models.RedTeam"]: - """List a redteam by name. + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.Routine"]: + """List routines. - :return: An iterator like instance of RedTeam - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RedTeam] + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of Routine + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Routine] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.RedTeam]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.Routine]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -14245,58 +14083,35 @@ def list(self, **kwargs: Any) -> ItemPaged["_models.RedTeam"]: } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_red_teams_list_request( - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + def prepare_request(_continuation_token=None): + _request = build_beta_routines_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.RedTeam], - deserialized.get("value", []), + List[_models.Routine], + deserialized.get("data", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + return deserialized.get("last_id") or None, iter(list_of_elem) - def get_next(next_link=None): - _request = prepare_request(next_link) + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access @@ -14306,65 +14121,247 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) - @overload - def create( - self, red_team: _models.RedTeam, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.RedTeam: - """Creates a redteam run. + @distributed_trace + def delete(self, routine_name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete a routine. - :param red_team: Redteam to be run. Required. - :type red_team: ~azure.ai.projects.models.RedTeam + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_routines_delete_request( + routine_name=routine_name, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore + + @distributed_trace + def list_runs( + self, + routine_name: str, + *, + filter: Optional[str] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.RoutineRun"]: + """List prior runs for a routine. + + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :keyword filter: An optional MLflow search-runs filter expression applied within the routine's + experiment. Default value is None. + :paramtype filter: str + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of RoutineRun + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RoutineRun] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.RoutineRun]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_routines_list_runs_request( + routine_name=routine_name, + filter=filter, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.RoutineRun], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @overload + def dispatch_async( + self, + routine_name: str, + *, + content_type: str = "application/json", + payload: Optional[_models.RoutineDispatchPayload] = None, + **kwargs: Any + ) -> _models.DispatchRoutineResponse: + """Queue an asynchronous routine dispatch. + + :param routine_name: The unique name of the routine. Required. + :type routine_name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :keyword payload: A direct action-input override sent downstream when testing a routine. + Default value is None. + :paramtype payload: ~azure.ai.projects.models.RoutineDispatchPayload + :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResponse :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create(self, red_team: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + def dispatch_async( + self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DispatchRoutineResponse: + """Queue an asynchronous routine dispatch. - :param red_team: Redteam to be run. Required. - :type red_team: JSON + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :param body: Required. + :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResponse :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create(self, red_team: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + def dispatch_async( + self, routine_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.DispatchRoutineResponse: + """Queue an asynchronous routine dispatch. - :param red_team: Redteam to be run. Required. - :type red_team: IO[bytes] + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :param body: Required. + :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResponse :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: Any) -> _models.RedTeam: - """Creates a redteam run. + def dispatch_async( + self, + routine_name: str, + body: Union[JSON, IO[bytes]] = _Unset, + *, + payload: Optional[_models.RoutineDispatchPayload] = None, + **kwargs: Any + ) -> _models.DispatchRoutineResponse: + """Queue an asynchronous routine dispatch. - :param red_team: Redteam to be run. Is one of the following types: RedTeam, JSON, IO[bytes] - Required. - :type red_team: ~azure.ai.projects.models.RedTeam or JSON or IO[bytes] - :return: RedTeam. The RedTeam is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.RedTeam + :param routine_name: The unique name of the routine. Required. + :type routine_name: str + :param body: Is either a JSON type or a IO[bytes] type. Required. + :type body: JSON or IO[bytes] + :keyword payload: A direct action-input override sent downstream when testing a routine. + Default value is None. + :paramtype payload: ~azure.ai.projects.models.RoutineDispatchPayload + :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DispatchRoutineResponse :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -14379,16 +14376,20 @@ def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: An _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.RedTeam] = kwargs.pop("cls", None) + cls: ClsType[_models.DispatchRoutineResponse] = kwargs.pop("cls", None) + if body is _Unset: + body = {"payload": payload} + body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(red_team, (IOBase, bytes)): - _content = red_team + if isinstance(body, (IOBase, bytes)): + _content = body else: - _content = json.dumps(red_team, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_red_teams_create_request( + _request = build_beta_routines_dispatch_async_request( + routine_name=routine_name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -14408,7 +14409,7 @@ def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: An response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -14424,7 +14425,7 @@ def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: An if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.RedTeam, response.json()) + deserialized = _deserialize(_models.DispatchRoutineResponse, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -14432,14 +14433,14 @@ def create(self, red_team: Union[_models.RedTeam, JSON, IO[bytes]], **kwargs: An return deserialized # type: ignore -class BetaRoutinesOperations: +class BetaSchedulesOperations: """ .. warning:: **DO NOT** instantiate this class directly. Instead, you should access the following operations through :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`routines` attribute. + :attr:`schedules` attribute. """ def __init__(self, *args, **kwargs) -> None: @@ -14449,104 +14450,14 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - def create_or_update( - self, - routine_name: str, - *, - triggers: dict[str, _models.RoutineTrigger], - action: _models.RoutineAction, - content_type: str = "application/json", - description: Optional[str] = None, - enabled: Optional[bool] = None, - **kwargs: Any - ) -> _models.Routine: - """Create or update a routine. - - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :keyword triggers: The triggers configured for the routine. In v1, exactly one trigger entry is - supported. Required. - :paramtype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] - :keyword action: The action executed when the routine fires. Required. - :paramtype action: ~azure.ai.projects.models.RoutineAction - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :keyword description: A human-readable description of the routine. Default value is None. - :paramtype description: str - :keyword enabled: Whether the routine is enabled. Default value is None. - :paramtype enabled: bool - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_or_update( - self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Routine: - """Create or update a routine. - - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :param body: Required. - :type body: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_or_update( - self, routine_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Routine: - """Create or update a routine. - - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :param body: Required. - :type body: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine - :raises ~azure.core.exceptions.HttpResponseError: - """ - @distributed_trace - def create_or_update( - self, - routine_name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - triggers: dict[str, _models.RoutineTrigger] = _Unset, - action: _models.RoutineAction = _Unset, - description: Optional[str] = None, - enabled: Optional[bool] = None, - **kwargs: Any - ) -> _models.Routine: - """Create or update a routine. + def delete(self, schedule_id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete a schedule. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword triggers: The triggers configured for the routine. In v1, exactly one trigger entry is - supported. Required. - :paramtype triggers: dict[str, ~azure.ai.projects.models.RoutineTrigger] - :keyword action: The action executed when the routine fires. Required. - :paramtype action: ~azure.ai.projects.models.RoutineAction - :keyword description: A human-readable description of the routine. Default value is None. - :paramtype description: str - :keyword enabled: Whether the routine is enabled. Default value is None. - :paramtype enabled: bool - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -14557,31 +14468,14 @@ def create_or_update( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.Routine] = kwargs.pop("cls", None) - - if body is _Unset: - if triggers is _Unset: - raise TypeError("missing required argument: triggers") - if action is _Unset: - raise TypeError("missing required argument: action") - body = {"action": action, "description": description, "enabled": enabled, "triggers": triggers} - body = {k: v for k, v in body.items() if v is not None} - content_type = content_type or "application/json" - _content = None - if isinstance(body, (IOBase, bytes)): - _content = body - else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_routines_create_or_update_request( - routine_name=routine_name, - content_type=content_type, + _request = build_beta_schedules_delete_request( + schedule_id=schedule_id, api_version=self._config.api_version, - content=_content, headers=_headers, params=_params, ) @@ -14590,45 +14484,28 @@ def create_or_update( } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.Routine, response.json()) + raise HttpResponseError(response=response) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: - """Retrieve a routine. + def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: + """Get a schedule by id. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -14642,10 +14519,10 @@ def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Routine] = kwargs.pop("cls", None) + cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) - _request = build_beta_routines_get_request( - routine_name=routine_name, + _request = build_beta_schedules_get_request( + schedule_id=schedule_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -14670,16 +14547,12 @@ def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Routine, response.json()) + deserialized = _deserialize(_models.Schedule, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -14687,15 +14560,29 @@ def get(self, routine_name: str, **kwargs: Any) -> _models.Routine: return deserialized # type: ignore @distributed_trace - def enable(self, routine_name: str, **kwargs: Any) -> _models.Routine: - """Enable a routine. + def list( + self, + *, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, + **kwargs: Any + ) -> ItemPaged["_models.Schedule"]: + """List all schedules. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine + :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". + Default value is None. + :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of Schedule + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Schedule] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[List[_models.Schedule]] = kwargs.pop("cls", None) + error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -14704,47 +14591,199 @@ def enable(self, routine_name: str, **kwargs: Any) -> _models.Routine: } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} + def prepare_request(next_link=None): + if not next_link: - cls: ClsType[_models.Routine] = kwargs.pop("cls", None) + _request = build_beta_schedules_list_request( + type=type, + enabled=enabled, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_routines_enable_request( - routine_name=routine_name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.Schedule], + deserialized.get("value", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("nextLink") or None, iter(list_of_elem) + + def get_next(next_link=None): + _request = prepare_request(next_link) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + raise HttpResponseError(response=response) + + return pipeline_response + + return ItemPaged(get_next, extract_data) + + @overload + def create_or_update( + self, schedule_id: str, schedule: _models.Schedule, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: ~azure.ai.projects.models.Schedule + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, schedule_id: str, schedule: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: JSON + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_or_update( + self, schedule_id: str, schedule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Required. + :type schedule: IO[bytes] + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_or_update( + self, schedule_id: str, schedule: Union[_models.Schedule, JSON, IO[bytes]], **kwargs: Any + ) -> _models.Schedule: + """Create or update operation template. + + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :param schedule: The resource instance. Is one of the following types: Schedule, JSON, + IO[bytes] Required. + :type schedule: ~azure.ai.projects.models.Schedule or JSON or IO[bytes] + :return: Schedule. The Schedule is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.Schedule + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _content = None + if isinstance(schedule, (IOBase, bytes)): + _content = schedule + else: + _content = json.dumps(schedule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + + _request = build_beta_schedules_create_or_update_request( + schedule_id=schedule_id, + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [200, 201]: if _stream: try: response.read() # Load the body in memory and close the socket except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Routine, response.json()) + deserialized = _deserialize(_models.Schedule, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -14752,13 +14791,15 @@ def enable(self, routine_name: str, **kwargs: Any) -> _models.Routine: return deserialized # type: ignore @distributed_trace - def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: - """Disable a routine. + def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: + """Get a schedule run by id. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :return: Routine. The Routine is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Routine + :param schedule_id: The unique identifier of the schedule. Required. + :type schedule_id: str + :param run_id: The unique identifier of the schedule run. Required. + :type run_id: str + :return: ScheduleRun. The ScheduleRun is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ScheduleRun :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -14772,10 +14813,11 @@ def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Routine] = kwargs.pop("cls", None) + cls: ClsType[_models.ScheduleRun] = kwargs.pop("cls", None) - _request = build_beta_routines_disable_request( - routine_name=routine_name, + _request = build_beta_schedules_get_run_request( + schedule_id=schedule_id, + run_id=run_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -14809,7 +14851,7 @@ def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Routine, response.json()) + deserialized = _deserialize(_models.ScheduleRun, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -14817,38 +14859,31 @@ def disable(self, routine_name: str, **kwargs: Any) -> _models.Routine: return deserialized # type: ignore @distributed_trace - def list( + def list_runs( self, + schedule_id: str, *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, + type: Optional[Union[str, _models.ScheduleTaskType]] = None, + enabled: Optional[bool] = None, **kwargs: Any - ) -> ItemPaged["_models.Routine"]: - """List routines. + ) -> ItemPaged["_models.ScheduleRun"]: + """List all schedule runs. - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. + :param schedule_id: Identifier of the schedule. Required. + :type schedule_id: str + :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". Default value is None. - :paramtype before: str - :return: An iterator like instance of Routine - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Routine] + :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType + :keyword enabled: Filter by the enabled status. Default value is None. + :paramtype enabled: bool + :return: An iterator like instance of ScheduleRun + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ScheduleRun] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.Routine]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.ScheduleRun]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -14858,186 +14893,61 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(_continuation_token=None): - - _request = build_beta_routines_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.Routine], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) - - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response + def prepare_request(next_link=None): + if not next_link: - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, + _request = build_beta_schedules_list_runs_request( + schedule_id=schedule_id, + type=type, + enabled=enabled, + api_version=self._config.api_version, + headers=_headers, + params=_params, ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return ItemPaged(get_next, extract_data) - - @distributed_trace - def delete(self, routine_name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete a routine. - - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) - - _request = build_beta_routines_delete_request( - routine_name=routine_name, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [204]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore - - @distributed_trace - def list_runs( - self, - routine_name: str, - *, - filter: Optional[str] = None, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.RoutineRun"]: - """List prior runs for a routine. - - :param routine_name: The unique name of the routine. Required. - :type routine_name: str - :keyword filter: An optional MLflow search-runs filter expression applied within the routine's - experiment. Default value is None. - :paramtype filter: str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of RoutineRun - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.RoutineRun] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.RoutineRun]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - def prepare_request(_continuation_token=None): + else: + # make call to next link with the client's api-version + _parsed_next_link = urllib.parse.urlparse(next_link) + _next_request_params = case_insensitive_dict( + { + key: [urllib.parse.quote(v) for v in value] + for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() + } + ) + _next_request_params["api-version"] = self._config.api_version + _request = HttpRequest( + "GET", + urllib.parse.urljoin(next_link, _parsed_next_link.path), + params=_next_request_params, + headers=_headers, + ) + path_format_arguments = { + "endpoint": self._serialize.url( + "self._config.endpoint", self._config.endpoint, "str", skip_quote=True + ), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) - _request = build_beta_routines_list_runs_request( - routine_name=routine_name, - filter=filter, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.RoutineRun], - deserialized.get("data", []), + List[_models.ScheduleRun], + deserialized.get("value", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) + return deserialized.get("nextLink") or None, iter(list_of_elem) - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) + def get_next(next_link=None): + _request = prepare_request(next_link) _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access @@ -15047,96 +14957,132 @@ def get_next(_continuation_token=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) + raise HttpResponseError(response=response) return pipeline_response return ItemPaged(get_next, extract_data) + +class BetaToolboxesOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`toolboxes` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @overload - def dispatch_async( + def create_version( self, - routine_name: str, + name: str, *, + tools: List[_models.Tool], content_type: str = "application/json", - payload: Optional[_models.RoutineDispatchPayload] = None, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + policies: Optional[_models.ToolboxPolicies] = None, **kwargs: Any - ) -> _models.DispatchRoutineResponse: - """Queue an asynchronous routine dispatch. + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. + :type name: str + :keyword tools: The list of tools to include in this version. Required. + :paramtype tools: list[~azure.ai.projects.models.Tool] :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword payload: A direct action-input override sent downstream when testing a routine. - Default value is None. - :paramtype payload: ~azure.ai.projects.models.RoutineDispatchPayload - :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DispatchRoutineResponse + :keyword description: A human-readable description of the toolbox. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is + None. + :paramtype metadata: dict[str, str] + :keyword policies: Policy configuration for this toolbox version. Default value is None. + :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def dispatch_async( - self, routine_name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DispatchRoutineResponse: - """Queue an asynchronous routine dispatch. + def create_version( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. + :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DispatchRoutineResponse + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def dispatch_async( - self, routine_name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.DispatchRoutineResponse: - """Queue an asynchronous routine dispatch. + def create_version( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. + :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DispatchRoutineResponse + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def dispatch_async( + def create_version( self, - routine_name: str, + name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - payload: Optional[_models.RoutineDispatchPayload] = None, + tools: List[_models.Tool] = _Unset, + description: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + policies: Optional[_models.ToolboxPolicies] = None, **kwargs: Any - ) -> _models.DispatchRoutineResponse: - """Queue an asynchronous routine dispatch. + ) -> _models.ToolboxVersionObject: + """Create a new version of a toolbox. If the toolbox does not exist, it will be created. - :param routine_name: The unique name of the routine. Required. - :type routine_name: str + :param name: The name of the toolbox. If the toolbox does not exist, it will be created. + Required. + :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword payload: A direct action-input override sent downstream when testing a routine. - Default value is None. - :paramtype payload: ~azure.ai.projects.models.RoutineDispatchPayload - :return: DispatchRoutineResponse. The DispatchRoutineResponse is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DispatchRoutineResponse + :keyword tools: The list of tools to include in this version. Required. + :paramtype tools: list[~azure.ai.projects.models.Tool] + :keyword description: A human-readable description of the toolbox. Default value is None. + :paramtype description: str + :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is + None. + :paramtype metadata: dict[str, str] + :keyword policies: Policy configuration for this toolbox version. Default value is None. + :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -15151,10 +15097,12 @@ def dispatch_async( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.DispatchRoutineResponse] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) if body is _Unset: - body = {"payload": payload} + if tools is _Unset: + raise TypeError("missing required argument: tools") + body = {"description": description, "metadata": metadata, "policies": policies, "tools": tools} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -15163,8 +15111,8 @@ def dispatch_async( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_routines_dispatch_async_request( - routine_name=routine_name, + _request = build_beta_toolboxes_create_version_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -15200,87 +15148,21 @@ def dispatch_async( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DispatchRoutineResponse, response.json()) + deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - -class BetaSchedulesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`schedules` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - - @distributed_trace - def delete(self, schedule_id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete a schedule. - - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: None - :rtype: None - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[None] = kwargs.pop("cls", None) - - _request = build_beta_schedules_delete_request( - schedule_id=schedule_id, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [204]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - if cls: - return cls(pipeline_response, None, {}) # type: ignore - @distributed_trace - def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: - """Get a schedule by id. + def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: + """Retrieve a toolbox. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: The name of the toolbox to retrieve. Required. + :type name: str + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -15294,10 +15176,10 @@ def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_request( - schedule_id=schedule_id, + _request = build_beta_toolboxes_get_request( + name=name, api_version=self._config.api_version, headers=_headers, params=_params, @@ -15322,12 +15204,16 @@ def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: except (StreamConsumedError, StreamClosedError): pass map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.Schedule, response.json()) + deserialized = _deserialize(_models.ToolboxObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -15338,25 +15224,35 @@ def get(self, schedule_id: str, **kwargs: Any) -> _models.Schedule: def list( self, *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, **kwargs: Any - ) -> ItemPaged["_models.Schedule"]: - """List all schedules. + ) -> ItemPaged["_models.ToolboxObject"]: + """List all toolboxes. - :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. Default value is None. - :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of Schedule - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.Schedule] + :paramtype before: str + :return: An iterator like instance of ToolboxObject + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxObject] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.Schedule]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.ToolboxObject]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -15366,60 +15262,35 @@ def list( } error_map.update(kwargs.pop("error_map", {}) or {}) - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_schedules_list_request( - type=type, - enabled=enabled, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + def prepare_request(_continuation_token=None): + _request = build_beta_toolboxes_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) return _request def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.Schedule], - deserialized.get("value", []), + List[_models.ToolboxObject], + deserialized.get("data", []), ) if cls: list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) + return deserialized.get("last_id") or None, iter(list_of_elem) - def get_next(next_link=None): - _request = prepare_request(next_link) + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access @@ -15429,81 +15300,53 @@ def get_next(next_link=None): if response.status_code not in [200]: map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) return pipeline_response return ItemPaged(get_next, extract_data) - @overload - def create_or_update( - self, schedule_id: str, schedule: _models.Schedule, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. - - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: ~azure.ai.projects.models.Schedule - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_or_update( - self, schedule_id: str, schedule: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. - - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: JSON - :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. - Default value is "application/json". - :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule - :raises ~azure.core.exceptions.HttpResponseError: - """ - - @overload - def create_or_update( - self, schedule_id: str, schedule: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + @distributed_trace + def list_versions( + self, + name: str, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.ToolboxVersionObject"]: + """List all versions of a toolbox. - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Required. - :type schedule: IO[bytes] - :keyword content_type: Body Parameter content-type. Content type parameter for binary body. - Default value is "application/json". - :paramtype content_type: str - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule + :param name: The name of the toolbox to list versions for. Required. + :type name: str + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of ToolboxVersionObject + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxVersionObject] :raises ~azure.core.exceptions.HttpResponseError: """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - @distributed_trace - def create_or_update( - self, schedule_id: str, schedule: Union[_models.Schedule, JSON, IO[bytes]], **kwargs: Any - ) -> _models.Schedule: - """Create or update operation template. + cls: ClsType[List[_models.ToolboxVersionObject]] = kwargs.pop("cls", None) - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :param schedule: The resource instance. Is one of the following types: Schedule, JSON, - IO[bytes] Required. - :type schedule: ~azure.ai.projects.models.Schedule or JSON or IO[bytes] - :return: Schedule. The Schedule is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.Schedule - :raises ~azure.core.exceptions.HttpResponseError: - """ error_map: MutableMapping = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, @@ -15512,69 +15355,65 @@ def create_or_update( } error_map.update(kwargs.pop("error_map", {}) or {}) - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.Schedule] = kwargs.pop("cls", None) - - content_type = content_type or "application/json" - _content = None - if isinstance(schedule, (IOBase, bytes)): - _content = schedule - else: - _content = json.dumps(schedule, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + def prepare_request(_continuation_token=None): - _request = build_beta_schedules_create_or_update_request( - schedule_id=schedule_id, - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) + _request = build_beta_toolboxes_list_versions_request( + name=name, + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.ToolboxVersionObject], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) - response = pipeline_response.http_response + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) - if response.status_code not in [200, 201]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.Schedule, response.json()) + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return pipeline_response - return deserialized # type: ignore + return ItemPaged(get_next, extract_data) @distributed_trace - def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.ScheduleRun: - """Get a schedule run by id. + def get_version(self, name: str, version: str, **kwargs: Any) -> _models.ToolboxVersionObject: + """Retrieve a specific version of a toolbox. - :param schedule_id: The unique identifier of the schedule. Required. - :type schedule_id: str - :param run_id: The unique identifier of the schedule run. Required. - :type run_id: str - :return: ScheduleRun. The ScheduleRun is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ScheduleRun + :param name: The name of the toolbox. Required. + :type name: str + :param version: The version identifier to retrieve. Required. + :type version: str + :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxVersionObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -15588,11 +15427,11 @@ def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.Sched _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ScheduleRun] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) - _request = build_beta_schedules_get_run_request( - schedule_id=schedule_id, - run_id=run_id, + _request = build_beta_toolboxes_get_version_request( + name=name, + version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -15626,238 +15465,83 @@ def get_run(self, schedule_id: str, run_id: str, **kwargs: Any) -> _models.Sched if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ScheduleRun, response.json()) + deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore - @distributed_trace - def list_runs( - self, - schedule_id: str, - *, - type: Optional[Union[str, _models.ScheduleTaskType]] = None, - enabled: Optional[bool] = None, - **kwargs: Any - ) -> ItemPaged["_models.ScheduleRun"]: - """List all schedule runs. - - :param schedule_id: Identifier of the schedule. Required. - :type schedule_id: str - :keyword type: Filter by the type of schedule. Known values are: "Evaluation" and "Insight". - Default value is None. - :paramtype type: str or ~azure.ai.projects.models.ScheduleTaskType - :keyword enabled: Filter by the enabled status. Default value is None. - :paramtype enabled: bool - :return: An iterator like instance of ScheduleRun - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ScheduleRun] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.ScheduleRun]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(next_link=None): - if not next_link: - - _request = build_beta_schedules_list_runs_request( - schedule_id=schedule_id, - type=type, - enabled=enabled, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - else: - # make call to next link with the client's api-version - _parsed_next_link = urllib.parse.urlparse(next_link) - _next_request_params = case_insensitive_dict( - { - key: [urllib.parse.quote(v) for v in value] - for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items() - } - ) - _next_request_params["api-version"] = self._config.api_version - _request = HttpRequest( - "GET", - urllib.parse.urljoin(next_link, _parsed_next_link.path), - params=_next_request_params, - headers=_headers, - ) - path_format_arguments = { - "endpoint": self._serialize.url( - "self._config.endpoint", self._config.endpoint, "str", skip_quote=True - ), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ScheduleRun], - deserialized.get("value", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("nextLink") or None, iter(list_of_elem) - - def get_next(next_link=None): - _request = prepare_request(next_link) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - raise HttpResponseError(response=response) - - return pipeline_response - - return ItemPaged(get_next, extract_data) - - -class BetaToolboxesOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. - - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`toolboxes` attribute. - """ - - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @overload - def create_version( - self, - name: str, - *, - tools: List[_models.Tool], - content_type: str = "application/json", - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - policies: Optional[_models.ToolboxPolicies] = None, - **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + def update( + self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. + :param name: The name of the toolbox to update. Required. :type name: str - :keyword tools: The list of tools to include in this version. Required. - :paramtype tools: list[~azure.ai.projects.models.Tool] + :keyword default_version: The version identifier that the toolbox should point to. When set, + the toolbox's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the toolbox. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is - None. - :paramtype metadata: dict[str, str] - :keyword policies: Policy configuration for this toolbox version. Default value is None. - :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_version( + def update( self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. + :param name: The name of the toolbox to update. Required. :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def create_version( + def update( self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. + :param name: The name of the toolbox to update. Required. :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def create_version( - self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, - *, - tools: List[_models.Tool] = _Unset, - description: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, - policies: Optional[_models.ToolboxPolicies] = None, - **kwargs: Any - ) -> _models.ToolboxVersionObject: - """Create a new version of a toolbox. If the toolbox does not exist, it will be created. + def update( + self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, default_version: str = _Unset, **kwargs: Any + ) -> _models.ToolboxObject: + """Update a toolbox to point to a specific version. - :param name: The name of the toolbox. If the toolbox does not exist, it will be created. - Required. + :param name: The name of the toolbox to update. Required. :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword tools: The list of tools to include in this version. Required. - :paramtype tools: list[~azure.ai.projects.models.Tool] - :keyword description: A human-readable description of the toolbox. Default value is None. - :paramtype description: str - :keyword metadata: Arbitrary key-value metadata to associate with the toolbox. Default value is - None. - :paramtype metadata: dict[str, str] - :keyword policies: Policy configuration for this toolbox version. Default value is None. - :paramtype policies: ~azure.ai.projects.models.ToolboxPolicies - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :keyword default_version: The version identifier that the toolbox should point to. When set, + the toolbox's default version will resolve to this version instead of the latest. Required. + :paramtype default_version: str + :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.ToolboxObject :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -15872,12 +15556,12 @@ def create_version( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) + cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) if body is _Unset: - if tools is _Unset: - raise TypeError("missing required argument: tools") - body = {"description": description, "metadata": metadata, "policies": policies, "tools": tools} + if default_version is _Unset: + raise TypeError("missing required argument: default_version") + body = {"default_version": default_version} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -15886,7 +15570,7 @@ def create_version( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_toolboxes_create_version_request( + _request = build_beta_toolboxes_update_request( name=name, content_type=content_type, api_version=self._config.api_version, @@ -15923,7 +15607,7 @@ def create_version( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) + deserialized = _deserialize(_models.ToolboxObject, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -15931,13 +15615,13 @@ def create_version( return deserialized # type: ignore @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: - """Retrieve a toolbox. + def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements + """Delete a toolbox and all its versions. - :param name: The name of the toolbox to retrieve. Required. + :param name: The name of the toolbox to delete. Required. :type name: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -15951,9 +15635,9 @@ def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_request( + _request = build_beta_toolboxes_delete_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -15964,20 +15648,14 @@ def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -15985,210 +15663,21 @@ def get(self, name: str, **kwargs: Any) -> _models.ToolboxObject: ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def list( - self, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.ToolboxObject"]: - """List all toolboxes. - - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of ToolboxObject - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxObject] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.ToolboxObject]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(_continuation_token=None): - - _request = build_beta_toolboxes_list_request( - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ToolboxObject], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) - - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return ItemPaged(get_next, extract_data) - - @distributed_trace - def list_versions( - self, - name: str, - *, - limit: Optional[int] = None, - order: Optional[Union[str, _models.PageOrder]] = None, - before: Optional[str] = None, - **kwargs: Any - ) -> ItemPaged["_models.ToolboxVersionObject"]: - """List all versions of a toolbox. - - :param name: The name of the toolbox to list versions for. Required. - :type name: str - :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and - 100, and the - default is 20. Default value is None. - :paramtype limit: int - :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for - ascending order and``desc`` - for descending order. Known values are: "asc" and "desc". Default value is None. - :paramtype order: str or ~azure.ai.projects.models.PageOrder - :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your - place in the list. - For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - subsequent call can include before=obj_foo in order to fetch the previous page of the list. - Default value is None. - :paramtype before: str - :return: An iterator like instance of ToolboxVersionObject - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.ToolboxVersionObject] - :raises ~azure.core.exceptions.HttpResponseError: - """ - _headers = kwargs.pop("headers", {}) or {} - _params = kwargs.pop("params", {}) or {} - - cls: ClsType[List[_models.ToolboxVersionObject]] = kwargs.pop("cls", None) - - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - def prepare_request(_continuation_token=None): - - _request = build_beta_toolboxes_list_versions_request( - name=name, - limit=limit, - order=order, - after=_continuation_token, - before=before, - api_version=self._config.api_version, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - return _request - - def extract_data(pipeline_response): - deserialized = pipeline_response.http_response.json() - list_of_elem = _deserialize( - List[_models.ToolboxVersionObject], - deserialized.get("data", []), - ) - if cls: - list_of_elem = cls(list_of_elem) # type: ignore - return deserialized.get("last_id") or None, iter(list_of_elem) - - def get_next(_continuation_token=None): - _request = prepare_request(_continuation_token) - - _stream = False - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - response = pipeline_response.http_response - - if response.status_code not in [200]: - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - return pipeline_response - - return ItemPaged(get_next, extract_data) + return cls(pipeline_response, None, {}) # type: ignore @distributed_trace - def get_version(self, name: str, version: str, **kwargs: Any) -> _models.ToolboxVersionObject: - """Retrieve a specific version of a toolbox. + def delete_version( # pylint: disable=inconsistent-return-statements + self, name: str, version: str, **kwargs: Any + ) -> None: + """Delete a specific version of a toolbox. :param name: The name of the toolbox. Required. :type name: str - :param version: The version identifier to retrieve. Required. + :param version: The version identifier to delete. Required. :type version: str - :return: ToolboxVersionObject. The ToolboxVersionObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxVersionObject + :return: None + :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -16202,9 +15691,9 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.Toolbox _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.ToolboxVersionObject] = kwargs.pop("cls", None) + cls: ClsType[None] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_get_version_request( + _request = build_beta_toolboxes_delete_version_request( name=name, version=version, api_version=self._config.api_version, @@ -16216,20 +15705,14 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.Toolbox } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) + _stream = False pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [200]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass + if response.status_code not in [204]: map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -16237,86 +15720,121 @@ def get_version(self, name: str, version: str, **kwargs: Any) -> _models.Toolbox ) raise HttpResponseError(response=response, model=error) - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.ToolboxVersionObject, response.json()) - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, None, {}) # type: ignore - return deserialized # type: ignore + +class BetaSkillsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`skills` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") @overload - def update( - self, name: str, *, default_version: str, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + def create( + self, + *, + name: str, + content_type: str = "application/json", + description: Optional[str] = None, + instructions: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.SkillDetails: + """Creates a skill. - :param name: The name of the toolbox to update. Required. - :type name: str - :keyword default_version: The version identifier that the toolbox should point to. When set, - the toolbox's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str + :keyword name: The unique name of the skill. Required. + :paramtype name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + def create(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: + """Creates a skill. - :param name: The name of the toolbox to update. Required. - :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + def create(self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: + """Creates a skill. - :param name: The name of the toolbox to update. Required. - :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update( - self, name: str, body: Union[JSON, IO[bytes]] = _Unset, *, default_version: str = _Unset, **kwargs: Any - ) -> _models.ToolboxObject: - """Update a toolbox to point to a specific version. + def create( + self, + body: Union[JSON, IO[bytes]] = _Unset, + *, + name: str = _Unset, + description: Optional[str] = None, + instructions: Optional[str] = None, + metadata: Optional[dict[str, str]] = None, + **kwargs: Any + ) -> _models.SkillDetails: + """Creates a skill. - :param name: The name of the toolbox to update. Required. - :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword default_version: The version identifier that the toolbox should point to. When set, - the toolbox's default version will resolve to this version instead of the latest. Required. - :paramtype default_version: str - :return: ToolboxObject. The ToolboxObject is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.ToolboxObject + :keyword name: The unique name of the skill. Required. + :paramtype name: str + :keyword description: A human-readable description of the skill. Default value is None. + :paramtype description: str + :keyword instructions: Instructions that define the behavior of the skill. Default value is + None. + :paramtype instructions: str + :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be + useful for storing additional information about the object in a structured + format, and querying for objects via API or the dashboard. + + Keys are strings with a maximum length of 64 characters. Values are strings + with a maximum length of 512 characters. Default value is None. + :paramtype metadata: dict[str, str] + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -16331,12 +15849,12 @@ def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.ToolboxObject] = kwargs.pop("cls", None) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) if body is _Unset: - if default_version is _Unset: - raise TypeError("missing required argument: default_version") - body = {"default_version": default_version} + if name is _Unset: + raise TypeError("missing required argument: name") + body = {"description": description, "instructions": instructions, "metadata": metadata, "name": name} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -16345,8 +15863,7 @@ def update( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_toolboxes_update_request( - name=name, + _request = build_beta_skills_create_request( content_type=content_type, api_version=self._config.api_version, content=_content, @@ -16366,7 +15883,7 @@ def update( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -16382,7 +15899,7 @@ def update( if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.ToolboxObject, response.json()) + deserialized = _deserialize(_models.SkillDetails, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore @@ -16390,13 +15907,82 @@ def update( return deserialized # type: ignore @distributed_trace - def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements - """Delete a toolbox and all its versions. + def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: + """Creates a skill from a zip package. - :param name: The name of the toolbox to delete. Required. + :param content: The zip package used to create the skill. Required. + :type content: bytes + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/zip")) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + + _content = content + + _request = build_beta_skills_create_from_package_request( + content_type=content_type, + api_version=self._config.api_version, + content=_content, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) + + if cls: + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: + """Retrieves a skill. + + :param name: The unique name of the skill. Required. :type name: str - :return: None - :rtype: None + :return: SkillDetails. The SkillDetails is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.SkillDetails :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -16410,9 +15996,9 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_delete_request( + _request = build_beta_skills_get_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -16423,14 +16009,20 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -16438,21 +16030,24 @@ def delete(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsist ) raise HttpResponseError(response=response, model=error) + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.SkillDetails, response.json()) + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, {}) # type: ignore + + return deserialized # type: ignore @distributed_trace - def delete_version( # pylint: disable=inconsistent-return-statements - self, name: str, version: str, **kwargs: Any - ) -> None: - """Delete a specific version of a toolbox. + def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: + """Downloads a skill package. - :param name: The name of the toolbox. Required. + :param name: The unique name of the skill. Required. :type name: str - :param version: The version identifier to delete. Required. - :type version: str - :return: None - :rtype: None + :return: Iterator[bytes] + :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -16466,11 +16061,10 @@ def delete_version( # pylint: disable=inconsistent-return-statements _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[None] = kwargs.pop("cls", None) + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) - _request = build_beta_toolboxes_delete_version_request( + _request = build_beta_skills_download_request( name=name, - version=version, api_version=self._config.api_version, headers=_headers, params=_params, @@ -16480,14 +16074,20 @@ def delete_version( # pylint: disable=inconsistent-return-statements } _request.url = self._client.format_url(_request.url, **path_format_arguments) - _stream = False + _decompress = kwargs.pop("decompress", True) + _stream = kwargs.pop("stream", True) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) response = pipeline_response.http_response - if response.status_code not in [204]: + if response.status_code not in [200]: + if _stream: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass map_error(status_code=response.status_code, response=response, error_map=error_map) error = _failsafe_deserialize( _models.ApiErrorResponse, @@ -16495,42 +16095,121 @@ def delete_version( # pylint: disable=inconsistent-return-statements ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if cls: - return cls(pipeline_response, None, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore + return deserialized # type: ignore -class BetaSkillsOperations: - """ - .. warning:: - **DO NOT** instantiate this class directly. + @distributed_trace + def list( + self, + *, + limit: Optional[int] = None, + order: Optional[Union[str, _models.PageOrder]] = None, + before: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged["_models.SkillDetails"]: + """Returns the list of all skills. - Instead, you should access the following operations through - :class:`~azure.ai.projects.AIProjectClient`'s - :attr:`skills` attribute. - """ + :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and + 100, and the + default is 20. Default value is None. + :paramtype limit: int + :keyword order: Sort order by the ``created_at`` timestamp of the objects. ``asc`` for + ascending order and``desc`` + for descending order. Known values are: "asc" and "desc". Default value is None. + :paramtype order: str or ~azure.ai.projects.models.PageOrder + :keyword before: A cursor for use in pagination. ``before`` is an object ID that defines your + place in the list. + For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page of the list. + Default value is None. + :paramtype before: str + :return: An iterator like instance of SkillDetails + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillDetails] + :raises ~azure.core.exceptions.HttpResponseError: + """ + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} - def __init__(self, *args, **kwargs) -> None: - input_args = list(args) - self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") - self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") - self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") - self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) + + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + def prepare_request(_continuation_token=None): + + _request = build_beta_skills_list_request( + limit=limit, + order=order, + after=_continuation_token, + before=before, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + return _request + + def extract_data(pipeline_response): + deserialized = pipeline_response.http_response.json() + list_of_elem = _deserialize( + List[_models.SkillDetails], + deserialized.get("data", []), + ) + if cls: + list_of_elem = cls(list_of_elem) # type: ignore + return deserialized.get("last_id") or None, iter(list_of_elem) + + def get_next(_continuation_token=None): + _request = prepare_request(_continuation_token) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + return pipeline_response + + return ItemPaged(get_next, extract_data) @overload - def create( + def update( self, - *, name: str, + *, content_type: str = "application/json", description: Optional[str] = None, instructions: Optional[str] = None, metadata: Optional[dict[str, str]] = None, **kwargs: Any ) -> _models.SkillDetails: - """Creates a skill. + """Updates an existing skill. - :keyword name: The unique name of the skill. Required. - :paramtype name: str + :param name: The unique name of the skill. Required. + :type name: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str @@ -16552,9 +16231,13 @@ def create( """ @overload - def create(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: - """Creates a skill. + def update( + self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Updates an existing skill. + :param name: The unique name of the skill. Required. + :type name: str :param body: Required. :type body: JSON :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. @@ -16566,9 +16249,13 @@ def create(self, body: JSON, *, content_type: str = "application/json", **kwargs """ @overload - def create(self, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any) -> _models.SkillDetails: - """Creates a skill. + def update( + self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any + ) -> _models.SkillDetails: + """Updates an existing skill. + :param name: The unique name of the skill. Required. + :type name: str :param body: Required. :type body: IO[bytes] :keyword content_type: Body Parameter content-type. Content type parameter for binary body. @@ -16580,22 +16267,22 @@ def create(self, body: IO[bytes], *, content_type: str = "application/json", **k """ @distributed_trace - def create( + def update( self, + name: str, body: Union[JSON, IO[bytes]] = _Unset, *, - name: str = _Unset, description: Optional[str] = None, instructions: Optional[str] = None, metadata: Optional[dict[str, str]] = None, **kwargs: Any ) -> _models.SkillDetails: - """Creates a skill. + """Updates an existing skill. + :param name: The unique name of the skill. Required. + :type name: str :param body: Is either a JSON type or a IO[bytes] type. Required. :type body: JSON or IO[bytes] - :keyword name: The unique name of the skill. Required. - :paramtype name: str :keyword description: A human-readable description of the skill. Default value is None. :paramtype description: str :keyword instructions: Instructions that define the behavior of the skill. Default value is @@ -16627,9 +16314,7 @@ def create( cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) if body is _Unset: - if name is _Unset: - raise TypeError("missing required argument: name") - body = {"description": description, "instructions": instructions, "metadata": metadata, "name": name} + body = {"description": description, "instructions": instructions, "metadata": metadata} body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None @@ -16638,76 +16323,8 @@ def create( else: _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_skills_create_request( - content_type=content_type, - api_version=self._config.api_version, - content=_content, - headers=_headers, - params=_params, - ) - path_format_arguments = { - "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), - } - _request.url = self._client.format_url(_request.url, **path_format_arguments) - - _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", False) - pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access - _request, stream=_stream, **kwargs - ) - - response = pipeline_response.http_response - - if response.status_code not in [201]: - if _stream: - try: - response.read() # Load the body in memory and close the socket - except (StreamConsumedError, StreamClosedError): - pass - map_error(status_code=response.status_code, response=response, error_map=error_map) - error = _failsafe_deserialize( - _models.ApiErrorResponse, - response, - ) - raise HttpResponseError(response=response, model=error) - - if _stream: - deserialized = response.iter_bytes() if _decompress else response.iter_raw() - else: - deserialized = _deserialize(_models.SkillDetails, response.json()) - - if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore - - return deserialized # type: ignore - - @distributed_trace - def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDetails: - """Creates a skill from a zip package. - - :param content: The zip package used to create the skill. Required. - :type content: bytes - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails - :raises ~azure.core.exceptions.HttpResponseError: - """ - error_map: MutableMapping = { - 401: ClientAuthenticationError, - 404: ResourceNotFoundError, - 409: ResourceExistsError, - 304: ResourceNotModifiedError, - } - error_map.update(kwargs.pop("error_map", {}) or {}) - - _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) - _params = kwargs.pop("params", {}) or {} - - content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/zip")) - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) - - _content = content - - _request = build_beta_skills_create_from_package_request( + _request = build_beta_skills_update_request( + name=name, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -16727,7 +16344,7 @@ def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDet response = pipeline_response.http_response - if response.status_code not in [201]: + if response.status_code not in [200]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -16751,13 +16368,13 @@ def create_from_package(self, content: bytes, **kwargs: Any) -> _models.SkillDet return deserialized # type: ignore @distributed_trace - def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: - """Retrieves a skill. + def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: + """Deletes a skill. :param name: The unique name of the skill. Required. :type name: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DeleteSkillResult :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -16771,9 +16388,9 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) - _request = build_beta_skills_get_request( + _request = build_beta_skills_delete_request( name=name, api_version=self._config.api_version, headers=_headers, @@ -16808,21 +16425,41 @@ def get(self, name: str, **kwargs: Any) -> _models.SkillDetails: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + deserialized = _deserialize(_models.DeleteSkillResult, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + +class BetaDatasetsOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.AIProjectClient`'s + :attr:`datasets` attribute. + """ + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AIProjectClientConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @distributed_trace - def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: - """Downloads a skill package. + def get_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: + """Get info about a data generation job. - :param name: The unique name of the skill. Required. - :type name: str - :return: Iterator[bytes] - :rtype: Iterator[bytes] + Gets the details of a data generation job by its ID. + + :param job_id: The ID of the job. Required. + :type job_id: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -16836,10 +16473,10 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) - _request = build_beta_skills_download_request( - name=name, + _request = build_beta_datasets_get_generation_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -16850,7 +16487,7 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: _request.url = self._client.format_url(_request.url, **path_format_arguments) _decompress = kwargs.pop("decompress", True) - _stream = kwargs.pop("stream", True) + _stream = kwargs.pop("stream", False) pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access _request, stream=_stream, **kwargs ) @@ -16871,9 +16508,12 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: raise HttpResponseError(response=response, model=error) response_headers = {} - response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["Retry-After"] = self._deserialize("int", response.headers.get("Retry-After")) - deserialized = response.iter_bytes() if _decompress else response.iter_raw() + if _stream: + deserialized = response.iter_bytes() if _decompress else response.iter_raw() + else: + deserialized = _deserialize(_models.DataGenerationJob, response.json()) if cls: return cls(pipeline_response, deserialized, response_headers) # type: ignore @@ -16881,15 +16521,19 @@ def download(self, name: str, **kwargs: Any) -> Iterator[bytes]: return deserialized # type: ignore @distributed_trace - def list( + def list_generation_jobs( self, *, limit: Optional[int] = None, order: Optional[Union[str, _models.PageOrder]] = None, before: Optional[str] = None, + scenario: Optional[Union[str, _models.DataGenerationJobScenario]] = None, + type: Optional[List[Union[str, _models.DataGenerationJobType]]] = None, **kwargs: Any - ) -> ItemPaged["_models.SkillDetails"]: - """Returns the list of all skills. + ) -> ItemPaged["_models.DataGenerationJob"]: + """Returns a list of data generation jobs. + + Returns a list of data generation jobs. :keyword limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the @@ -16905,14 +16549,19 @@ def list( subsequent call can include before=obj_foo in order to fetch the previous page of the list. Default value is None. :paramtype before: str - :return: An iterator like instance of SkillDetails - :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.SkillDetails] + :keyword scenario: Filter data generation jobs by their scenario. Known values are: + "supervised_finetuning", "reinforcement_finetuning", and "evaluation". Default value is None. + :paramtype scenario: str or ~azure.ai.projects.models.DataGenerationJobScenario + :keyword type: Filter data generation jobs by their type. Default value is None. + :paramtype type: list[str or ~azure.ai.projects.models.DataGenerationJobType] + :return: An iterator like instance of DataGenerationJob + :rtype: ~azure.core.paging.ItemPaged[~azure.ai.projects.models.DataGenerationJob] :raises ~azure.core.exceptions.HttpResponseError: """ _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[_models.SkillDetails]] = kwargs.pop("cls", None) + cls: ClsType[List[_models.DataGenerationJob]] = kwargs.pop("cls", None) error_map: MutableMapping = { 401: ClientAuthenticationError, @@ -16924,11 +16573,13 @@ def list( def prepare_request(_continuation_token=None): - _request = build_beta_skills_list_request( + _request = build_beta_datasets_list_generation_jobs_request( limit=limit, order=order, after=_continuation_token, before=before, + scenario=scenario, + type=type, api_version=self._config.api_version, headers=_headers, params=_params, @@ -16942,7 +16593,7 @@ def prepare_request(_continuation_token=None): def extract_data(pipeline_response): deserialized = pipeline_response.http_response.json() list_of_elem = _deserialize( - List[_models.SkillDetails], + List[_models.DataGenerationJob], deserialized.get("data", []), ) if cls: @@ -16971,107 +16622,98 @@ def get_next(_continuation_token=None): return ItemPaged(get_next, extract_data) @overload - def update( + def create_generation_job( self, - name: str, + job: _models.DataGenerationJob, *, + operation_id: Optional[str] = None, content_type: str = "application/json", - description: Optional[str] = None, - instructions: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, **kwargs: Any - ) -> _models.SkillDetails: - """Updates an existing skill. + ) -> _models.DataGenerationJob: + """Creates a data generation job. - :param name: The unique name of the skill. Required. - :type name: str + Creates a data generation job. + + :param job: The job to create. Required. + :type job: ~azure.ai.projects.models.DataGenerationJob + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, body: JSON, *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Updates an existing skill. + def create_generation_job( + self, job: JSON, *, operation_id: Optional[str] = None, content_type: str = "application/json", **kwargs: Any + ) -> _models.DataGenerationJob: + """Creates a data generation job. - :param name: The unique name of the skill. Required. - :type name: str - :param body: Required. - :type body: JSON + Creates a data generation job. + + :param job: The job to create. Required. + :type job: JSON + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. Default value is "application/json". :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @overload - def update( - self, name: str, body: IO[bytes], *, content_type: str = "application/json", **kwargs: Any - ) -> _models.SkillDetails: - """Updates an existing skill. + def create_generation_job( + self, + job: IO[bytes], + *, + operation_id: Optional[str] = None, + content_type: str = "application/json", + **kwargs: Any + ) -> _models.DataGenerationJob: + """Creates a data generation job. - :param name: The unique name of the skill. Required. - :type name: str - :param body: Required. - :type body: IO[bytes] + Creates a data generation job. + + :param job: The job to create. Required. + :type job: IO[bytes] + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str :keyword content_type: Body Parameter content-type. Content type parameter for binary body. Default value is "application/json". :paramtype content_type: str - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ @distributed_trace - def update( + def create_generation_job( self, - name: str, - body: Union[JSON, IO[bytes]] = _Unset, + job: Union[_models.DataGenerationJob, JSON, IO[bytes]], *, - description: Optional[str] = None, - instructions: Optional[str] = None, - metadata: Optional[dict[str, str]] = None, + operation_id: Optional[str] = None, **kwargs: Any - ) -> _models.SkillDetails: - """Updates an existing skill. + ) -> _models.DataGenerationJob: + """Creates a data generation job. - :param name: The unique name of the skill. Required. - :type name: str - :param body: Is either a JSON type or a IO[bytes] type. Required. - :type body: JSON or IO[bytes] - :keyword description: A human-readable description of the skill. Default value is None. - :paramtype description: str - :keyword instructions: Instructions that define the behavior of the skill. Default value is - None. - :paramtype instructions: str - :keyword metadata: Set of 16 key-value pairs that can be attached to an object. This can be - useful for storing additional information about the object in a structured - format, and querying for objects via API or the dashboard. + Creates a data generation job. - Keys are strings with a maximum length of 64 characters. Values are strings - with a maximum length of 512 characters. Default value is None. - :paramtype metadata: dict[str, str] - :return: SkillDetails. The SkillDetails is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.SkillDetails + :param job: The job to create. Is one of the following types: DataGenerationJob, JSON, + IO[bytes] Required. + :type job: ~azure.ai.projects.models.DataGenerationJob or JSON or IO[bytes] + :keyword operation_id: Client-generated unique ID for idempotent retries. When absent, the + server creates the job unconditionally. Default value is None. + :paramtype operation_id: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -17086,20 +16728,17 @@ def update( _params = kwargs.pop("params", {}) or {} content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) - cls: ClsType[_models.SkillDetails] = kwargs.pop("cls", None) + cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) - if body is _Unset: - body = {"description": description, "instructions": instructions, "metadata": metadata} - body = {k: v for k, v in body.items() if v is not None} content_type = content_type or "application/json" _content = None - if isinstance(body, (IOBase, bytes)): - _content = body + if isinstance(job, (IOBase, bytes)): + _content = job else: - _content = json.dumps(body, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore + _content = json.dumps(job, cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore - _request = build_beta_skills_update_request( - name=name, + _request = build_beta_datasets_create_generation_job_request( + operation_id=operation_id, content_type=content_type, api_version=self._config.api_version, content=_content, @@ -17119,7 +16758,7 @@ def update( response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [201]: if _stream: try: response.read() # Load the body in memory and close the socket @@ -17132,24 +16771,30 @@ def update( ) raise HttpResponseError(response=response, model=error) + response_headers = {} + response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location")) + response_headers["Location"] = self._deserialize("str", response.headers.get("Location")) + if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.SkillDetails, response.json()) + deserialized = _deserialize(_models.DataGenerationJob, response.json()) if cls: - return cls(pipeline_response, deserialized, {}) # type: ignore + return cls(pipeline_response, deserialized, response_headers) # type: ignore return deserialized # type: ignore @distributed_trace - def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: - """Deletes a skill. + def cancel_generation_job(self, job_id: str, **kwargs: Any) -> _models.DataGenerationJob: + """Cancels a data generation job. - :param name: The unique name of the skill. Required. - :type name: str - :return: DeleteSkillResult. The DeleteSkillResult is compatible with MutableMapping - :rtype: ~azure.ai.projects.models.DeleteSkillResult + Cancels a data generation job by its ID. + + :param job_id: The ID of the job to cancel. Required. + :type job_id: str + :return: DataGenerationJob. The DataGenerationJob is compatible with MutableMapping + :rtype: ~azure.ai.projects.models.DataGenerationJob :raises ~azure.core.exceptions.HttpResponseError: """ error_map: MutableMapping = { @@ -17163,10 +16808,10 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[_models.DeleteSkillResult] = kwargs.pop("cls", None) + cls: ClsType[_models.DataGenerationJob] = kwargs.pop("cls", None) - _request = build_beta_skills_delete_request( - name=name, + _request = build_beta_datasets_cancel_generation_job_request( + job_id=job_id, api_version=self._config.api_version, headers=_headers, params=_params, @@ -17200,9 +16845,65 @@ def delete(self, name: str, **kwargs: Any) -> _models.DeleteSkillResult: if _stream: deserialized = response.iter_bytes() if _decompress else response.iter_raw() else: - deserialized = _deserialize(_models.DeleteSkillResult, response.json()) + deserialized = _deserialize(_models.DataGenerationJob, response.json()) if cls: return cls(pipeline_response, deserialized, {}) # type: ignore return deserialized # type: ignore + + @distributed_trace + def delete_generation_job( # pylint: disable=inconsistent-return-statements + self, job_id: str, **kwargs: Any + ) -> None: + """Deletes a data generation job. + + Deletes a data generation job by its ID. + + :param job_id: The ID of the job to delete. Required. + :type job_id: str + :return: None + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_beta_datasets_delete_generation_job_request( + job_id=job_id, + api_version=self._config.api_version, + headers=_headers, + params=_params, + ) + path_format_arguments = { + "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True), + } + _request.url = self._client.format_url(_request.url, **path_format_arguments) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = _failsafe_deserialize( + _models.ApiErrorResponse, + response, + ) + raise HttpResponseError(response=response, model=error) + + if cls: + return cls(pipeline_response, None, {}) # type: ignore From a9e9412c80799f71be93fa160ab1bd6741539b7a Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Fri, 22 May 2026 00:32:50 +0530 Subject: [PATCH 08/14] Revert aio _patch.py to base; minimize sync _patch.py diff for BetaModelsOperations --- .../azure/ai/projects/aio/operations/_patch.py | 4 ++++ .../azure-ai-projects/azure/ai/projects/operations/_patch.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index 613c3526d92f..c9b8cfff7731 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py @@ -18,6 +18,7 @@ from ._patch_sessions_async import BetaAgentsOperations from ...operations._patch import _BETA_OPERATION_FEATURE_HEADERS, _OperationMethodHeaderProxy from ._operations import ( + BetaDatasetsOperations, BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, @@ -63,6 +64,8 @@ class BetaOperations(GeneratedBetaOperations): """:class:`~azure.ai.projects.aio.operations.BetaToolboxesOperations` operations""" skills: BetaSkillsOperations """:class:`~azure.ai.projects.aio.operations.BetaSkillsOperations` operations""" + datasets: BetaDatasetsOperations + """:class:`~azure.ai.projects.aio.operations.BetaDatasetsOperations` operations""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -84,6 +87,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: __all__: List[str] = [ "AgentsOperations", "BetaAgentsOperations", + "BetaDatasetsOperations", "BetaEvaluationTaxonomiesOperations", "BetaEvaluatorsOperations", "BetaInsightsOperations", diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index acb0c08f5008..276c9fd5d2d7 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -21,10 +21,10 @@ from ._patch_models import BetaModelsOperations from ._patch_sessions import BetaAgentsOperations from ._operations import ( + BetaDatasetsOperations, BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, - BetaModelsOperations, BetaOperations as GeneratedBetaOperations, BetaRedTeamsOperations, BetaRoutinesOperations, @@ -119,6 +119,8 @@ class BetaOperations(GeneratedBetaOperations): """:class:`~azure.ai.projects.operations.BetaToolboxesOperations` operations""" skills: BetaSkillsOperations """:class:`~azure.ai.projects.operations.BetaSkillsOperations` operations""" + datasets: BetaDatasetsOperations + """:class:`~azure.ai.projects.operations.BetaDatasetsOperations` operations""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) @@ -142,6 +144,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: __all__: List[str] = [ "AgentsOperations", "BetaAgentsOperations", + "BetaDatasetsOperations", "BetaEvaluationTaxonomiesOperations", "BetaEvaluatorsOperations", "BetaInsightsOperations", From 64e996897a5a8143b65ddc552c05ac920af1f7d4 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Fri, 22 May 2026 15:07:15 +0530 Subject: [PATCH 09/14] Address PR #46842 review comments Darren (dargilco): - D1: Merge feature/azure-ai-projects/2.2.0 into branch (separate merge commit). - D2: Remove duplicate '.beta.models' CHANGELOG bullet. - D3: Remove stray blank line in CHANGELOG. - D4: Revert apiview-properties.json to base. - D5: Wire async patched BetaModelsOperations into aio/operations/_patch.py; add azure/ai/projects/aio/operations/_patch_models_async.py with async create_version() using azure.storage.blob.aio.ContainerClient. Howie (howieleung): - H1: Rename helper models_create -> create_version (and validator). - H2: Rename sample_models{,_async}.py -> sample_models_basic{,_async}.py. - H3: Print friendly per-field summaries in samples instead of raw model repr. - H4: Guard against None return from create_version before accessing fields. Also follows TypeSpec rename: generated create_async() -> pending_create_version(). --- sdk/ai/azure-ai-projects/CHANGELOG.md | 10 +- sdk/ai/azure-ai-projects/README.md | 4 +- .../azure-ai-projects/apiview-properties.json | 42 +-- .../ai/projects/aio/operations/_patch.py | 4 +- .../aio/operations/_patch_models_async.py | 271 ++++++++++++++++++ .../azure/ai/projects/operations/_patch.py | 2 +- .../ai/projects/operations/_patch_models.py | 28 +- ...ample_models.py => sample_models_basic.py} | 31 +- ..._async.py => sample_models_basic_async.py} | 28 +- .../models/sample_models_without_patch.py | 12 +- .../tests/models/test_models.py | 28 +- .../tests/models/test_models_async.py | 4 +- .../tests/models/test_patch_models.py | 52 ++-- 13 files changed, 390 insertions(+), 126 deletions(-) create mode 100644 sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py rename sdk/ai/azure-ai-projects/samples/models/{sample_models.py => sample_models_basic.py} (77%) rename sdk/ai/azure-ai-projects/samples/models/{sample_models_async.py => sample_models_basic_async.py} (86%) diff --git a/sdk/ai/azure-ai-projects/CHANGELOG.md b/sdk/ai/azure-ai-projects/CHANGELOG.md index 54e5cc721a85..b8e64f5e3ec4 100644 --- a/sdk/ai/azure-ai-projects/CHANGELOG.md +++ b/sdk/ai/azure-ai-projects/CHANGELOG.md @@ -20,9 +20,7 @@ * New optional `force` parameter on `agents.delete` and `agents.delete_version` methods. * New optional `blueprint_reference` parameters on `agents.create_version` method. * New sample `sample_dataset_generation_job_with_evaluation.py` showing an end-to-end flow that generates a QnA dataset via `.beta.datasets.create_generation_job` and runs an OpenAI evaluation. - -* New `.beta.models` sub-client for registering and managing local model weights as Foundry `ModelVersion` resources. Generated operations: `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `create_async`, `get_credentials`. -* New convenience method `.beta.models.models_create()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `create_async`) and polls `get()` until the new `ModelVersion` is observable. +* New convenience method `.beta.models.create_version()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `pending_create_version`) and polls `get()` until the new `ModelVersion` is observable. ### Breaking Changes @@ -55,9 +53,9 @@ Breaking changes in beta classes: * Updated the other Hosted Agent samples to reuse an existing Hosted Agent as a prerequisite, instead of creating a new hosted agent version in each sample. * Added Toolbox tool-search sample `sample_toolboxes_with_search_preview.py` and `sample_toolboxes_with_search_preview_async.py`, demonstrating creating a Toolbox version with `ToolboxSearchPreviewTool` and invoking `MCPTool`. * Added `.beta.models` samples under `samples/models/`: - * `sample_models.py` — synchronous end-to-end registration via the `models_create` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. - * `sample_models_without_patch.py` — alternative synchronous registration that hand-rolls the spec's three-step flow (`pending_upload` → upload via `azure-storage-blob` → `create_async` + poll), without taking a dependency on `azcopy`. - * `sample_models_async.py` — asynchronous version of the same three-step flow using `azure.ai.projects.aio.AIProjectClient` and `azure.storage.blob.aio.ContainerClient`. + * `sample_models_basic.py` — synchronous end-to-end registration via the `create_version` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + * `sample_models_without_patch.py` — alternative synchronous registration that hand-rolls the spec's three-step flow (`pending_upload` → upload via `azure-storage-blob` → `pending_create_version` + poll), without taking a dependency on `azcopy`. + * `sample_models_basic_async.py` — asynchronous version of the same three-step flow using `azure.ai.projects.aio.AIProjectClient` and `azure.storage.blob.aio.ContainerClient`. ## 2.1.0 (2026-04-20) diff --git a/sdk/ai/azure-ai-projects/README.md b/sdk/ai/azure-ai-projects/README.md index 1b9eda4d9ac0..ad53682d7be0 100644 --- a/sdk/ai/azure-ai-projects/README.md +++ b/sdk/ai/azure-ai-projects/README.md @@ -35,7 +35,7 @@ resources in your Microsoft Foundry Project. Use it to: * **Enumerate AI Models** deployed to your Foundry Project using `.deployments` operations. * **Enumerate connected Azure resources** in your Foundry project using `.connections` operations. * **Upload documents and create Datasets** to reference them using `.datasets` operations. -* **Register and manage local model weights** as Foundry `ModelVersion` resources using `.beta.models` operations, including the `models_create` end-to-end helper. +* **Register and manage local model weights** as Foundry `ModelVersion` resources using `.beta.models` operations, including the `create_version` end-to-end helper. * **Create and enumerate Search Indexes** using `.indexes` operations. The client library uses version `v1` of the Microsoft Foundry [data plane REST APIs](https://aka.ms/azsdk/azure-ai-projects-v2/api-reference-v1). @@ -167,7 +167,7 @@ Full descriptions and working code for all of the above are available in: | Deployments | [Deployment types](https://learn.microsoft.com/azure/foundry/foundry-models/concepts/deployment-types) | `samples/deployments/` | | Connections | [Connections operations](https://learn.microsoft.com/python/api/overview/azure/ai-projects-readme?view=azure-python#connections-operations) | `samples/connections/` | | Datasets | [Dataset operations](https://learn.microsoft.com/python/api/overview/azure/ai-projects-readme?view=azure-python#dataset-operations) | `samples/datasets/` | -| Models (preview) | Register local model weights as Foundry `ModelVersion` resources via `.beta.models` (`models_create`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `create_async`, `get_credentials`). | `samples/models/` | +| Models (preview) | Register local model weights as Foundry `ModelVersion` resources via `.beta.models` (`create_version`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `pending_create_version`, `get_credentials`). | `samples/models/` | | Indexes | [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) | `samples/indexes/` | | Files (upload, retrieve, list, delete) | [OpenAI Files API](https://platform.openai.com/docs/api-reference/files) | `samples/files/` | | Fine-tuning | [Fine-Tuning in AI Foundry](https://github.com/microsoft-foundry/fine-tuning) | `samples/finetuning/` | diff --git a/sdk/ai/azure-ai-projects/apiview-properties.json b/sdk/ai/azure-ai-projects/apiview-properties.json index 7c1bdca261e5..7e6e38b214d3 100644 --- a/sdk/ai/azure-ai-projects/apiview-properties.json +++ b/sdk/ai/azure-ai-projects/apiview-properties.json @@ -10,10 +10,14 @@ "azure.ai.projects.models.AgentClusterInsightRequest": "Azure.AI.Projects.AgentClusterInsightRequest", "azure.ai.projects.models.InsightResult": "Azure.AI.Projects.InsightResult", "azure.ai.projects.models.AgentClusterInsightResult": "Azure.AI.Projects.AgentClusterInsightResult", + "azure.ai.projects.models.DataGenerationJobSource": "Azure.AI.Projects.DataGenerationJobSource", + "azure.ai.projects.models.AgentDataGenerationJobSource": "Azure.AI.Projects.AgentDataGenerationJobSource", "azure.ai.projects.models.AgentDefinition": "Azure.AI.Projects.AgentDefinition", "azure.ai.projects.models.AgentDetails": "Azure.AI.Projects.AgentObject", "azure.ai.projects.models.AgentEndpointAuthorizationScheme": "Azure.AI.Projects.AgentEndpointAuthorizationScheme", "azure.ai.projects.models.AgentEndpointConfig": "Azure.AI.Projects.AgentEndpointConfig", + "azure.ai.projects.models.EvaluatorGenerationJobSource": "Azure.AI.Projects.EvaluatorGenerationJobSource", + "azure.ai.projects.models.AgentEvaluatorGenerationJobSource": "Azure.AI.Projects.AgentEvaluatorGenerationJobSource", "azure.ai.projects.models.BaseCredentials": "Azure.AI.Projects.BaseCredentials", "azure.ai.projects.models.AgenticIdentityPreviewCredentials": "Azure.AI.Projects.AgenticIdentityPreviewCredentials", "azure.ai.projects.models.AgentIdentity": "Azure.AI.Projects.AgentIdentity", @@ -142,11 +146,6 @@ "azure.ai.projects.models.EvaluationRunClusterInsightResult": "Azure.AI.Projects.EvaluationRunClusterInsightResult", "azure.ai.projects.models.ScheduleTask": "Azure.AI.Projects.ScheduleTask", "azure.ai.projects.models.EvaluationScheduleTask": "Azure.AI.Projects.EvaluationScheduleTask", - "azure.ai.projects.models.EvaluationSuiteRunRequest": "Azure.AI.Projects.EvaluationSuiteRunRequest", - "azure.ai.projects.models.EvaluationSuiteRunResponse": "Azure.AI.Projects.EvaluationSuiteRunResponse", - "azure.ai.projects.models.EvaluationSuiteRunResult": "Azure.AI.Projects.EvaluationSuiteRunResult", - "azure.ai.projects.models.EvaluationSuiteVersion": "Azure.AI.Projects.EvaluationSuiteVersion", - "azure.ai.projects.models.EvaluationSuiteVersionInputMessagesTemplate1": "Azure.AI.Projects.EvaluationSuiteVersion.input_messages.template.anonymous", "azure.ai.projects.models.EvaluationTaxonomy": "Azure.AI.Projects.EvaluationTaxonomy", "azure.ai.projects.models.EvaluatorCredentialRequest": "Azure.AI.Projects.EvaluatorCredentialRequest", "azure.ai.projects.models.EvaluatorGenerationArtifacts": "Azure.AI.Projects.EvaluatorGenerationArtifacts", @@ -159,6 +158,8 @@ "azure.ai.projects.models.FabricDataAgentToolParameters": "Azure.AI.Projects.FabricDataAgentToolParameters", "azure.ai.projects.models.FabricIQPreviewTool": "Azure.AI.Projects.FabricIQPreviewTool", "azure.ai.projects.models.FieldMapping": "Azure.AI.Projects.FieldMapping", + "azure.ai.projects.models.FileDataGenerationJobOutput": "Azure.AI.Projects.FileDataGenerationJobOutput", + "azure.ai.projects.models.FileDataGenerationJobSource": "Azure.AI.Projects.FileDataGenerationJobSource", "azure.ai.projects.models.FileDatasetVersion": "Azure.AI.Projects.FileDatasetVersion", "azure.ai.projects.models.FileSearchTool": "OpenAI.FileSearchTool", "azure.ai.projects.models.VersionSelectionRule": "Azure.AI.Projects.VersionSelectionRule", @@ -182,8 +183,6 @@ "azure.ai.projects.models.ImageGenToolInputImageMask": "OpenAI.ImageGenToolInputImageMask", "azure.ai.projects.models.InlineSkillParam": "OpenAI.InlineSkillParam", "azure.ai.projects.models.InlineSkillSourceParam": "OpenAI.InlineSkillSourceParam", - "azure.ai.projects.models.InputAudio": "OpenAI.InputAudio", - "azure.ai.projects.models.InputAudioInputAudio": "OpenAI.InputAudioInputAudio", "azure.ai.projects.models.Insight": "Azure.AI.Projects.Insight", "azure.ai.projects.models.InsightCluster": "Azure.AI.Projects.InsightCluster", "azure.ai.projects.models.InsightModelConfiguration": "Azure.AI.Projects.InsightModelConfiguration", @@ -255,6 +254,8 @@ "azure.ai.projects.models.PromptAgentDefinition": "Azure.AI.Projects.PromptAgentDefinition", "azure.ai.projects.models.PromptAgentDefinitionTextOptions": "Azure.AI.Projects.PromptAgentDefinitionTextOptions", "azure.ai.projects.models.PromptBasedEvaluatorDefinition": "Azure.AI.Projects.PromptBasedEvaluatorDefinition", + "azure.ai.projects.models.PromptDataGenerationJobSource": "Azure.AI.Projects.PromptDataGenerationJobSource", + "azure.ai.projects.models.PromptEvaluatorGenerationJobSource": "Azure.AI.Projects.PromptEvaluatorGenerationJobSource", "azure.ai.projects.models.ProtocolVersionRecord": "Azure.AI.Projects.ProtocolVersionRecord", "azure.ai.projects.models.RaiConfig": "Azure.AI.Projects.RaiConfig", "azure.ai.projects.models.RankingOptions": "OpenAI.RankingOptions", @@ -277,6 +278,7 @@ "azure.ai.projects.models.SessionLogEvent": "Azure.AI.Projects.SessionLogEvent", "azure.ai.projects.models.SharepointGroundingToolParameters": "Azure.AI.Projects.SharepointGroundingToolParameters", "azure.ai.projects.models.SharepointPreviewTool": "Azure.AI.Projects.SharepointPreviewTool", + "azure.ai.projects.models.SimpleQnADataGenerationJobOptions": "Azure.AI.Projects.SimpleQnADataGenerationJobOptions", "azure.ai.projects.models.SkillDetails": "Azure.AI.Projects.SkillObject", "azure.ai.projects.models.SkillReferenceParam": "OpenAI.SkillReferenceParam", "azure.ai.projects.models.ToolChoiceParam": "OpenAI.ToolChoiceParam", @@ -288,7 +290,6 @@ "azure.ai.projects.models.TaxonomyCategory": "Azure.AI.Projects.TaxonomyCategory", "azure.ai.projects.models.TaxonomySubCategory": "Azure.AI.Projects.TaxonomySubCategory", "azure.ai.projects.models.TelemetryConfig": "Azure.AI.Projects.TelemetryConfig", - "azure.ai.projects.models.TestingCriterionAzureAIEvaluator": "Azure.AI.Projects.TestingCriterionAzureAIEvaluator", "azure.ai.projects.models.TextResponseFormat": "OpenAI.TextResponseFormatConfiguration", "azure.ai.projects.models.TextResponseFormatJsonObject": "OpenAI.TextResponseFormatConfigurationResponseFormatJsonObject", "azure.ai.projects.models.TextResponseFormatJsonSchema": "OpenAI.TextResponseFormatJsonSchema", @@ -400,6 +401,11 @@ "azure.ai.projects.models.RecurrenceType": "Azure.AI.Projects.RecurrenceType", "azure.ai.projects.models.DayOfWeek": "Azure.AI.Projects.DayOfWeek", "azure.ai.projects.models.ScheduleTaskType": "Azure.AI.Projects.ScheduleTaskType", + "azure.ai.projects.models.DataGenerationJobSourceType": "Azure.AI.Projects.DataGenerationJobSourceType", + "azure.ai.projects.models.DataGenerationJobType": "Azure.AI.Projects.DataGenerationJobType", + "azure.ai.projects.models.SimpleQnAFineTuningQuestionType": "Azure.AI.Projects.SimpleQnAFineTuningQuestionType", + "azure.ai.projects.models.DataGenerationJobScenario": "Azure.AI.Projects.DataGenerationJobScenario", + "azure.ai.projects.models.DataGenerationJobOutputType": "Azure.AI.Projects.DataGenerationJobOutputType", "azure.ai.projects.models.EvaluationRuleActionType": "Azure.AI.Projects.EvaluationRuleActionType", "azure.ai.projects.models.EvaluationRuleEventType": "Azure.AI.Projects.EvaluationRuleEventType", "azure.ai.projects.models.ConnectionType": "Azure.AI.Projects.ConnectionType", @@ -407,10 +413,6 @@ "azure.ai.projects.models.DatasetType": "Azure.AI.Projects.DatasetType", "azure.ai.projects.models.DeploymentType": "Azure.AI.Projects.DeploymentType", "azure.ai.projects.models.IndexType": "Azure.AI.Projects.IndexType", - "azure.ai.projects.models.EvaluationSuiteSubtype": "Azure.AI.Projects.EvaluationSuiteSubtype", - "azure.ai.projects.models.EvalItemContentItemObjectType": "OpenAI.EvalItemContentItemObjectType", - "azure.ai.projects.models.EvaluationLevel": "Azure.AI.Projects.EvaluationLevel", - "azure.ai.projects.models.JobStatus": "Azure.AI.Projects.JobStatus", "azure.ai.projects.models.MemoryStoreUpdateStatus": "Azure.AI.Projects.MemoryStoreUpdateStatus", "azure.ai.projects.operations.AgentsOperations.get": "Azure.AI.Projects.Agents.getAgent", "azure.ai.projects.aio.operations.AgentsOperations.get": "Azure.AI.Projects.Agents.getAgent", @@ -465,20 +467,6 @@ "azure.ai.projects.operations.IndexesOperations.delete": "Azure.AI.Projects.Indexes.deleteVersion", "azure.ai.projects.aio.operations.IndexesOperations.delete": "Azure.AI.Projects.Indexes.deleteVersion", "azure.ai.projects.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion", - "azure.ai.projects.aio.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion", - "azure.ai.projects.operations.EvaluationSuitesOperations.list_versions": "Azure.AI.Projects.EvaluationSuites.listVersions", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.list_versions": "Azure.AI.Projects.EvaluationSuites.listVersions", - "azure.ai.projects.operations.EvaluationSuitesOperations.list_latest": "Azure.AI.Projects.EvaluationSuites.listLatest", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.list_latest": "Azure.AI.Projects.EvaluationSuites.listLatest", - "azure.ai.projects.operations.EvaluationSuitesOperations.get_version": "Azure.AI.Projects.EvaluationSuites.getVersion", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.get_version": "Azure.AI.Projects.EvaluationSuites.getVersion", - "azure.ai.projects.operations.EvaluationSuitesOperations.delete_version": "Azure.AI.Projects.EvaluationSuites.deleteVersion", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.delete_version": "Azure.AI.Projects.EvaluationSuites.deleteVersion", - "azure.ai.projects.operations.EvaluationSuitesOperations.create_or_update_version": "Azure.AI.Projects.EvaluationSuites.createOrUpdateVersion", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.create_or_update_version": "Azure.AI.Projects.EvaluationSuites.createOrUpdateVersion", - "azure.ai.projects.operations.EvaluationSuitesOperations.create_evaluation_suite_version": "Azure.AI.Projects.EvaluationSuites.createEvaluationSuiteVersion", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.create_evaluation_suite_version": "Azure.AI.Projects.EvaluationSuites.createEvaluationSuiteVersion", - "azure.ai.projects.operations.EvaluationSuitesOperations.run": "Azure.AI.Projects.EvaluationSuites.run", - "azure.ai.projects.aio.operations.EvaluationSuitesOperations.run": "Azure.AI.Projects.EvaluationSuites.run" + "azure.ai.projects.aio.operations.IndexesOperations.create_or_update": "Azure.AI.Projects.Indexes.createOrUpdateVersion" } } \ No newline at end of file diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index c9b8cfff7731..b54ed57c6a80 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py @@ -15,6 +15,7 @@ from ._patch_telemetry_async import TelemetryOperations from ._patch_connections_async import ConnectionsOperations from ._patch_memories_async import BetaMemoryStoresOperations +from ._patch_models_async import BetaModelsOperations from ._patch_sessions_async import BetaAgentsOperations from ...operations._patch import _BETA_OPERATION_FEATURE_HEADERS, _OperationMethodHeaderProxy from ._operations import ( @@ -22,7 +23,6 @@ BetaEvaluationTaxonomiesOperations, BetaEvaluatorsOperations, BetaInsightsOperations, - BetaModelsOperations, BetaOperations as GeneratedBetaOperations, BetaRedTeamsOperations, BetaRoutinesOperations, @@ -75,6 +75,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) # Replace with patched class that includes begin_update_memories self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) + # Replace with patched class that includes create_version (3-step upload helper) + self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) for property_name, foundry_features_value in _BETA_OPERATION_FEATURE_HEADERS.items(): setattr( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py new file mode 100644 index 000000000000..720df949d6ea --- /dev/null +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py @@ -0,0 +1,271 @@ +# pylint: disable=line-too-long,useless-suppression +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" + +import asyncio +import logging +import os +from pathlib import Path +from typing import Any, Optional, Union + +from azure.core.exceptions import ResourceNotFoundError +from azure.core.tracing.decorator_async import distributed_trace_async + +from ._operations import BetaModelsOperations as BetaModelsOperationsGenerated +from ...models._models import ( + ModelPendingUploadRequest, + ModelPendingUploadResponse, + ModelVersion, + PendingUploadType, +) + +logger = logging.getLogger(__name__) + + +class BetaModelsOperations(BetaModelsOperationsGenerated): + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.ai.projects.aio.AIProjectClient`'s + :attr:`beta.models ` attribute. + """ + + @staticmethod + def _extract_pending_upload_targets( + response: Union[ModelPendingUploadResponse, dict], + ) -> "tuple[str, str, Optional[str]]": + """Return ``(sas_uri, container_blob_uri, pending_upload_id)`` from a pending-upload response. + + The service currently returns the raw datastore-style payload + (``blobReferenceForConsumption`` / ``temporaryDataReferenceId``) for some + Foundry deployments rather than the SDK-modeled ``ModelPendingUploadResponse`` + shape (``blobReference`` / ``pendingUploadId``). Tolerate both wire + shapes so callers don't have to. + """ + payload = response.as_dict() if hasattr(response, "as_dict") else dict(response) + + blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} + sas_uri = (blob_ref.get("credential") or {}).get("sasUri") + container_blob_uri = blob_ref.get("blobUri") + pending_upload_id = payload.get("temporaryDataReferenceId") or payload.get("pendingUploadId") + + if not sas_uri or not container_blob_uri: + raise ValueError("Could not locate SAS URI / blob URI in pending_upload response: " f"{payload!r}") + return sas_uri, container_blob_uri, pending_upload_id + + @staticmethod + def _validate_create_version_inputs( + *, + name: str, + version: str, + source: Union[str, "os.PathLike[str]"], + wait_for_commit: bool, + polling_timeout: float, + polling_interval: float, + ) -> Path: + """Validate ``create_version`` inputs up-front, before any service call. + + Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for + bad inputs. + """ + if not isinstance(name, str) or not name.strip(): + raise ValueError("`name` must be a non-empty string.") + if not isinstance(version, str) or not version.strip(): + raise ValueError("`version` must be a non-empty string.") + + source_path = Path(os.fspath(source)) + if not source_path.exists(): + raise ValueError(f"Upload source does not exist: {source_path}") + if source_path.is_dir() and not any(p.is_file() for p in source_path.rglob("*")): + raise ValueError(f"Upload source directory is empty: {source_path}") + if source_path.is_file() and source_path.stat().st_size == 0: + raise ValueError(f"Upload source file is empty: {source_path}") + + if wait_for_commit: + if polling_timeout <= 0: + raise ValueError("`polling_timeout` must be > 0 when `wait_for_commit` is True.") + if polling_interval <= 0: + raise ValueError("`polling_interval` must be > 0 when `wait_for_commit` is True.") + + return source_path + + @staticmethod + async def _upload_with_container_client(source: Path, sas_uri: str) -> None: + """Upload ``source`` to the SAS container using ``azure.storage.blob.aio.ContainerClient``. + + :raises RuntimeError: If ``azure-storage-blob`` is not installed. + """ + try: + from azure.storage.blob.aio import ContainerClient # pylint: disable=import-outside-toplevel + except ImportError as ex: + raise RuntimeError( + "`azure-storage-blob` is required for the async `create_version` helper. " + "Install it with `pip install azure-storage-blob aiohttp`." + ) from ex + + if source.is_dir(): + files = [p for p in source.rglob("*") if p.is_file()] + if not files: + raise ValueError(f"Upload source directory is empty: {source}") + elif source.is_file(): + files = [source] + else: + raise ValueError(f"Upload source does not exist: {source}") + + # Don't log the SAS query string — it's a credential. + redacted = sas_uri.split("?", 1)[0] + "?" + logger.info("[create_version] uploading %d file(s) to %s", len(files), redacted) + + async with ContainerClient.from_container_url(sas_uri) as container_client: + for f in files: + rel = f.relative_to(source).as_posix() if source.is_dir() else f.name + with f.open("rb") as fp: + await container_client.upload_blob(name=rel, data=fp, overwrite=True) + logger.debug("[create_version] uploaded %s (%d bytes)", rel, f.stat().st_size) + + @distributed_trace_async + async def create_version( + self, + *, + name: str, + version: str, + source: Union[str, "os.PathLike[str]"], + weight_type: Optional[str] = None, + base_model: Optional[str] = None, + description: Optional[str] = None, + tags: Optional["dict[str, str]"] = None, + wait_for_commit: bool = True, + polling_timeout: float = 300.0, + polling_interval: float = 2.0, + **kwargs: Any, + ) -> Optional[ModelVersion]: + """Register a local model by running the full upload-first sequence (async). + + This wraps the three mandatory steps of the model-registration spec + into a single call: + + 1. :meth:`pending_upload` — provision a project-managed blob container + and obtain a SAS URI. + 2. Upload the local weight files to the SAS container using + :class:`azure.storage.blob.aio.ContainerClient`. + 3. :meth:`pending_create_version` — finalize registration with the + ``ModelVersion`` body (``blob_uri``, ``weight_type``, ``base_model``, + ``description``, ``tags``). + + Requires the ``azure-storage-blob`` package (with ``aiohttp``) for the + upload step. + + :keyword name: Name of the model to register. Required. + :paramtype name: str + :keyword version: Version identifier for the model. Required. + :paramtype version: str + :keyword source: Local file or directory containing the model weights. + If a directory, its contents are uploaded recursively to the SAS + container root. Required. + :paramtype source: str or os.PathLike[str] + :keyword weight_type: Optional weight type (e.g. ``"FullWeight"``, + ``"LoRA"``, ``"DraftModel"``). + :paramtype weight_type: str + :keyword base_model: Optional base model asset ID. + :paramtype base_model: str + :keyword description: Optional asset description. + :paramtype description: str + :keyword tags: Optional asset tags. + :paramtype tags: dict[str, str] + :keyword wait_for_commit: When True (default) poll :meth:`get` until + the committed ``ModelVersion`` is observable, and return it. + When False, return ``None`` after the async commit is accepted. + :paramtype wait_for_commit: bool + :keyword polling_timeout: Total seconds to poll for commit completion. + :paramtype polling_timeout: float + :keyword polling_interval: Seconds between poll attempts. + :paramtype polling_interval: float + :return: The committed :class:`~azure.ai.projects.models.ModelVersion` + when ``wait_for_commit`` is True, otherwise ``None``. + :rtype: ~azure.ai.projects.models.ModelVersion or None + :raises ValueError: If ``name``/``version`` are empty, ``source`` does + not exist or is empty, polling parameters are non-positive, or the + pending-upload response is missing the SAS / blob URI. + :raises RuntimeError: If ``azure-storage-blob`` is not installed or + the registration does not commit before ``polling_timeout`` elapses. + """ + # --- Step 0: validate inputs up-front -------------------------------- + source_path = self._validate_create_version_inputs( + name=name, + version=version, + source=source, + wait_for_commit=wait_for_commit, + polling_timeout=polling_timeout, + polling_interval=polling_interval, + ) + + # --- Step 1: StartPendingUpload -------------------------------------- + logger.info( + "[create_version] step 1/3 pending_upload(name=%r, version=%r)", + name, + version, + ) + pending = await self.pending_upload( + name=name, + version=version, + body=ModelPendingUploadRequest( + pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, + ), + **kwargs, + ) + sas_uri, container_blob_uri, pending_upload_id = self._extract_pending_upload_targets(pending) + logger.info( + "[create_version] pending_upload_id=%s blob_uri=%s", + pending_upload_id, + container_blob_uri, + ) + + # --- Step 2: Upload via async ContainerClient ------------------------ + logger.info("[create_version] step 2/3 async upload from %s", source_path) + await self._upload_with_container_client(source_path, sas_uri) + + # --- Step 3: Commit registration ------------------------------------- + body = ModelVersion( + blob_uri=container_blob_uri, + weight_type=weight_type, + base_model=base_model, + description=description, + tags=tags or {}, + ) + logger.info( + "[create_version] step 3/3 pending_create_version(name=%r, version=%r)", + name, + version, + ) + await self.pending_create_version(name=name, version=version, body=body, **kwargs) + + if not wait_for_commit: + return None + + # The async op returns 202; the service materializes the ModelVersion + # asynchronously. Poll get() until it appears or we time out. + import time # pylint: disable=import-outside-toplevel + + deadline = time.monotonic() + polling_timeout + last_exc: Optional[BaseException] = None + while True: + try: + return await self.get(name=name, version=version, **kwargs) + except ResourceNotFoundError as ex: + last_exc = ex + if time.monotonic() >= deadline: + raise RuntimeError( + f"Model {name!r}@{version!r} did not appear within " f"{polling_timeout}s after pending_create_version." + ) from last_exc + await asyncio.sleep(polling_interval) + + +__all__ = ["BetaModelsOperations"] diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index 276c9fd5d2d7..60fe8f466752 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -130,7 +130,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) # Replace with patched class that includes begin_update_memories self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) - # Replace with patched class that includes models_create (3-step upload helper) + # Replace with patched class that includes create_version (3-step upload helper) self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) for property_name, foundry_features_value in _BETA_OPERATION_FEATURE_HEADERS.items(): diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py index 5d8971693fe5..dd094177fe8e 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -76,7 +76,7 @@ def _resolve_azcopy(azcopy_path: Optional[str] = None) -> str: return azcopy @staticmethod - def _validate_models_create_inputs( + def _validate_create_version_inputs( *, name: str, version: str, @@ -86,7 +86,7 @@ def _validate_models_create_inputs( polling_timeout: float, polling_interval: float, ) -> Path: - """Validate ``models_create`` inputs up-front, before any service call. + """Validate ``create_version`` inputs up-front, before any service call. Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for bad inputs and ``RuntimeError`` if ``azcopy`` cannot be located. @@ -139,13 +139,13 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None # Don't log the SAS query string — it's a credential. redacted = cmd.copy() redacted[3] = sas_uri.split("?", 1)[0] + "?" - logger.info("[models_create] running: %s", " ".join(redacted)) + logger.info("[create_version] running: %s", " ".join(redacted)) completed = subprocess.run(cmd, check=False, capture_output=True, text=True) if completed.stdout: - logger.debug("[models_create] azcopy stdout:\n%s", completed.stdout) + logger.debug("[create_version] azcopy stdout:\n%s", completed.stdout) if completed.stderr: - logger.debug("[models_create] azcopy stderr:\n%s", completed.stderr) + logger.debug("[create_version] azcopy stderr:\n%s", completed.stderr) if completed.returncode != 0: raise RuntimeError( f"azcopy exited with code {completed.returncode}.\n" @@ -153,7 +153,7 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None ) @distributed_trace - def models_create( + def create_version( self, *, name: str, @@ -178,7 +178,7 @@ def models_create( and obtain a SAS URI. 2. ``azcopy copy`` — upload the local weight files directly to the SAS container. - 3. :meth:`create_async` — finalize registration with the + 3. :meth:`pending_create_version` — finalize registration with the ``ModelVersion`` body (``blob_uri``, ``weight_type``, ``base_model``, ``description``, ``tags``). @@ -223,7 +223,7 @@ def models_create( # --- Step 0: validate inputs up-front -------------------------------- # Cheap local checks so we don't provision a SAS container or run # azcopy when something obviously wrong was passed in. - source_path = self._validate_models_create_inputs( + source_path = self._validate_create_version_inputs( name=name, version=version, source=source, @@ -235,7 +235,7 @@ def models_create( # --- Step 1: StartPendingUpload -------------------------------------- logger.info( - "[models_create] step 1/3 pending_upload(name=%r, version=%r)", + "[create_version] step 1/3 pending_upload(name=%r, version=%r)", name, version, ) @@ -249,13 +249,13 @@ def models_create( ) sas_uri, container_blob_uri, pending_upload_id = self._extract_pending_upload_targets(pending) logger.info( - "[models_create] pending_upload_id=%s blob_uri=%s", + "[create_version] pending_upload_id=%s blob_uri=%s", pending_upload_id, container_blob_uri, ) # --- Step 2: Upload via azcopy --------------------------------------- - logger.info("[models_create] step 2/3 azcopy upload from %s", source_path) + logger.info("[create_version] step 2/3 azcopy upload from %s", source_path) self._run_azcopy(source_path, sas_uri, azcopy_path=azcopy_path) # --- Step 3: Commit registration ------------------------------------- @@ -267,11 +267,11 @@ def models_create( tags=tags or {}, ) logger.info( - "[models_create] step 3/3 create_async(name=%r, version=%r)", + "[create_version] step 3/3 pending_create_version(name=%r, version=%r)", name, version, ) - self.create_async(name=name, version=version, body=body, **kwargs) + self.pending_create_version(name=name, version=version, body=body, **kwargs) if not wait_for_commit: return None @@ -287,7 +287,7 @@ def models_create( last_exc = ex if time.monotonic() >= deadline: raise RuntimeError( - f"Model {name!r}@{version!r} did not appear within " f"{polling_timeout}s after create_async." + f"Model {name!r}@{version!r} did not appear within " f"{polling_timeout}s after pending_create_version." ) from last_exc time.sleep(polling_interval) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py similarity index 77% rename from sdk/ai/azure-ai-projects/samples/models/sample_models.py rename to sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py index 75c9f7712042..9129c84273c7 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py @@ -12,18 +12,18 @@ update version metadata, and delete a model version. The recommended entry point is the patched helper - `project_client.beta.models.models_create(...)`, which packs the spec's - three required steps (`pending_upload` -> `azcopy copy` -> `create_async`) + `project_client.beta.models.create_version(...)`, which packs the spec's + three required steps (`pending_upload` -> `azcopy copy` -> `pending_create_version`) into a single call and polls until the new ModelVersion is observable. USAGE: - python sample_models.py + python sample_models_basic.py Before running the sample: pip install "azure-ai-projects>=2.2.0" azure-identity python-dotenv - AzCopy must also be installed and on PATH (used by `models_create` to + AzCopy must also be installed and on PATH (used by `create_version` to upload weight files): winget install --id Microsoft.Azure.AZCopy.10 -e @@ -76,21 +76,26 @@ print( f"Register a local model named `{model_name}` version `{model_version}` " - f"by uploading the contents of `{data_folder}` via `models_create`." + f"by uploading the contents of `{data_folder}` via `create_version`." ) - model = project_client.beta.models.models_create( + model = project_client.beta.models.create_version( name=model_name, version=model_version, source=data_folder, weight_type=FoundryModelWeightType.FULL_WEIGHT, - description="Sample model registered from sample_models.py", - tags={"source": "sample_models.py"}, + description="Sample model registered from sample_models_basic.py", + tags={"source": "sample_models_basic.py"}, ) - print(model) + if model is None: + raise RuntimeError( + f"`create_version` returned None for `{model_name}`@`{model_version}` " + "(use `wait_for_commit=True` to receive the committed ModelVersion)." + ) + print(f"Created (name: {model.name}, version: {model.version}, blob_uri: {model.blob_uri})") print(f"Get a specific model version `{model_name}`@`{model_version}`:") fetched = project_client.beta.models.get(name=model_name, version=model_version) - print(fetched) + print(f"Fetched (name: {fetched.name}, version: {fetched.version}, blob_uri: {fetched.blob_uri})") print(f"List all versions of model `{model_name}`:") for mv in project_client.beta.models.list_versions(name=model_name): @@ -106,7 +111,7 @@ version=model_version, body=ModelCredentialRequest(blob_uri=model.blob_uri), ) - print(creds) + print(f"Credentials (type: {type(creds).__name__})") print(f"Update description and tags on `{model_name}`@`{model_version}`:") updated = project_client.beta.models.update( @@ -114,10 +119,10 @@ version=model_version, body=UpdateModelVersionRequest( description="Updated description", - tags={"source": "sample_models.py", "updated": "true"}, + tags={"source": "sample_models_basic.py", "updated": "true"}, ), ) - print(updated) + print(f"Updated (name: {updated.name}, version: {updated.version}, description: {updated.description})") print(f"Delete the model version created above (`{model_name}`@`{model_version}`):") project_client.beta.models.delete(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py similarity index 86% rename from sdk/ai/azure-ai-projects/samples/models/sample_models_async.py rename to sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py index c66e0eb740f0..a6f5d1fa61de 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_async.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py @@ -8,10 +8,10 @@ DESCRIPTION: Given an asynchronous AIProjectClient, this sample demonstrates how to register a local model with a Microsoft Foundry project and exercise the - asynchronous `.beta.models` operations: `pending_upload`, `create_async`, + asynchronous `.beta.models` operations: `pending_upload`, `pending_create_version`, `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. - The async client does not expose the `models_create` convenience helper + The async client does not expose the `create_version` convenience helper (which shells out to the synchronous `azcopy` CLI). This sample instead drives the spec's three-step upload-first sequence directly: @@ -19,12 +19,12 @@ blob container and returns a SAS URI. 2) Upload the local weight files to that SAS container using `azure.storage.blob.aio.ContainerClient`. - 3) `create_async(...)` -- commit the registration. The service returns + 3) `pending_create_version(...)` -- commit the registration. The service returns 202 Accepted and finalizes the ModelVersion asynchronously, so we poll `get(...)` until the new version is observable. USAGE: - python sample_models_async.py + python sample_models_basic_async.py Before running the sample: @@ -113,19 +113,19 @@ async def main() -> None: await container_client.upload_blob(name=rel, data=fp, overwrite=True) print(f" uploaded {rel} ({f.stat().st_size} bytes)") - print(f"Step 3/3: create_async(name=`{model_name}`, version=`{model_version}`)") - await project_client.beta.models.create_async( + print(f"Step 3/3: pending_create_version(name=`{model_name}`, version=`{model_version}`)") + await project_client.beta.models.pending_create_version( name=model_name, version=model_version, body=ModelVersion( blob_uri=container_blob_uri, weight_type=FoundryModelWeightType.FULL_WEIGHT, - description="Sample model registered from sample_models_async.py", - tags={"source": "sample_models_async.py"}, + description="Sample model registered from sample_models_basic_async.py", + tags={"source": "sample_models_basic_async.py"}, ), ) - # `create_async` returns 202 Accepted; poll `get` until the committed + # `pending_create_version` returns 202 Accepted; poll `get` until the committed # ModelVersion is observable. print(f"Polling get(`{model_name}`, `{model_version}`) until the ModelVersion is committed...") deadline = time.monotonic() + 300.0 @@ -137,10 +137,10 @@ async def main() -> None: except ResourceNotFoundError: if time.monotonic() >= deadline: raise RuntimeError( - f"Model `{model_name}`@`{model_version}` did not appear within 300s after create_async." + f"Model `{model_name}`@`{model_version}` did not appear within 300s after pending_create_version." ) await asyncio.sleep(2.0) - print(model) + print(f"Created (name: {model.name}, version: {model.version}, blob_uri: {model.blob_uri})") print(f"List all versions of model `{model_name}`:") async for mv in project_client.beta.models.list_versions(name=model_name): @@ -156,7 +156,7 @@ async def main() -> None: version=model_version, body=ModelCredentialRequest(blob_uri=model.blob_uri), ) - print(creds) + print(f"Credentials (type: {type(creds).__name__})") print(f"Update description and tags on `{model_name}`@`{model_version}`:") updated = await project_client.beta.models.update( @@ -164,10 +164,10 @@ async def main() -> None: version=model_version, body=UpdateModelVersionRequest( description="Updated description", - tags={"source": "sample_models_async.py", "updated": "true"}, + tags={"source": "sample_models_basic_async.py", "updated": "true"}, ), ) - print(updated) + print(f"Updated (name: {updated.name}, version: {updated.version}, description: {updated.description})") print(f"Delete the model version created above (`{model_name}`@`{model_version}`):") await project_client.beta.models.delete(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py index ba65999cbfcc..4a05cf2cd51c 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py @@ -8,7 +8,7 @@ DESCRIPTION: Given an AIProjectClient, this sample demonstrates how to register a local model with a Microsoft Foundry project WITHOUT relying on the - `models_create` helper or the `azcopy` CLI. It hand-rolls the spec's + `create_version` helper or the `azcopy` CLI. It hand-rolls the spec's three-step upload-first sequence using only the generated `.beta.models` operations and `azure-storage-blob`: @@ -16,7 +16,7 @@ blob container and returns a SAS URI. 2) Upload the local weight files directly to that SAS container using `azure.storage.blob.ContainerClient`. - 3) `create_async(...)` -- commit the registration. The service returns + 3) `pending_create_version(...)` -- commit the registration. The service returns 202 Accepted and finalizes the ModelVersion asynchronously, so we poll `get(...)` until the new version is observable. @@ -108,8 +108,8 @@ container_client.upload_blob(name=rel, data=fp, overwrite=True) print(f" uploaded {rel} ({f.stat().st_size} bytes)") - print(f"Step 3/3: create_async(name=`{model_name}`, version=`{model_version}`)") - project_client.beta.models.create_async( + print(f"Step 3/3: pending_create_version(name=`{model_name}`, version=`{model_version}`)") + project_client.beta.models.pending_create_version( name=model_name, version=model_version, body=ModelVersion( @@ -120,7 +120,7 @@ ), ) - # `create_async` returns 202 Accepted; poll `get` until the committed + # `pending_create_version` returns 202 Accepted; poll `get` until the committed # ModelVersion is observable. print(f"Polling get(`{model_name}`, `{model_version}`) until the ModelVersion is committed...") deadline = time.monotonic() + 300.0 @@ -132,7 +132,7 @@ except ResourceNotFoundError: if time.monotonic() >= deadline: raise RuntimeError( - f"Model `{model_name}`@`{model_version}` did not appear within 300s after create_async." + f"Model `{model_name}`@`{model_version}` did not appear within 300s after pending_create_version." ) time.sleep(2.0) print(model) diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models.py b/sdk/ai/azure-ai-projects/tests/models/test_models.py index e87d196c311a..a0e99d6dab88 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models.py @@ -7,7 +7,7 @@ These tests exercise the generated ``BetaModelsOperations`` (``list``, ``list_versions``, ``get``, ``pending_upload``, ``get_credentials``, ``delete``) -and the patched ``models_create`` end-to-end helper. They follow the same +and the patched ``create_version`` end-to-end helper. They follow the same "upload + record" pattern used by ``test_datasets.py``. ``create_or_update`` is intentionally not tested here. The Foundry data plane @@ -40,11 +40,11 @@ ) class TestModels(TestBase): - # cls & pytest tests\models\test_models.py::TestModels::test_models_models_create -s + # cls & pytest tests\models\test_models.py::TestModels::test_create_version_version -s @servicePreparer() @recorded_by_proxy - def test_models_models_create(self, **kwargs): - """End-to-end: pending_upload -> azcopy -> create_async -> get/list/delete.""" + def test_create_version_version(self, **kwargs): + """End-to-end: pending_upload -> azcopy -> pending_create_version -> get/list/delete.""" model_name = self.test_models_params["model_name_1"] model_version = self.test_models_params["model_version"] expected_model_name = model_name if is_live() else "sanitized-model-name" @@ -52,40 +52,40 @@ def test_models_models_create(self, **kwargs): with self.create_client(**kwargs) as project_client: - print(f"[test_models_models_create] models_create {model_name}@{model_version}") - registered = project_client.beta.models.models_create( + print(f"[test_create_version_version] create_version {model_name}@{model_version}") + registered = project_client.beta.models.create_version( name=model_name, version=model_version, source=data_folder, weight_type="FullWeight", - description="Registered by test_models_models_create", + description="Registered by test_create_version_version", tags={"source": "test_models.py"}, ) assert registered is not None assert registered.name == expected_model_name assert registered.version == model_version - assert registered.blob_uri, "blob_uri should be populated after models_create" + assert registered.blob_uri, "blob_uri should be populated after create_version" - print(f"[test_models_models_create] get {model_name}@{model_version}") + print(f"[test_create_version_version] get {model_name}@{model_version}") fetched = project_client.beta.models.get(name=model_name, version=model_version) assert fetched.id == registered.id assert fetched.name == expected_model_name assert fetched.version == model_version - print(f"[test_models_models_create] list_versions({model_name!r})") + print(f"[test_create_version_version] list_versions({model_name!r})") versions = list(project_client.beta.models.list_versions(name=model_name)) assert any( mv.version == model_version for mv in versions ), f"version {model_version!r} not found in list_versions" - print("[test_models_models_create] list (latest of every model)") + print("[test_create_version_version] list (latest of every model)") empty = True for mv in project_client.beta.models.list(): empty = False assert mv.name and mv.version assert not empty, "list() returned no models even though we just registered one" - print(f"[test_models_models_create] get_credentials {model_name}@{model_version}") + print(f"[test_create_version_version] get_credentials {model_name}@{model_version}") from azure.ai.projects.models import ModelCredentialRequest creds = project_client.beta.models.get_credentials( @@ -99,7 +99,7 @@ def test_models_models_create(self, **kwargs): assert blob_ref.credential is not None assert blob_ref.credential.sas_uri - print(f"[test_models_models_create] delete {model_name}@{model_version}") + print(f"[test_create_version_version] delete {model_name}@{model_version}") try: project_client.beta.models.delete(name=model_name, version=model_version) except HttpResponseError as ex: @@ -108,7 +108,7 @@ def test_models_models_create(self, **kwargs): if ex.status_code != 200: raise - print(f"[test_models_models_create] get on deleted {model_name}@{model_version} should 404") + print(f"[test_create_version_version] get on deleted {model_name}@{model_version} should 404") with pytest.raises((ResourceNotFoundError, HttpResponseError)): project_client.beta.models.get(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py index 1f7575926b59..631e9609c515 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py @@ -5,7 +5,7 @@ # ------------------------------------ """Live, recorded async tests for ``project_client.beta.models``. -Mirrors :mod:`tests.models.test_models` for the async client. ``models_create`` +Mirrors :mod:`tests.models.test_models` for the async client. ``create_version`` itself is implemented only on the sync client (it shells out to ``azcopy``); the async surface is exercised via ``list``, ``list_versions``, ``get`` and ``delete`` against a model registered with the sync helper as part of the @@ -54,7 +54,7 @@ async def test_models_async_list_get_delete(self, **kwargs): endpoint=endpoint, credential=self.get_credential(SyncAIProjectClient, is_async=False), ) as sync_client: - registered = sync_client.beta.models.models_create( + registered = sync_client.beta.models.create_version( name=model_name, version=model_version, source=data_folder, diff --git a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py index 774abc5b14ae..5798714fdee6 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py @@ -7,7 +7,7 @@ These tests do not contact the Foundry service. They cover the patch helpers ``_extract_pending_upload_targets`` and ``_run_azcopy``, and the orchestration -performed by ``models_create`` (mocking ``pending_upload``, ``create_async`` +performed by ``create_version`` (mocking ``pending_upload``, ``pending_create_version`` and ``get`` on the base class). """ @@ -169,7 +169,7 @@ def test_nonzero_exit_raises_runtime_error(self, tmp_path): # --------------------------------------------------------------------------- -# models_create orchestration +# create_version orchestration # --------------------------------------------------------------------------- @@ -188,7 +188,7 @@ def _pending_payload() -> dict: } -class TestModelsCreateOrchestration: +class TestCreateVersionOrchestration: @pytest.fixture(autouse=True) def _stub_azcopy_on_path(self): """Pretend azcopy is installed so the up-front validator passes.""" @@ -223,7 +223,7 @@ def fake_run_azcopy(source, sas_uri, *, azcopy_path=None): # noqa: ARG001 assert azcopy_path == "/custom/azcopy" def fake_create_async(**kwargs): - calls.append("create_async") + calls.append("pending_create_version") assert kwargs["name"] == "my-model" assert kwargs["version"] == "1" body = kwargs["body"] @@ -241,10 +241,10 @@ def fake_get(**kwargs): with mock.patch.object(ops, "pending_upload", side_effect=fake_pending_upload), mock.patch.object( BetaModelsOperations, "_run_azcopy", staticmethod(fake_run_azcopy) - ), mock.patch.object(ops, "create_async", side_effect=fake_create_async), mock.patch.object( + ), mock.patch.object(ops, "pending_create_version", side_effect=fake_create_async), mock.patch.object( ops, "get", side_effect=fake_get ): - result = ops.models_create( + result = ops.create_version( name="my-model", version="1", source=tmp_path, @@ -255,7 +255,7 @@ def fake_get(**kwargs): ) assert result is committed - assert calls == ["pending_upload", "azcopy", "create_async", "get"] + assert calls == ["pending_upload", "azcopy", "pending_create_version", "get"] def test_models_create_wait_for_commit_false_returns_none_and_does_not_poll(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") @@ -264,8 +264,8 @@ def test_models_create_wait_for_commit_false_returns_none_and_does_not_poll(self with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) - ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object(ops, "get", get_mock): - result = ops.models_create( + ), mock.patch.object(ops, "pending_create_version", return_value=None), mock.patch.object(ops, "get", get_mock): + result = ops.create_version( name="m", version="1", source=tmp_path, @@ -290,12 +290,12 @@ def test_models_create_polls_until_get_succeeds(self, tmp_path): with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) - ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object( + ), mock.patch.object(ops, "pending_create_version", return_value=None), mock.patch.object( ops, "get", get_mock ), mock.patch( "azure.ai.projects.operations._patch_models.time.sleep" ) as sleep: - result = ops.models_create( + result = ops.create_version( name="m", version="1", source=tmp_path, @@ -314,7 +314,7 @@ def test_models_create_polling_timeout_raises_runtime_error(self, tmp_path): times = iter([1000.0, 1000.0, 9999.0]) with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) - ), mock.patch.object(ops, "create_async", return_value=None), mock.patch.object( + ), mock.patch.object(ops, "pending_create_version", return_value=None), mock.patch.object( ops, "get", side_effect=ResourceNotFoundError(message="never") ), mock.patch( "azure.ai.projects.operations._patch_models.time.monotonic", @@ -323,7 +323,7 @@ def test_models_create_polling_timeout_raises_runtime_error(self, tmp_path): "azure.ai.projects.operations._patch_models.time.sleep" ): with pytest.raises(RuntimeError, match="did not appear within"): - ops.models_create( + ops.create_version( name="m", version="1", source=tmp_path, @@ -336,16 +336,16 @@ def test_models_create_missing_source_raises_before_calling_service(self, tmp_pa pending = mock.Mock() with mock.patch.object(ops, "pending_upload", pending): with pytest.raises(ValueError, match="does not exist"): - ops.models_create(name="m", version="1", source=ghost) + ops.create_version(name="m", version="1", source=ghost) pending.assert_not_called() # --------------------------------------------------------------------------- -# _validate_models_create_inputs +# _validate_create_version_inputs # --------------------------------------------------------------------------- -class TestValidateModelsCreateInputs: +class TestValidateCreateVersionInputs: @pytest.fixture(autouse=True) def _stub_azcopy_on_path(self): with mock.patch( @@ -369,36 +369,36 @@ def _kwargs(self, **overrides): def test_valid_directory_source_returns_path(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") - result = BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=tmp_path)) + result = BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=tmp_path)) assert result == tmp_path @pytest.mark.parametrize("bad_name", ["", " ", None, 123]) def test_empty_or_non_string_name_raises(self, tmp_path, bad_name): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="`name`"): - BetaModelsOperations._validate_models_create_inputs(**self._kwargs(name=bad_name, source=tmp_path)) + BetaModelsOperations._validate_create_version_inputs(**self._kwargs(name=bad_name, source=tmp_path)) @pytest.mark.parametrize("bad_version", ["", " ", None, 1]) def test_empty_or_non_string_version_raises(self, tmp_path, bad_version): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="`version`"): - BetaModelsOperations._validate_models_create_inputs(**self._kwargs(version=bad_version, source=tmp_path)) + BetaModelsOperations._validate_create_version_inputs(**self._kwargs(version=bad_version, source=tmp_path)) def test_empty_directory_raises(self, tmp_path): with pytest.raises(ValueError, match="directory is empty"): - BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=tmp_path)) + BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=tmp_path)) def test_empty_file_raises(self, tmp_path): empty = tmp_path / "weights.bin" empty.write_bytes(b"") with pytest.raises(ValueError, match="file is empty"): - BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=empty)) + BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=empty)) @pytest.mark.parametrize("bad_timeout", [0, -1.0]) def test_non_positive_polling_timeout_raises(self, tmp_path, bad_timeout): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="polling_timeout"): - BetaModelsOperations._validate_models_create_inputs( + BetaModelsOperations._validate_create_version_inputs( **self._kwargs(source=tmp_path, polling_timeout=bad_timeout) ) @@ -406,14 +406,14 @@ def test_non_positive_polling_timeout_raises(self, tmp_path, bad_timeout): def test_non_positive_polling_interval_raises(self, tmp_path, bad_interval): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="polling_interval"): - BetaModelsOperations._validate_models_create_inputs( + BetaModelsOperations._validate_create_version_inputs( **self._kwargs(source=tmp_path, polling_interval=bad_interval) ) def test_polling_params_skipped_when_wait_for_commit_false(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") # Negative polling values are tolerated when not waiting for commit. - result = BetaModelsOperations._validate_models_create_inputs( + result = BetaModelsOperations._validate_create_version_inputs( **self._kwargs(source=tmp_path, wait_for_commit=False, polling_timeout=-1, polling_interval=-1) ) assert result == tmp_path @@ -425,7 +425,7 @@ def test_missing_azcopy_raises(self, tmp_path): return_value=None, ): with pytest.raises(RuntimeError, match="azcopy"): - BetaModelsOperations._validate_models_create_inputs(**self._kwargs(source=tmp_path)) + BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=tmp_path)) def test_models_create_validates_before_calling_pending_upload(self, tmp_path): """Validation runs before any service operation.""" @@ -436,5 +436,5 @@ def test_models_create_validates_before_calling_pending_upload(self, tmp_path): "azure.ai.projects.operations._patch_models.shutil.which", return_value=None ): with pytest.raises(RuntimeError, match="azcopy"): - ops.models_create(name="m", version="1", source=tmp_path) + ops.create_version(name="m", version="1", source=tmp_path) pending.assert_not_called() From 360623585a877c42b414131c1b5f27235c1dc582 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Fri, 22 May 2026 16:57:42 +0530 Subject: [PATCH 10/14] Rename .beta.models patched helper create_version -> create - Renames patched BetaModelsOperations.create_version() to create() (sync + async). - Renames internal validator _validate_create_version_inputs -> _validate_create_inputs. - Updates samples, tests, README, and CHANGELOG to use the new name. - Leaves generated spec method pending_create_version unchanged. --- sdk/ai/azure-ai-projects/CHANGELOG.md | 4 +-- sdk/ai/azure-ai-projects/README.md | 4 +-- .../ai/projects/aio/operations/_patch.py | 2 +- .../aio/operations/_patch_models_async.py | 22 ++++++------ .../azure/ai/projects/operations/_patch.py | 2 +- .../ai/projects/operations/_patch_models.py | 22 ++++++------ .../samples/models/sample_models_basic.py | 10 +++--- .../models/sample_models_basic_async.py | 2 +- .../models/sample_models_without_patch.py | 2 +- .../tests/models/test_models.py | 26 +++++++------- .../tests/models/test_models_async.py | 4 +-- .../tests/models/test_patch_models.py | 36 +++++++++---------- 12 files changed, 68 insertions(+), 68 deletions(-) diff --git a/sdk/ai/azure-ai-projects/CHANGELOG.md b/sdk/ai/azure-ai-projects/CHANGELOG.md index b8e64f5e3ec4..28c5256c1576 100644 --- a/sdk/ai/azure-ai-projects/CHANGELOG.md +++ b/sdk/ai/azure-ai-projects/CHANGELOG.md @@ -20,7 +20,7 @@ * New optional `force` parameter on `agents.delete` and `agents.delete_version` methods. * New optional `blueprint_reference` parameters on `agents.create_version` method. * New sample `sample_dataset_generation_job_with_evaluation.py` showing an end-to-end flow that generates a QnA dataset via `.beta.datasets.create_generation_job` and runs an OpenAI evaluation. -* New convenience method `.beta.models.create_version()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `pending_create_version`) and polls `get()` until the new `ModelVersion` is observable. +* New convenience method `.beta.models.create()` that wraps the spec's three-step upload-first sequence (`pending_upload` → `azcopy copy` → `pending_create_version`) and polls `get()` until the new `ModelVersion` is observable. ### Breaking Changes @@ -53,7 +53,7 @@ Breaking changes in beta classes: * Updated the other Hosted Agent samples to reuse an existing Hosted Agent as a prerequisite, instead of creating a new hosted agent version in each sample. * Added Toolbox tool-search sample `sample_toolboxes_with_search_preview.py` and `sample_toolboxes_with_search_preview_async.py`, demonstrating creating a Toolbox version with `ToolboxSearchPreviewTool` and invoking `MCPTool`. * Added `.beta.models` samples under `samples/models/`: - * `sample_models_basic.py` — synchronous end-to-end registration via the `create_version` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. + * `sample_models_basic.py` — synchronous end-to-end registration via the `create` helper (uses `azcopy`), followed by `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. * `sample_models_without_patch.py` — alternative synchronous registration that hand-rolls the spec's three-step flow (`pending_upload` → upload via `azure-storage-blob` → `pending_create_version` + poll), without taking a dependency on `azcopy`. * `sample_models_basic_async.py` — asynchronous version of the same three-step flow using `azure.ai.projects.aio.AIProjectClient` and `azure.storage.blob.aio.ContainerClient`. diff --git a/sdk/ai/azure-ai-projects/README.md b/sdk/ai/azure-ai-projects/README.md index ad53682d7be0..44365a930a5f 100644 --- a/sdk/ai/azure-ai-projects/README.md +++ b/sdk/ai/azure-ai-projects/README.md @@ -35,7 +35,7 @@ resources in your Microsoft Foundry Project. Use it to: * **Enumerate AI Models** deployed to your Foundry Project using `.deployments` operations. * **Enumerate connected Azure resources** in your Foundry project using `.connections` operations. * **Upload documents and create Datasets** to reference them using `.datasets` operations. -* **Register and manage local model weights** as Foundry `ModelVersion` resources using `.beta.models` operations, including the `create_version` end-to-end helper. +* **Register and manage local model weights** as Foundry `ModelVersion` resources using `.beta.models` operations, including the `create` end-to-end helper. * **Create and enumerate Search Indexes** using `.indexes` operations. The client library uses version `v1` of the Microsoft Foundry [data plane REST APIs](https://aka.ms/azsdk/azure-ai-projects-v2/api-reference-v1). @@ -167,7 +167,7 @@ Full descriptions and working code for all of the above are available in: | Deployments | [Deployment types](https://learn.microsoft.com/azure/foundry/foundry-models/concepts/deployment-types) | `samples/deployments/` | | Connections | [Connections operations](https://learn.microsoft.com/python/api/overview/azure/ai-projects-readme?view=azure-python#connections-operations) | `samples/connections/` | | Datasets | [Dataset operations](https://learn.microsoft.com/python/api/overview/azure/ai-projects-readme?view=azure-python#dataset-operations) | `samples/datasets/` | -| Models (preview) | Register local model weights as Foundry `ModelVersion` resources via `.beta.models` (`create_version`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `pending_create_version`, `get_credentials`). | `samples/models/` | +| Models (preview) | Register local model weights as Foundry `ModelVersion` resources via `.beta.models` (`create`, `list`, `list_versions`, `get`, `update`, `delete`, `pending_upload`, `pending_create_version`, `get_credentials`). | `samples/models/` | | Indexes | [Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) | `samples/indexes/` | | Files (upload, retrieve, list, delete) | [OpenAI Files API](https://platform.openai.com/docs/api-reference/files) | `samples/files/` | | Fine-tuning | [Fine-Tuning in AI Foundry](https://github.com/microsoft-foundry/fine-tuning) | `samples/finetuning/` | diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index b54ed57c6a80..9840dd5a6ac6 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py @@ -75,7 +75,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) # Replace with patched class that includes begin_update_memories self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) - # Replace with patched class that includes create_version (3-step upload helper) + # Replace with patched class that includes create (3-step upload helper) self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) for property_name, foundry_features_value in _BETA_OPERATION_FEATURE_HEADERS.items(): diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py index 720df949d6ea..dd6b0b57740f 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py @@ -62,7 +62,7 @@ def _extract_pending_upload_targets( return sas_uri, container_blob_uri, pending_upload_id @staticmethod - def _validate_create_version_inputs( + def _validate_create_inputs( *, name: str, version: str, @@ -71,7 +71,7 @@ def _validate_create_version_inputs( polling_timeout: float, polling_interval: float, ) -> Path: - """Validate ``create_version`` inputs up-front, before any service call. + """Validate ``create`` inputs up-front, before any service call. Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for bad inputs. @@ -107,7 +107,7 @@ async def _upload_with_container_client(source: Path, sas_uri: str) -> None: from azure.storage.blob.aio import ContainerClient # pylint: disable=import-outside-toplevel except ImportError as ex: raise RuntimeError( - "`azure-storage-blob` is required for the async `create_version` helper. " + "`azure-storage-blob` is required for the async `create` helper. " "Install it with `pip install azure-storage-blob aiohttp`." ) from ex @@ -122,17 +122,17 @@ async def _upload_with_container_client(source: Path, sas_uri: str) -> None: # Don't log the SAS query string — it's a credential. redacted = sas_uri.split("?", 1)[0] + "?" - logger.info("[create_version] uploading %d file(s) to %s", len(files), redacted) + logger.info("[create] uploading %d file(s) to %s", len(files), redacted) async with ContainerClient.from_container_url(sas_uri) as container_client: for f in files: rel = f.relative_to(source).as_posix() if source.is_dir() else f.name with f.open("rb") as fp: await container_client.upload_blob(name=rel, data=fp, overwrite=True) - logger.debug("[create_version] uploaded %s (%d bytes)", rel, f.stat().st_size) + logger.debug("[create] uploaded %s (%d bytes)", rel, f.stat().st_size) @distributed_trace_async - async def create_version( + async def create( self, *, name: str, @@ -198,7 +198,7 @@ async def create_version( the registration does not commit before ``polling_timeout`` elapses. """ # --- Step 0: validate inputs up-front -------------------------------- - source_path = self._validate_create_version_inputs( + source_path = self._validate_create_inputs( name=name, version=version, source=source, @@ -209,7 +209,7 @@ async def create_version( # --- Step 1: StartPendingUpload -------------------------------------- logger.info( - "[create_version] step 1/3 pending_upload(name=%r, version=%r)", + "[create] step 1/3 pending_upload(name=%r, version=%r)", name, version, ) @@ -223,13 +223,13 @@ async def create_version( ) sas_uri, container_blob_uri, pending_upload_id = self._extract_pending_upload_targets(pending) logger.info( - "[create_version] pending_upload_id=%s blob_uri=%s", + "[create] pending_upload_id=%s blob_uri=%s", pending_upload_id, container_blob_uri, ) # --- Step 2: Upload via async ContainerClient ------------------------ - logger.info("[create_version] step 2/3 async upload from %s", source_path) + logger.info("[create] step 2/3 async upload from %s", source_path) await self._upload_with_container_client(source_path, sas_uri) # --- Step 3: Commit registration ------------------------------------- @@ -241,7 +241,7 @@ async def create_version( tags=tags or {}, ) logger.info( - "[create_version] step 3/3 pending_create_version(name=%r, version=%r)", + "[create] step 3/3 pending_create_version(name=%r, version=%r)", name, version, ) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index 60fe8f466752..29adf947b535 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -130,7 +130,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.agents = BetaAgentsOperations(self._client, self._config, self._serialize, self._deserialize) # Replace with patched class that includes begin_update_memories self.memory_stores = BetaMemoryStoresOperations(self._client, self._config, self._serialize, self._deserialize) - # Replace with patched class that includes create_version (3-step upload helper) + # Replace with patched class that includes create (3-step upload helper) self.models = BetaModelsOperations(self._client, self._config, self._serialize, self._deserialize) for property_name, foundry_features_value in _BETA_OPERATION_FEATURE_HEADERS.items(): diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py index dd094177fe8e..fbcd7aa827b7 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -76,7 +76,7 @@ def _resolve_azcopy(azcopy_path: Optional[str] = None) -> str: return azcopy @staticmethod - def _validate_create_version_inputs( + def _validate_create_inputs( *, name: str, version: str, @@ -86,7 +86,7 @@ def _validate_create_version_inputs( polling_timeout: float, polling_interval: float, ) -> Path: - """Validate ``create_version`` inputs up-front, before any service call. + """Validate ``create`` inputs up-front, before any service call. Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for bad inputs and ``RuntimeError`` if ``azcopy`` cannot be located. @@ -139,13 +139,13 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None # Don't log the SAS query string — it's a credential. redacted = cmd.copy() redacted[3] = sas_uri.split("?", 1)[0] + "?" - logger.info("[create_version] running: %s", " ".join(redacted)) + logger.info("[create] running: %s", " ".join(redacted)) completed = subprocess.run(cmd, check=False, capture_output=True, text=True) if completed.stdout: - logger.debug("[create_version] azcopy stdout:\n%s", completed.stdout) + logger.debug("[create] azcopy stdout:\n%s", completed.stdout) if completed.stderr: - logger.debug("[create_version] azcopy stderr:\n%s", completed.stderr) + logger.debug("[create] azcopy stderr:\n%s", completed.stderr) if completed.returncode != 0: raise RuntimeError( f"azcopy exited with code {completed.returncode}.\n" @@ -153,7 +153,7 @@ def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None ) @distributed_trace - def create_version( + def create( self, *, name: str, @@ -223,7 +223,7 @@ def create_version( # --- Step 0: validate inputs up-front -------------------------------- # Cheap local checks so we don't provision a SAS container or run # azcopy when something obviously wrong was passed in. - source_path = self._validate_create_version_inputs( + source_path = self._validate_create_inputs( name=name, version=version, source=source, @@ -235,7 +235,7 @@ def create_version( # --- Step 1: StartPendingUpload -------------------------------------- logger.info( - "[create_version] step 1/3 pending_upload(name=%r, version=%r)", + "[create] step 1/3 pending_upload(name=%r, version=%r)", name, version, ) @@ -249,13 +249,13 @@ def create_version( ) sas_uri, container_blob_uri, pending_upload_id = self._extract_pending_upload_targets(pending) logger.info( - "[create_version] pending_upload_id=%s blob_uri=%s", + "[create] pending_upload_id=%s blob_uri=%s", pending_upload_id, container_blob_uri, ) # --- Step 2: Upload via azcopy --------------------------------------- - logger.info("[create_version] step 2/3 azcopy upload from %s", source_path) + logger.info("[create] step 2/3 azcopy upload from %s", source_path) self._run_azcopy(source_path, sas_uri, azcopy_path=azcopy_path) # --- Step 3: Commit registration ------------------------------------- @@ -267,7 +267,7 @@ def create_version( tags=tags or {}, ) logger.info( - "[create_version] step 3/3 pending_create_version(name=%r, version=%r)", + "[create] step 3/3 pending_create_version(name=%r, version=%r)", name, version, ) diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py index 9129c84273c7..ce5f99910ca1 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py @@ -12,7 +12,7 @@ update version metadata, and delete a model version. The recommended entry point is the patched helper - `project_client.beta.models.create_version(...)`, which packs the spec's + `project_client.beta.models.create(...)`, which packs the spec's three required steps (`pending_upload` -> `azcopy copy` -> `pending_create_version`) into a single call and polls until the new ModelVersion is observable. @@ -23,7 +23,7 @@ pip install "azure-ai-projects>=2.2.0" azure-identity python-dotenv - AzCopy must also be installed and on PATH (used by `create_version` to + AzCopy must also be installed and on PATH (used by `create` to upload weight files): winget install --id Microsoft.Azure.AZCopy.10 -e @@ -76,9 +76,9 @@ print( f"Register a local model named `{model_name}` version `{model_version}` " - f"by uploading the contents of `{data_folder}` via `create_version`." + f"by uploading the contents of `{data_folder}` via `create`." ) - model = project_client.beta.models.create_version( + model = project_client.beta.models.create( name=model_name, version=model_version, source=data_folder, @@ -88,7 +88,7 @@ ) if model is None: raise RuntimeError( - f"`create_version` returned None for `{model_name}`@`{model_version}` " + f"`create` returned None for `{model_name}`@`{model_version}` " "(use `wait_for_commit=True` to receive the committed ModelVersion)." ) print(f"Created (name: {model.name}, version: {model.version}, blob_uri: {model.blob_uri})") diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py index a6f5d1fa61de..f45f3761ddf9 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py @@ -11,7 +11,7 @@ asynchronous `.beta.models` operations: `pending_upload`, `pending_create_version`, `get`, `list_versions`, `list`, `get_credentials`, `update`, and `delete`. - The async client does not expose the `create_version` convenience helper + The async client does not expose the `create` convenience helper (which shells out to the synchronous `azcopy` CLI). This sample instead drives the spec's three-step upload-first sequence directly: diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py index 4a05cf2cd51c..b5ef6c72fb3e 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py @@ -8,7 +8,7 @@ DESCRIPTION: Given an AIProjectClient, this sample demonstrates how to register a local model with a Microsoft Foundry project WITHOUT relying on the - `create_version` helper or the `azcopy` CLI. It hand-rolls the spec's + `create` helper or the `azcopy` CLI. It hand-rolls the spec's three-step upload-first sequence using only the generated `.beta.models` operations and `azure-storage-blob`: diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models.py b/sdk/ai/azure-ai-projects/tests/models/test_models.py index a0e99d6dab88..356a83d14d3e 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models.py @@ -7,7 +7,7 @@ These tests exercise the generated ``BetaModelsOperations`` (``list``, ``list_versions``, ``get``, ``pending_upload``, ``get_credentials``, ``delete``) -and the patched ``create_version`` end-to-end helper. They follow the same +and the patched ``create`` end-to-end helper. They follow the same "upload + record" pattern used by ``test_datasets.py``. ``create_or_update`` is intentionally not tested here. The Foundry data plane @@ -40,10 +40,10 @@ ) class TestModels(TestBase): - # cls & pytest tests\models\test_models.py::TestModels::test_create_version_version -s + # cls & pytest tests\models\test_models.py::TestModels::test_create -s @servicePreparer() @recorded_by_proxy - def test_create_version_version(self, **kwargs): + def test_create(self, **kwargs): """End-to-end: pending_upload -> azcopy -> pending_create_version -> get/list/delete.""" model_name = self.test_models_params["model_name_1"] model_version = self.test_models_params["model_version"] @@ -52,40 +52,40 @@ def test_create_version_version(self, **kwargs): with self.create_client(**kwargs) as project_client: - print(f"[test_create_version_version] create_version {model_name}@{model_version}") - registered = project_client.beta.models.create_version( + print(f"[test_create] create {model_name}@{model_version}") + registered = project_client.beta.models.create( name=model_name, version=model_version, source=data_folder, weight_type="FullWeight", - description="Registered by test_create_version_version", + description="Registered by test_create", tags={"source": "test_models.py"}, ) assert registered is not None assert registered.name == expected_model_name assert registered.version == model_version - assert registered.blob_uri, "blob_uri should be populated after create_version" + assert registered.blob_uri, "blob_uri should be populated after create" - print(f"[test_create_version_version] get {model_name}@{model_version}") + print(f"[test_create] get {model_name}@{model_version}") fetched = project_client.beta.models.get(name=model_name, version=model_version) assert fetched.id == registered.id assert fetched.name == expected_model_name assert fetched.version == model_version - print(f"[test_create_version_version] list_versions({model_name!r})") + print(f"[test_create] list_versions({model_name!r})") versions = list(project_client.beta.models.list_versions(name=model_name)) assert any( mv.version == model_version for mv in versions ), f"version {model_version!r} not found in list_versions" - print("[test_create_version_version] list (latest of every model)") + print("[test_create] list (latest of every model)") empty = True for mv in project_client.beta.models.list(): empty = False assert mv.name and mv.version assert not empty, "list() returned no models even though we just registered one" - print(f"[test_create_version_version] get_credentials {model_name}@{model_version}") + print(f"[test_create] get_credentials {model_name}@{model_version}") from azure.ai.projects.models import ModelCredentialRequest creds = project_client.beta.models.get_credentials( @@ -99,7 +99,7 @@ def test_create_version_version(self, **kwargs): assert blob_ref.credential is not None assert blob_ref.credential.sas_uri - print(f"[test_create_version_version] delete {model_name}@{model_version}") + print(f"[test_create] delete {model_name}@{model_version}") try: project_client.beta.models.delete(name=model_name, version=model_version) except HttpResponseError as ex: @@ -108,7 +108,7 @@ def test_create_version_version(self, **kwargs): if ex.status_code != 200: raise - print(f"[test_create_version_version] get on deleted {model_name}@{model_version} should 404") + print(f"[test_create] get on deleted {model_name}@{model_version} should 404") with pytest.raises((ResourceNotFoundError, HttpResponseError)): project_client.beta.models.get(name=model_name, version=model_version) diff --git a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py index 631e9609c515..b92c0c6e54c1 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_models_async.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_models_async.py @@ -5,7 +5,7 @@ # ------------------------------------ """Live, recorded async tests for ``project_client.beta.models``. -Mirrors :mod:`tests.models.test_models` for the async client. ``create_version`` +Mirrors :mod:`tests.models.test_models` for the async client. ``create`` itself is implemented only on the sync client (it shells out to ``azcopy``); the async surface is exercised via ``list``, ``list_versions``, ``get`` and ``delete`` against a model registered with the sync helper as part of the @@ -54,7 +54,7 @@ async def test_models_async_list_get_delete(self, **kwargs): endpoint=endpoint, credential=self.get_credential(SyncAIProjectClient, is_async=False), ) as sync_client: - registered = sync_client.beta.models.create_version( + registered = sync_client.beta.models.create( name=model_name, version=model_version, source=data_folder, diff --git a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py index 5798714fdee6..211613f82e82 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py @@ -7,7 +7,7 @@ These tests do not contact the Foundry service. They cover the patch helpers ``_extract_pending_upload_targets`` and ``_run_azcopy``, and the orchestration -performed by ``create_version`` (mocking ``pending_upload``, ``pending_create_version`` +performed by ``create`` (mocking ``pending_upload``, ``pending_create_version`` and ``get`` on the base class). """ @@ -169,7 +169,7 @@ def test_nonzero_exit_raises_runtime_error(self, tmp_path): # --------------------------------------------------------------------------- -# create_version orchestration +# create orchestration # --------------------------------------------------------------------------- @@ -244,7 +244,7 @@ def fake_get(**kwargs): ), mock.patch.object(ops, "pending_create_version", side_effect=fake_create_async), mock.patch.object( ops, "get", side_effect=fake_get ): - result = ops.create_version( + result = ops.create( name="my-model", version="1", source=tmp_path, @@ -265,7 +265,7 @@ def test_models_create_wait_for_commit_false_returns_none_and_does_not_poll(self with mock.patch.object(ops, "pending_upload", return_value=_pending_payload()), mock.patch.object( BetaModelsOperations, "_run_azcopy", staticmethod(lambda *a, **kw: None) ), mock.patch.object(ops, "pending_create_version", return_value=None), mock.patch.object(ops, "get", get_mock): - result = ops.create_version( + result = ops.create( name="m", version="1", source=tmp_path, @@ -295,7 +295,7 @@ def test_models_create_polls_until_get_succeeds(self, tmp_path): ), mock.patch( "azure.ai.projects.operations._patch_models.time.sleep" ) as sleep: - result = ops.create_version( + result = ops.create( name="m", version="1", source=tmp_path, @@ -323,7 +323,7 @@ def test_models_create_polling_timeout_raises_runtime_error(self, tmp_path): "azure.ai.projects.operations._patch_models.time.sleep" ): with pytest.raises(RuntimeError, match="did not appear within"): - ops.create_version( + ops.create( name="m", version="1", source=tmp_path, @@ -336,12 +336,12 @@ def test_models_create_missing_source_raises_before_calling_service(self, tmp_pa pending = mock.Mock() with mock.patch.object(ops, "pending_upload", pending): with pytest.raises(ValueError, match="does not exist"): - ops.create_version(name="m", version="1", source=ghost) + ops.create(name="m", version="1", source=ghost) pending.assert_not_called() # --------------------------------------------------------------------------- -# _validate_create_version_inputs +# _validate_create_inputs # --------------------------------------------------------------------------- @@ -369,36 +369,36 @@ def _kwargs(self, **overrides): def test_valid_directory_source_returns_path(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") - result = BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=tmp_path)) + result = BetaModelsOperations._validate_create_inputs(**self._kwargs(source=tmp_path)) assert result == tmp_path @pytest.mark.parametrize("bad_name", ["", " ", None, 123]) def test_empty_or_non_string_name_raises(self, tmp_path, bad_name): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="`name`"): - BetaModelsOperations._validate_create_version_inputs(**self._kwargs(name=bad_name, source=tmp_path)) + BetaModelsOperations._validate_create_inputs(**self._kwargs(name=bad_name, source=tmp_path)) @pytest.mark.parametrize("bad_version", ["", " ", None, 1]) def test_empty_or_non_string_version_raises(self, tmp_path, bad_version): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="`version`"): - BetaModelsOperations._validate_create_version_inputs(**self._kwargs(version=bad_version, source=tmp_path)) + BetaModelsOperations._validate_create_inputs(**self._kwargs(version=bad_version, source=tmp_path)) def test_empty_directory_raises(self, tmp_path): with pytest.raises(ValueError, match="directory is empty"): - BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=tmp_path)) + BetaModelsOperations._validate_create_inputs(**self._kwargs(source=tmp_path)) def test_empty_file_raises(self, tmp_path): empty = tmp_path / "weights.bin" empty.write_bytes(b"") with pytest.raises(ValueError, match="file is empty"): - BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=empty)) + BetaModelsOperations._validate_create_inputs(**self._kwargs(source=empty)) @pytest.mark.parametrize("bad_timeout", [0, -1.0]) def test_non_positive_polling_timeout_raises(self, tmp_path, bad_timeout): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="polling_timeout"): - BetaModelsOperations._validate_create_version_inputs( + BetaModelsOperations._validate_create_inputs( **self._kwargs(source=tmp_path, polling_timeout=bad_timeout) ) @@ -406,14 +406,14 @@ def test_non_positive_polling_timeout_raises(self, tmp_path, bad_timeout): def test_non_positive_polling_interval_raises(self, tmp_path, bad_interval): (tmp_path / "weights.bin").write_bytes(b"x") with pytest.raises(ValueError, match="polling_interval"): - BetaModelsOperations._validate_create_version_inputs( + BetaModelsOperations._validate_create_inputs( **self._kwargs(source=tmp_path, polling_interval=bad_interval) ) def test_polling_params_skipped_when_wait_for_commit_false(self, tmp_path): (tmp_path / "weights.bin").write_bytes(b"x") # Negative polling values are tolerated when not waiting for commit. - result = BetaModelsOperations._validate_create_version_inputs( + result = BetaModelsOperations._validate_create_inputs( **self._kwargs(source=tmp_path, wait_for_commit=False, polling_timeout=-1, polling_interval=-1) ) assert result == tmp_path @@ -425,7 +425,7 @@ def test_missing_azcopy_raises(self, tmp_path): return_value=None, ): with pytest.raises(RuntimeError, match="azcopy"): - BetaModelsOperations._validate_create_version_inputs(**self._kwargs(source=tmp_path)) + BetaModelsOperations._validate_create_inputs(**self._kwargs(source=tmp_path)) def test_models_create_validates_before_calling_pending_upload(self, tmp_path): """Validation runs before any service operation.""" @@ -436,5 +436,5 @@ def test_models_create_validates_before_calling_pending_upload(self, tmp_path): "azure.ai.projects.operations._patch_models.shutil.which", return_value=None ): with pytest.raises(RuntimeError, match="azcopy"): - ops.create_version(name="m", version="1", source=tmp_path) + ops.create(name="m", version="1", source=tmp_path) pending.assert_not_called() From 5a2d9f8b35cc24ffce85fa3be5c8fe2c3a13b523 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Fri, 22 May 2026 22:03:51 +0530 Subject: [PATCH 11/14] Add sample recordings for .beta.models and fix generated arg names - Add parameterized sample tests test_models_samples (sync + async). - Add slim modelsServicePreparer (only foundry_project_endpoint). - Add sanitizers for random model name, Foundry storage account/container, /workspaces/, azureai:// asset URIs, account/project from FOUNDRY_PROJECT_ENDPOINT, and SAS query parameters (sig, skoid, sktid). - Use per-recording random MODEL_NAME (recsmplmdl) and sanitize to a stable value on playback (Foundry asset-store reserves / permanently). - Update assets.json tag to point at the new recordings. Bug fixes surfaced by live runs (renamed generated kwargs): - pending_upload: body= -> pending_upload_request= - pending_create_version: body= -> model_version= - get_credentials: body= -> credential_request= Applied to patched create() helper (sync + async), all three model samples, and the test_patch_models mock. Notes: - sample_models_basic.py (which uses AzCopy) is excluded from the parameterized sample tests because AzCopy traffic isn't captured by the test proxy. - LLM print-call validation is not invoked for models tests (canary project has no Azure OpenAI connection). --- sdk/ai/azure-ai-projects/assets.json | 2 +- .../aio/operations/_patch_models_async.py | 6 +- .../ai/projects/operations/_patch_models.py | 6 +- .../samples/models/sample_models_basic.py | 2 +- .../models/sample_models_basic_async.py | 6 +- .../models/sample_models_without_patch.py | 4 +- sdk/ai/azure-ai-projects/tests/conftest.py | 76 +++++++++++++++++++ .../tests/models/test_patch_models.py | 2 +- .../tests/samples/test_samples.py | 36 ++++++++- .../tests/samples/test_samples_async.py | 29 ++++++- sdk/ai/azure-ai-projects/tests/test_base.py | 10 +++ 11 files changed, 163 insertions(+), 16 deletions(-) diff --git a/sdk/ai/azure-ai-projects/assets.json b/sdk/ai/azure-ai-projects/assets.json index 6ba48111cd83..8ef395189e25 100644 --- a/sdk/ai/azure-ai-projects/assets.json +++ b/sdk/ai/azure-ai-projects/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/ai/azure-ai-projects", - "Tag": "python/ai/azure-ai-projects_b13a910d61" + "Tag": "python/ai/azure-ai-projects_f04966e97c" } diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py index dd6b0b57740f..6d169427e547 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py @@ -216,7 +216,7 @@ async def create( pending = await self.pending_upload( name=name, version=version, - body=ModelPendingUploadRequest( + pending_upload_request=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), **kwargs, @@ -233,7 +233,7 @@ async def create( await self._upload_with_container_client(source_path, sas_uri) # --- Step 3: Commit registration ------------------------------------- - body = ModelVersion( + model_version_body = ModelVersion( blob_uri=container_blob_uri, weight_type=weight_type, base_model=base_model, @@ -245,7 +245,7 @@ async def create( name, version, ) - await self.pending_create_version(name=name, version=version, body=body, **kwargs) + await self.pending_create_version(name=name, version=version, model_version=model_version_body, **kwargs) if not wait_for_commit: return None diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py index fbcd7aa827b7..4d27fc764d4e 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -242,7 +242,7 @@ def create( pending = self.pending_upload( name=name, version=version, - body=ModelPendingUploadRequest( + pending_upload_request=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), **kwargs, @@ -259,7 +259,7 @@ def create( self._run_azcopy(source_path, sas_uri, azcopy_path=azcopy_path) # --- Step 3: Commit registration ------------------------------------- - body = ModelVersion( + model_version_body = ModelVersion( blob_uri=container_blob_uri, weight_type=weight_type, base_model=base_model, @@ -271,7 +271,7 @@ def create( name, version, ) - self.pending_create_version(name=name, version=version, body=body, **kwargs) + self.pending_create_version(name=name, version=version, model_version=model_version_body, **kwargs) if not wait_for_commit: return None diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py index ce5f99910ca1..badcdcf4c40b 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic.py @@ -109,7 +109,7 @@ creds = project_client.beta.models.get_credentials( name=model_name, version=model_version, - body=ModelCredentialRequest(blob_uri=model.blob_uri), + credential_request=ModelCredentialRequest(blob_uri=model.blob_uri), ) print(f"Credentials (type: {type(creds).__name__})") diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py index f45f3761ddf9..d0fd70bde4a5 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_basic_async.py @@ -89,7 +89,7 @@ async def main() -> None: pending = await project_client.beta.models.pending_upload( name=model_name, version=model_version, - body=ModelPendingUploadRequest( + pending_upload_request=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), ) @@ -117,7 +117,7 @@ async def main() -> None: await project_client.beta.models.pending_create_version( name=model_name, version=model_version, - body=ModelVersion( + model_version=ModelVersion( blob_uri=container_blob_uri, weight_type=FoundryModelWeightType.FULL_WEIGHT, description="Sample model registered from sample_models_basic_async.py", @@ -154,7 +154,7 @@ async def main() -> None: creds = await project_client.beta.models.get_credentials( name=model_name, version=model_version, - body=ModelCredentialRequest(blob_uri=model.blob_uri), + credential_request=ModelCredentialRequest(blob_uri=model.blob_uri), ) print(f"Credentials (type: {type(creds).__name__})") diff --git a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py index b5ef6c72fb3e..e04c0473c7d9 100644 --- a/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py +++ b/sdk/ai/azure-ai-projects/samples/models/sample_models_without_patch.py @@ -83,7 +83,7 @@ pending = project_client.beta.models.pending_upload( name=model_name, version=model_version, - body=ModelPendingUploadRequest( + pending_upload_request=ModelPendingUploadRequest( pending_upload_type=PendingUploadType.TEMPORARY_BLOB_REFERENCE, ), ) @@ -112,7 +112,7 @@ project_client.beta.models.pending_create_version( name=model_name, version=model_version, - body=ModelVersion( + model_version=ModelVersion( blob_uri=container_blob_uri, weight_type=FoundryModelWeightType.FULL_WEIGHT, description="Sample model registered from sample_models_pending_upload.py", diff --git a/sdk/ai/azure-ai-projects/tests/conftest.py b/sdk/ai/azure-ai-projects/tests/conftest.py index 154c6bb3f36a..9ebb3ace9ec6 100644 --- a/sdk/ai/azure-ai-projects/tests/conftest.py +++ b/sdk/ai/azure-ai-projects/tests/conftest.py @@ -134,6 +134,82 @@ def sanitize_url_paths(): # Pattern 2: "Eval Run for -" (agent name already sanitized) add_general_regex_sanitizer(regex=r"sanitized-agent-name -\d{10}", value="sanitized-agent-name -SANITIZED-TS") + # Sanitize per-recording random model name used by `.beta.models` sample tests. + # Live re-recordings need a unique `/` namespace (Foundry's + # asset store reserves it permanently after `delete`), so we use a random + # suffix at recording time and normalize it here so playback URLs match. + add_general_regex_sanitizer(regex=r"recsmplmdl[a-f0-9]+", value="recsmplmdl00000000") + + # Sanitize Foundry project-managed Azure Storage account hostnames returned + # by `.beta.models.pending_upload` (shape: `sa<14 hex chars>.blob.core.windows.net`). + add_general_regex_sanitizer( + regex=r"sa[a-z0-9]{14,}\.blob\.core\.windows\.net", + value="sanitized-storage-account.blob.core.windows.net", + ) + + # Sanitize the per-pending-upload container name returned by Foundry + # (shape: `-pr-`). + add_general_regex_sanitizer( + regex=r"/[a-z0-9-]+-pr-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + value="/sanitized-pending-upload-container", + ) + + # Sanitize SAS-token query strings returned by `.beta.models.pending_upload` + # (signed URLs to a Foundry-managed Storage container). Match conservatively + # on the `sig=` parameter which is unique to SAS tokens and isn't used by + # regular Azure API URLs. + add_general_regex_sanitizer( + regex=r"sig=[A-Za-z0-9%]+", + value="sig=sanitized-sas-sig", + ) + add_general_regex_sanitizer( + regex=r"skoid=[A-Fa-f0-9\-]+", + value="skoid=00000000-0000-0000-0000-000000000000", + ) + add_general_regex_sanitizer( + regex=r"sktid=[A-Fa-f0-9\-]+", + value="sktid=00000000-0000-0000-0000-000000000000", + ) + + # Sanitize `/workspaces/` URL segments (some Foundry asset-store URLs + # reference the underlying ML workspace by name, which leaks the project + # resource name). + add_general_regex_sanitizer( + regex=r"/workspaces/([-\w\._\(\)]+)", + value=sanitized_values["account_name"], + group_for_replace="1", + ) + + # Sanitize Foundry `azureai://` asset URIs whose `accounts/` and + # `projects/` segments embed the project resource name. + add_general_regex_sanitizer( + regex=r"azureai://accounts/([^/]+)/projects/([^/]+)", + value=f"azureai://accounts/{sanitized_values['account_name']}/projects/{sanitized_values['project_name']}", + ) + + # Sanitize the live Foundry project's account/project names anywhere they + # appear in URLs, headers, or bodies. Derived from the live endpoint shape + # `https://.services.ai.azure.com/api/projects/` so we + # cover trailing leaks like `@@AML/...` asset IDs and + # `publisherId` fields that aren't matched by URL-segment sanitizers. + _live_endpoint = os.environ.get("FOUNDRY_PROJECT_ENDPOINT") or os.environ.get("foundry_project_endpoint") + if _live_endpoint: + _ep_match = re.match( + r"https?://(?P[^.]+)\.[^/]+/api/projects/(?P[^/?#]+)", + _live_endpoint, + ) + if _ep_match: + _live_account = _ep_match.group("account") + _live_project = _ep_match.group("project") + # Order matters: the longer (account) name often contains the shorter + # (project) name as a prefix; replace the longer one first. + for _name, _placeholder in ( + (_live_account, sanitized_values["account_name"]), + (_live_project, sanitized_values["project_name"]), + ): + add_general_regex_sanitizer(regex=re.escape(_name), value=_placeholder) + add_body_string_sanitizer(target=_name, value=_placeholder) + # Sanitize image-generation deployment name from live env when present. # This value is commonly emitted in request headers (for example # `x-ms-oai-image-generation-deployment`) and may come from either diff --git a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py index 211613f82e82..d2c8dd6da57a 100644 --- a/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py +++ b/sdk/ai/azure-ai-projects/tests/models/test_patch_models.py @@ -226,7 +226,7 @@ def fake_create_async(**kwargs): calls.append("pending_create_version") assert kwargs["name"] == "my-model" assert kwargs["version"] == "1" - body = kwargs["body"] + body = kwargs["model_version"] # The blob_uri from the pending response is plumbed into the commit body. assert body.blob_uri == "https://acct.blob.core.windows.net/c/path" assert body.weight_type == "FullWeight" diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_samples.py b/sdk/ai/azure-ai-projects/tests/samples/test_samples.py index b6bc0593a102..36d498394278 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/test_samples.py +++ b/sdk/ai/azure-ai-projects/tests/samples/test_samples.py @@ -6,7 +6,7 @@ import pytest import os from devtools_testutils import recorded_by_proxy, AzureRecordedTestCase, RecordedTransport -from test_base import servicePreparer, fineTuningServicePreparer +from test_base import servicePreparer, fineTuningServicePreparer, modelsServicePreparer from sample_executor import ( AdditionalSampleTestDetail, SyncSampleExecutor, @@ -149,6 +149,40 @@ def test_deployments_samples(self, sample_path: str, **kwargs) -> None: executor.execute() executor.validate_print_calls_by_llm() + @pytest.mark.parametrize( + "sample_path", + get_sample_paths( + "models", + samples_to_test=[ + # `sample_models_basic.py` uses the `create()` helper which shells out + # to AzCopy. AzCopy traffic isn't captured by the test proxy, so the + # sample can't be replayed from a recording. Live re-recording is still + # exercised via the standalone tests in `tests/models/`. + "sample_models_without_patch.py", + ], + ), + ) + @modelsServicePreparer() + @SamplePathPasser() + @recorded_by_proxy(RecordedTransport.AZURE_CORE, RecordedTransport.HTTPX) + def test_models_samples(self, sample_path: str, **kwargs) -> None: + import secrets # local import to avoid module-level dep + + env_vars = get_sample_env_vars(kwargs) + # Foundry permanently reserves a `/` asset namespace even + # after `models.delete`, so every live re-recording needs a unique name. + # Sanitize back to a stable value in conftest so playback URLs match. + suffix = secrets.token_hex(4) if self.is_live else "00000000" + env_vars["MODEL_NAME"] = f"recsmplmdl{suffix}" + env_vars["MODEL_VERSION"] = "1" + executor = SyncSampleExecutor(self, sample_path, env_vars=env_vars, **kwargs) + executor.execute() + # `validate_print_calls_by_llm` is intentionally not called: it requires + # an Azure OpenAI connection on the Foundry project, which the canary + # project used for `.beta.models` recordings does not have. The sample + # is still validated end-to-end by `executor.execute()` (any exception + # fails the test). + @servicePreparer() @additionalSampleTests( [ diff --git a/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py b/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py index 401374346664..1ad721c28fe6 100644 --- a/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py +++ b/sdk/ai/azure-ai-projects/tests/samples/test_samples_async.py @@ -6,7 +6,7 @@ import pytest, os from devtools_testutils.aio import recorded_by_proxy_async from devtools_testutils import AzureRecordedTestCase, RecordedTransport -from test_base import servicePreparer +from test_base import servicePreparer, modelsServicePreparer from sample_executor import ( AdditionalSampleTestDetail, AsyncSampleExecutor, @@ -135,6 +135,33 @@ async def test_deployments_samples(self, sample_path: str, **kwargs) -> None: await executor.execute_async() await executor.validate_print_calls_by_llm_async() + @pytest.mark.parametrize( + "sample_path", + get_async_sample_paths( + "models", + samples_to_test=[ + "sample_models_basic_async.py", + ], + ), + ) + @modelsServicePreparer() + @SamplePathPasser() + @recorded_by_proxy_async(RecordedTransport.AZURE_CORE, RecordedTransport.HTTPX) + async def test_models_samples(self, sample_path: str, **kwargs) -> None: + import secrets # local import to avoid module-level dep + + env_vars = get_sample_env_vars(kwargs) + # Foundry permanently reserves a `/` asset namespace even + # after `models.delete`, so every live re-recording needs a unique name. + # Sanitize back to a stable value in conftest so playback URLs match. + suffix = secrets.token_hex(4) if self.is_live else "00000000" + env_vars["MODEL_NAME"] = f"recsmplmdl{suffix}" + env_vars["MODEL_VERSION"] = "1" + executor = AsyncSampleExecutor(self, sample_path, env_vars=env_vars, **kwargs) + await executor.execute_async() + # `validate_print_calls_by_llm_async` is intentionally not called: see + # the comment on the synchronous `test_models_samples` for details. + @pytest.mark.parametrize( "sample_path", get_async_sample_paths( diff --git a/sdk/ai/azure-ai-projects/tests/test_base.py b/sdk/ai/azure-ai-projects/tests/test_base.py index 2787bdc0d99e..5b69b45ce21a 100644 --- a/sdk/ai/azure-ai-projects/tests/test_base.py +++ b/sdk/ai/azure-ai-projects/tests/test_base.py @@ -87,6 +87,16 @@ azure_ai_projects_azure_aoai_account="sanitized-aoai-account", ) +# Slim preparer for `.beta.models` samples/tests. These exercise local-file +# upload + ModelVersion registration; they only need a Foundry project endpoint +# and the LLM-validation endpoint used by sample tests. +modelsServicePreparer = functools.partial( + EnvironmentVariableLoader, + "", + foundry_project_endpoint="https://sanitized-account-name.services.ai.azure.com/api/projects/sanitized-project-name", + llm_validation_project_endpoint="https://sanitized-account-name.services.ai.azure.com/api/projects/sanitized-project-name", +) + # Fine-tuning job type constants SFT_JOB_TYPE: Final[str] = "sft" DPO_JOB_TYPE: Final[str] = "dpo" From bbb13c91f1576e6bcf26c1e11b1827972de7778a Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Mon, 25 May 2026 13:10:28 +0530 Subject: [PATCH 12/14] Exclude .beta.models.create from foundry-features header test The multi-step orchestrator helper performs local input validation before any HTTP call, so the test framework's synthetic placeholder args (e.g. source={}) cause it to raise TypeError before _RequestCaptured is ever raised. Add a shared EXCLUDED_BETA_METHODS mapping and skip excluded methods in both sync and async discovery. The header invariant is still enforced for every underlying HTTP method create() calls (pending_upload, pending_create_version, get). --- .../foundry_features_header_test_base.py | 21 +++++++++++++++++++ ...ndry_features_header_on_beta_operations.py | 4 ++++ ...eatures_header_on_beta_operations_async.py | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py b/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py index b20ee15b9ce7..2c5c275b9f35 100644 --- a/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py +++ b/sdk/ai/azure-ai-projects/tests/foundry_features_header/foundry_features_header_test_base.py @@ -49,6 +49,27 @@ "agents": "HostedAgents=V1Preview,WorkflowAgents=V1Preview,AgentEndpoints=V1Preview,CodeAgents=V1Preview,ExternalAgents=V1Preview,AgentsOptimization=V1Preview", } +# Methods on .beta sub-clients that are NOT simple one-HTTP-call wrappers and +# therefore cannot be exercised by the generic header-injection test (which +# captures the first outgoing HttpRequest). +# +# Multi-step orchestrator helpers (validate locally -> HTTP -> external process +# -> HTTP -> poll) fall into this bucket: they perform local input validation +# and/or external side effects (e.g. subprocess calls) before the first HTTP +# request, so synthetic placeholder arguments cause them to abort with a +# TypeError/ValueError/RuntimeError before any request is ever sent. +# +# The header-injection invariant is still enforced for these methods because +# every nested HTTP call they make is routed through other public sub-client +# methods that ARE covered by this test (e.g. .beta.models.create internally +# calls .beta.models.pending_upload and .beta.models.pending_create_version, +# both of which are tested separately and pass). +# +# Format: { "": frozenset({"", ...}) } +EXCLUDED_BETA_METHODS: dict[str, frozenset] = { + "models": frozenset({"create"}), # multi-step helper: validate -> pending_upload -> azcopy -> pending_create_version -> poll get +} + # Shared test cases for non-beta methods that optionally send the Foundry-Features header. # Used by both test_foundry_features_header_optional.py (sync) and # test_foundry_features_header_optional_async.py (async). diff --git a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations.py b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations.py index ac3186a1225f..43db5c0811f6 100644 --- a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations.py +++ b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations.py @@ -38,6 +38,7 @@ from azure.ai.projects import AIProjectClient from foundry_features_header_test_base import ( + EXCLUDED_BETA_METHODS, EXPECTED_FOUNDRY_FEATURES, FAKE_ENDPOINT, FOUNDRY_FEATURES_HEADER, @@ -111,9 +112,12 @@ def _discover_test_cases() -> list[pytest.param]: # return no public methods. Methods are still fetched via getattr(sc, ...) so # the header-injecting proxy wrapper is exercised. _underlying_op = getattr(sc, "_operation", sc) + _excluded = EXCLUDED_BETA_METHODS.get(sc_name, frozenset()) for m_name in sorted(dir(_underlying_op)): if m_name.startswith("_"): continue + if m_name in _excluded: + continue method = getattr(sc, m_name) if not callable(method): continue diff --git a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations_async.py b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations_async.py index 30eed85005a5..afb065d6a155 100644 --- a/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations_async.py +++ b/sdk/ai/azure-ai-projects/tests/foundry_features_header/test_foundry_features_header_on_beta_operations_async.py @@ -40,6 +40,7 @@ from azure.ai.projects.aio import AIProjectClient as AsyncAIProjectClient from foundry_features_header_test_base import ( + EXCLUDED_BETA_METHODS, EXPECTED_FOUNDRY_FEATURES, FAKE_ENDPOINT, FOUNDRY_FEATURES_HEADER, @@ -116,9 +117,12 @@ def _discover_async_test_cases() -> list[pytest.param]: # return no public methods. Methods are still fetched via getattr(sc, ...) so # the header-injecting proxy wrapper is exercised. _underlying_op = getattr(sc, "_operation", sc) + _excluded = EXCLUDED_BETA_METHODS.get(sc_name, frozenset()) for m_name in sorted(dir(_underlying_op)): if m_name.startswith("_"): continue + if m_name in _excluded: + continue method = getattr(sc, m_name) if not callable(method): continue From a9a8b1e5df53f33a994db4304f565b0889b40db5 Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Mon, 25 May 2026 14:04:57 +0530 Subject: [PATCH 13/14] Add cspell entries: recsmplmdl, simpleqna, skoid --- sdk/ai/azure-ai-projects/cspell.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/ai/azure-ai-projects/cspell.json b/sdk/ai/azure-ai-projects/cspell.json index e26c824b5807..dd14b6b68b0e 100644 --- a/sdk/ai/azure-ai-projects/cspell.json +++ b/sdk/ai/azure-ai-projects/cspell.json @@ -30,7 +30,10 @@ "Ministral", "mpkjc", "quantitive", + "recsmplmdl", "reraises", + "simpleqna", + "skoid", "Tadmaq", "Udbk", "UPIA", From aef129ad1bbfc33bf07fd7b81618b7b7315ed90a Mon Sep 17 00:00:00 2001 From: Kshitij Chawla Date: Mon, 25 May 2026 14:56:29 +0530 Subject: [PATCH 14/14] Fix pyright and pylint issues in BetaModelsOperations patches - Replace hasattr-based duck typing with isinstance(dict) check so pyright can narrow types correctly on _extract_pending_upload_targets. - Remove unused HttpResponseError import. - Suppress do-not-import-asyncio for asyncio.sleep used in the async polling loop (transport sleep is not applicable). - Add :param/:keyword/:return/:rtype docstring sections on private helpers to satisfy azure-pylint-guidelines-checker. --- .../aio/operations/_patch_models_async.py | 28 +++++++++++- .../ai/projects/operations/_patch_models.py | 45 +++++++++++++++++-- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py index 6d169427e547..c28382735599 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch_models_async.py @@ -8,7 +8,7 @@ Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize """ -import asyncio +import asyncio # pylint: disable=do-not-import-asyncio import logging import os from pathlib import Path @@ -49,8 +49,13 @@ def _extract_pending_upload_targets( Foundry deployments rather than the SDK-modeled ``ModelPendingUploadResponse`` shape (``blobReference`` / ``pendingUploadId``). Tolerate both wire shapes so callers don't have to. + + :param response: The pending-upload response from the service. + :type response: ~azure.ai.projects.models.ModelPendingUploadResponse or dict + :return: A tuple of ``(sas_uri, container_blob_uri, pending_upload_id)``. + :rtype: tuple[str, str, str or None] """ - payload = response.as_dict() if hasattr(response, "as_dict") else dict(response) + payload = dict(response) if isinstance(response, dict) else response.as_dict() blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} sas_uri = (blob_ref.get("credential") or {}).get("sasUri") @@ -75,6 +80,21 @@ def _validate_create_inputs( Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for bad inputs. + + :keyword name: Name of the model to register. + :paramtype name: str + :keyword version: Version identifier for the model. + :paramtype version: str + :keyword source: Local file or directory containing the model weights. + :paramtype source: str or os.PathLike[str] + :keyword wait_for_commit: Whether to poll for commit completion. + :paramtype wait_for_commit: bool + :keyword polling_timeout: Total seconds to poll for commit completion. + :paramtype polling_timeout: float + :keyword polling_interval: Seconds between poll attempts. + :paramtype polling_interval: float + :return: The resolved ``Path`` for ``source``. + :rtype: pathlib.Path """ if not isinstance(name, str) or not name.strip(): raise ValueError("`name` must be a non-empty string.") @@ -101,6 +121,10 @@ def _validate_create_inputs( async def _upload_with_container_client(source: Path, sas_uri: str) -> None: """Upload ``source`` to the SAS container using ``azure.storage.blob.aio.ContainerClient``. + :param source: Local file or directory to upload. + :type source: pathlib.Path + :param sas_uri: SAS URI for the destination container. + :type sas_uri: str :raises RuntimeError: If ``azure-storage-blob`` is not installed. """ try: diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py index 4d27fc764d4e..e123b943af29 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch_models.py @@ -16,7 +16,7 @@ from pathlib import Path from typing import Any, Optional, Union -from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.core.exceptions import ResourceNotFoundError from azure.core.tracing.decorator import distributed_trace from ._operations import BetaModelsOperations as BetaModelsOperationsGenerated @@ -51,8 +51,13 @@ def _extract_pending_upload_targets( Foundry deployments rather than the SDK-modeled ``ModelPendingUploadResponse`` shape (``blobReference`` / ``pendingUploadId``). Tolerate both wire shapes so callers don't have to. + + :param response: The pending-upload response from the service. + :type response: ~azure.ai.projects.models.ModelPendingUploadResponse or dict + :return: A tuple of ``(sas_uri, container_blob_uri, pending_upload_id)``. + :rtype: tuple[str, str, str or None] """ - payload = response.as_dict() if hasattr(response, "as_dict") else dict(response) + payload = dict(response) if isinstance(response, dict) else response.as_dict() blob_ref = payload.get("blobReferenceForConsumption") or payload.get("blobReference") or {} sas_uri = (blob_ref.get("credential") or {}).get("sasUri") @@ -65,7 +70,14 @@ def _extract_pending_upload_targets( @staticmethod def _resolve_azcopy(azcopy_path: Optional[str] = None) -> str: - """Locate the ``azcopy`` executable or raise ``RuntimeError``.""" + """Locate the ``azcopy`` executable or raise ``RuntimeError``. + + :param azcopy_path: Optional explicit path to the azcopy executable. + Defaults to ``shutil.which("azcopy")``. + :type azcopy_path: str or None + :return: Absolute path to the resolved azcopy executable. + :rtype: str + """ azcopy = azcopy_path or shutil.which("azcopy") if not azcopy: raise RuntimeError( @@ -90,6 +102,23 @@ def _validate_create_inputs( Returns the resolved ``Path`` for ``source``. Raises ``ValueError`` for bad inputs and ``RuntimeError`` if ``azcopy`` cannot be located. + + :keyword name: Name of the model to register. + :paramtype name: str + :keyword version: Version identifier for the model. + :paramtype version: str + :keyword source: Local file or directory containing the model weights. + :paramtype source: str or os.PathLike[str] + :keyword azcopy_path: Optional explicit path to the azcopy executable. + :paramtype azcopy_path: str or None + :keyword wait_for_commit: Whether to poll for commit completion. + :paramtype wait_for_commit: bool + :keyword polling_timeout: Total seconds to poll for commit completion. + :paramtype polling_timeout: float + :keyword polling_interval: Seconds between poll attempts. + :paramtype polling_interval: float + :return: The resolved ``Path`` for ``source``. + :rtype: pathlib.Path """ if not isinstance(name, str) or not name.strip(): raise ValueError("`name` must be a non-empty string.") @@ -116,7 +145,15 @@ def _validate_create_inputs( @staticmethod def _run_azcopy(source: Path, sas_uri: str, *, azcopy_path: Optional[str] = None) -> None: - """Shell out to ``azcopy copy`` to upload ``source`` to the SAS container.""" + """Shell out to ``azcopy copy`` to upload ``source`` to the SAS container. + + :param source: Local file or directory to upload. + :type source: pathlib.Path + :param sas_uri: SAS URI for the destination container. + :type sas_uri: str + :keyword azcopy_path: Optional explicit path to the azcopy executable. + :paramtype azcopy_path: str or None + """ azcopy = BetaModelsOperations._resolve_azcopy(azcopy_path) if source.is_dir():